Задача
На самом деле захотелось прикинуть — насколько реально перегнать Библиотеку, Чье Имя Нельзя Произносить Вслух, из fb2 в docbook. В связи со «специфичностью» FB2 надо прикинуть — какие теги можно просто пропустить ввиду редкости. Т.е. просто пересчитать количество вхождения каждого тега во все файлы.
По дороге планировалось сравнить разные sax-парсеры. К сожалению — тестирования не получилось, т.к. и xml.sax и lxml на первом же fb2 поломались. В итоге остался xml.parsers.expat.
Да, и еще — файлы *.fb2 упакованы в zip-архивы.
Исходные данные
Исходными данными является снапшот Библиотеки по состоянию на 2013.02.01, цельнотянутый из тор Интернетов: 242525 файла *.fb2 общим весом 183909288096 байт, упакованые в 56 zip-архивов общим весом 82540008 байт.
Платформа: Asus X5DIJ (Pentium DualCore T4500 (2×2.30), 2GB RAM); Fedora 18, python 2.7.
Код
Написано на скорую руку, с претензией на универсальность:
#!/bin/env python # -*- coding: utf-8 -*- ''' ''' import sys, os, zipfile, hashlib, pprint import xml.parsers.expat, magic mime = magic.open(magic.MIME_TYPE) mime.load() tags = dict() files = 0 reload(sys) sys.setdefaultencoding('utf-8') def start_element(name, attrs): tags[name] = tags[name] + 1 if name in tags else 1 def parse_dir(fn): dirlist = os.listdir(fn) dirlist.sort() for i in dirlist: parse_file(os.path.join(fn, i)) def parse_file(fn): m = mime.file(fn) if (m == 'application/zip'): parse_zip(fn) elif (m == 'application/xml'): parse_fb2(fn) else: print >> sys.stderr, 'Unknown mime type (%s) of file %s' % (m, fn) def parse_zip(fn): print >> sys.stderr, 'Zip:', os.path.basename(fn) z = zipfile.ZipFile(fn, 'r') filelist = z.namelist() filelist.sort() for n in filelist: try: parse_fb2(z.open(n)) print >> sys.stderr, n except: print >> sys.stderr, 'X:', n def parse_fb2(fn): global files if isinstance(fn, str): fn = open(fn) parser = xml.parsers.expat.ParserCreate() parser.StartElementHandler = start_element parser.Parse(fn.read(), True) files += 1 def print_result(): out = open('result.txt', 'w') for k, v in tags.iteritems(): out.write(u'%s\t%d\n' % (k, v)) print 'Files:', files if (__name__ == '__main__'): if len(sys.argv) != 2: print >> sys.stderr, 'Usage: %s <xmlfile|zipfile|folder>' % sys.argv[0] sys.exit(1) src = sys.argv[1] if (os.path.isdir(src)): parse_dir(src) else: parse_file(src) print_result()
Результаты
Заряжаем:
time nice ./thisfile.py ~/Torrent/....ec > out.txt 2>err.txt
Получаем:
* Время выполнения — 74’15..45" (параллельно выполнялась небольшая работа и слушалась музыка, ессно);
* Получилось, что скорость обработки — ~40 MB/s (или 58 тактов/байт)
* Отброшено 2584 файлов *.fb2 (expat хоть и non validate parser — но не до такой же степени…) — ~10%;
* в файле results.txt — чего только нет…
А быстрее — можно? На python.
ссылка на оригинал статьи http://habrahabr.ru/post/171447/
Добавить комментарий