跳转到内容

在 Scrapy 中配置代理:高效抓取且不被封禁

Инструменты
在 Scrapy 中配置代理:高效抓取且不被封禁

在 Scrapy 中配置代理,是通过把请求分散到一个由独立 IP 地址组成的代理池,来绕过基于 IP 的限流和反爬防护的首要方法。有效的做法是利用 Scrapy 的 middleware 架构,把代理凭据注入到每个 Request 对象的 meta 属性中,让目标服务器认为流量来自多个不同用户,而不是同一个爬虫。

现代网页抓取为何离不开代理

Scrapy 是为高性能爬取而设计的异步框架,但在面对现代反爬系统时,它默认的速度恰恰是最大的隐患。没有代理层,一个 Scrapy spider 很容易从单个 IP 地址每分钟发出数百个请求,从而立刻触发 Cloudflare、Akamai 或 DataDome 等 Web 应用防火墙(WAF)的封禁。

使用 GProxy 这类服务商构建稳健的代理策略,可以实现三项关键功能:

  • IP 轮换:防止目标服务器识别出来自单一来源的请求模式。
  • 地域定向:通过特定国家或城市的出口节点转发流量,让 spider 能访问特定地区的内容。
  • 请求分散:通过分摊负载支持更高并发,这对涉及数百万 URL 的大规模数据抽取项目至关重要。

做企业级抓取时,依赖免费或公共代理注定失败。这些 IP 往往早已被拉黑,而且不提供加密。GProxy 的高质量住宅代理提供由 ISP 真实分配地址的可信度,使您的 Scrapy 流量与自然用户行为无法区分。

在 Scrapy 中配置代理:高效抓取且不被封禁

Scrapy 中的基础代理配置

在 Scrapy 中使用代理最简单的方式,是把代理 URL 直接传入 scrapy.Requestmeta 参数。Scrapy 内置的 HttpProxyMiddleware(默认启用)会在请求元数据中查找 proxy 键。


import scrapy

class SimpleProxySpider(scrapy.Spider):
    name = "proxy_spider"

    def start_requests(self):
        # 格式: http://user:password@proxy_host:proxy_port
        proxy_url = "http://username:[email protected]:7000"
        urls = ["https://httpbin.org/ip"]
        
        for url in urls:
            yield scrapy.Request(
                url=url, 
                callback=self.parse,
                meta={'proxy': proxy_url}
            )

    def parse(self, response):
        self.logger.info(f"Response from IP: {response.text}")

这种方式对小脚本可行,但在大型项目中效率低下,因为它要求在 spider 逻辑内手动管理代理字符串。这违背了关注点分离原则:spider 应专注解析逻辑,而请求路由应由基础设施处理。

用自定义 Middleware 自动轮换代理

要有效扩展,应把代理逻辑迁移到 middlewares.py。这样无需修改 spider,就能自动为每个出站请求附加代理。在使用 GProxy 的轮换住宅出口时尤其有用,因为单一入口点会在后端自动完成轮换。

第 1 步:创建 Middleware

在您的 Scrapy 项目中打开 middlewares.py,定义一个负责分配代理的类:


class GProxyMiddleware:
    def __init__(self, proxy_url):
        self.proxy_url = proxy_url

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            proxy_url=crawler.settings.get('GPROXY_URL')
        )

    def process_request(self, request, spider):
        # 仅在尚未设置时才设置代理
        if 'proxy' not in request.meta:
            request.meta['proxy'] = self.proxy_url

第 2 步:更新 settings.py

如果要处理复杂逻辑,您需要启用自定义 middleware 并禁用默认的 HttpProxyMiddleware,不过通常您的自定义 middleware 可以与它并存。把优先级设置为小于 750(HttpProxyMiddleware 的默认值),以确保它更早执行。


# settings.py

GPROXY_URL = "http://username:[email protected]:7000"

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.GProxyMiddleware': 400,
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
}

Scrapy Spider 的代理类型对比

代理类型的选择会显著影响抓取作业的成功率和成本效率。下表对比了 Scrapy 环境中常用的三大类代理。

代理类型 匿名等级 速度 成本 最佳适用场景
数据中心 极高 对基础防护网站进行高速抓取。
静态住宅 维持会话或管理社交媒体账号。
轮换住宅 最高 中等 突破激进的反爬系统(Amazon、Google 等)。

对大多数 Scrapy 用户而言,轮换住宅代理是黄金标准。它们为每个请求从数百万规模的池中提供一个新 IP,使目标服务器在统计意义上不可能凭 IP 规律封禁您的整套作业。

