11

私は現在、エラーをログに記録するか、成功した結果を保存するために、すべてのリクエストが適切に処理されるようにするために非常に重要なスクレイパー プロジェクトに取り組んでいます。私はすでに基本的なスパイダーを実装しており、リクエストの 99% を正常に処理できるようになりましたが、キャプチャ、50x、30x、または結果に十分なフィールドがないなどのエラーが発生する可能性があります (その後、別の Web サイトを試してみます不足しているフィールドを見つけます)。

最初は、解析コールバックで例外を発生させ、それらをすべて 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
4

2 に答える 2

11

編集 2012 年 11 月 16 日: Scrapy >=0.16 は別のメソッドを使用してシグナルにメソッドをアタッチし、追加の例を追加

最も簡単な解決策は、Scrapy シグナルを使用して、失敗をキャプチャする拡張機能を作成することです。例えば; 次の拡張機能は、すべてのエラーをキャッチし、トレースバックを出力します。

データベースに保存したり、電子メールを送信したりするなど、 Failure で何でもできます。これはそれ自体が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、ツイストはdefferedsを使用します-それがコールバックが必要な理由です。

通常、scrapy の唯一の非同期部分はダウンローダーであり、他のすべての部分は同期的に動作します。

したがって、ダウンローダー以外のすべてのエラーをキャッチしたい場合は、自分で行ってください。

  • コールバックで大きな try/except を行う
  • または、これを行うコールバック用のデコレータを作成します(私はこのアイデアがもっと好きです)
于 2012-06-17T13:45:58.093 に答える