Pull to refresh

Comments 16

У вас скорее всего возникнут проблемы с мониторингом на этапе реализации. На схеме он никак не связан с главными процессами, хотя может это проблема схемы)
Разделение этапов загрузки и проверки не имеет особого смысла, и уж тем более такая их последовательность. Судя по описанному в статье, вы сначала пытаетесь загрузить данные, а потом узнать можно ли это сделать (например проверка на 404 ответ сервера). Думаю можно вынести обработку случаев, отличных от успешного получения данных. Но сами проверки совместить с модулем загрузки.

Что касается нестандартных ситуаций, то их очень много. Но при этом получение страницы для установки куков принципиально не отличается от получения любой другой страницы.
Поэтому я бы посоветовал придумать миханизм, который позволит управлять логикой поведения модуля загрузки. Обычно ситуации с капчами и куками выглядят как зависимость одной страницы от другой. И когда будет происходить загрузка, то система должна знать об этой зависимости и выполнять дополнительный запрос. Это немного портит идею того, что загружать за раз можно только одну сущность(страницу, файл, и тд). Но это упростит архитектуру и реализацию. Меньше точек нужно будет мониторить.

Интересно как вы подойдете к реализации. Я подобную систему разрабатывал в одном из проектов,. там у меня схожие принципы применялись. Как раз вот готовлю статью на эту тему.

Спасибо за развёрнутый комментарий.

Вы правы, что модуль мониторинга должен быть связан с остальными модулями, но схема верхнего уровня, поэтому обозначена основная роль — взаимодействие с пользователем: предоставление информации по результатам обработки и инициализация новых итераций. Совсем не показан процесс получения новых заданий для загрузки, но это лишь усложнило бы схему, при этом архитектура принципиально не изменилась бы.

Обычно ситуации с капчами и куками выглядят как зависимость одной страницы от другой. И когда будет происходить загрузка, то система должна знать об этой зависимости и выполнять дополнительный запрос.
В схеме старался максимально уменьшить каждый блок, а также сделать некоторый стандартный набор, который можно будет повторно использовать с помощью минимальной параметризации для другого сайта. Модуль загрузки универсален и может быть единым для всех сайтов.

Модуль загрузки не должен принимать решение о специальных действиях, вроде авторизации на сайте, поскольку параллельно идут и другие запросы к этому же сайту. Если каждый будет авторизовываться, то это просто в два раза увеличит количество запросов, а также приведёт к сомнительной активности в логах сайта.

Хочу отметить, что блоки 1-3 очень тесно связаны между собой. Модуль проверки, фактически, должен выполняться моментально после загрузки, скорее всего, это будет простой callback, но считаю верным их разделить логически.

О зависимостях страниц думал в контексте сохранения ссылки для проверки, не потерялась ли она. Вы натолкнули меня на мысль, что необходимо добавить ещё chain и в модуль загрузки.

Интересно как вы подойдете к реализации. Я подобную систему разрабатывал в одном из проектов,. там у меня схожие принципы применялись. Как раз вот готовлю статью на эту тему.
Вашу статью с интересом прочитаю. Сейчас планирую подойти к реализации максимально просто. У меня есть набор скриптов (на Node.js), которые отлично занимаются загрузкой, но любая ошибка приводит к множеству дополнительных действий на исправление логики, а также времени на повторную загрузку. Начну с более чёткого деления на модули и некоторого обобщения внутренних структур.

Самым неприятным для реализации сейчас представляется модуль обновления и структура хранилища. Мне хочется, чтобы платформа сама позволяла хранить различные именованные сущности, причём с поддержкой версий.

P.S. Где-то надеялся, что уже есть готовое решение, поэтому можно будет обойтись без собственной разработки.
Самым неприятным для реализации сейчас представляется модуль обновления и структура хранилища. Мне хочется, чтобы платформа сама позволяла хранить различные именованные сущности, причём с поддержкой версий.


Ну с обновлениями не так страшно, просто по расписанию ставить задачи для повторного сбора. Тут конечно подумать над вариантами обновлений, просто страницу обновлять или же писать историю полную. А для хранения данных могу посоветовать MongoDB использовать.

Во-первых как минимум на этапе сбора страниц оно удобно, потому что вы просто пихаете контент и заголовки в виде json-документа в коллекцию. То есть получается веб-страница = документ в монге.

