Есть ли способ принудительно вставить 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 ответ:
Я понял, что промежуточное ПО было правильным путем, но это было промежуточное ПО загрузчика, а не 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 для выхода из очереди, как только он появился через этот пункт. Таким образом, оба этих решения вместе = все фиксировано.