如何处理scrapy项目中的各种异常,在errback和回调中?

时间:2012-06-17 05:28:31

标签: python scrapy

我目前正在开发一个刮刀项目,这对确保每个请求得到妥善处理非常重要,即记录错误或保存成功结果。我已经实现了基本的蜘蛛,我现在可以成功处理99%的请求,但是我可能会遇到像captcha,50x,30x,甚至结果中没有足够字段的错误(然后我会尝试另一个网站到找到缺少的字段。)

首先,我认为在解析回调中引发异常并在errback中处理所有异常更“合乎逻辑”,这可以使代码更具可读性。但我试图发现errback只能捕获下载器模块中的错误,例如非200响应状态。如果我在回调中引发了一个自我实现的ParseError,那么蜘蛛只会提升它并停止。

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

我承认我对scrapy相对较新,但我已经来回试了好几天但仍然无法让这个工作......我已经检查过每一个问题而没有人匹配,感谢提前帮助

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

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

2 个答案:

答案 0 :(得分:8)

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

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

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

对于Scrapy版本直到0.16:

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,
}

答案 1 :(得分:1)

  

起初,我认为提出异常更为“符合逻辑”   解析回调并在errback中处理它们,这可以使得   代码更具可读性。但我试着发现errback只能陷阱   下载程序模块中的错误,例如非200响应状态。如果   我在回调中引发了一个自我实现的ParseError,只是蜘蛛   提出并停止。

是的,你是对的 - callbackerrback只能用于下载程序,因为twisted用于下载资源,而扭曲使用deffereds - 这就是回调的原因需要。

scrapy中唯一的异步部分通常是下载程序,所有其他部分同步工作。

因此,如果您想捕获所有非下载程序错误 - 请自行执行:

  • 在回调中进行大尝试/除外
  • 或为你的回调制作一个装饰者(我更喜欢这个想法)