越来越多站点把列表、详情甚至整站导航交给 JavaScript 渲染。结果是在浏览器里一切正常,在蜘蛛那边却只拿到一个空壳 HTML。要排查这类问题,先得理解一件事:搜索蜘蛛处理一个 URL,往往不是一次抓取,而是两次。
第一次:拉取原始 HTML
蜘蛛首先请求服务器返回的源码,也就是未执行脚本的那份 HTML。这个阶段它能读到服务端输出的标题、正文、链接、结构化数据和 meta 标签。如果链接在源码里就已经存在,蜘蛛可以直接顺着走;如果链接是脚本执行后才插入 DOM 的,第一次抓取时它看不到。
一个实用的判断标准是:关掉浏览器 JS,页面还剩多少可读内容和可点链接。剩下的那部分,就是蜘蛛在第一时间能拿到的东西。
第二次:进入渲染队列
对于确认依赖脚本的页面,搜索引擎会安排一次渲染,用无头浏览器执行 JS 并读取渲染后的 DOM。这一步有几个特点:
- 排队:渲染资源有限,通常是先发现、后渲染,存在延迟,也不是每个 URL 都能排上。
- 超时:脚本执行、接口请求、图片与字体加载都有时间上限,超出的部分拿不到。
- 不交互:不会点按钮、不会滚动到底、不会关闭弹窗、不会填表单。
换句话说,渲染阶段能救回一部分内容,但它不是保险,更像一次补考。
常见的抓取断点
1. 内容完全靠接口异步拉取
页面源码里只有容器和脚本,数据要等接口返回才出现。如果接口响应慢、需要特定请求头,或者对爬虫 UA 返回不同结果,渲染时同样可能拿不到东西。
2. 链接依赖点击或滚动
加载更多按钮、无限滚动、Tab 切换,都会让后续内容在渲染阶段也不出现在首屏。分页入口如果只是脚本事件而不是真实链接,抓取路径就断在这里。
3. 懒加载与占位内容
图片、评论区等资源进入视口才加载,渲染器不一定滚动,于是这部分可能长期不参与抓取。
4. 登录、验证码与地区限制
被拦住的页面在源码阶段就可能拿到 403 或跳到登录页,后续渲染更无从谈起。
5. 渲染脚本本身报错
JS 抛错、依赖的外链资源被墙、跨域请求被拒,都会让 DOM 停在半成品状态。
怎么确认蜘蛛到底看到了什么
- 用搜索引擎提供的 URL 检查工具,对比原始 HTML 与渲染后 HTML 两种视图。
- 在服务器日志里看该 URL 的抓取次数与状态码,渲染抓取有时表现为同一路径的再次访问或来自不同 UA 的请求。
- 用浏览器禁用 JS 打开页面,记录缺失的正文和链接。
- 检查接口是否对爬虫请求做了差异化返回,这一点往往最容易被忽略。
让链路更稳的一些做法
- 关键内容与主导航尽量服务端渲染,或做同构输出,让源码里就有可读信息。
- 分页、详情入口用真实的链接标签承载,而不是纯点击事件。
- canonical、robots meta 这类指令放在服务端输出,不要靠脚本动态写入。
- 接口保持稳定响应,避免对正常抓取做额外拦截。
- 懒加载尽量留一条不依赖交互的加载路径,或让首屏内容直接输出。
还要提醒一点:渲染能力是逐步获得的。新站、内容更新频率低的站点,排到渲染队列的机会相对更少。把关键内容放进源码,永远比等渲染更省事,也更可控。
能被抓取的内容,往往先能被“不执行脚本”地读到。