olamedia/nokogiri

Скрипт не может корректно обработать большой объём входного html.

KhArtNJava opened this issue · 7 comments

Привет.
Пытаюсь распарсить
http://ihtik.lib.ru/2011.07_ihtik_hudlit-ru/
Нужно выбрать все имена файлов.
Если делаю:
$elements = $saw->get('table[class=dirlistertable] tr')->toArray();
то падает с ошибкой
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 64 bytes) in /home/u1326/domains/khartn.name/public_html/dev/modules/nokogiri.php on line 217
.
Если же пытаюсь выполнить
$elements = $saw->get('table[class=dirlistertable] tr td:first-child')->toArray();
то падает в тайм-аут.

В первом варианте, когда не падает в тайм-аут, может стоило бы сделать вывод массива в файл, например, сериализовав его?
Тогда можно было бы избежать переполнения.
Или как-то разбивать данные, сбрасывая их на файловую подсистему.
Если есть ещё какие-то идеи - готов к обсуждению.

потестирую сейчас

Итак, 6Мб исходный документ, 28 Мб после get('tr'), 102 Мб после toArray().
В итоге рекомендую отказаться от ->toArray(), а вызвать ->toDom() и работать напрямую с ним, раз не предвидится больше памяти (по времени разница в одну секунду на разбор этих 6 Мб - 41 и 42 секунды)

Уточню почему:

  1. сам массив занимает дополнительное место.
  2. в массиве используются текстовые ключи для удобства (class, #text) доступа к тексту и атрибутам по их названию. так что массив занимает на порядок больше места.
  3. В данном случае получалось 75 тысяч элементов, на каждый из них массив с текстом и аттрибутами. В итоге около 60 Мб + 30Мб осталось в DOM в самой пиле.

Выбор стоит либо добавить памяти либо общаться напрямую с DOM

По таймауту действительно странно.
Сам xpath формируется вроде как верно: //table[@class='dirlistertable']//tr//td[1]
Если написать table[class=dirlistertable]>tbody>tr>td:first-child, то отрабатывает за те же 40 секунд с xpath //table[@class='dirlistertable']/tbody/tr/td[1] и 36 Мб

А на хостинге ограничение - 30 сек. :).
Вобщем, решил не заморачиваться и сделал всё на регулярках.
Отлетает за 1-2 секунды теперь.
P.S. Отказался от nokogiri - проект ещё слишком сырой и работает медленно.
Желаю удачи в допиливании библиотеки :).

set_time_limit() не катит?
P.S. скорость работы nokogiri сравнима со скоростью встроенных расширений DOM/libxml. Если говорите, что работает медленно, сравнивайте с аналогами.

strpos работает еще быстрее, может не стоило заморачиваться с регулярками? )

Touché ))).
set_time_limit() не катит... Отключён на хостинге.
А если сравнивать с другими аналогами, то да, nokogiri заметно быстрее парсит данные.
Но в любом случае стоит ещё поработать над nokogiri в плане оптимизации производительности...
Так, чтобы nokogiri могла без проблем обрабатывать такие вот файлы, как описано в данной заявке.