Во-вторых свободная структура будет удобна для множества ситуаций с парсингом, потому что наверняка структура данных для страниц форумов будет отличаться от новостных сайтов. Таким образом у вас на каждом этапе, где нужно сохранять данные, будет абстракция «хранилище» о которой особо заботиться не нужно в этом контексте — просто помещаем туда документы.

Конечно есть обратная сторона. Нужно описывать структуру документов отдельно, потому что со временем хаос начинается. Хотя можно строго изолирвать код, который работает с конкретным «типом» документов, тогда знание о конкретной структуре будет в одном месте.
Если каждый будет авторизовываться

Аутентифицироваться все же. Каждый раз делать это вовсе не обязательно. Парсер всегда может определить факт входа по содержимому страницы. Так же модуль загрузки должен если не сам знать, то хотя бы знать кого дернуть, что бы решить, можно ли загружать следующую страницу или нет. Поэтому совсем элементарным его сделать не получается.
Реализовывал подобную систему на java, основываясь на crawler4j — правда пришлось его полностью переписать, слишком он был ограничен на тему сложной логики поведения, для выборки контента использовал boilerpipe, данные хранил в hsqldb+hibernate для полнотекстового поиска использовал lucene, модули для анализа контента и сайт-специфичной логики писались на DSL, основанном на groovy. Кластеризация инстансов на базе hazelcast. В случае необходимости разбора страницы с выполнением js-кода, это производитлось headless-браузером, управляемым через Geb. Вообще для такой задачи мне java кажется куда более привлекательной, чем node.js — лучше проработана многопоточность, есть множество инструментов для распараллеливания и кластеризации.
Мне кажется, у вас на схеме слишком сильно разделены модули, которые по логике будут сильно связаны и не видно места для какой-то более сложной логики поведения чем «есть список задач, прошёлся, получил каждую, разобрал, сохранил». Поведение бота на сайте — поведенческий алгоритм, ему далеко не всегда нужно грести всё подряд.
Я решал подобную задачу (и продолжаю решать) следующим образом:

1. Скрипт для PhantomJS выкачивающий и сохраняющий нужные страницы + авторизация + обработка капчи. Можно на Selenium — у него вроде возможностей побольше.
2. Модуль парсинга на Perl
3. Обвязка на Perl для получения заданий из очереди, отправки событий мониторинга в специальный сервис, сохранение метаданных результатов парсинга в БД, отправка в очередь уведомлений о завершении заданий

Исходники полученных страниц хранятся в s3 чтобы можно было запустить процесс репарсинга.

Все это работает на aws и масштабируется на любое количество машин простым запуском дополнительных инстансов из базового образа.
1. Не больше. Ровно столько, сколько может выполнить сам PhantomJS.
Всё это давно, надёжно, гибко, модульно, масштабируемо реализовано в Scrapy.
На Scrapy смотрел, но меня смутили два момента. Во-первых, предварительное определение Item, то есть структур данных, что вносит дополнительные неудобства в «быстрый старт», а также нет уверенности, что последующее добавление полей не приведёт к ликвидации уже собранных данных. Во-вторых, не нашёл информации об инкрементальном обходе. В-третьих, нет информации о возможности проведения отдельно от загрузки. Каким образом можно запустить вначале только загрузку, а потом парсинг с обновлёнными скриптами?

К сожалению, примеров реализации более-менее сложных проектов не нашёл. Для простой скачки меня вполне wget устраивает. Парсинг страниц смогу без проблем написать. Вы можете проконсультировать по поводу правильной настройки Scrapy, чтобы он полностью скачал phpBB форум и умел докачивать новые темы и сообщения (без полного обхода всего сайта)?
Насчет повторного обхода и разделения парсинга/загрузки — можно просто кэш включить. Правила кеширования там вполне гибко настраиваются — если стандартные не устраивают, можно свой «policy» написать. Стандартные — dummy и RFC2616: github.com/scrapy/scrapy/blob/master/scrapy/contrib/httpcache.py

Для рестарта там есть doc.scrapy.org/en/latest/topics/jobs.html — правда, сам не пользовался. См. также github.com/scrapinghub/scrapylib/blob/master/scrapylib/deltafetch.py. Мы у себя кастомную мидлварь используем, которая очередь запросов в HBase держит.

