有没有办法强制Scrapy进入解析方法,即使存在未处理的异常?

时间:2013-04-10 18:10:02

标签: python queue multiprocessing twisted scrapy

我有一个使用Scrapy的相当复杂的多处理程序。它大约95%的时间都可以正常工作,但偶尔会遇到来自Twisted的未处理异常,当它遇到导致DNSLookupError / TCPTimedOutError的坏站点时。

这不是一个问题,但不幸的是,这些错误导致Scrapy跳过BaseSpider解析方法,我已经设置了一个队列来处理响应。由于它会跳过队列,我无法确定跳过了哪些网址。

有没有办法始终确保每个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)

如您所见,它非常基本。

稍后,队列将按如下方式处理:

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的Queue,它将解决我所有的问题。

由于

1 个答案:

答案 0 :(得分:3)

我明白了,中间件是正确的轨道,但它是下载中间件而不是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语句,一旦遇到该项就退出队列。所以这两个解决方案在一起=全部固定。