前言:
单纯讲重试的问题---因为今天有人私了我 `他的代码`,我忽然觉得这里有一个误区;顺便给哥们你混淆的理论里,再搅和搅和....哈哈哈
正文:
拨乱反正:
在Scrapy中,默认情况下,当一个请求失败时,会进行自动重试。重试次数的计算是基于原始请求的 meta 属性中的 retry_times 字段。
例如,若全局重试次数设置为3,当第一次请求失败时,retry_times 字段的初始值为3。随后,经过每次重试,retry_times 的值会依次减少,直到为0。
案例说明:
python
class MySpider(scrapy.Spider):
name = 'example'
def start_requests(self):
url = 'http://www.example.com'
yield scrapy.Request(url, self.parse, meta={'retry_times': self.settings.get('RETRY_TIMES', 3)})
def parse(self, response):
if response.status == 200:
# 成功处理响应的逻辑
pass
else:
retry_times = response.meta.get('retry_times', self.settings.get('RETRY_TIMES', 3))
if retry_times > 0:
next_request = response.request.copy()
next_request.meta['retry_times'] = retry_times - 1
yield next_request
else:
# 超过重试次数,放弃重试
pass
----我为什么要说这个呢? 因为我看到他的代码,在增加"retry_times"的次数,导致这个request如果失效,他能一直错下去; (正确的代码如下,哥们儿你自己提哈):
python
def process_response(self, request, response, spider):
if response.status >= 400: # 请求超时,可能是IP的问题
# 获取当前使用的代理IP
proxy = request.meta.get('proxy', None)
if proxy:
self.remove_proxy(proxy) # 从代理池中删除该IP
if request.meta['retry_times'] > 0:
# 重新获取一个随机的代理IP,并重试请求
new_proxy = self.get_proxy() # 获取一个新的代理IP
if new_proxy:
new_request = request.copy()
new_request.meta['proxy'] = new_proxy
new_request.meta['retry_times'] -= 1
return new_request
return response
我稍微改进了一下,如果重试都失败了,那抛异常没毛病了吧:
python
def process_response(self, request, response, spider):
if response.status >= 400: # 请求超时,可能是IP的问题
# 获取当前使用的代理IP
proxy = request.meta.get('proxy', None)
if proxy:
self.remove_proxy(proxy) # 从代理池中删除该IP
if request.meta['retry_times'] > 0:
new_proxy = self.get_proxy() # 获取一个新的代理IP
if new_proxy:
new_request = request.copy()
new_request.meta['proxy'] = new_proxy
new_request.meta['retry_times'] -= 1
if new_request.meta['retry_times'] == 0:
# 重试次数超过全局重试次数时,抛出异常
raise Exception('URL重试次数超过限制')
return new_request
return response
备注:(记得从你的全局settings中,获取重试次数哈),如果你不获取的话,虽然scrapy默认会重试,但你获取不到重试的值!!! 因为他不是显式的!
python
global_retry_times = get_project_settings().get('RETRY_TIMES', 3) # 获取全局设置的重试次数
request_retry_times = request.meta.get('retry_times', global_retry_times) # 获取请求的重试次数
或者,你在spiders的时候,meta函数里面添加个'RETRY_TIMES';例如:
python
custom_settings = {
'RETRY_TIMES': 3, # 设置重试次数为 3 次
}
def start_requests(self):
yield scrapy.Request(f'https://www.example.com/zq/1?date={self.timeday}', callback=self.parse,meta={'retry_times': self.settings.getint('RETRY_TIMES')})
最后,我再补个知识点(看了你的代码):
关于中间件的:
python
DOWNLOADER_MIDDLEWARES = {
"你的爬虫名.middlewares.A!!!!Middleware": 543,
"你的爬虫名.middlewares.B!!!!Middleware": 600,
"你的爬虫名.middlewares.C!!!!Middleware": 900,
}
正常来说:
请求(request)的时候他的执行顺序,如你听到的--->从A到B到C;
但是:
响应(response)的时候,他的执行顺序,不如你所写--->从C到B到A!!!
对咯--->他是倒着来的! 不是按你理解的那个顺序跑的...
所以,别在不是处理异常的中间件类里边写异常~容易给你自己玩跑偏了,导致该接收异常的收不到!!!
你去看看我
爬虫工作量由小到大的思维转变---<第二十八章 Scrapy中间件说明书>-CSDN博客
.... 在A类里边干B类的事,就是耍流氓....哪怕你发现了,什么都别做,他会根据流程滚到属于管他的那个类里边被处理掉的;放心...
总结:
1.重试是在做减法! 不要去给他+了;
2.不要一出异常就抛,给每个url请求一个机会,也有可能是咱网络或者IP其他别的问题呢?
3.彻底抛出url请求异常,最好写在重试次数结束之后;