Как обработать все виды исключений в проекте scrapy, в errback и callback?

В настоящее время я работаю над проектом скребка, который очень важен для обеспечения правильной обработки КАЖДОГО запроса, то есть либо для регистрации ошибки, либо для сохранения успешного результата. Я уже реализовал базовый паук, и теперь я могу успешно обработать 99% запросов, но в результате я мог получить ошибки, такие как captcha, 50x, 30x или даже недостаточно полей (тогда я попробую другой веб-сайт, чтобы найти пропущенные поля).

Сначала я подумал, что это более "логично". Вызывать исключения в обратном вызове синтаксического анализа и обрабатывать их все в ошибке, это может сделать код более читабельным. Но я попытался только выяснить, что ошибка может только перехватывать ошибки в модуле загрузчика, такие как статусы ответов, отличные от 200. Если я вызову самореализованный ParseError в обратном вызове, паук просто поднимает его и останавливается.

Даже если мне придется обрабатывать запрос синтаксического анализа непосредственно в обратном вызове, я не знаю, как немедленно повторить запрос в обратном вызове в чистом виде. вы знаете, мне может потребоваться включить другой прокси-сервер для отправки другого запроса или изменить какой-либо заголовок запроса.

Я признаю, что я относительно новичок в области скрапа, но я пробовал туда-сюда несколько дней и до сих пор не могу заставить его работать & # x2026; Я проверил каждый вопрос на 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

Ответы на вопрос(2)

РЕДАКТИРОВАТЬ 16 ноября 2012 г .: Scrapy & gt; = 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())

Для версий Scrapy от 0.16 и выше:

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,
}
 Shadow Lau18 июн. 2012 г., 12:03
Спасибо Sjaak, я просто внимательно посмотрел документацию по расширению scrapy, это звучит как раз в моих требованиях! Очень жаль, что я не очень хорошо поняла это неделю назад, когда начала делать терапию. Я попробую позже, я подумываю использовать список повторов для составления расписания.
 29 янв. 2016 г., 09:46
Не уверен, что для этого нужен другой вопрос, но не могли бы вы объяснить, какие изменения необходимо внести, чтобы включитьFailLogger класс в остальной части scrapy? Я модифицировалEXTENSIONS вsettings.py, и добавилfaillog.py кextensions каталог. Scrapy выходы2016-01-29 16:24:07 [scrapy] INFO: Enabled extensions: FailLoggerтак что я думаю, что моя реализация в порядке. Я тестирую наthis link, который возвращаетDNSLookupError, но заявление о печати вFailLogger класс не возвращается ...

At first, I thought it's more "logical" to raise exceptions in the parsing callback and process them all in errback, this could make the code more readable. But I tried only to find out errback can only trap errors in the downloader module, such as non-200 response statuses. If I raise a self-implemented ParseError in the callback, the spider just raises it and stops.

Да ты прав -callback а такжеerrback предназначены для использования только с загрузчиком, так какtwisted используется для загрузки ресурса, а витая использует deffereds - поэтому необходимы обратные вызовы.

Единственной асинхронной частью в scrapy обычно является загрузчик, все остальные части работают синхронно.

Итак, если вы хотите отлавливать все ошибки, не связанные с загрузкой, - сделайте это самостоятельно:

make a big try/except in the callback or make a decorator for your callbacks which will do this (i like this idea more)
 Shadow Lau18 июн. 2012 г., 12:00
спасибо за разъяснение обязанностейcallback а такжеerr back! Это озадачивало меня долгое время ... думаю, я должен был это выяснить, написав несколько тестовых пауков раньше ...

Ваш ответ на вопрос