Как я могу ограничить количество элементов, извлеченных для каждого домена в scrapy?

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

class CustomSpider(CrawlSpider):
name = "myspider"
start_urls = ['https://www.example1.com/']
allowed_domains = ['www.example1.com']
rules = [Rule(LinkExtractor(allow=()), callback='parse_info', follow = True)]

def parse_info(self, response):
    scrape_count = self.crawler.stats.get_value('item_scraped_count')
    if scrape_count == 20:
        raise CloseSpider("Limit Reached")

Мой вопрос в том, как расширить этот код для следующего сценария:

class CustomSpider(CrawlSpider):
name = "myspider"
start_urls = ['https://www.example1.com/', 'https://www.example2.com/']
allowed_domains = ['www.example1.com', 'www.example2.com/']
rules = [Rule(LinkExtractor(allow=()), callback='parse_info', follow = True)]

def parse_info(self, response):
suggest change in logic here
    scrape_count = self.crawler.stats.get_value('item_scraped_count')
    if scrape_count == 20:
        raise CloseSpider("Limit Reached")

person user3797806    schedule 03.01.2018    source источник
comment
это зависит от того, как вы связываете item с domain, есть ли в нем поле, указывающее, к какому домену он принадлежит? что-то вроде item = {'domain': 'www.example2.com'}?   -  person eLRuLL    schedule 04.01.2018
comment
В настоящее время он не делает ничего подобного. Предполагая, что я делаю эту часть, как я могу достичь желаемой логики?   -  person user3797806    schedule 04.01.2018


Ответы (2)


См. пример этой игрушки:

from __future__ import print_function

import collections
try:
    from urllib.urlparse import urlsplit
except ImportError:
    from urlparse import urlsplit

from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class MySpider(CrawlSpider):
    name = 'myspider'
    start_urls = ['http://quotes.toscrape.com/',
                  'http://webscraper.io/test-sites']
    allowed_domains = ['quotes.toscrape.com', 'webscraper.io']

    scraped_count = collections.defaultdict(int)
    limit = 10

    rules = [Rule(LinkExtractor(allow=()), callback='parse_page',
                  follow=True, process_request='process_request')]

    def parse_page(self, response):
        yield {
            'url': response.url
        }

    def process_request(self, request):
        url = urlsplit(request.url)[1]
        if self.scraped_count[url] < self.limit:
            self.scraped_count[url] += 1
            return request
        else:
            print('Limit reached for {}'.format(url))

Он отслеживает количество извлеченных элементов для каждого домена в атрибуте scraped_count. Атрибут limit содержит ограничение на домен. Логика заложена в методе process_request, который передается в качестве аргумента Rule и вызывается для каждого запроса, извлекаемого этим правилом (см. документацию). При превышении лимита запрос фильтруется, в противном случае возвращается без изменений и обрабатывается.

Если вам нужно что-то более сложное или применимое к нескольким паукам, я бы посоветовал вам расширить CloseSpider, реализовать там логику и заменить класс по умолчанию в settings.py.

person Tomáš Linhart    schedule 04.01.2018
comment
Привет @Tomáš Linhart, спасибо за предложение. Это близко к тому, что я хочу. Но я не пытаюсь фильтровать запросы после достижения лимита. Я хочу, чтобы паук прекратил отправлять запросы в этот домен... и как только были достигнуты ограничения для всех доменов, паук останавливается. - person user3797806; 04.01.2018

Вы можете использовать CLOSESPIDER_ITEMCOUNT

Целое число, указывающее количество элементов. Если паук очистит больше, чем это количество, и эти элементы будут переданы конвейером элементов, паук будет закрыт с причиной closespider_itemcount. Запросы, которые в настоящее время находятся в очереди загрузчика (до запросов CONCURRENT_REQUESTS), все еще обрабатываются. Если ноль (или не задано), пауки не будут закрываться по количеству переданных элементов.

person parik    schedule 04.01.2018
comment
Привет, парик... Я могу установить ограничение на количество элементов, очищаемых пауком. Я хочу установить ограничение на количество элементов на домен в моем start_urls. - person user3797806; 04.01.2018
comment
если вы хотите, чтобы этот паук прекратил отправлять запросы в этот домен, вы можете подсчитать элемент каждого домена и поместить их в одну переменную или диктовать, перед отправкой запроса вы можете иметь условие, если количество элементов меньше числа что ты хочешь - person parik; 04.01.2018
comment
Это то, о чем говорит решение @Tomáš Linhart. Я ищу более сложный способ заставить scrapy понять, чтобы не генерировать больше запросов, а не прекращать запросы - person user3797806; 04.01.2018