爬虫1:从 HTTP 请求伪装到浏览器指纹的攻防博弈

一、 协议层对抗:当 HTTP head不再管用

长期以来,Python 的 Requests 库统治了爬虫领域。对于简单的任务,它依然有效。但在面对 Cloudflare 等现代防火墙时,开发者常会遇到一个困惑:“明明复制了浏览器所有的 Header,为什么还是被拦截?”

答案往往不在应用层(HTTP),而在传输层(TLS)。

1. TLS 指纹

当爬虫发起 HTTPS 请求时,在发送 HTTP 头之前,必须先完成 TLS 握手。在 ClientHello 数据包中,客户端会发送加密套件列表、TLS 版本、压缩算法以及一系列扩展字段。

  • 真实浏览器(如 Chrome、Safari)和编程语言库(如 Python urllib3、Go net/http)在构建这些参数时的顺序和选择存在细微但固定的差异。
  • 反爬系统通过提取这些特征计算哈希值,这就是 JA3 指纹

如果你的 User-Agent 声称自己是 Chrome,但 JA3 指纹却显示你是 Python 脚本,防御系统会立即判定为异常流量。这就是为什么传统的 requests 库在高端反爬面前逐渐失效的原因。

2. 突围利器:curl_cffi

为了突破这一封锁,基于 Python 的解决方案必须深入到底层。curl_cffi 成为了对抗高等级反爬的标准配置。

它基于 curl-impersonate 项目,不仅仅修改 HTTP 头,而是深入 TLS 握手层:

  • 完美模拟:能够精确复刻 Chrome、Firefox 的加密套件顺序和 TLS 扩展排列。
  • 指纹随机化:针对 Chrome 110+ 引入的 TLS ClientHello 扩展顺序随机化机制,curl_cffi 支持动态生成随机指纹,使流量特征在统计学上与真人无法区分。

这使得爬虫开发者可以在保持 Python 开发效率的同时,获得 C 语言级别的性能和浏览器级别的隐蔽性。

二、 渲染层对抗: 解决js动态渲染

对于单页应用,数据由 JavaScript 动态渲染,单纯的 HTTP 客户端已无能为力。浏览器自动化工具经历了从“测试工具”到“爬虫利器”的蜕变。

1. 工具的代际更替

  • 第一代:Selenium
    鼻祖级工具,但受限于 WebDriver 协议的 HTTP 请求-响应模式,高频交互延迟大,且极易通过 navigator.webdriver 属性被检测。
  • 第二代:Puppeteer
    利用 Chrome DevTools Protocol (CDP) 直接控制内核,性能大增,但在 Python 生态中缺乏强有力的官方支持。
  • 第三代:Playwright (当前的王者)
    Microsoft 推出的 Playwright 彻底改变了游戏规则。它全程使用 WebSocket 保持长连接,通信效率极高。

2. Playwright 的杀手锏:浏览器上下文

Playwright 最具革命性的特性是 Browser Contexts(浏览器上下文)
在过去,为了实现并发隔离,我们需要启动多个浏览器进程,内存消耗巨大。而在 Playwright 中,单一浏览器实例可以创建数百个独立的“上下文”。每个上下文拥有独立的 Cookie、缓存和存储空间,类似于数百个“隐身模式”窗口并行运行。这极大地提高了单机并发抓取的资源利用率。

三、渲染层对抗:Canvas 指纹

当你运行一个headless浏览器时,你实际上是在运行一个完整的渲染引擎。反爬系统会利用这一点,通过 Canvas 指纹技术 来识别设备。

1. 什么是 Canvas 指纹?

网站会在后台调用 HTML5 <canvas> 绘制一张复杂的图像(包含特定文字、表情、叠加模式),然后通过 toDataURL() 获取图像的 Base64 编码。由于显卡型号、驱动版本、字体渲染引擎的微小差异,同一段代码在不同设备上生成的哈希值是唯一的。

这意味着,即使你不断更换 IP,只要 Canvas 指纹不变,依然会被追踪。

2. 对抗策略:噪音与一致性的悖论

对抗 Canvas 指纹的核心是“混淆”,通常通过 Hook 浏览器的 Canvas API 注入微小的噪音(例如微调 RGB 值)。

然而,这里存在一个“一致性陷阱”:

  • 初级对抗:随机注入噪音。但这会导致同一个会话中,两次获取的指纹不一致,直接暴露伪造身份。
  • 高级对抗:基于“种子”生成噪音。确保在同一个会话(Session)内指纹保持一致,但在不同会话间变化。

配合 puppeteer-extra-plugin-stealth 等工具,爬虫可以抹除 navigator.webdriver 标志,注入虚假的插件列表,并模拟正常的分辨率(拒绝默认的 800x600),从而在机器视觉层面实现“隐身”。

四、 行为层对抗:模仿人类的生物特征

这是最高级的博弈。当你在协议和环境上都伪装完美后,反爬系统开始分析你的“动作”。

1. 鼠标与键盘轨迹

  • 机器人特征:移动鼠标通常是点对点的直线,速度恒定,点击间隔极度规律。
  • 人类特征:鼠标移动是非线性的,带有加速度,且在点击目标前通常会有微小的“抖动”或校准。
  • 对抗策略:使用专门的 Ghost Cursor 库,结合 Playwright 生成符合人类生物力学的鼠标轨迹,并引入随机化的输入延迟。

