如何基于Python Scrapy实现双API SDK代理的故障转移?
Scrapy代理故障转移实现方案(支持Zyte Proxy Manager/Scrapeops.io)
核心思路:基于重试中间件切换代理
Scrapy的重试中间件(RetryMiddleware)是实现故障转移的核心——当请求因代理失效返回特定错误码(如403、503、超时)时,触发重试逻辑并更换代理即可完成故障转移。以下针对你提到的两款代理服务给出具体实现步骤:
一、Zyte Proxy Manager(ZPM)的故障转移实现
ZPM本身自带代理池和基础故障转移机制,但你可以通过自定义重试中间件增强失效场景的控制:
- 基础ZPM代理配置
在项目settings.py中配置ZPM代理地址及中间件:
DOWNLOADER_MIDDLEWARES = { 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110, } # 替换为你的ZPM认证信息 ZYTE_PROXY_URL = 'http://你的用户名:你的密码@proxy.zyte.com:8011'
- 自定义重试中间件处理代理失效
当ZPM返回代理失效相关错误时,强制触发新会话获取新代理:
from scrapy.downloadermiddlewares.retry import RetryMiddleware from scrapy.utils.response import response_status_message class ZyteRetryMiddleware(RetryMiddleware): def process_response(self, request, response, spider): # 匹配代理失效的典型状态码 if response.status in [403, 503, 543]: # 附加new_session参数,让ZPM分配新代理 request.meta['proxy'] = f"{ZYTE_PROXY_URL}?new_session=1" reason = response_status_message(response.status) return self._retry(request, reason, spider) or response return super().process_response(request, response, spider)
接着在settings.py中替换默认重试中间件:
DOWNLOADER_MIDDLEWARES.update({ 'scrapy.downloadermiddlewares.retry.RetryMiddleware': None, '你的项目名.middlewares.ZyteRetryMiddleware': 550, })
二、Scrapeops.io代理的故障转移实现
Scrapeops通过API动态返回代理,需要结合重试中间件在代理失效时重新获取新代理:
- 代理获取中间件配置
先写一个中间件用于从Scrapeops接口获取代理:
import requests from scrapy.exceptions import NotConfigured class ScrapeopsProxyMiddleware: def __init__(self, api_key): self.api_key = api_key self.proxy_api_url = f'http://proxy.scrapeops.io/v1/?api_key={api_key}' @classmethod def from_crawler(cls, crawler): api_key = crawler.settings.get('SCRAPEOPS_API_KEY') if not api_key: raise NotConfigured("未配置SCRAPEOPS_API_KEY") return cls(api_key) def process_request(self, request, spider): # 仅当请求无代理时获取新代理 if 'proxy' not in request.meta: resp = requests.get(self.proxy_api_url) if resp.status_code == 200: proxy_info = resp.json() request.meta['proxy'] = proxy_info.get('proxy')
在settings.py中启用该中间件:
DOWNLOADER_MIDDLEWARES = { 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110, '你的项目名.middlewares.ScrapeopsProxyMiddleware': 100, } SCRAPEOPS_API_KEY = '你的Scrapeops API密钥'
- 自定义重试中间件触发代理切换
当请求失败时,清除当前代理,让中间件重新获取新代理:
from scrapy.downloadermiddlewares.retry import RetryMiddleware from scrapy.utils.response import response_status_message class ScrapeopsRetryMiddleware(RetryMiddleware): def process_response(self, request, response, spider): if response.status in [403, 500, 503, 429]: # 清除当前代理,下次请求将获取新代理 request.meta.pop('proxy', None) reason = response_status_message(response.status) return self._retry(request, reason, spider) or response return super().process_response(request, response, spider) def process_exception(self, request, exception, spider): # 处理超时、连接失败等代理异常 if isinstance(exception, (ConnectionError, TimeoutError)): request.meta.pop('proxy', None) return self._retry(request, str(exception), spider) return super().process_exception(request, exception, spider)
同样在settings.py中替换默认重试中间件:
DOWNLOADER_MIDDLEWARES.update({ 'scrapy.downloadermiddlewares.retry.RetryMiddleware': None, '你的项目名.middlewares.ScrapeopsRetryMiddleware': 550, })
通用配置优化
- 调整重试参数控制重试次数和触发条件:
RETRY_TIMES = 3 # 最大重试次数 RETRY_HTTP_CODES = [403, 500, 503, 543, 429] # 触发重试的状态码
- 可在重试中间件中添加短暂延迟,避免频繁请求导致目标网站封禁。
内容的提问来源于stack exchange,提问作者webbie1985
相关产品推荐
相关产品推荐

