接入指南
Scrapy 代理设置:request.meta 用法
Scrapy 自带一个默认开启的代理中间件。你在请求的 meta 里写上代理 URL,认证头由 Scrapy 替你生成。
开始之前
- Scrapy 2.13 或更新版本,下面用到的异步 start() 方法从这个版本开始提供。旧版本请把它改名为 start_requests,并去掉 async 关键字。
- 服务页面上的 HOST、PORT、USERNAME 和 PASSWORD。
- 一个 Scrapy 项目,或者一个用 scrapy runspider 运行的单文件爬虫。
你的连接信息
登录控制台,打开你购买的服务。服务页面上会显示该服务的主机、端口、用户名和密码。ProxyPanda 没有一个统一的固定地址,所以每次都请从那里复制。指南中的代码使用下面这些占位符,请逐一替换成你自己的值。
- HOST
- 该服务的代理地址,按服务页面上显示的原样填写。
- PORT
- 要连接的端口。请和主机一起复制,因为不同服务的端口可能不同。
- USERNAME
- 你的代理登录名。它与你登录控制台所用的邮箱是分开的。
- PASSWORD
- 请完整复制。住宅代理在控制台中选择的选项会附加在密码末尾,凭记忆手动输入的密码会丢失这些选项。
把你用来连接的 IP 地址加入服务的白名单,就可以不用用户名和密码。这时代码里只需要 HOST 和 PORT。
示例都使用 HTTP,它可以通过加密隧道访问 https 网站。SOCKS5 同样可用:住宅代理的端口两种都接受,ISP 和数据中心代理在控制台里切换协议。
步骤
在请求上设置 meta["proxy"]
HttpProxyMiddleware 会读取每个请求的 proxy 键。URL 中带有 USERNAME:PASSWORD 时,中间件会把它们转成 Proxy-Authorization 头,不需要其他配置。
ip_spider.py import scrapy PROXY = "http://USERNAME:PASSWORD@HOST:PORT" class IpSpider(scrapy.Spider): name = "ip" async def start(self): yield scrapy.Request("https://httpbin.org/ip", meta={"proxy": PROXY}) def parse(self, response): yield response.json()运行爬虫,查看出口 IP
httpbin.org/ip 会返回它看到的地址。out.json 里的 origin 字段应该是代理 IP。
terminal scrapy runspider ip_spider.py -O out.json cat out.json用环境变量覆盖所有请求
想让整个抓取都走代理又不想逐个修改 Request,可以在启动 Scrapy 前导出 https_proxy。中间件会在抓取开始时读取它。某个请求的 meta 里设置了代理时,以 meta 为准。
terminal export https_proxy="http://USERNAME:PASSWORD@HOST:PORT" scrapy crawl your_spider
轮换 IP 与粘性 IP
Scrapy 会同时发出很多请求。住宅代理选“随机 IP”时,这些请求会从许多不同地址发出,列表页和搜索页的抓取就能分散到整个 IP 池。
登录、购物车以及任何依赖会话 Cookie 的流程,从头到尾都需要同一个地址。这类爬虫请用“粘性 IP”,或者用整个租期内保持不变的 ISP IP。
常见错误与解决办法
TunnelError: Could not open CONNECT tunnel with proxy ... {'status': 407}
代理 URL 中的凭据被拒绝。从服务页面重新复制 USERNAME 和 PASSWORD,并对其中的 @、: 等字符做百分号编码。
IP 回显服务返回 Crawled (400),但代理连接正常
有些 IP 回显服务即使不走代理也会拒绝 Scrapy 的默认客户端。怀疑代理之前,先像上面那样用 httpbin.org/ip 测试。
并发调高后开始超时
调低 CONCURRENT_REQUESTS_PER_DOMAIN,调高 DOWNLOAD_TIMEOUT。RETRY_TIMES 可以应对偶尔较慢的住宅节点,不至于让整个抓取失败。
大量 403 或 429 响应
网站在限流或封锁你。打开 AUTOTHROTTLE_ENABLED,设置一个真实的 USER_AGENT;如果换了 IP 还是被封,就从数据中心代理换成住宅代理。
其他接入指南
有不明白的词? 术语表用大白话解释。
卡在某一步了?
把命令和报错贴到 Discord,记得先删掉密码。那里的人大多遇到过这些错误。