2012-06-17 7 views
9

Actualmente estoy trabajando en un proyecto de raspador, que es muy importante para garantizar que TODAS las solicitudes se manejen correctamente, es decir, para registrar un error o guardar un resultado exitoso. Ya implementé la araña básica, y ahora puedo procesar el 99% de las solicitudes con éxito, pero puedo obtener errores como captcha, 50x, 30x o incluso no hay suficientes campos en el resultado (entonces intentaré con otro sitio web para encontrar los campos faltantes).cómo procesar todo tipo de excepción en un proyecto de scrapy, en errback y callback?

Al principio, pensé que es más "lógico" para elevar excepciones en la devolución de llamada analizar y procesar a todos ellos en errback, esto podría hacer que el código sea más legible. Pero intenté solo descubrir que el error errback solo puede atrapar errores en el módulo de descarga, como estados de respuesta que no sean 200. Si elevo un ParseError autoaplicado en la devolución de llamada, la araña simplemente lo levanta y se detiene.

Incluso si voy a tener que procesar la solicitud de análisis directamente en la devolución de llamada, no sé cómo volver a intentar la solicitud inmediatamente en la devolución de llamada de una manera limpia. Ya sabes, es posible que deba incluir un proxy diferente para enviar otra solicitud o modificar algún encabezado de solicitud.

Admito que soy relativamente nuevo en scrapy pero lo he intentado de un lado a otro durante días y todavía no puedo hacer que funcione ... Revisé cada pregunta en SO y nadie coincide, gracias de antemano por la ayuda.

ACTUALIZACIÓN: Me da cuenta de que esto podría ser una cuestión muy compleja, así que intenta ilustrar el escenario en el siguiente pseudo código, espero que esta ayuda:

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 

Respuesta

0

Al principio, pensé que es más "lógico "para generar excepciones en la devolución de llamada de análisis y procesarlas todas en errback, esto podría hacer que el código sea más legible. Pero intenté solo descubrir que errback solo puede atrapar errores en el módulo de descarga, como estados de respuesta que no sean 200. Si elevo un ParseError autoaplicado en la devolución de llamada, el spider solo lo levanta y se detiene.

Sí, tienes razón - callback y errback están destinados a ser utilizados únicamente con descargador, como twisted se utiliza para la descarga de un recurso, y retorcido utiliza deffereds - por eso son necesarias las devoluciones de llamada.

La única parte asíncrono en scrapy por lo general es descargador, todas las demás partes que trabajan de forma sincrónica.

lo tanto, si se desea capturar todos los errores no descargador - hágalo usted mismo:

  • hacer una gran try/excepto en la devolución de llamada
  • o hacer un decorador para sus devoluciones de llamada que hacer esto (me gusta esta idea más)
+0

gracias por aclarar las responsabilidades de 'callback' y' err back'! Esto me ha estado confundiendo por mucho tiempo ... supongo que debería haberlo entendido escribiendo algunas arañas de prueba antes ... –

8

EDITAR 16 nov 2012: Scrapy> = 0,16 utiliza un método diferente para fijar métodos a las señales, ejemplo extra añadido

La solución más sencilla sería escribir una extensión en la que capture fallas, usando señales de Scrapy. Por ejemplo; la siguiente extensión detectará todos los errores e imprimirá un traceback.

Puede hacer cualquier cosa con la falla, como guardar en su base de datos, o enviar un correo electrónico, que a su vez es una instancia de twisted.python.failure.Failure.

Para las versiones Scrapy hasta 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()) 

Para las versiones Scrapy entre 0,16 y hasta:

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()) 

le permitiría la ampliación de la configuración, con algo como:

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

Gracias Sjaak, acabo de ver la documentación con respecto a la extensión de la máscara con más cuidado, esto suena bien en forma mis requisitos! Lástima que no lo entendí bien hace una semana cuando comencé con el tratamiento. Le daré una oportunidad más tarde, estoy pensando en usar una lista de redis para la programación. –

+0

No estoy seguro si esto necesita otra pregunta, pero ¿podría explicar qué modificaciones se deben hacer para incorporar la clase 'FailLogger' en el resto de la terapia? Modifiqué 'EXTENSIONS' en' settings.py', y agregué 'faillog.py' al directorio' extensions'. Salidas de Scrapy '2016-01-29 16:24:07 [scrapy] INFO: Extensiones habilitadas: FailLogger', así que creo que mi implementación está bien. Estoy probando en [este enlace] (https://www.release.tdnet.info/inbs/140120160122493328.pdf), que devuelve un 'DNSLookupError', pero la declaración de impresión en la clase' FailLogger' no se devuelve. .. – JSB

Cuestiones relacionadas