11

我目前正在研究一个刮板项目,这对于确保每个请求都得到正确处理非常重要,即记录错误或保存成功的结果。我已经实现了基本的爬虫,现在我可以成功处理 99% 的请求,但我可能会收到验证码、50x、30x 之类的错误,甚至结果中没有足够的字段(然后我会尝试另一个网站找到缺失的字段)。

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

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

我承认我对scrapy比较陌生,但我已经来回尝试了好几天,仍然无法让它发挥作用……我已经检查了关于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
4

2 回答 2

11

编辑 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,
}
于 2012-06-18T08:21:57.477 回答
3

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

是的,你是对的 -callback并且errback仅用于下载器,twisted用于下载资源,而扭曲使用延迟 - 这就是需要回调的原因。

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

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

  • 在回调中进行大尝试/除外
  • 或者为你的回调做一个装饰器来做这个(我更喜欢这个想法)
于 2012-06-17T13:45:58.093 回答