You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Python Scrapy实现双API SDK代理的故障转移?

Scrapy代理故障转移实现方案(支持Zyte Proxy Manager/Scrapeops.io)

核心思路:基于重试中间件切换代理

Scrapy的重试中间件(RetryMiddleware)是实现故障转移的核心——当请求因代理失效返回特定错误码(如403、503、超时)时,触发重试逻辑并更换代理即可完成故障转移。以下针对你提到的两款代理服务给出具体实现步骤:


一、Zyte Proxy Manager(ZPM)的故障转移实现

ZPM本身自带代理池和基础故障转移机制,但你可以通过自定义重试中间件增强失效场景的控制:

  1. 基础ZPM代理配置
    在项目settings.py中配置ZPM代理地址及中间件:
DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110,
}
# 替换为你的ZPM认证信息
ZYTE_PROXY_URL = 'http://你的用户名:你的密码@proxy.zyte.com:8011'
  1. 自定义重试中间件处理代理失效
    当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动态返回代理,需要结合重试中间件在代理失效时重新获取新代理:

  1. 代理获取中间件配置
    先写一个中间件用于从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密钥'
  1. 自定义重试中间件触发代理切换
    当请求失败时,清除当前代理,让中间件重新获取新代理:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 04:30:26