如何在一个棘手的项目中,在回调和回调中处理各种异常



我目前正在从事一个抓取器项目,这对于确保每个请求都得到正确处理非常重要,即记录错误或保存成功的结果。我已经实现了基本的蜘蛛,现在我可以成功处理 99% 的请求,但我可能会遇到验证码、50x、30x 等错误,甚至结果中没有足够的字段(然后我会尝试另一个网站来查找缺少的字段)。

起初,我认为在解析回调中引发异常并在 errback 中处理它们更"合乎逻辑",这可能会使代码更具可读性。但我只尝试找出 errback 只能捕获下载器模块中的错误,例如非 200 响应状态。如果我在回调中引发一个自我实现的 ParseError,蜘蛛就会引发它并停止。

即使我必须直接在回调中处理解析请求,我也不知道如何以干净的方式立即在回调中重试请求。 您知道,我可能必须包含不同的代理来发送另一个请求,或修改某些请求标头。

我承认我对刮擦相对较新,但我已经来回尝试了几天,但仍然无法让它工作......我已经检查了SO上的每一个问题,没有人匹配,提前感谢您的帮助。

更新:我意识到这可能是一个非常复杂的问题,所以我尝试用下面的伪代码来说明这个场景,希望这有帮助:

from scraper.myexceptions import *
def parseRound1(self, response):
    .... some parsing routines ...
    if something wrong happened:
       # this causes the spider raises a SpiderException and stops
       raise CaptchaError
    ...
    if no enough fields scraped:
       raise ParseError(task, "no enough fields")
    else:
       return items
def parseRound2(self, response):
    ...some other parsing routines...
def errHandler(self, failure):
    # how to trap all the exceptions?
    r = failure.trap()
    # cannot trap ParseError here
    if r == CaptchaError:
       # how to enqueue the original request here?
       retry
    elif r == ParseError:
        if raised from parseRound1:
            new request for Round2
        else:
            some other retry mechanism
    elif r == HTTPError:
       ignore or retry

> 编辑 2012年11月16日:Scrapy>=0.16 使用不同的方法将方法附加到信号,添加了额外的示例

最简单的解决方案是编写一个扩展,在其中使用 Scrapy 信号捕获故障。例如;以下扩展将捕获所有错误并打印回溯。

你可以对失败做任何事情 - 比如保存到你的数据库,或者发送电子邮件 - 它本身就是twisted.python.failure.Failure的一个实例。

对于 0.16 之前的 Scrapy 版本:

from scrapy import signals
from scrapy.xlib.pydispatch import dispatcher
class FailLogger(object):
  def __init__(self):
    """ 
    Attach appropriate handlers to the signals
    """
    dispatcher.connect(self.spider_error, signal=signals.spider_error)
  def spider_error(self, failure, response, spider):
    print "Error on {0}, traceback: {1}".format(response.url, failure.getTraceback())

对于 0.16 及更高版本的 Scrapy 版本:

from scrapy import signals
class FailLogger(object):
  @classmethod
  def from_crawler(cls, crawler):
    ext = cls()
    crawler.signals.connect(ext.spider_error, signal=signals.spider_error)
    return ext
  def spider_error(self, failure, response, spider):
    print "Error on {0}, traceback: {1}".format(response.url, failure.getTraceback())  

您将在设置中启用扩展,如下所示:

EXTENSIONS = {
'spiders.extensions.faillog.FailLogger': 599,
}

起初,我认为在 解析回调并在 errback 中处理它们,这可能会使 代码更具可读性。但我试图只找出错误只能陷阱 下载器模块中的错误,例如非 200 响应状态。如果 我在回调中提出了一个自我实现的 ParseError,蜘蛛只是 举起它并停止。

是的,你是对的 - callbackerrback 只能与下载器一起使用,因为twisted用于下载资源,而 twisted 使用 deffereds - 这就是为什么需要回调。

刮擦中唯一的异步部分通常是下载器,所有其他部分同步工作。

因此,如果您想捕获所有非下载器错误 - 自己做:

  • 大试一试/回调除外
  • 或者为您的回调制作一个装饰器来做到这一点(我更喜欢这个想法)

最新更新