从调试到稳定抓取:一次 Python requests 反爬突破的完整记录
引言
很多数据抓取项目在本地试跑一切正常,一上真实目标站就频繁 403/429、页面返回空数据或重定向到验证码页。本文选择“Python 编程语言”为主题,分享我用 requests 对接某资讯站点时,从出现问题到稳定抓取的完整调试过程与关键实现,希望为你提供一套可迁移的方法论。
背景与问题现象
- 目标:按关键词抓取资讯搜索页的结果列表,并解析标题、链接和摘要。
- 初版方案:直接用 requests.get(url) 抓取 HTML 再用选择器解析。
- 现象:
- 第一轮能拿到部分数据,稍微加快频率后迅速被 403 Forbidden。
- 偶发 429 Too Many Requests,或被重定向到验证码页面。
- 相同 URL 在浏览器可正常访问,说明“请求特征”被识别为爬虫。
排查步骤与思路
复现与最小化问题
- 保留最小请求参数,只打印状态码、关键响应头、是否被重定向。
观察指纹差异
- 对比浏览器与脚本:UA、Accept-Language、Accept、Referer、Cookie 是否缺失;是否启用了压缩;是否跟随重定向。
会话与 Cookie 持久化
- 使用 requests.Session 复用连接、自动携带 Cookie,减少“冷启动”特征。
标准化请求头
- 模拟常见浏览器头部,尤其是 User-Agent、Accept、Accept-Language、Referer、Cache-Control、Accept-Encoding。
限速与重试
- 对 429/5xx 实施指数退避重试;为连接错误配置 Retry;在成功-失败之间加抖动延时。
IP 维度治理(可选)
- 使用稳定代理池,遇到持续性 403 时切换出口;注意代理质量与合规。
动态内容与 JS 渲染
- 若页面主要数据由前端接口渲染,优先直连 API;实在需要可引入 Playwright/Selenium,但要评估成本。
合规与友好
- 尊重目标站 robots/ToS,设置合理频率与缓存,必要时申请正式数据接口。
最小复现代码(问题版)
关键修复实现(稳定版)
代码要点说明
- Session + 连接池:减少握手成本、提升吞吐,且可保留 Cookie。
- Retry 策略:对 429/5xx 与连接错误实施指数退避;尊重 Retry-After。
- 头部伪装:尽量贴近真实浏览器请求,必要时带上 Referer。
- 抖动与速率控制:避免等间隔请求形成“节拍特征”。
- 代理与降级方案:长时间 403 时切换出口;获取不到关键数据时要能优雅降级或回退缓存。
效果与复盘
- 修复后,抓取在中低速率下稳定,无明显 403/429;峰值时仍需结合 IP 池与更严格的节流策略。
- 真正的“反爬突破”不是一招鲜,而是请求指纹治理 + 会话/重试 + 速率/代理 + 业务降级的组合拳。
小结与建议
- 从“最小可复现”开始,优先观察指纹差异与服务端提示(状态码、Retry-After、重定向)。
- 固化稳定基线:Session、标准化 UA/头部、指数退避重试、抖动与缓存。
- 能用官方 API 就别硬爬;确需抓取时务必遵循站点规则与合规要求。
- 将调试经验沉淀为组件:请求模板、拦截器、限速器、代理抽象、可观测性(请求轨迹、耗时、错误分布)。