lesson-03
💡 进群学习加 wx: agentupdate
(申请发送: agentupdate)
(申请发送: agentupdate)
3.1 JavaScript 渲染挑战
大多数现代网站的核心内容是通过 JavaScript 动态加载的,而不是嵌在 HTML 里的。这是对抗简单 HTTP 爬虫的天然屏障。
sequenceDiagram
participant SimpleCrawler as 简单爬虫 (requests)
participant Browser as 真实浏览器 / Playwright
participant Server as 目标服务器
SimpleCrawler->>Server: GET /page
Server-->>SimpleCrawler: HTML (含 )
SimpleCrawler->>SimpleCrawler: 解析 HTML... 内容为空!❌
Browser->>Server: GET /page
Server-->>Browser: HTML + JS Bundle
Browser->>Browser: 执行 JS,触发 API 请求
Browser->>Server: GET /api/content
Server-->>Browser: JSON 数据
Browser->>Browser: 渲染完整内容 ✅典型的 SPA(单页应用)陷阱
import requests
from bs4 import BeautifulSoup
# ❌ 对 React/Vue 等 SPA 网站完全无效
response = requests.get('https://example-spa.com/articles')
soup = BeautifulSoup(response.text, 'html.parser')
articles = soup.find_all('article')
print(len(articles)) # 输出: 0 —— 因为内容还没渲染
3.2 Cloudflare Bot Management
Cloudflare 是全球最广泛使用的 WAF/CDN,其 Bot Management 系统是目前最难绕过的反爬系统之一。
Cloudflare 的五层检测体系
graph LR
A[请求到达 CF 边缘] --> B[L1: IP 信誉检查]
B --> C[L2: TLS 指纹 JA3/JA4]
C --> D[L3: HTTP 头部顺序分析]
D --> E[L4: JavaScript 质询]
E --> F[L5: 行为生物特征]
F --> G{Bot Score}
G -->|Score < 30| H[✅ 正常通过]
G -->|30-70| I[⚠️ CAPTCHA 验证]
G -->|Score > 70| J[🚫 直接封锁]Cloudflare Turnstile(取代 reCAPTCHA)
Cloudflare 在 2022 年推出了 Turnstile,它在后台静默运行,无需用户点击图片。但它会执行一系列 JavaScript 检测:
// Turnstile 内部执行的部分检测(简化版)
const checks = {
// 检测 navigator 属性是否真实
webdriver: navigator.webdriver, // 自动化浏览器会返回 true
// 检测插件列表(真实浏览器有很多插件)
plugins: navigator.plugins.length === 0, // 无头浏览器通常为 0
// 检测屏幕分辨率
screen: screen.width === 0 || screen.height === 0,
// 检测时区与语言是否匹配
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
};
3.3 行为生物特征分析
这是最高级的反爬手段,通过记录鼠标轨迹、键盘节奏、滚动行为来判断是否为人类:
| 行为特征 | 机器行为 | 人类行为 |
|---|---|---|
| 鼠标移动 | 直线或折线,完美精确 | 贝塞尔曲线,有抖动 |
| 点击间隔 | 固定 ms(如总是 100ms) | 不规律,有时快有时慢 |
| 滚动行为 | 匀速,固定步长 | 惯性滚动,有停顿 |
| 页面停留时间 | 极短(抓取完立即离开) | 一般 30s 以上 |
| 鼠标悬停 | 直接点击,不悬停 | 先悬停再点击 |
3.4 蜜罐链接(Honeypot Traps)
网站在 HTML 中隐藏了对人类不可见的链接,机器人会抓取并访问,从而暴露自己:
<!-- 蜜罐链接:CSS 将其隐藏,人类看不到也不会点击 -->
<a href="/trap-page" style="display:none; visibility:hidden">
Click here for more info
</a>
<!-- 或者用 CSS 类隐藏 -->
<a href="/honeypot" class="hidden-link">Do not click</a>
# ✅ 防蜜罐:在爬取前过滤掉隐藏元素
from bs4 import BeautifulSoup
def get_visible_links(html):
soup = BeautifulSoup(html, 'html.parser')
links = []
for a in soup.find_all('a', href=True):
# 检查是否被 CSS 隐藏
style = a.get('style', '')
if 'display:none' in style or 'visibility:hidden' in style:
continue
# 检查是否有隐藏类
classes = a.get('class', [])
if any('hidden' in c.lower() for c in classes):
continue
links.append(a['href'])
return links
3.5 课后问题
- 什么是 Cloudflare Bot Score?它如何影响请求的处理方式?
- 为什么使用 Selenium/Puppeteer 有时也会被检测到?
- 蜜罐链接如何工作?如何在爬虫中规避它?