Использование одного патча Scrapy для нескольких веб-сайтов
Мне нужно создать настраиваемый пользователем веб-паук/искатель, и я думаю об использовании Scrapy. Но я не могу жестко закодировать домены и разрешать URL-адрес regex: es - вместо этого он будет настраиваться в графическом интерфейсе.
Как мне (как можно проще) создать паука или набор пауков с помощью Scrapy, где домены и разрешенные URL-адреса regex: es динамически настраиваются? Например. Я пишу конфигурацию в файл, и паук читает ее как-то.
Ответы
Ответ 1
ПРЕДУПРЕЖДЕНИЕ: этот ответ был для Scrapy v0.7, с тех пор паук-менеджер api сильно изменился.
Переопределите класс SpiderManager по умолчанию, загрузите свои пользовательские правила из базы данных или в другое место и создайте собственный паук с вашими собственными правилами/регулярными выражениями и доменным именем
в mybot/settings.py:
SPIDER_MANAGER_CLASS = 'mybot.spidermanager.MySpiderManager'
в mybot/spidermanager.py:
from mybot.spider import MyParametrizedSpider
class MySpiderManager(object):
loaded = True
def fromdomain(self, name):
start_urls, extra_domain_names, regexes = self._get_spider_info(name)
return MyParametrizedSpider(name, start_urls, extra_domain_names, regexes)
def close_spider(self, spider):
# Put here code you want to run before spiders is closed
pass
def _get_spider_info(self, name):
# query your backend (maybe a sqldb) using `name` as primary key,
# and return start_urls, extra_domains and regexes
...
return (start_urls, extra_domains, regexes)
и теперь ваш пользовательский класс пауков, в mybot/spider.py:
from scrapy.spider import BaseSpider
class MyParametrizedSpider(BaseSpider):
def __init__(self, name, start_urls, extra_domain_names, regexes):
self.domain_name = name
self.start_urls = start_urls
self.extra_domain_names = extra_domain_names
self.regexes = regexes
def parse(self, response):
...
Примечания:
- Вы также можете расширить CrawlSpider, если хотите воспользоваться своей системой правил.
- Для запуска использования паука:
./scrapy-ctl.py crawl <name>
, где name
передается в SpiderManager.fromdomain и является ключом для получения более подробной информации о пауках из бэкэнд-системы
- Поскольку решение переопределяет по умолчанию SpiderManager, кодирование классического паука (модуль python для SPIDER) не работает, но, я думаю, это не проблема для вас. Дополнительная информация о менеджере пауков по умолчанию TwistedPluginSpiderManager
Ответ 2
Вам нужно динамически создавать классы пауков, подклассифицируя ваш любимый общий паук-класс, предоставляемый подклассами scrapy
(CrawlSpider
с добавленным вами rules
или XmlFeedSpider
или любым другим) и добавив domain_name
, start_urls
и, возможно, extra_domain_names
(и/или start_requests()
и т.д.), так как вы получаете или выводите их из своего графического интерфейса (или файла конфигурации или что-то еще).
Python упрощает выполнение такого динамического создания объектов класса; может быть очень простой пример:
from scrapy import spider
def makespider(domain_name, start_urls,
basecls=spider.BaseSpider):
return type(domain_name + 'Spider',
(basecls,),
{'domain_name': domain_name,
'start_urls': start_urls})
allspiders = []
for domain, urls in listofdomainurlpairs:
allspiders.append(makespider(domain, urls))
Это дает вам список очень простых головоломок - вы, вероятно, захотите добавить к ним методы parse
, прежде чем создавать их. Сезон по вкусу...; -).
Ответ 3
Бесстыдная самореклама на domo! вам нужно создать экземпляр искателя, как указано в примерах, для вашего проекта.
Также вам нужно будет настроить искатель во время выполнения, который просто передает конфигурацию сканеру и переопределяет настройки во время выполнения, когда конфигурация изменилась.
Ответ 4
В настоящее время очень легко настроить скрипинг для этих целей:
-
О первых URL-адресах, которые вы можете посетить, вы можете передать в качестве атрибута при вызове паука с помощью -a
и использовать функцию start_requests
для настройки запуска паука
-
Вам не нужно настраивать переменную allowed_domains
для пауков. Если вы не включите эту переменную класса, паук сможет разрешить каждый домен.
Это должно закончиться чем-то вроде:
class MySpider(Spider):
name = "myspider"
def start_requests(self):
yield Request(self.start_url, callback=self.parse)
def parse(self, response):
...
и вы должны позвонить ему:
scrapy crawl myspider -a start_url="http://example.com"