自定义代理池中间件(灵活可控的推荐方案)

核心原理

通过process_request方法为每个请求随机分配代理IP,同时借助process_responseprocess_exception方法检测代理失效状态(如403、502等状态码或请求超时),自动触发更换代理并重新发起请求,从根源上保障采集任务的连续性。

中间件代码实现

在项目的middlewares.py文件中编写如下代码:

import random
import base64

class RandomProxyMiddleware:
    def __init__(self, proxy_list):
        self.proxy_list = proxy_list  # 代理池列表

    @classmethod
    def from_crawler(cls, crawler):
        # 从settings读取代理列表
        proxy_list = crawler.settings.getlist("PROXY_LIST")
        return cls(proxy_list)

    def process_request(self, request, spider):
        """请求前自动设置代理"""
        if self.proxy_list:
            proxy = random.choice(self.proxy_list)
            request.meta["proxy"] = proxy
            spider.logger.info(f"使用代理: {proxy}")

            # 带账号密码的代理(可选)
            if "@" in proxy:
                auth_str = proxy.split("//")[1].split("@")[0]
                encoded = base64.b64encode(auth_str.encode()).decode()
                request.headers["Proxy-Authorization"] = f"Basic {encoded}"
        return None

    def process_response(self, request, response, spider):
        """响应异常时更换代理重试"""
        # 常见访问受限/代理失效状态码
        if response.status in {403, 407, 502, 503, 504}:
            spider.logger.warning(f"代理失效,状态码: {response.status},更换代理重试")
            if self.proxy_list:
                new_proxy = random.choice(self.proxy_list)
                request.meta["proxy"] = new_proxy
                return request.copy()  # 重新发起请求,避免去重过滤
        return response

    def process_exception(self, request, exception, spider):
        """请求异常(超时/连接失败)时更换代理"""
        spider.logger.error(f"代理 {request.meta.get('proxy')} 异常: {exception},更换代理")
        if self.proxy_list:
            new_proxy = random.choice(self.proxy_list)
            request.meta["proxy"] = new_proxy
            return request.copy()

配置启用步骤

在项目的settings.py文件中进行如下配置:

# 1. 定义代理池列表(也可后续通过动态方式加载)

PROXY_LIST = [
    "http://123.12.13.14:8080",
    "https://223.45.67.89:9090",
    "http://user:pass@111.22.33.44:3128",  # 带认证的代理格式
]

# 2. 启用自定义代理中间件,注意优先级设置

DOWNLOADER_MIDDLEWARES = {
    # 关闭默认代理中间件,避免冲突
    "scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": None,
    # 自定义代理中间件(优先级建议700-800,确保先于重试中间件执行)
    "my_scraper.middlewares.RandomProxyMiddleware": 750,
    # 重试中间件配置(优先级低于代理中间件)
    "scrapy.downloadermiddlewares.retry.RetryMiddleware": 90,
}

# 3. 可选:重试策略配置

RETRY_TIMES = 3
RETRY_HTTP_CODES = [403, 407, 502, 503, 504]

第三方库快速实现(无需自定义开发)

scrapy-proxies:轻量随机轮换方案

适合快速搭建基础的代理轮换机制,无需编写复杂的中间件代码:

  1. 安装依赖
    pip install scrapy-proxies
  2. 配置settings.py
    PROXY_LIST = [
    "http://ip:port",
    "https://ip:port",
    ]
    PROXY_MODE = 0  # 0=随机轮换,1=固定单个代理,2=自定义逻辑
    DOWNLOADER_MIDDLEWARES = {
    "scrapy_proxies.RandomProxy": 100,
    "scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": 110,
    }

scrapy-rotated-proxy:支持失效代理管理

具备代理失效自动拉黑、恢复的能力,适合对代理稳定性有一定要求的场景:

  1. 安装依赖
    pip install scrapy-rotated-proxy
  2. 配置settings.py
    ROTATED_PROXY_ENABLED = True
    PROXY_FILE_PATH = "proxies.json"  # 存储代理的JSON文件路径
    DOWNLOADER_MIDDLEWARES = {
    "scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": None,
    "scrapy_rotated_proxy.downloadmiddlewares.proxy.RotatedProxyMiddleware": 750,
    }

    proxies.json示例格式:

    ["http://ip1:port", "https://ip2:port"]

进阶:动态代理获取与维护(生产环境适配)

从API动态拉取代理

生产环境中,固定的代理池容易出现批量失效的问题,可通过调用代理服务商的API定时拉取最新代理,确保代理池的有效性:

import requests

def fetch_proxies():
    # 替换为专业代理服务商的API接口
    resp = requests.get("https://api.qg.net/get_proxies?count=10")
    return [f"http://{item['ip']}:{item['port']}" for item in resp.json()["data"]]