Добавление полей не приведет к ликвидации собранных данных, т.к. данные по дефолту никуда не сохраняются :) В scrapy есть возможность настраивать, куда и как данные сохранять (с помощью Item Exporters или мидлвари), и есть несколько дефолтных способов экспорта (json, csv, xml). Мы у себя все автоматом в HBase складываем (раньше монга была), + внутренняя админка к этому. Ну как внутренняя, за деньги клиенты на этой всей инфраструктуре своих спайдеров могут запускать.

C Item'ами удобно — понятно, какой на выходе будет json или csv, например. Если нужны совсем неструктурированные данные (на самом деле это большая редкость), то создать Item c полем data, да и все. Или совсем их не использовать — никто не мешает в обработчике делать с извлеченными данными что угодно, сохранять их в базу, например, или сразу в csv файл дописывать.

Чтоб парсить jsvascript, мы с одним из авторов Scrapy делаем велосипед: github.com/scrapinghub/splash. Это сервис на PyQT4 / webkit / twisted, который к scrapy никак не привязан, но позволяет через HTTP API выполнять js на сайтах, получать результаты вычислений, получать html и делать скриншоты. Подход немного не такой, как в phantomjs и т.д.; иногда может быть удобнее, иногда нет; вроде должно работать быстрее — можно считать, что на каждый запрос к сервису вкладка браузера открывается, все параллелится средствами webkit.

У Scrapy, как мне кажется, есть одна довольно серьезная проблема — это туториал. Там все очень запутанно, и не с той стороны объясняется: ни слова про метод start_requests, например. Это в рамках туториала на этом PyCon US поправится, скорее всего.
Огромное спасибо за пояснения.

К сожалению, сложилось впечатление, что получается «каша из топора», поскольку за всеми дополнениями уже почти не видно самого scrapy, а интеграцию «бесшовной» вряд ли назовёшь.

На Python программирую «со словарём», поэтому правильная настройка и подбор всех составных частей может занять некоторое время. В ходе поиска приемлемой документации по созданию решения сложнее «Hello, world!» наткнулся ещё на Grab:Spider habrahabr.ru/post/142212/, который выглядит более простым, чем scrapy.

Сейчас думаю, что набросаю первую версию платформы для решения своих конкретных задач. После этого смогу уже помериться с другими решениями.
Архитектура в целом стандартна и рабочая, во всех решениях вроде Scrapy подобным образом и сделано, поэтому еще раз подумайте, настолько ли уж вам необходимо писать свой велосипед.

P.S. И мне очень режет слово «интеллектуальный», так как ничего интеллектуального в этом нет. Так же как это не имеет никакого отношение к Data Mining (имеет лишь косвенное отношение к Data Extraction, но никак не Data Mining)
Scrapy исполняет клиентский JS код?
Вы упомянули «все решения вроде Scrapy», а можете привести несколько примеров подобных решений? При поиске натыкался только на Scrapy, если не принимать во внимание поисковики вроде Xapian, Nutch и Solr.

Для меня самого более привлекательным выглядит вариант использования готового решения. В статье привёл семь основных требований к платформе, при этом для разбора нового сайта мне потребуется лишь реализовать парсинг страниц, причём в итерационном режиме. В качестве неплохого критерия предлагаю парсинг форума phpBB. Это должно быть простой задачей, требующей от меня лишь разбора страниц. Если знаете подходящее решение, то дайте, пожалуйста, конкретные рекомендации к реализации.

Частично соглашусь по поводу Data Mining и Data Extraction, но тут очень субъективно, особенно, если учесть, например, обогощение данных при обновлениях.

Паук, который умеет разбирать уже ранее скаченные документы является более продвинутым, чем тот, который этого не умеет. Аналогично с возможностью загрузки дополнительных данных и дополнению ранее полученных. Для измерения интеллекта Интернет-пауков давайте введём понятие «коэффициента интеллекта» аналогично человеческому. Тогда надо взять всех Интернет-пауков, оценить их по критериям (семь уже предложил, можем взять и другие), после чего построить нормальное распределение и можно уже оценивать интеллект. Если учесть количество простейших пауков, то ИнКр будет среди них интеллектуалом. Вам проще всего привести примеры более продвинутых вариантов, которые доступны для использования.
Паук, который умеет разбирать уже ранее скаченные документы является более продвинутым, чем тот, который этого не умеет.

Паук который качает данные, а потом их парсит правилами которые для него написал человек, не может считать «интеллектуальным». Он просто представляет собой этак механизации. Более продвинутый вариант это все же тот, который сам может провести анализ незнакомого ресурса и самому себе написать правила.
Sign up to leave a comment.

Articles