一、爬虫面临的新挑战:为什么传统方法会失效?
如果你还在用 requests + BeautifulSoup 去爬一个 React / Vue 构建的网站,有时会拿到一个只有 <div id="root"></div> 的空壳 HTML。但这未必是代码问题,也未必适用于所有现代站点 ------关键在于它属于哪种渲染模式。
1.1 先判断渲染模式(决定取数策略)
|------------------|----------------------------------|---------------|---------------------|
| 渲染模式 | 代表框架 | 首屏 HTML 是否含数据 | 推荐策略 |
| CSR(纯客户端渲染) | 裸 React/Vue + react-router | ❌ 空壳,靠 JS 渲染 | 无头浏览器 / 抓接口 |
| SSR(服务端渲染) | Next.js、Nuxt.js | ✅ 含完整 HTML | requests 直接解析即可 |
| SSG(静态生成) | Next.js output: export、Nuxt 静态 | ✅ 构建期已生成 | requests 直接解析 |
| ISR(增量静态再生成) | Next.js | ✅ 首屏有,后续增量 | requests + 必要时补接口 |
结论:下次遇到"空壳"别急着上浏览器,先
curl一下看源码里到底有没有数据。很多 Next.js 站点源码里就有完整正文。
1.2 静态网站 vs. 动态网站的本质区别
- 静态网站:服务器直接返回完整 HTML,内容在响应那一刻就已确定。传统爬虫发请求→拿响应→解析即可。
- 动态网站(SPA/CSR):服务器返回的只是骨架页(通常只有一个根节点),真正的业务数据通过 JavaScript 发起 Ajax / Fetch / GraphQL 请求获取,再由前端框架在浏览器端动态渲染。
1.3 三个核心痛点
- 内容不在源码里 :
curl/requests拿到的 HTML 中根本没有目标数据。
- 客户端路由:SPA 用 react-router / vue-router,URL 变化不触发新服务器请求,靠遍历 URL 列表的思路失效。
- 无限滚动与懒加载:抛弃传统分页,数据随滚动动态加载,需模拟用户行为才能触发。
1.4 隐藏技巧:从内嵌 JSON 直接取数(最容易被忽略)
许多框架会把首屏状态序列化进页面 <script>:
- Next.js →
<script id="__NEXT_DATA__" type="application/json">
- Nuxt.js →
window.__NUXT__或<script>__NUXT__({...})</script>
- 通用 → Redux 的
window.__PRELOADED_STATE__、JSON-LD(application/ld+json)
这条技巧能让你不开浏览器就拿到大批数据,优先级应排在"无头浏览器"之前。
二、解决方案全景图:不同架构该用什么工具?
方案一:适用于 CSR / 需要交互的 SPA ------ 无头浏览器
既然内容在浏览器里渲染,就用真实浏览器执行 JavaScript。这是最通用的方案。
主流工具选型
|----------------|----------------------|-----------------------|-------------------------------------------------|
| 工具 | 语言/环境 | 适用场景 | 特点 |
| Playwright | Python / Node.js | 现代 SPA 爬虫首选(微软出品) | 异步并发、自动等待、跨浏览器(Chromium/WebKit/Firebase) |
| Puppeteer | Node.js | Chrome/Chromium 自动化 | Google 出品,生态成熟,Node 技术栈首选 |
| Selenium | 多语言(Java/Python/...) | 传统自动化测试、跨浏览器兼容 | 老牌;Selenium 4 自带 Selenium Manager 自动管理驱动;并发性能偏弱 |
| Pyppeteer | Python | Puppeteer 的 Python 移植 | ⚠️ 已多年不活跃,新项目建议直接用 Playwright |
注:Playwright 同时提供
sync_api(同步)和async_api(异步)两套 API,小规模脚本用同步版更省心。
为什么 Playwright 更值得推荐(生产级场景)
- 事件驱动的 DOM 等待 :
wait_for_selector基于浏览器内部事件判断元素是否渲染,精准高效,告别time.sleep()。
- 原生异步并发 :完美支持
asyncio,单进程内并发管理多个浏览器上下文,每个context独立 cookie 与 session。
- Auto-waiting :执行
click()/fill()时自动等待元素达到可交互状态,降低网络抖动导致的脚本不稳定。
基础示例(Python + Playwright,已修正反检测)
重要提醒 :
--disable-blink-features=AutomationControlled单独使用不足以 隐藏自动化特征,不少站点(如 Cloudflare、部分登录页)还会检查navigator.webdriver,必须配合add_init_script覆盖。更强隐藏可用 playwright-stealth 库。
方案二:分析接口(Ajax / GraphQL)------ 更轻量的替代方案
若无需复杂交互(点击、滚动),直接分析网站 API 往往效率最高。
操作步骤
- 打开 Chrome DevTools(F12)→ Network(网络) 面板;
- 刷新页面,筛选 XHR / Fetch 请求;
- 找到返回数据的请求,复制其 URL、参数、请求头;
- 用
requests模拟发送。
注意两类"现代变体"
- GraphQL :现代 SPA 常用单个 GraphQL 端点(通常是
POST),参数在请求体{"query": "...", "variables": {...}}里。抓包时要看 Payload 而非 URL 参数。
- WebSocket 推送 :行情、聊天、实时榜单类数据常走 WS,普通
requests抓不到,需用websocket-client或浏览器监听。
优势与局限
- ✅ 效率极高、无需启动浏览器、资源消耗小;
- ❌ 接口有加密参数(token / sign)、需登录态、或走 WebSocket 时,此路不通。
方案三:Java 技术栈 ------ Jsoup + Selenium 组合
Jsoup 是 Java 首选 HTML 解析库,但不能执行 JS。用 Selenium 加载页面拿源码,再用 Jsoup 解析:
同样建议给
ChromeDriver加--disable-blink-features=AutomationControlled等参数隐藏特征;解析完毕用quit()而非close()。
方案四(增补):工程化大规模爬取 ------ Scrapy + Playwright
纯 Playwright 脚本难以做分布式、去重、限速、持久化。Python 生态推荐 Scrapy + scrapy-playwright 中间件:Scrapy 负责调度/限速/管道,Playwright 负责渲染。适合中大规模、需要稳定运维的采集任务。
三、进阶技巧:提升稳定性与效率
1. 处理客户端路由(CSR)
SPA 路由变化不触发服务器请求。解法:模拟真实点击触发路由切换,或通过 Playwright 的 page.click() 间接操作;也可直接调用 page.evaluate 操作 History API 后等待新内容。
2. 应对无限滚动(已修正:事件驱动,而非硬编码 sleep)
原则:优先用"等待新元素 / 等待网络空闲"代替
sleep。注意wait_for_load_state("networkidle")在长轮询 / WebSocket 站点上可能永远不触发,应改用domcontentloaded+ 显式选择器等待。
3. 反爬对抗策略
- 模拟人类行为 :随机停顿、随机鼠标轨迹(Playwright 的
mouse.move可加steps)。
- 代理 IP 池:避免单 IP 高频触发限流;注意代理质量(数据中心 IP 易被 Cloudflare 标记,必要时用住宅/移动代理)。
- 伪装 UA 与浏览器指纹 :
--disable-blink-features=AutomationControlled+add_init_script覆盖navigator.webdriver(见第一节示例);更高阶用playwright-stealth/puppeteer-extra-plugin-stealth。
- 限速与退避 :尊重
429 / Retry-After,采用指数退避;不要无脑并发。
- 验证码:出现验证码通常意味着已被风控,应降低频率或改用接口方案;破解验证码涉及法律与道德边界,请谨慎评估合规性。
4. AI 驱动的智能爬虫(说法需谨慎)
前沿方案引入 AI:用 NLP 模型自动识别页面数据区域、减少手写 XPath;用强化学习动态调整频率与代理。这类方案确实能提升稳定性,但"可减少约 30% 被封禁概率"属示例性表述,需以自身场景实测为准,不宜当作既定结论引用。
四、实战工具推荐(已修正)
|-------------------|------------------------------------------------------------------------------------------------|
| 场景 | 推荐工具组合 |
| 快速爬取单个 SPA 页面 | Playwright(Python,同步/异步均可)或 Puppeteer(Node.js) |
| 大规模分布式爬取 | Scrapy + scrapy-playwright + 代理池 |
| 生成 SPA 站点地图 | super-simple-sitemap-generator(基于 Playwright 的 npm 包,确有其物) |
| 通用正文/文章提取 | trafilatura、newspaper3k、readability、extruct(结构化元数据/JSON-LD) |
| 通用浏览器型抓取(含 AI 抽取) | universal-scraper(PyPI 上的 AI 驱动包,依赖 selenium+beautifulsoup+litellm)或自建 Flask + Playwright 服务 |
| 反爬对抗 | 隧道代理 + 浏览器指纹伪装(playwright-stealth 等) |
修正:原文"universal-scraper(Flask + Playwright + Selenium)"描述与事实不符,已按真实形态更正;通用内容提取优先推荐 trafilatura / newspaper3k / extruct 等专业库,而非笼统套一个"万能爬虫"。
五、合规提醒(已补充中国法视角)
采集前请务必:
- 查看 robots.txt :了解允许爬取的路径。注意 robots.txt 是行业惯例/君子协定,并非法律强制,但无视它可能被作为"主观恶意"的佐证。
- 遵守网站使用条款:避免侵犯版权或构成不正当竞争。
- 控制请求频率:避免对目标服务器造成过大压力(DoS 风险)。
-
(中国)法律红线务必留意 :
- 《网络安全法》《数据安全法》:非法侵入、干扰、获取或破坏计算机信息系统/数据可能承担责任;
- 《个人信息保护法》(PIPL):采集姓名、电话、人脸等个人信息需有合法基础,否则涉嫌违法;
- 刑事风险:突破技术措施、批量窃取数据可能触犯非法获取计算机信息系统数据罪 、侵犯公民个人信息罪等;
- 参考判例:微博诉脉脉、大众点评诉百度等对"数据不正当抓取"已有明确司法态度。
- 负责任的数据采集是技术长期可持续的前提:仅采集公开必要数据、做好脱敏与存储安全、留存合规记录。
六、选型决策指南(新增)
按场景快速选方案:
- 页面是 Next.js/Nuxt 且源码含数据 → 直接
requests解析源码 / 提取__NEXT_DATA__;
- 纯 CSR 且数据走简单 REST 接口 → 抓 Ajax/Fetch 接口(最轻量);
- 数据走 GraphQL / WebSocket → 抓对应接口或 WS;
- 需要点击、登录、滚动等交互 → Playwright / Puppeteer 无头浏览器;
- Java 技术栈、只需渲染后解析 → Selenium + Jsoup;
- 中大规模、要稳定运维 → Scrapy + scrapy-playwright + 代理池;
- 触及个人信息 / 需登录态 / 有加密参数 → 先评估合规与技术成本,优先接口方案,必要时谨慎使用浏览器。
一句话心法:能不开浏览器就不开浏览器;能抓接口就别渲染页面;必须渲染时,优先事件驱动等待而非 sleep。