Правила Scrapy, обратный вызов для позволенных доменов и другой обратный вызов для запрещенных доменов - PullRequest
2 голосов
/ 26 марта 2019

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

Я использую следующие правила:

rules = [Rule(LinkExtractor(allow=(), deny_domains = allowed_domains), callback='parse_denied_item', follow=True),
Rule(LinkExtractor(allow_domains = allowed_domains), callback='parse_item', follow=True)]

Обычно я хочу, чтобы parse_item вызывался всякий раз, когда есть запрос от allowed_domain (или субдомена одного из этих доменов). Затем я хочу, чтобы parse_denied_item вызывался для всех запросов, которые не занесены в белый список allowed_domains.

Как я могу это сделать?

Ответы [ 2 ]

2 голосов
/ 26 марта 2019

На основании ответа Галласио. Альтернативным вариантом является использование process_request из Rule. process_request захватит запрос до его отправки.

Насколько я понимаю (что может быть не так), Scrapy будет сканировать только домены, перечисленные в self.allowed_domains (при условии, что он используется). Однако, если на очищенной странице встречается внешняя ссылка, Scrapy в некоторых случаях отправляет один запрос на эту внешнюю ссылку [1]. Я не уверен, почему это происходит. Я думаю, что это возможно, потому что целевой сайт выполняет перенаправление 301 или 302, и сканер автоматически следует этому URL. В противном случае, это, вероятно, ошибка.

process_request может использоваться для выполнения обработки запроса перед его выполнением. В моем случае я хотел регистрировать все ссылки, которые не сканируются. Поэтому я проверяю, что разрешенный домен находится в request.url, прежде чем продолжить, и регистрирую любые из тех, которые не являются.

Вот пример:

rules = [Rule(LinkExtractor(), callback='parse_item', process_request='process_item', follow=True)]

def process_item(self, request):
    found = False
    for url in self.allowed_domains:
        if url in request.url:
            #an allowed domain is in the request.url, proceed
            found = True

    if found == False: #otherwise log it
        self.logDeniedDomain(urlparse(request.url).netloc)

        # according to: https://docs.scrapy.org/en/latest/topics/spiders.html#scrapy.spiders.Rule
        # setting request to None should prevent this call from being executed (which is not the case for all)
        # middleware is used to catch these few requests
        request = None

    return request

[1]: Если вы столкнулись с этой проблемой, то, по-видимому, используйте process_request в промежуточном программном обеспечении Downloader.

Мое Downloader промежуточное ПО:

def process_request(self, request, spider):
    #catch any requests that should be filtered, and ignore them
    found = False
    for url in spider.allowed_domains:
        if url in request.url:
            #an allowed domain is in the request.url, proceed
            found = True

    if found == False:
        print("[ignored] "+request.url)
        raise IgnoreRequest('Offsite link, ignore')

    return None

Убедитесь, что вы импортируете также IgnoreRequest:

from scrapy.exceptions import IgnoreRequest

и включите промежуточное ПО Downloader в settings.py.

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

2 голосов
/ 26 марта 2019

Я считаю, что лучше всего использовать , а не , чтобы использовать allowed_domains на LinkExtractor, а вместо этого анализировать домен из response.url в вашем методе parse_* и выполнять другую логику в зависимости отdomain.

Вы можете хранить отдельные методы parse_* и метод сортировки, который в зависимости от доменов вызывает yield from self.parse_*(response) (Python 3) с соответствующим методом parse_*:

rules = [Rule(LinkExtractor(), callback='parse_all', follow=True)]

def parse_all(self, response):
    # [Get domain out of response.url]
    if domain in allowed_domains:
        yield from self.parse_item(response)
    else:
        yield from self.parse_denied_item(response)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...