Честно говоря, иногда подумываю написать обёртку для регекспов, какой-нить облегчённый xpath. Просто бывает, когда надо парсить миллионы страниц, xpath слишком медленный, вернее само построение DOM-дерева.
SAX непременим для разбора невалидных XML. Все сайты невалидные. Чтобы получить валидный XML из битого HTML, нужно затратить усилия, сравнимые с построением DOM-дерева. Поправьте, если я ошибаюсь.
А та же ситуация будет ведь и для регекспов и, тем более, для xpath? Честно говоря, вам должно быть виднее.
В дотнете есть библиотека HtmlAgilityPack, там, например, незакрытые теги HTML4 (даже br) увеличивают степень вложенности следующих за ними. Это к вопросу о затрачиваемых усилиях.
А что регекспы? Регекспу /<div[^>]*>([^<]+) абсоюлтно пофиг, какой документ, валидный или нет, он просто ищет текст внутри div-тэга.
Вся сложность с регекспами в том, что очень сложно описать вложенные тэги. Банальное xpath выражение "//div/div" с помощью регкспов описывается монстрообразным (не проверял):
Написание своей обертки для xpath приведет к написанию… xpath! Причем скорее всего менее расширяемого и, возможно, более тормозного. Так зачем?
Есть отличный инструмент в виде xpath, есть различные библиотеки реализующие работу с ним, смысла изобретать своё нет и в данном случае, имхо, разумнее масштабироваться горизонтально. И тогда не важно, что конкретный разбор идет долго (что делать, за гибкость xpath нужно платить), главное разбросать это на Х параллельных работ.
> Написание своей обертки для xpath приведет к написанию… xpath! Причем скорее всего менее расширяемого и, возможно, более тормозного. Так зачем?
Регекспы работают очень быстро. Естественно не нужно заново изобретать xpath, достаточно очень простого синтаксиса, чтобы описать пару самых распространнённых случаев:
1) найти тэг с заданным class/id
2) найти тэг с заданным class/id, у родителя которого заданный class2/id2
3) У тэга из 1 и 2 получить аттрибут какой-нибудь
4) У тэга из 1 и 2 получить содержимое.
Не нужна расширяемость, нужна быстрая реализация простых паттернов.
Горизонтальное масштабирование хорошо, когда есть под рукой облако, желательно бесплатное :) В этом направлении я тоже копаю постепенно, например, щас в grab:spider можно разбить выполнение задачи по ядрам, но особого прироста это не даёт, двукратное ускорение на моём четырёхядерном-athlon. Да и ещё оказалось, что модуль multiprocessing не шибко удобная штука, распараллеливание по сети в нём вроде как вообще нету. Думаю посмотреть в сторону какого-нить pyro
Приведенный примеры действительно хорошо партируются на регекспы и работают быстрее (у меня в среднем где-то в раз 8-10 работали). Тут не поспоришь. Только вот чаще всего на практике они полезны в очень небольшом спектре задач. А для парсинга чаще всего как раз нужен механизм хитрых вытаскиваний которых на регекспах 1) ужасны (в плане вида и сложности, как следствие сложность супорта такого кода); 2) содержат ошибки которые могут проявится не сразу.
Под масштабированием я понимаю раскидку задачи по нескольким хостам. Не важно, как долго страница грузиться на отдельном хосте, важно, что таких хостов много и в сумме они могут достаточно быстро лить обработанные данные на агрегирующий сервер (который по сути выполнят роль менеджера задач + БД для сохранения результатов).
Лично я для парсера выбрал PHP. Можно накупить дешевого харед хостинга. Загрузку и обработку данных можно делать на них, агрегирующий сервер может быть уже любым. В виде плюшек получаем: «скрытый» парсер (т.е. «снаружи» агрегирующий сервер не видно, а хосты шаред хостинга легко добавляются/удаляются, так что IP адрес самого парсера не палится и не может быть забанен), возможность быстрого горизонтального масштабирования.
Извиняюсь, но тогда нахрена такой хостинг нужен? С него же тогда даже банально курс валют не получить, RSS не прочесть и ни какой внешний API в духе вконтакте или твиттера не получить. Так что нет, ни чего не отрубают, curl (или другие механизмы достучаться из скрипта наружу) есть на многих. А у кого нет, это не хостинги.
А отрубают за спам, за большую нагрузку на БД ну и в целом по ситуации. Если не наглеть, то жить вполне себе в их условиях можно.
Вполне возможно, что под парсингом вы подразумеваете какую-нибудь более узкую задачу.
Универсальную библиотеку для парсинга HTML на регэкспах сделать впринципе невозможно. То есть, если у вас стоит задача в рамках одного проекта извлекать информацию из разнородных документов, то вам нужно что-то более для этого приспособленное.
Если же нужно из пары страниц с известной структурой вытащить, например, все ссылки, то регекспами пользоваться можно и иногда даже нужно.
Cмотря, что называть принципиальным отличием. С высоты птичьего полёта — та же петрушка. А если смотреть оооочень детально, то в двух разных минорных версиях Scrapy можно найти принципиальные отличия :)
Увы, не могу ничего вам обещать. Но есть пример: мы с товарищем по grablab вместе занимаемся парсингом, он сначала использовал scrapy, а потом как-то не могу побороть один баг, попробовал grab:spider, да так на нём и остался. Причём он его без всякой документации юзает т.к. по сути там апи не сильно сложный.
Архитектура у обоих фреймворков одинаковая: пишем функции для обработки ответа от сервера, внутри функции можно порождать новые запросы. В данный момент в grab:spider нет никаких фишек для деплоя — я беру файл, называю его spider.py и фигачу туда всю логику, затем я запускаю его через команду python spider.py — вот и весь деплой :) В принципе, довольно удобно, в скрапи меня напрягала вся эта возня с проектами, с настройками, с пайплайнами. В спайдере нету пайплайнов, куда хотим — туда и пишем ручками… Я пишу в mongodb обычно.
В spider есть одна фича — не знаю, есть ли она в scrapy. Эта фича сильно обгечает отладку парсинга и повторный парсинг. Все GET-запросы кэшируются в монгодб. Очень-очень удобно :)
за день? ) пара примеров и все ясно, xpath и там и там один и тот же, общие принципы работы тоже. мне как-то пришлось несколько пауков переписывать (scrapy->grab), управился за пару часов.
кстати есть конференция в жаббере, я думаю там с радостью ответят на возникающие вопросы =)
использовал scrapy достаточно продолжительное время, grab понравился больше.
тому есть множество причин, например скорость парсинга в грабе у меня получается на порядок (!!!) выше. ну и он проще, больше контроля. если скрапи это как бы django в мире парсинга, то grab — это flask ) как-то так.
на скрапи канешно много всего — всякие фишки для деплоя, получение информации о работе пауков. но мне это (да и обычному программисту) чаще всего не нужно.
к плюсам граб можно отнести то что он на 100% проверен в деле т.е. бро itforge писал/дописывал зачастую параллельно с какими-то проектам которые на полную использовали функционал библиотеки, поэтому она получилас весьма удобной и продуманной до мелочей.
Я так понял JavaScript в пролете? Если так, то очень жаль.
Сейчас бывает порой, пол сайта генерит JavaScript. Сам пользуюсь Mechanize или Selenium там где много скриптов, но далеко на нем конечно не уедешь.
> или это для каких-то других целей сделано?
`g.search`, по-умолчанию, работает с уникодом и ищет в unicode-представлении документа. То есть вам не нужно думать, в какой кодировке документ, вы можете всегда исползовать unicode-аргумент для поиска. Если же вы хотите искать таки байтовую строку, то нужно передать дополнительный аргумент `byte=True`, тогда поиск будет происходить в `g.response.body`.
Насчет urllib с этой либой есть проблемы в транспортной части, она не может подключится к ряду сайтов. Например wikipedia.org Поэтому использую grab, с ним еще проблем не возникало.
С urllib всё в порядке. Просто для подключения к википедии надо указывать реальный User-Agent. Возможно что-то ещё, я давно не заморачиваюсь такими вещами т.к. в Grab все нужные заголовки генерируются.
Документация по Grab — библиотеке для парсинга сайтов