Scrapy的301、302重定向问题原因及解决办法
根据 HTTP标准 ,返回值为200-300之间的值为成功的response。
Scrapy运行爬虫过程中,目标网站返回301或302,而没有获取到想要的网页内容,表示请求失败。eg:
2019-02-13 17:18:32 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2019-02-13 17:18:33 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (301) to <GET http://www.baidu.com/search/?lm=0&rn=10&pn=0&fr=search&ie=gbk&word=%D3%E2%C6%DA%C1%CB%D3%D0%BA%DC%C3%B4%CE%A3%BA%A6> from <GET https://zhidao.baidu.com/search?lm=0&rn=10&pn=0&fr=search&ie=gbk&word=%D3%E2%C6%DA%C1%CB%D3%D0%BA%DC%C3%B4%CE%A3%BA%A6>
2019-02-13 17:18:36 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (302) to <GET http://www.baidu.com/forbiddenip/forbidden.html> from <GET http://www.baidu.com/search/?lm=0&rn=10&pn=0&fr=search&ie=gbk&word=%D3%E2%C6%DA%C1%CB%D3%D0%BA%DC%C3%B4%CE%A3%BA%A6>
2019-02-13 17:18:40 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://www.baidu.com/forbiddenip/forbidden.html> (referer: None)
2019-02-13 17:18:41 [scrapy.core.engine] INFO: Closing spider (finished)
2019-02-13 17:18:41 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 2295,
301、302
301 :(永久重定向) 被请求的资源已永久移动到新位置
302:(暂时的重定向)
两个都属于重定向的问题,原因和解决办法差不多,通常是由原因1或原因2导致的。
原因1:网址发生改变,而我们还用旧网址去访问。
参考:https://www.cnblogs.com/haitianzhimen/p/8618251.html
比如,我们访问 http😕/www.baidu.com 会跳转到 https😕/www.baidu.com,发送请求之后,就会返回301状态码,然后返回一个location,提示新的地址,浏览器就会拿着这个新的地址去访问。
解决办法:根据重定向的网址(即新的网址)来请求
原因2:爬虫伪装的不够好,被服务器识别出是爬虫。
参考:https://www.cnblogs.com/zhengdongdong/p/10876523.html
解决办法:添加User-Agent,Cookie等伪装手段,可以在浏览器中输入about:version查看User-Agent,Cookie。
如何伪装爬虫:https://zhidao.baidu.com/question/814573192067571772.html
原因3:在REQUEST_HEADERS指定了Host。
参考:https://www.jianshu.com/p/001d6aa123cb
解决办法:注释或删除相关设置
“错误”的解决办法:
“错误”不是指真正的错误,而是指大概率不管用,但也值得一试。
方式1:在请求时添加handle_httpstatus_list,eg:
def start_requests(self):
for i in self.start_urls:
yield scrapy.Request(url=i, meta={
'dont_redirect': True, # 这个可以
'handle_httpstatus_list': [301, 302] # 这个不行
}, callback=self.parse)
这个等于掩耳盗铃,不能真正解决问题
方式2:在yield里面加上dont_filter=True
yield scrapy.Request(url=listUrl[i],callback=self.get_content,meta={'item':item},method='GET',dont_filter=True)
部分帖子说在yield里面加上dont_filter=True,能解决这个问题,但实际上不是所有问题都能解决。dont_filter是对出现问题的url将会再次被传递,只是代表多试几次,若是像原因1这样的,无论请求多少次,都是301.
方式3:在settings中添加HTTPERROR_ALLOWED_CODES,eg:
HTTPERROR_ALLOWED_CODES = [302]
这个表示允许302的错误而不处理。
这几种方式可能对你有用,因为不同的环境原因不同,我之所以将其归到“错误”,是因为我曾经遇到了一个301问题,因为我用了旧的http://,而新的为https://,试过了上面几种方式都不能解决。
也因为如此,将这些可能的原因及解决办法汇总,供后来者参考。