Способы создания заданий¶
Spider это по сути набор функций-обработчиков сетевых запросов. Каждый обработчик в свою очередь может создать новые запросы или просто сохранить куда-либо данные. Каждый запрос описывается Task-объектом. Паук добавляет каждый новый запрос в очередь и выполняет его по мере освобождения сетевых ресурсов. Каждому Task-объекту присваиваетя имя. Когда становится доступен результат сетевого запроса, то с помощью этого имени определяется имя функции-обработчика и вызывается эта функция.
Например, если мы создадим задание с именем “contact_page”, то мы должны будем объявить в нашем классе паука метод c именем “task_contact_page”:
...
self.add_task(Task('contact_page', url='http://domain.com/contact.html'))
...
def task_contact_page(self, grab, task):
...
Имя функции-обработчика определяется так: берётся имя задания и добавляется префикс “task_”.
Рассмотрим различные способы создания Task-заданий.
initial_urls¶
В атрибуте паука initial_urls Можно указать список адресов, с обработки которых паук должен начать свою работу:
class ExampleSpider(Spider):
initial_urls = ['http://google.com/', 'http://yahoo.com/']
Для всех адресов, перечисленных в initial_urls будет создано задание с именем ‘initial’. Это самый простой способ создания заданий, вы не можете управлять ничем кроме адресов запрашиваемых документов.
task_generator¶
Более сложный способ создания начальных заданий. Метод с именем task_generator должен являться python-генератором т.е. функцией выдающей множество значений с помощью инструкции yield. Spider будет обращаться к новым задания из task_generator каждый раз, когда его очередь будет опустошаться. Это позволяет не опасаться того, что вы создадите слишком много заданий. Выглядит это так: в начале работы паук извлекает некоторое количество заданий с помощью task_generator и помещает их в очередь, далее он выполняет запросы и следит за количеством заданий в очереди. Как только их становится слишком мало, паук обращется ещё раз к task_generator и добавляет новые задания.
К примеру, вы можете открыть файл с миллионом записей и последовательно читать строки из него, создавая всё новые и новые задания:
class ExampleSpider(Spider):
def task_generator(self):
for line in open('var/urls.txt'):
yield Task('download', url=line.strip())
add_task¶
Независимо от того, каким способом вы создали новое задание, в очередь заданий оно попадёт с помощью метода add_task. В случае использования intial_urls или task_generator метод add_task будет вызван неявно, но вы, конечно, можете использовать его напрямую, чтобы добавить новое задание в любом месте выполнения программы. Это можно делать даже до начала работы паука. Например:
bot = ExampleSpider()
bot.add_task('google', url='http://google.com')
bot.run()
yield¶
Инструкцию yield для создания заданий вы можете использовать в двух местах, во-первых, в методе task_generator, о чём уже писалось выше, во-вторых, в любой функции-обработчике результата. При вызове функции-обработчика Spider ловит все задания, которые она генерирует и складывает в очередь заданий. Создание заданий с помощью yield ничем не отличается от использования метода add_task, разве что запись получается более короткая:
class ExampleSpider(Spider):
initial_urls = ['http://google.com']
def task_initial(self, grab, task):
# Google page was fetched
# Now let's download yahoo page
yield Task('yahoo', url='yahoo.com')
def task_yahoo(self, grab, task):
pass
Резюме¶
Для задания начальных заданий используйте атрибут initial_urls, если вам нужна более сложная логика создания начальных заданий, используйте метод task_generator. Для создания заданий внутри функций-обработчиков используйте инструкцию yield. Использовать метод add_task напрямую вам практически никога не понадобится.
Есть также ряд методов для типичных случаев генерации новых заданий: обработка пагинации, обработка списка ссылок. Смотрите модуль grab.spider.pattern.