2012-06-11 9 views
8

Sono nuovo di scrapy. Sto scrivendo uno spider progettato per controllare un lungo elenco di URL per i codici di stato del server e, dove appropriato, a quali URL sono reindirizzati. È importante sottolineare che, se esiste una catena di reindirizzamenti, ho bisogno di conoscere il codice di stato e l'url ad ogni salto. Sto usando response.meta ['redirect_urls'] per catturare gli url, ma non sono sicuro di come acquisire i codici di stato - non sembra esserci una meta chiave di risposta per questo.Cattura di codici di stato http con ragno graffiato

Mi rendo conto che potrebbe essere necessario scrivere alcuni middlewear personalizzati per esporre questi valori, ma non sono abbastanza chiaro come registrare i codici di stato per ogni salto, né come accedere a questi valori dallo spider. Ho dato un'occhiata ma non riesco a trovare un esempio di qualcuno che lo faccia. Se qualcuno può indicarmi la giusta direzione, sarebbe molto apprezzato.

Per esempio,

items = [] 
    item = RedirectItem() 
    item['url'] = response.url 
    item['redirected_urls'] = response.meta['redirect_urls']  
    item['status_codes'] = #???? 
    items.append(item) 

Modifica - Sulla base del feedback da warawauk e qualche aiuto davvero proattiva dai ragazzi sul canale IRC (freenode #scrappy) sono riuscito a fare questo. Credo che sia un po 'hacky modo eventuali commenti per il miglioramento di benvenuto:

(1) Disattivare il middleware di default nelle impostazioni, e aggiungere il proprio:

DOWNLOADER_MIDDLEWARES = { 
    'scrapy.contrib.downloadermiddleware.redirect.RedirectMiddleware': None, 
    'myproject.middlewares.CustomRedirectMiddleware': 100, 
} 

(2) Crea il tuo CustomRedirectMiddleware nei tuoi middleware .py. Si eredita dalla classe redirectmiddleware principale e cattura il reindirizzamento:

class CustomRedirectMiddleware(RedirectMiddleware): 
    """Handle redirection of requests based on response status and meta-refresh html tag""" 

    def process_response(self, request, response, spider): 
     #Get the redirect status codes 
     request.meta.setdefault('redirect_status', []).append(response.status) 
     if 'dont_redirect' in request.meta: 
      return response 
     if request.method.upper() == 'HEAD': 
      if response.status in [301, 302, 303, 307] and 'Location' in response.headers: 
       redirected_url = urljoin(request.url, response.headers['location']) 
       redirected = request.replace(url=redirected_url) 

       return self._redirect(redirected, request, spider, response.status) 
      else: 
       return response 

     if response.status in [302, 303] and 'Location' in response.headers: 
      redirected_url = urljoin(request.url, response.headers['location']) 
      redirected = self._redirect_request_using_get(request, redirected_url) 
      return self._redirect(redirected, request, spider, response.status) 

     if response.status in [301, 307] and 'Location' in response.headers: 
      redirected_url = urljoin(request.url, response.headers['location']) 
      redirected = request.replace(url=redirected_url) 
      return self._redirect(redirected, request, spider, response.status) 

     if isinstance(response, HtmlResponse): 
      interval, url = get_meta_refresh(response) 
      if url and interval < self.max_metarefresh_delay: 
       redirected = self._redirect_request_using_get(request, url) 
       return self._redirect(redirected, request, spider, 'meta refresh') 


     return response 

(3) A questo punto è possibile accedere all'elenco di reindirizzamenti nel vostro ragno con

request.meta['redirect_status'] 
+1

Si dovrebbe pubblicare la soluzione come risposta – raben

risposta

2

Credo che sia disponibile come

response.status 

Vedi http://doc.scrapy.org/en/0.14/topics/request-response.html#scrapy.http.Response

+0

Grazie per la risposta Lindelof. La mia difficoltà è che l'utilizzo tipico di response.status fornisce lo stato di risposta della risposta finale, dopo tutti i reindirizzamenti. Ho bisogno di response.status per ogni salto e non sono chiaro su come catturarli tutti. Ha senso? – reportingmonkey

+0

Puoi anche aggiungere lo statuscode nello stesso modo in cui apparentemente popola ['redirect_urls'];) –

+0

Oh capisco, ho frainteso. Quindi penso che sia necessario sottoclasse 'scrapy.contrib.spidermiddleware.SpiderMiddleware' secondo http://doc.scrapy.org/en/0.14/topics/spider-middleware.html#writing-your-own-spider-middleware e sovrascrivere 'process_spider_input' per aggiungere i codici di stato intermedi a, ad esempio,' response.meta ['status_codes'] 'che dovrebbe essere inizializzato come una lista vuota. Ma non ho provato questo. – lindelof

3

response.meta['redirect_urls' è popolato da RedirectMiddleware. Il tuo callback spider non riceverà mai risposte intermedie, solo l'ultimo dopo tutti i reindirizzamenti.

Se si desidera controllare il processo, sottoclasse RedirectMiddleware, disabilitare quello originale e abilitare il proprio. Quindi è possibile controllare il processo di reindirizzamento, incluso il monitoraggio degli stati di risposta.

Ecco l'implementazione originale (scrapy.contrib.downloadermiddleware.redirect.RedirectMiddleware):

class RedirectMiddleware(object): 
    """Handle redirection of requests based on response status and meta-refresh html tag""" 

    def _redirect(self, redirected, request, spider, reason): 
     ... 
            redirected.meta['redirect_urls'] = request.meta.get('redirect_urls', []) + \ 
                [request.url] 

Come vedete _redirect metodo che viene chiamato da diverse parti crea meta['redirect_urls']

E nel metodo process_response Viene chiamato return self._redirect(redirected, request, spider, response.status), il che significa che la risposta originale non viene passata allo spider.

+0

Grazie warwaruk, questo ha senso. Stavo guardando il redirectmiddleware. Penso di poter decodificare questa parte. Penso che manchi ancora qualcosa qui, anche se questa classe fa riferimento a request.meta.get ['redirect_urls'], quindi penso che i valori vengano passati per ogni richiesta. Anche questo ha senso, ma non riesco a trovare dove stia realmente accadendo. Modificherò il mio post originale per vedere se riesco a chiarire dove sto lottando – reportingmonkey

+0

@ user1449163, questo middleware è quello che crea 'meta ['redirect_urls']' - vedi l'aggiornamento alla risposta – warvariuc

0

soluzione BACIO: Ho pensato che fosse meglio aggiungere allo stretto di codice per catturare il nuovo campo di reindirizzamento, e lasciare che RedirectMiddleware fare il resto:

from scrapy.contrib.downloadermiddleware.redirect import RedirectMiddleware 

class CustomRedirectMiddleware(RedirectMiddleware): 
    """Handle redirection of requests based on response status and meta-refresh html tag""" 

    def process_response(self, request, response, spider): 
    #Get the redirect status codes 
    request.meta.setdefault('redirect_status', []).append(response.status) 
    response = super(CustomRedirectMiddleware, self).process_response(request, response, spider) 
    return response 

Poi, sottoclasse BaseSpider, si può accedere al redirect_status con il seguente:

def parse(self, response): 
     item = ScrapyGoogleindexItem() 
     item['redirections'] = response.meta.get('redirect_times', 0) 
     item['redirect_status'] = response.meta['redirect_status'] 
     return item 
Problemi correlati