我有一个相当复杂的使用 Scrapy 的多处理程序。它在大约 95% 的时间里工作得很好,但偶尔当 Twisted 遇到导致 DNSLookupError/TCPTimedOutError 的不良站点时,我会收到未处理的异常。
这不会是一个问题,但不幸的是,这些错误导致 Scrapy 跳过 BaseSpider 解析方法,在该方法中我设置了一个队列来处理响应。由于它跳过了队列,因此我无法确定跳过了哪些 URL。
有没有办法始终确保每个 Scrapy 请求都以该解析方法结束?我所需要的只是一种访问那些失败的响应对象并将它们放入队列中的方法。
这是我的蜘蛛代码的示例:
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)
如您所见,这是非常基本的。
稍后,Queue 的处理方式如下:
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
我在队列超时中添加了一个临时解决方案,这样它就不会在等待队列中不存在的项目时无限期地挂起。如果我能保证某种响应对象将进入 start_urls 列表中每个 URL 的队列,那么它就可以解决我的所有问题。
谢谢
最佳答案
我发现,中间件是正确的轨道,但它是下载器中间件而不是 scrapy 中间件。在我使用 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 语句,以便在遇到该项目时退出队列。所以这两个解决方案加在一起 = 全部修复。
关于python - 即使存在未处理的异常,是否有办法强制 Scrapy 进入解析方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15933231/