为什么要讲这个RetryMiddleware呢?因为他很重要~ 至少在你装配代理ip或者一切关于重试的时候需要用到!----最关键的是:大部分的教学视频里面,没有提及这个!!!!
这个RetryMiddleware是来自:
from scrapy.downloadermiddlewares.retry import RetryMiddleware
我们可以看他的源码:(我已经添加了中文注释)
class RetryMiddleware:
EXCEPTIONS_TO_RETRY = (
defer.TimeoutError, # 等待超时错误
TimeoutError, # 执行超时错误
DNSLookupError, # DNS解析错误
ConnectionRefusedError, # 连接被拒绝错误
ConnectionDone, # 连接已关闭错误
ConnectError, # 连接错误
ConnectionLost, # 连接丢失错误
TCPTimedOutError, # TCP超时错误
ResponseFailed, # 响应失败错误
IOError, # IO错误(通常发生在HttpCompression中间件尝试解压缩空响应时)
TunnelError, # 隧道错误
)
def __init__(self, settings):
if not settings.getbool("RETRY_ENABLED"):
raise NotConfigured
self.max_retry_times = settings.getint("RETRY_TIMES")
self.retry_http_codes = set(
int(x) for x in settings.getlist("RETRY_HTTP_CODES")
)
self.priority_adjust = settings.getint("RETRY_PRIORITY_ADJUST")
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings)
def process_response(self, request, response, spider):
if request.meta.get("dont_retry", False):
return response
if response.status in self.retry_http_codes:
reason = response_status_message(response.status)
return self._retry(request, reason, spider) or response
return response
def process_exception(self, request, exception, spider):
if isinstance(exception, self.EXCEPTIONS_TO_RETRY) and not request.meta.get(
"dont_retry", False
):
return self._retry(request, exception, spider)
def _retry(self, request, reason, spider):
max_retry_times = request.meta.get("max_retry_times", self.max_retry_times)
priority_adjust = request.meta.get("priority_adjust", self.priority_adjust)
return get_retry_request(
request,
reason=reason,
spider=spider,
max_retry_times=max_retry_times,
priority_adjust=priority_adjust,
)
这段代码是Scrapy框架中scrapy.downloadermiddlewares.retry
模块中的RetryMiddleware
类。它是重试下载器中间件,用于处理下载请求的重试逻辑。
让我来逐行解释这段代码的注释和功能:
EXCEPTIONS_TO_RETRY
是一个元组,包含了需要重试的异常类型。如果发生这些异常而且请求没有设置dont_retry
元数据标志,则会进行重试。__init__
方法初始化重试中间件的参数。它从settings
中获取配置信息,包括是否启用重试、最大重试次数、重试的HTTP响应状态码和优先级调整。from_crawler
是一个类方法,用于从crawler
对象获取设置,创建RetryMiddleware
实例并返回。process_response
方法处理响应。如果请求的dont_retry
元数据标志为True,直接返回响应。如果响应的状态码在重试的HTTP响应状态码列表中,使用_retry
方法进行重试并返回重试请求,否则返回响应本身。process_exception
方法处理异常。如果发生的异常属于EXCEPTIONS_TO_RETRY
类型并且请求的dont_retry
元数据标志为False,使用_retry
方法进行重试。_retry
方法执行实际的重试逻辑。它从请求的元数据中获取最大重试次数和优先级调整,然后使用get_retry_request
方法创建一个带有重试参数的新请求,并返回该请求。为什么要修改这个源代码?因为,在修改他的时候,你能通过这个已经封装好的重试中间件,做很多自定义的事情!!!
修改后的代码:(这里以:对超过重试次数的ip在redis里面删除为例)
from scrapy.downloadermiddlewares.retry import RetryMiddleware
# 确保在 retry_times 用尽后仍然移除失败代理,需要重写 RetryMiddleware
class RedisRetryMiddleware(RetryMiddleware):
"""
继承并重写RetryMiddleware,添加代理移除逻辑
"""
def __init__(self, settings):
# Redis 实例化逻辑,读取配置
self.server = redis.StrictRedis(
host=settings.get('REDIS_HOST'),
port=settings.get('REDIS_PORT'),
db=settings.get('REDIS_DB')
) #获取redis的链接设置
self.proxy_key = settings.get('REDIS_PROXY_KEY') #redis的key值
super(RedisRetryMiddleware, self).__init__(settings)
@classmethod
def from_crawler(cls, crawler):
# 读取爬虫配置的 RETRY_TIMES
return cls(crawler.settings)
def _retry(self, request, reason, spider):
proxy = request.meta.get('proxy')
if proxy:
# 代理失败,删除代理
self.server.srem(self.proxy_key, proxy)
spider.logger.debug(f'Remove Proxy: {proxy}. Reason: {reason}')
# 调用超类(爬虫默认)重试方法
return super(RedisRetryMiddleware, self)._retry(request, reason, spider)
from scrapy.downloadermiddlewares.retry import RetryMiddleware
是用来导入Scrapy框架内置的RetryMiddleware
中间件类。这个中间件类用于处理请求的重试逻辑,当请求失败或遇到特定的异常时,可以根据配置的参数进行自动重试。
在Scrapy-Redis中,你可以根据需要使用RetryMiddleware
来实现诸如以下功能:
RETRY_TIMES
设置项来增加请求的最大重试次数。RETRY_HTTP_CODES
设置项,指定需要重试的HTTP响应状态码。当相应的HTTP响应状态码出现时,中间件会自动发起重试。process_response
和process_exception
方法,在特定条件下进行自定义的重试逻辑判断。例如,可以根据响应内容确定是否需要重试,或是自定义异常类型进行处理。RETRY_PRIORITY_ADJUST
设置项来调整重试请求的优先级,使其具有比原始请求更高或更低的优先级。RetryMiddleware
,实现在集群中共享重试请求和状态。总而言之,RetryMiddleware
是Scrapy框架提供的一个非常实用的中间件,用于处理请求的重试,可以根据需要进行配置和定制。在Scrapy-Redis中,它常常被用来增加爬虫的容错性和稳定性,确保爬取的数据的完整性和准确性。