Scrapy句柄302响应代码

时间:2016-02-11 04:18:11

标签: redirect scrapy web-crawler scrapy-spider

我正在使用简单的CrawlSpider实施来抓取网站。默认情况下,Scrapy跟随302重定向到目标位置,并忽略最初请求的链接。在特定网站上,我遇到了一个302重定向到另一个页面的页面。我的目的是记录原始链接(响应302)和目标位置(在HTTP响应头中指定)并使用parse_item CrawlSpider方法处理它们。请指导我,我怎样才能做到这一点?

我遇到了提及使用dont_redirect=TrueREDIRECT_ENABLE=False的解决方案,但我实际上并不想忽略重定向,实际上我也想考虑(即不要忽略)重定向页面。 / p>

例如:我访问http://www.example.com/page1,它发送302重定向HTTP响应并重定向到http://www.example.com/page2。默认情况下,scrapy忽略page1,跟随page2并处理它。我想在page1中处理page2parse_item

修改 我已经在蜘蛛的类定义中使用handle_httpstatus_list = [500, 404]来处理500中的404parse_item个响应代码,但如果我302,则handle_httpstatus_listperform中指定。

2 个答案:

答案 0 :(得分:7)

Scrapy 1.0.5(我写这些行的最新官方)在内置的RedirectMiddleware中没有使用handle_httpstatus_list - 请参阅this issue。 来自Scrapy 1.1.0(1.1.0rc1 is available),the issue is fixed

即使您禁用了重定向,您仍然可以模仿其回调中的行为,检查Location标头并将Request返回到重定向

示例蜘蛛:

$ cat redirecttest.py
import scrapy


class RedirectTest(scrapy.Spider):

    name = "redirecttest"
    start_urls = [
        'http://httpbin.org/get',
        'https://httpbin.org/redirect-to?url=http%3A%2F%2Fhttpbin.org%2Fip'
    ]
    handle_httpstatus_list = [302]

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url, dont_filter=True, callback=self.parse_page)

    def parse_page(self, response):
        self.logger.debug("(parse_page) response: status=%d, URL=%s" % (response.status, response.url))
        if response.status in (302,) and 'Location' in response.headers:
            self.logger.debug("(parse_page) Location header: %r" % response.headers['Location'])
            yield scrapy.Request(
                response.urljoin(response.headers['Location']),
                callback=self.parse_page)

控制台日志:

$ scrapy runspider redirecttest.py -s REDIRECT_ENABLED=0
[scrapy] INFO: Scrapy 1.0.5 started (bot: scrapybot)
[scrapy] INFO: Optional features available: ssl, http11
[scrapy] INFO: Overridden settings: {'REDIRECT_ENABLED': '0'}
[scrapy] INFO: Enabled extensions: CloseSpider, TelnetConsole, LogStats, CoreStats, SpiderState
[scrapy] INFO: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, MetaRefreshMiddleware, HttpCompressionMiddleware, CookiesMiddleware, ChunkedTransferMiddleware, DownloaderStats
[scrapy] INFO: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware
[scrapy] INFO: Enabled item pipelines: 
[scrapy] INFO: Spider opened
[scrapy] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
[scrapy] DEBUG: Telnet console listening on 127.0.0.1:6023
[scrapy] DEBUG: Crawled (200) <GET http://httpbin.org/get> (referer: None)
[redirecttest] DEBUG: (parse_page) response: status=200, URL=http://httpbin.org/get
[scrapy] DEBUG: Crawled (302) <GET https://httpbin.org/redirect-to?url=http%3A%2F%2Fhttpbin.org%2Fip> (referer: None)
[redirecttest] DEBUG: (parse_page) response: status=302, URL=https://httpbin.org/redirect-to?url=http%3A%2F%2Fhttpbin.org%2Fip
[redirecttest] DEBUG: (parse_page) Location header: 'http://httpbin.org/ip'
[scrapy] DEBUG: Crawled (200) <GET http://httpbin.org/ip> (referer: https://httpbin.org/redirect-to?url=http%3A%2F%2Fhttpbin.org%2Fip)
[redirecttest] DEBUG: (parse_page) response: status=200, URL=http://httpbin.org/ip
[scrapy] INFO: Closing spider (finished)

请注意,您需要http_handlestatus_list,其中包含302,否则,您会看到此类日志(来自HttpErrorMiddleware):

[scrapy] DEBUG: Crawled (302) <GET https://httpbin.org/redirect-to?url=http%3A%2F%2Fhttpbin.org%2Fip> (referer: None)
[scrapy] DEBUG: Ignoring response <302 https://httpbin.org/redirect-to?url=http%3A%2F%2Fhttpbin.org%2Fip>: HTTP status code is not handled or not allowed

答案 1 :(得分:1)

重定向中间件会在到达您的httperror中间件之前“捕获”响应,并使用重定向网址启动新请求。同时,原始响应不会被返回,即,您甚至没有“看到”302代码,因为它们没有达到httperror。因此,handle_httpstatus_list中的302没有效果。

在scrapy.downloadermiddlewares.redirect.RedirectMiddleware中查看其来源:在process_response()中,您可以看到发生了什么。它会启动一个新请求,并使用redirected_url替换原始URL。没有“回复” - &gt;原来的反应就会被丢弃。

除了使用redirected_url发送另一个请求之外,基本上你只需要通过添加一行“return response”来覆盖process_response()函数。

在parse_item中,您可能想要设置一些条件语句,具体取决于它是否是重定向?我想它看起来不一样,所以也许你的项目也会看起来很不一样。另一种选择也可以是使用不同的解析器进行响应(取决于原始或重定向的URL是“特殊页面”),然后您需要的是在您的蜘蛛中使用不同的解析函数,例如parse_redirected_urls()。在重定向请求中通过回调调用该解析函数

相关问题