Есть ли способ принудительно вставить Scrapy в метод синтаксического анализа, даже если есть необработанное исключение?


У меня есть довольно сложная многопроцессорная программа, которая использует Scrapy. Он отлично работает примерно в 95% случаев, но иногда я получаю необработанные исключения из Twisted, когда он попадает на плохие сайты, которые приводят к DNSLookupError/TCPTimedOutError.

Это не было бы проблемой, но, к сожалению, эти ошибки приводят к тому, что Scrapy пропускает метод анализа BaseSpider, где я настроил очередь для обработки ответов. Поскольку он пропускает очередь, у меня нет возможности выяснить, какие URL были пропущенный.

Есть ли способ всегда гарантировать, что каждый скрап-запрос заканчивается в этом методе синтаксического анализа? Все, что мне нужно, - это способ получить доступ к этим неудачным объектам ответа и поместить их в очередь.

Вот пример моего кода spider:

class SeerSpider(BaseSpider):
    """Scrapy-based html retrieval system."""

    name = "SeerSpider"

    def __init__(self, spider_queue, url_list):
        self.queue = spider_queue
        self.allowed_domains = []
        self.start_urls = []
        for url in url_list:
            self.allowed_domains.append(str(urlparse(url).netloc))
            self.start_urls.append(url)
        super(SeerSpider, self).__init__()

    def parse(self, response):
        """Extracts information from each website in start_urls."""
        self.queue.put(response)

Как вы можете видеть, это очень просто.

Далее очередь обрабатывается следующим образом:

while True:
    response = spider_queue.get()
    ### DO STUFF HERE ###
    results_queue.put(result)

И затем...

while True:
    try:
        result = results_queue.get(True, 60)
    except:
        print 'HALP', sys.exc_info()
        result = ['ERROR']
    self.results.append(result)
    counter -= 1
    if counter <= 0 or self.exit == True:
        for process in process_list:
            process.terminate()
        break

Я добавил в тайм-аут очереди как временное решение, чтобы он не зависал бесконечно, как это ожидает несуществующие элементы в очереди. Если бы я мог просто гарантировать, что какой-то объект ответа войдет в очередь для каждого URL в списке start_urls, это решило бы все мои проблемы.

Спасибо

1 2

1 ответ:

Я понял, что промежуточное ПО было правильным путем, но это было промежуточное ПО загрузчика, а не scrapy middleware. После того, как я реализовал промежуточное программное обеспечение загрузчика с помощью метода process_exception, мне удалось заставить его работать.

Код здесь:

class SpiderFailSignal(object):

    def process_exception(self, request, exception, spider):
        response = Response(request.url, status=666, body='error')
        spider.queue.put(response)
        return response

Затем я добавил

settings.overrides['DOWNLOADER_MIDDLEWARES'] = {'seerspider.SpiderFailSignal': 901}

И это сработало.

Хотя, я также закончил тем, что добавил фиктивное значение в очередь, как только сработал сигнал scrapy spider_idle, а затем создал оператор if для выхода из очереди, как только он появился через этот пункт. Таким образом, оба этих решения вместе = все фиксировано.