在 Scrapy 中配置代理:高效抓取且不被封禁

处理代理认证与安全

包括 GProxy 在内的多数高级代理服务都需要认证。Scrapy 主要支持两种方式:URL 内认证Proxy-Authorization 请求头

URL 内认证

这就是前面示例中使用的方式:http://user:pass@host:port。实现简单,但如果密码含特殊字符就可能出问题。若密码中包含 @: 之类的符号,必须对其做 URL 编码。

基于请求头的认证

如果想要更干净的做法,尤其是凭据比较复杂时,可以使用 Proxy-Authorization 请求头。这需要把 username:password 字符串做 Base64 编码。


import base64

class SecureProxyMiddleware:
    def process_request(self, request, spider):
        user_pass = "username:password"
        encoded_user_pass = base64.b64encode(user_pass.encode('utf-8')).decode('utf-8')
        request.meta['proxy'] = "http://gate.gproxy.com:7000"
        request.headers['Proxy-Authorization'] = 'Basic ' + encoded_user_pass

进阶策略:会话管理与重试

抓取需要登录或多步结账流程的网站时,每个请求都换 IP 会导致会话中断。这种情况下您需要 "sticky sessions"。

实现 Sticky Session

GProxy 允许在用户名字符串中加入会话 ID,从而在指定时长内保持同一个 IP(例如 user-username-session-12345:password)。在 Scrapy 中,您可以把会话 ID 与某个 spider 实例或某段爬取任务绑定来管理它。

处理代理失败

没有哪个代理池能做到 100% 稳定。总有部分请求会超时或返回 502/503 错误。您应配置 Scrapy 的重试 middleware 来妥善处理。在 settings.py 中调整重试设置,确保 spider 不会因为某个代理节点失败就放弃某个 URL。


RETRY_ENABLED = True
RETRY_TIMES = 5  # 提高重试次数以应对代理波动
RETRY_HTTP_CODES = [500, 502, 503, 504, 408, 429]

发生重试时,如果您使用的是轮换代理入口,下一次尝试会自动走另一个 IP,通常能立即解决问题。

性能优化:并发与延迟

一个常见错误是使用大规模代理池的同时仍保留 Scrapy 的默认设置。Scrapy 默认把并发限制为 16 个请求。如果您能使用 GProxy 的大规模住宅代理池,可以放心调高该值以提升吞吐量。

  • CONCURRENT_REQUESTS:根据 CPU 和网络带宽,把它提升到 32、64 甚至 128。
  • DOWNLOAD_DELAY:使用高质量住宅代理时,通常可以把 DOWNLOAD_DELAY 降到 0 或极小的值(例如 0.2),因为 IP 轮换本身已经带来"类人"的节奏。
  • AUTOTHROTTLE_ENABLED:启用它,让 Scrapy 根据代理延迟和目标服务器响应时间动态调整爬取速度。

# 针对 GProxy 的 settings.py 优化
CONCURRENT_REQUESTS = 100
CONCURRENT_REQUESTS_PER_DOMAIN = 50
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 1
AUTOTHROTTLE_MAX_DELAY = 10

监控与调试代理流量

为确认代理按预期工作,应定期记录出口 IP。这对验证轮换是否真正生效至关重要。您可以创建一个简单的 Spider SignalLogFormatter,跟踪正在使用哪些 IP 及各自的成功率。

如果发现 403(Forbidden)错误比例很高,通常说明您的 User-Agent 或浏览器请求头与服务器预期的指纹不匹配,或者您的代理被识别为数据中心 IP。改用 GProxy 住宅 IP,并使用 scrapy-user-agents 包让请求头随 IP 一同轮换,通常即可解决。

关键要点

在 Scrapy 中配置代理不仅仅是为了避免被封,更是为了搭建一条有韧性、可扩展的数据抽取流水线。把代理逻辑迁移到 middleware 并利用高质量住宅代理池,能显著延长爬虫的生命周期。

  • 使用 Middleware:切勿把代理硬编码在 spider 中;使用 middlewares.py 获得更清晰、更易维护的架构。
  • 优先使用住宅 IP:只要网站有哪怕最基础的反爬防护,GProxy 住宅代理的成功率都远高于数据中心方案。
  • 精调重试:RETRY_TIMES 设为至少 5,并加入 429 和 503 错误码,以便在失败时充分利用 IP 轮换。
  • 请求头与 IP 匹配:始终让 User-Agent 字符串与代理同步轮换,避免指纹不一致导致的瞬间封禁。
support_agent
GProxy Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.