Как стать автором
Обновить

Комментарии 43

Ну вот теперь вы меня заинтересовали :) Еще бы (py)curl из зависимостей убрать — было бы вообще шикарно :)
Хорошо, что вы комментарий написали, а то тут так пусто :)
Curl я почти выпилил уже. Ну из Grab то его, допустим, можно лего вытащить и юзать urllib, сейчас транспорт почти готов. А вот из Spider вытащить то я уже вытащил, но альтернативой пока что может служить только пул тредов (или процессов) а это значит, что собо много потоков нельзя будет запустить — cpu убьётся или память. В общем, я эти фичи щас попиливаю потихоньку. Чувствую, где-то в течении месяца уже работающие вещи будут.
можно еще твистед по идее заместо multicurl юзать
Еще есть gevent, который можно использовать напрямую или пропатчить им urllib
Вобщем как только — так сразу на ваш фрэймворк со Scrapy перейду :)
а в чем проблема с pycurl? все равно придется что-то использовать или его или Twisted (как в scrapy)
Проблема в том что он требует curl, который на некоторых хостингах не поставить, ибо не в sudoers
Вопрос может не совсем в тему. Но колебаюсь сейчас взять Grab или искать(писать) аналоги.
Так вот вопрос:
Есть ли замеры по производительности/нагрузке? Особенно когда нужно грабить большой объём страниц и большой объём данных на каждой странице.
Ну и так же каковы пожелания по аппаратной составляющей сервера, на котором всё это будет крутится (под большие объёмы, постоянного граббинга).
Неа, пока каких-то инструментов для сравнения нету. Библиотека пишется спонтанно. Естественно, если вы будете писать своё решение, то будучи заточенное под задачу он будет быстрее Grab работать.
Пожелания по железу. Используя асинхронность вы скорее всего упрётесь раньше в CPU или жёсткий диск или в канал. Также учтите что для парсинга Grab использует только одно ядро.
Ограничение GIL'a?
Как это? У вас же программа асинхронно выполняется, откуда там GIL?
Тогда откуда ограничение на одно ядро?
Ну, оттуда. Вот запустили вы парсер, он работает на одном ядре :)
Один процесс — одно ядро. Чтобы работал на нескольких ядрах, одного желания мало. Надо ещё писать код, который будет синхронизироать работу нескольких процессов.
а, ну вот я про это и говорю…
То есть очередей нет, и процессы не спаунятся?
Очередь есть, но пока она как просто хранилище заданий в памяти работает. Если вынести очередь в какой-нить мемкэшед или редис, то уже по идее с некоторыми предосторожностями можно запустить несколько спайдеров. Ну, это один из будущих шагов рефакторинга. Выделения очереди как отдельного слоя архитектуры и различные бэкенды для очереди.
ну стандартно — Redis, Celery…
Вообще конечно хотелось бы на кластере научиться запускаться %-)
Учитывая, что точка входа для парсинга обычна одна (к примеру, главная страница) ну или же как минимум известно, что парсим (т.е. понимаем структуру и логические связи в данных на странице), то распалить задачу парсинга на Х нод становиться довольно просто. Я к тому, что какого-то особого слоя архитектуры тут не требуется. Поясню пожалуй на примере парсинга каталога товаров.

Есть начальная страница каталога на которой есть меню первого уровня. Есть знание того, каким образом на внутренних страницах можно выцепить ссылки на подразделы каталога что бы спускаться вниз по иерархии. Есть центральная нода которая непосредственно не занимается, есть куча нод которые и ходят по сайту. Центральная нода оправляет на любую из подчиненных задание скачать начальную страницу, выдергивает из её контента ссылки на подкатегории первого уровня и оправляет задание на рекурсивное скачивание подчиненным. Причем подраздел только на одну ноду, т.е. один подраздел не может скачиваеться двумя нодами. Если следовать этому правилу, то отпадает необходимость синхронизации. А поскольку мы знаем структуру входных данных, то уходя вниз рекурсивно по иерархии подчиненые ноды ни когда не уходят на «левые» ссылки и идут четко по дереву. Ситуация, когда две ноды скачали одну страницу вполне возможна если на сайте есть ошибки (две разных ссылки ведут по сути на одну страницу), но это не проблема, кроме того такие ошибки вполне отлавливаемые ибо мы знаем структуры данных которые мы парсим.

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

Наверное стоит отдельно упомянуть на чем это имплементировал я. А сделано это на PHP. Причем код мастер ноды и рабочих нод один и тот же. А кто в кластере будет мастером регулируется через конфиги. На каждой ноде есть файл конфига где описаны реквизиты для связи с остальными нодами и роль этой ноды в кластере. В качестве правил для парсера используются XPath инструкции. Схема удобная тем, что позволяет развернуть кластер на базе банального шаред хостинга.
> Центральная нода оправляет на любую из подчиненных задание скачать начальную страницу, выдергивает из её контента ссылки на подкатегории первого уровня и оправляет задание на рекурсивное скачивание подчиненным.

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