# 在自定义中间件的__init__方法中调用,或通过定时任务定期更新
# self.proxy_list = fetch_proxies()

从本地文件读取代理

若需要手动维护代理列表,可从本地文件加载,方便快速更新:

def load_proxies(file_path="proxies.txt"):
    with open(file_path, "r", encoding="utf-8") as f:
        return [line.strip() for line in f if line.strip() and not line.startswith("#")]

生产环境下的专业代理服务选择

生产环境中,免费代理的可用率极低、稳定性差,难以满足持续的数据采集需求,不少企业会选择专业的代理IP服务商,青果网络作为国内领先的企业级代理IP服务商,深耕行业十一年,能为Scrapy这类数据采集场景提供可靠的支持。

高可用的资源池保障

青果网络的国内代理资源基于三大运营商宽带构建,每日更新600万+纯净IP资源,覆盖全国300多个城市与地区,网络延迟低于100毫秒,可用率高达99.9%。这种高稳定性的资源池,能有效避免Scrapy采集过程中因代理失效导致的任务中断,保障采集效率。

适配不同场景的产品灵活性

青果网络提供多种代理产品类型,包括短效代理、隧道代理静态代理等。其中短效代理适合需要频繁切换IP的大规模采集场景,隧道代理适合需要保持会话连续性的采集任务,能完美适配Scrapy不同的业务需求。

业务连续性与技术支持

青果网络采用自研代理服务端和业务分池技术,整体业务成功率比行业平均高出约30%,能有效提升Scrapy采集的成功率。同时,提供国内代理IP 6小时测试与7×24小时技术支持,在接入过程中遇到的任何问题,都能快速得到专业解答,保障任务的持续运行。

总结

在Scrapy中实现自动切换代理IP,可根据业务需求选择不同方案:自定义下载中间件适合需要高度定制化逻辑的场景,第三方库适合快速搭建基础功能,而生产环境则更推荐使用青果网络这类专业的代理IP服务商,以保障采集任务的稳定性和连续性。无论选择哪种方案,都需要注意代理格式的正确性、中间件的优先级配置,以及异常处理逻辑的完善。

常见问题解答

Q1:Scrapy中代理中间件的优先级为什么很重要?
A1:Scrapy的下载中间件是按照优先级数值从小到大的顺序执行的,代理中间件需要先于默认的HttpProxyMiddleware执行,才能确保自定义的代理设置生效,否则会被默认中间件的逻辑覆盖,导致代理切换不生效。

Q2:免费代理和专业代理服务在Scrapy采集中的核心区别是什么?
A2:免费代理的可用率通常不足30%,且容易出现延迟高、批量失效的情况,仅适合短期测试场景;专业代理服务如青果网络的IP资源经过严格验证,可用率高达99.9%,能满足生产环境下持续、稳定的大规模采集需求。

Q3:如何避免Scrapy重试请求时被去重机制过滤?
A3:在自定义代理中间件的process_response或process_exception方法中,使用request.copy()方法生成新的请求对象再发起重试,这样可以绕过Scrapy的去重过滤,确保更换代理后的请求能正常执行。

青果网络代理IP - CTA Banner
点赞(45)
不同业务场景下的企业级海外代理IP分层选型策略
海外代理IP 全球代理IP 爬虫代理 HTTP代理 海外IP
2026-04-01

企业级海外代理IP需按高需求、中小团队、入门测试分层选型,青果网络拥2000W+纯净全球HTTP代理IP,99.9%可用率,适配多场景。

国内出海团队如何选择高性价比海外代理IP
海外代理IP HTTP代理 海外IP 爬虫代理 代理IP池
2026-04-01

国内出海团队选高性价比海外代理IP,可从资源、成本、稳定性、服务判断,青果网络2000W+纯净HTTP代理IP,全中文服务、灵活计费,适配多出海场景。

HTTP代理与SOCKS5代理的核心差异及场景选择建议
HTTP代理 SOCKS5代理 代理IP 爬虫代理 动态代理
2026-04-01

HTTP与SOCKS5代理在层级、场景、性能等差异显著:前者适配网页类基础需求,配置简单;后者支持多场景、速度更快。青果网络提供全类型高稳定企业级代理IP服务,满足各类业务需求。

企业级代理IP服务商选型的核心标准与场景适配全解析
代理IP 爬虫代理 海外代理IP 隧道代理 静态代理
2026-04-01

企业级代理IP选型可从合规资质、性能、场景适配维度筛选,不同业务场景有对应方向,青果网络以优质资源适配多企业场景需求。

返回
顶部