2. 蜜罐技术 (Honeypot)

  • 陷阱:网站在页面中通过 CSS (display: none, visibility: hidden) 或移出视口区域,隐藏一些人类不可见的链接。
  • 触发:无脑提取页面所有 <a> 标签的爬虫会访问这些链接。一旦访问,IP 立即被封禁。
  • 防御:在提取链接前,必须判断元素的可见性(Visibility)。Playwright 的 element.isVisible() 方法在此处至关重要,严禁点击人类看不见的内容。

3. 视觉混淆:字体反爬与 CSS 偏移

这是电商(如某宝、某东)和本地生活(如某团、某点评)最喜欢用的手段。“所见非所得”是其核心逻辑。

  • 防御方 :
    • 自定义字体: 网页 HTML 源码中显示的数字是 &#x958f; 或乱码,但通过加载一个动态生成的 .woff 字体文件,浏览器渲染出来是“¥100”。爬虫直接提取源码只能得到乱码。
    • CSS 偏移: 类似于拼图。源码中的文字顺序是乱的(例如“元001”),但通过 CSS 的 left: -20px 等属性将它们强行移动到正确的位置显示(“100元”)。
  • 攻击方 :
    • OCR 识别: 简单粗暴,对页面截图,使用 ocr直接读取图片上的文字。
    • 字体映射库: 下载 .woff 文件,使用 fontTools 库解析 XML,建立“编码-字形”的映射关系。虽然映射关系经常变,但字形的 SVG 路径是不变的,可以通过对比路径相似度来还原。

4. 代码逻辑层:JS 逆向与参数加密

当 API 接口受到保护时,URL 中通常带有一个或多个加密参数(如 _signature, token, analysis)。

  • 防御方:
    • 代码混淆: 使用工具将 JS 变量名改成 _0xa2b1,加入大量死代码、控制流平坦化,使得代码难以阅读。
    • 无限 Debugger: 在代码中注入定时器,一旦打开开发者工具(F12),就会陷入无限断点循环,卡死浏览器。
    • 环境检测: JS 代码在计算签名前,会校验 windowdocument 等对象的属性是否被篡改(防 Hook)。
  • 攻击方 :
    • AST (抽象语法树) 还原: 将混淆的代码解析为 AST,写脚本自动去除死代码、还原变量名。
    • Hook 技术: 使用 Tampermonkey 脚本或浏览器控制台,Hook 关键函数(如 JSON.stringify 或加密入口),在数据加密前截获明文。
    • RPC (远程过程调用): 这是当下的主流黑科技(如 Sekiro, JsRPC)。不需要完全看懂复杂的加密逻辑,只需在浏览器中注入一段 WebSocket 代码,将浏览器变成一个“签名服务器”。爬虫在 Python 端发请求,通过 WebSocket 呼叫浏览器执行加密函数,直接拿回签名。

5. 验证码 2.0:从识别到行为

传统的数字验证码已死,现在是行为验证的时代。

  • 防御方:
    • 滑块/拼图: 校验拖动的轨迹、速度、加速度。
    • 点选/文字顺序: “请按顺序点击图中的:房子、大树、气球”。
    • 空间推理: “请旋转图片直到动物站立”。
  • 攻击方:
    • 打码平台: 对接 2Captcha, YesCaptcha 等廉价人工/AI 平台。
    • YOLO/CNN 模型: 训练专门的目标检测模型识别滑块缺口位置。
    • 轨迹库模拟: 收集真人的鼠标轨迹数据(贝塞尔曲线、抖动、回退),建立轨迹库,在滑动时随机抽取使用。

五、 移动端与基础设施

1. 移动端攻防:APP 逆向

随着 Web 端防护越来越严,很多数据只能从 APP 接口获取。

  • 防御方:
    • SSL Pinning (证书绑定): APP 内部硬编码了服务器证书,拒绝连接 Charles/Fiddler 等抓包工具的伪造证书,导致抓包失败(显示网络错误)。
    • JNI/So 层加密: 将核心加密算法写在 C/C++ 层(.so 文件),比 Java 代码更难反编译。
  • 攻击方 :
    • Frida / Xposed: 动态插桩工具。可以在 APP 运行时 Hook 内存中的函数,绕过 SSL Pinning,或直接调用加密函数。
    • 脱壳机: 针对加固(加壳)的 APP,在内存中提取解密后的 Dex 文件。

2. 账号体系:Cookie 池与信誉分

对于必须登录才能查看的数据(如 微信公众号)。

  • 防御方 :
    • 账号风控: 分析账号的活跃度、注册时间、行为模式。如果一个账号 24 小时不停翻页,直接封号。
    • 手机号验证: 提高注册门槛。
  • 攻击方 :
    • Cookie 池: 维护成百上千个账号的 Cookie。爬虫每次请求随机从池中取一个 Cookie,用完放回或标记冷却。
    • 养号策略: 模拟正常用户行为(随机浏览、点赞、不抓取),提高账号的“信誉分”。

3. 网络层进阶:住宅代理

  • 防御方 :
    • ASN 封锁: 直接封锁阿里云、AWS、DigitalOcean 等云服务商的 IP 段(数据中心 IP),因为正常用户不会用服务器逛淘宝。
  • 攻击方:
    • 住宅 IP: 购买由真实家庭宽带组成的代理网络(通常来自安装了特定 SDK 的免费软件用户)。这些 IP 看起来和普通用户一模一样,极其昂贵但极难被封锁。
    • 4G/5G 移动代理: 利用基站 IP 共享的特性(由于 IPv4 短缺,成千上万个手机共用一个出口 IP),网站通常不敢轻易封锁移动端 IP。