> Причем подраздел только на одну ноду, т.е. один подраздел не может скачиваеться двумя нодами.

Я разрабатываю универсальное решение — у сайта вообще не может быть структуры, самого сайта не может быть, может быть просто список ссылок например или на сайте может не быть разделов. Что угодно может быть.
Имхо, универсальные решения слишком много ресурсов требуют на разработку. И если их пилить, то на постоянке. Напилить группу парсеров каждый из которых решает свою задачу, как показывает мой опыт, проще, в том числе и на будущем сапорте кода. Что не исключает наличия некоего универсального парсера-объекта через API которого и идет взаимодействия наружу. Он просто инкапсулирует в себе эту группу. Единственное неудобство, нужно явно в конфиге указывать, какого типа контент тянем.
> Имхо, универсальные решения слишком много ресурсов требуют на разработку. И если их пилить, то на постоянке. Напилить группу парсеров каждый из которых решает свою задачу, как показывает мой опыт, проще, в том числе и на будущем сапорте кода.

У меня несколько более глобальная задача. Содать универсальное решение, создать community-вокруг него. Сделать экосистему для библиотеки и компании grablab, которая занимается парсингом сайтов.
Глобально. Это радует. Особенно на фоне того, что в среднем по больничке все как-то уныло. Удачи в этом начинании!
Спасибо. Есть и приятные примеры. Вон парни, которые пилят scrapy, какой-то стартап замутили связанный с запуском scrapy-пауков — инвестирования собирают.
Пару недель назад грабил несколько тысяч порнороликов с туб-сайта.
Сервер с 1гигабитным каналом — 8гигабайт памяти, все ок (20 потоков), запускал на сервере с 4я гигабайтами — бывало вылетал (не хватало памяти).

Объем страниц парсил «за раз» в районе одного миллиона (каталог софта) — никаких проблем (кроме того что они места занимают немало).

Замеры, хочу попрбовать сравнить Scrapy vs. Grab, но это скорее всего на следующей неделе, а то мы уже задолбали тут наверное всех с этим grab'ом )
Вылетал, наверное, потому что ты там слишком много заданий в очередь добавлял.
Замеры, хочу попрбовать сравнить Scrapy vs. Grab, но это скорее всего на следующей неделе
Действуйте. Интересно будет почитать.
Хорошая статья, хотя и не пользуюсь Grab, сохранил на будущее.
Хотелось бы также видеть статьи по ещё одному парсеру — Scrapy, его документация, увы, не раскрывает всех подробностей его работы.
Scrapy != parser.
Scrapy == crawler.

И статья на Хабре есть.
И статья на Хабре есть.
Всего одна! И я уже её неоднократно читал. Хочу moar статей!
Скрапи очень быстро меняется… Проще на практике изучать. Единственная асболютно неудобная вещь в нем — pipelines. Вообще непонятно зачем она существует, если в нее срут все пауки. Если бы был маппинг по Item() — было бы лучше…
Я в граб в начале одну сущность сделал, впрочем она и сейчас есть, но оказалось что она ненужная. Можно из функци-обработчика сделать не yield Task(name), а yield Data(name) (ещё один спецкласс) и тогда Spider вызовет функцию `def data_` в которой можно сохранить куда-надо данные. Возможно при разработке многоядерной-многомшинной архитектуры это подходет будет более важен, а пока можно прямо из любого обработчика ответа сохранять данные, что как-то проще, чем ещё дополнительные функции городить.
Проще делать как в djcelery, оборачивая каждый таск декоратором.
Что за декоратор такой?
@task(delay)
def task_initial(self, grab, task):
    return/yield result
Не знаю, я вообще не люблю декораторы использовать, как-то уродливо выглядят. В данном случае декоратор будет бесполезен т.к. функция-обработчик может yieldить результаты разных типов для которых нужны разные обработчики.
Простите, перепутал ветку. Это к очередям относится.
А про разные типы данных — просто по неймингу классов ориентироваться, и указать в гайде: ASpider(Spider), AItem(Item), APipeline(Pipeline), etc…
Проще на практике изучать.
С этого момента поподробнее, пожалуйста.
zalil.ru/33094662
На правильность не претендую…
habrahabr.ru/users/seriyPS/ трясите с него, он вроде юзает активно scrapy :)
А, так вот чего…
Ну не знаю, я лично в свое время открыл doc.scrapy.org/en/0.14/intro/tutorial.html и сделал по образу и подобию. Может у меня мозг как то по особому устроен, но никаких проблем не встретил, документация у Scrapy очень подробная.
Единственное с чем постоянно приходится бороться так это с сохранением результатов в базу данных и постобработкой данных. Если делать это в Pipeline с применением ресурсоемких операций или блокирующего IO (сохранение в MySQL/Postgres с проверкой «а не сохранено ли уже» например), то будут тормоза и 100% процессора на нем не выжмешь. В последнем проекте прикрутил неблокирующий AMQP и отдельных воркеров — сохранятелей… Уперся в CPU, и это хорошо)
А как Spider'у выставить значение User-agent?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации