Scrapy 配代理完整指南

作者:Mechelle Henderson · 发布:2026 年 9 月 7 日 · 阅读约 6 分钟

一句话总结: 临时用,把代理放进请求的 meta:meta={"proxy": "http://用户名:密码@gw.roamproxy.com:41080"} —— Scrapy 内置的 HttpProxyMiddleware 会处理认证。整个爬虫用,写一个下载中间件在每个请求上设 request.meta["proxy"]。要轮换 IP,就保持同一个网关、按请求改变用户名里的粘性会话标记。

最简写法:request.meta

Scrapy 已经默认启用了 HttpProxyMiddleware。它会从每个请求的 meta 里读代理,当 URL 带凭据时,自动把凭据提取成 Proxy-Authorization 请求头。所以最小可用示例根本不用改 settings:

import scrapy

class IpSpider(scrapy.Spider):
    name = "ip"

    def start_requests(self):
        yield scrapy.Request(
            "https://ip.sb",
            meta={"proxy": "http://YOUR_USERNAME:[email protected]:41080"},
            callback=self.parse,
        )

    def parse(self, response):
        self.logger.info("出口 IP: %s", response.text.strip())

运行后,日志里的出口 IP 应该是 Roam 的住宅地址,而不是你服务器的地址。这种写法适合快速测试,或只需要一个代理的爬虫。

可复用写法:下载中间件

把凭据硬编码进每个 Request 会很乱。把它挪进下载中间件,这样每个请求(包括 Scrapy 自动产生的重试和重定向)都走代理,爬虫代码也保持干净:

# myproject/middlewares.py
class RoamProxyMiddleware:
    GATEWAY = "gw.roamproxy.com:41080"
    USER = "YOUR_USERNAME"
    PASSWORD = "YOUR_PASSWORD"

    def process_request(self, request, spider):
        request.meta["proxy"] = f"http://{self.USER}:{self.PASSWORD}@{self.GATEWAY}"
# myproject/settings.py
DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.RoamProxyMiddleware": 610,
}

把凭据写代理 URL,交给 Scrapy 处理请求头。现代 Scrapy 里,HttpProxyMiddleware(优先级 750)会读 meta["proxy"],把 user:pass 提取成 Proxy-Authorization 头,再把凭据从存储的 URL 里剥掉。别自己设这个头 —— 自 2022 年一个安全修复起,Scrapy 会在每个请求上把 Proxy-Authorization 重写成与代理 URL 一致,所以手动设的头会在重定向和重试时被丢掉。

按请求轮换 IP

用轮换住宅代理,你不用维护一堆代理 IP —— 所有请求都指向同一个网关,只改变用户名里嵌入的粘性会话标记。每个不同的会话对应一个不同的住宅出口 IP,所以每个请求换一个新标记,就能用一套凭据实现每请求换一个 IP:

import itertools

class RotatingRoamProxyMiddleware:
    GATEWAY = "gw.roamproxy.com:41080"
    USER = "YOUR_USERNAME"
    PASSWORD = "YOUR_PASSWORD"
    _counter = itertools.count()

    def process_request(self, request, spider):
        session = next(self._counter)
        user = f"{self.USER}_session_{session}"
        request.meta["proxy"] = f"http://{user}:{self.PASSWORD}@{self.GATEWAY}"

需要几个请求共用一个 IP 时(登录流程、翻页结果集),就复用同一个会话标记;想换新 IP 时再生成新的。粘性会话的原理见什么是轮换代理

能轮换不等于可以猛怼站点。保持 DOWNLOAD_DELAYAUTOTHROTTLE_ENABLED 开着,尊重目标的限流 —— 每请求换 IP 但完全不控速,照样像一次攻击。参见如何避免被封

当问题不在 IP 时

干净的住宅 IP 能解决基于信誉的封锁,但解决不了「一眼看穿是 Python」的 TLS 指纹,也解决不了纯 HTTP 客户端跑不了的 JavaScript 挑战。如果换了住宅代理还是被封,说明目标在给你的握手打指纹、或要求真浏览器 —— 见用 curl_cffi 绕过 TLS/JA3 指纹如何绕过 Cloudflare。当页面确实需要浏览器时,就让 Playwright 或 Puppeteer 走同一个代理

常见问题

怎么给单个 Scrapy 请求设代理?

放进请求的 meta:yield scrapy.Request(url, meta={"proxy": "http://用户名:密码@gw.roamproxy.com:41080"})。Scrapy 内置的 HttpProxyMiddleware 默认开启,会读 meta["proxy"],并自动把 user:pass 提取成 Proxy-Authorization 头。单次使用无需改 settings。

怎么让整个爬虫都走同一个代理?

写一个下载中间件,在 process_request 里给每个请求设 request.meta["proxy"],并在 DOWNLOADER_MIDDLEWARES 里启用它。这样凭据不散落在爬虫代码里,而且爬取产生的每个请求(含重试和重定向)都会走代理。

Scrapy 里怎么按请求轮换 IP?

用轮换住宅代理就不用维护代理列表。所有请求指向同一网关,按请求改变用户名里的粘性会话标记 —— 每个不同会话对应一个不同的住宅出口 IP。一个每次 process_request 都生成新 username_session_N 的中间件,就能用一套凭据每请求换 IP。

Scrapy 为什么报 407 Proxy Authentication Required?

407 表示代理没收到有效凭据。最常见的原因是 meta["proxy"] 写成了裸 http://host:port、漏了 user:pass。把凭据写进代理 URL —— http://user:pass@host:port —— 交给 HttpProxyMiddleware 转成 Proxy-Authorization 头。别自己手动设这个头:现代 Scrapy 会把它重写成与代理 URL 一致,手动设的头会在重定向和重试时被丢掉。

Scrapy 需要的就是一个 host:port 代理加凭据 —— 正是 Roam 提供的。轮换住宅 $2/GB、静态住宅 $4/IP/月,支持 HTTP 和 SOCKS5,粘性会话可做每请求轮换。注册账号,拿 300MB 免费试用流量,让你的第一个爬虫从住宅出口出去。