No se puede hacer que Scrapy analice y siga las redirecciones 301, 302

Estoy tratando de escribir un rastreador de sitios web muy simple para enumerar las URL junto con los códigos de referencia y de estado para los códigos de estado de 200, 301, 302 y 404 de http.

Resulta que Scrapy funciona muy bien y mi script lo usa correctamente para rastrear el sitio web y puede enumerar las URL con los códigos de estado 200 y 404 sin problemas.

El problema es: no puedo encontrar la forma de hacer que scrapy siga las redirecciones Y las analice / envíe. Puedo conseguir uno para trabajar pero no ambos.

Lo que he probado hasta ahora:

Aquí está el repository público si desea echar un vistazo al código.

Si desea analizar las respuestas 301 y 302 y seguirlas al mismo tiempo, solicite que su callback procese 301 y 302 e imite el comportamiento de RedirectMiddleware.

Prueba 1 (no funciona)

Vamos a ilustrar con una araña simple para comenzar (no funciona como usted espera todavía):

 import scrapy class HandleSpider(scrapy.Spider): name = "handle" start_urls = ( 'https://httpbin.org/get', 'https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F', ) def parse(self, response): self.logger.info("got response for %r" % response.url) 

En este momento, la araña solicita 2 páginas, y la segunda debe redirigir a http://www.example.com

 $ scrapy runspider test.py 2016-09-30 11:28:17 [scrapy] INFO: Scrapy 1.1.3 started (bot: scrapybot) 2016-09-30 11:28:18 [scrapy] DEBUG: Crawled (200)  (referer: None) 2016-09-30 11:28:18 [scrapy] DEBUG: Redirecting (302) to  from  2016-09-30 11:28:18 [handle] INFO: got response for 'https://httpbin.org/get' 2016-09-30 11:28:18 [scrapy] DEBUG: Crawled (200)  (referer: None) 2016-09-30 11:28:18 [handle] INFO: got response for 'http://example.com/' 2016-09-30 11:28:18 [scrapy] INFO: Spider closed (finished) 

El 302 es manejado por RedirectMiddleware automáticamente y no pasa a su callback.

Prueba 2 (todavía no del todo bien)

Vamos a configurar la araña para manejar 301 y 302s en la callback, usando la lista de handle_httpstatus_list :

 import scrapy class HandleSpider(scrapy.Spider): name = "handle" start_urls = ( 'https://httpbin.org/get', 'https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F', ) handle_httpstatus_list = [301, 302] def parse(self, response): self.logger.info("got response %d for %r" % (response.status, response.url)) 

Vamos a ejecutarlo:

 $ scrapy runspider test.py 2016-09-30 11:33:32 [scrapy] INFO: Scrapy 1.1.3 started (bot: scrapybot) 2016-09-30 11:33:32 [scrapy] DEBUG: Crawled (200)  (referer: None) 2016-09-30 11:33:32 [scrapy] DEBUG: Crawled (302)  (referer: None) 2016-09-30 11:33:33 [handle] INFO: got response 200 for 'https://httpbin.org/get' 2016-09-30 11:33:33 [handle] INFO: got response 302 for 'https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F' 2016-09-30 11:33:33 [scrapy] INFO: Spider closed (finished) 

Aquí, nos falta la redirección.

Prueba 3 (trabajando)

Haga lo mismo que RedirectMiddleware pero en la callback de la araña:

 from six.moves.urllib.parse import urljoin import scrapy from scrapy.utils.python import to_native_str class HandleSpider(scrapy.Spider): name = "handle" start_urls = ( 'https://httpbin.org/get', 'https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F', ) handle_httpstatus_list = [301, 302] def parse(self, response): self.logger.info("got response %d for %r" % (response.status, response.url)) # do something with the response here... # handle redirection # this is copied/adapted from RedirectMiddleware if response.status >= 300 and response.status < 400: # HTTP header is ascii or latin1, redirected url will be percent-encoded utf-8 location = to_native_str(response.headers['location'].decode('latin1')) # get the original request request = response.request # and the URL we got redirected to redirected_url = urljoin(request.url, location) if response.status in (301, 307) or request.method == 'HEAD': redirected = request.replace(url=redirected_url) yield redirected else: redirected = request.replace(url=redirected_url, method='GET', body='') redirected.headers.pop('Content-Type', None) redirected.headers.pop('Content-Length', None) yield redirected 

Y vuelve a correr la araña:

 $ scrapy runspider test.py 2016-09-30 11:45:20 [scrapy] INFO: Scrapy 1.1.3 started (bot: scrapybot) 2016-09-30 11:45:21 [scrapy] DEBUG: Crawled (302)  (referer: None) 2016-09-30 11:45:21 [scrapy] DEBUG: Crawled (200)  (referer: None) 2016-09-30 11:45:21 [handle] INFO: got response 302 for 'https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F' 2016-09-30 11:45:21 [handle] INFO: got response 200 for 'https://httpbin.org/get' 2016-09-30 11:45:21 [scrapy] DEBUG: Crawled (200)  (referer: https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F) 2016-09-30 11:45:21 [handle] INFO: got response 200 for 'http://example.com/' 2016-09-30 11:45:21 [scrapy] INFO: Spider closed (finished) 

Nos redirigimos a http://www.example.com y también obtuvimos la respuesta a través de nuestra callback.