为什么蜘蛛看到的和你看到的不一样
在浏览器里打开页面,内容齐全、排版正常,于是很多人默认抓取工具看到的也是同一份东西。实际情况是,你看到的是浏览器执行完 JavaScript 之后的页面,而抓取工具第一眼拿到的往往是服务器返回的原始 HTML。如果正文、列表、链接都是脚本执行后才插入的,那么初始 HTML 里可能只有一个空的挂载节点和几行脚本引用。内容不是不存在,只是出现得太晚,甚至根本不出现。
这不是某个框架的错,而是渲染方式的选择问题。问题在于,很多站点是在上线之后才发现这件事,此时页面已经被抓过一轮,索引里的状态和实际内容对不上。
三步自查:确认正文到底在不在初始 HTML 里
第一步:直接请求源码
用命令行工具带上常见抓取工具的 User-Agent 请求目标页,把返回的 HTML 保存下来,然后在文本里搜索正文中的一句话。搜不到,说明正文不在初始响应里。这一步比看浏览器「查看源代码」更可靠,因为有些浏览器的源码视图会显示执行后的 DOM。
第二步:关掉 JavaScript 再看一遍
在浏览器设置里禁用 JavaScript 后重新打开页面。如果页面只剩导航骨架、加载动画或一片空白,而正文完全没有出现,那基本可以确认内容依赖脚本渲染。这个方法简单,适合批量抽查栏目页、详情页、列表页。
第三步:核对链接是否是真实链接
列表页和分页导航尤其要注意。如果翻页、进入详情都靠点击事件跳转,HTML 里没有带 href 的 a 标签,那么爬虫在列表页就找不到下一层的入口。把鼠标悬停在链接上,看状态栏是否显示地址,是一个快速的判断方式。
常见的几种「藏内容」写法
- 正文通过接口异步获取,首屏只有一个骨架屏;
- 列表使用无限滚动,没有对应的分页地址;
- 标签页、折叠面板里的内容只在点击后才请求;
- 图片和文字都用懒加载,滚动到可视区域才插入 DOM;
- 整站是单页应用,路由变化不改变服务器返回的 HTML。
这些写法对用户体验未必是坏事,但对抓取来说,入口和内容都变得不确定。尤其当站点内容量大、更新频繁时,抓取到的空页面会占用访问额度,却没有带来任何有效发现。
处理思路:从轻到重
不必一上来就重写整个前端,可以按成本从低到高选择。
- 关键内容服务端输出。把标题、正文首段、主要导航和列表链接改为服务端渲染,交互部分仍交给前端。改动范围小,收益直接。
- 静态生成。内容更新频率不高的站点,可以在构建时生成 HTML,部署后直接返回完整页面,抓取和访问速度都好。
- 预渲染。对少量重点页面在构建或请求时生成静态快照,适合内容不依赖登录态的展示型页面。
- 服务端渲染。内容型站点、需要实时数据的页面可以考虑,但要做好缓存,否则会明显增加服务器压力。
- 分页链接改为真实地址。无限滚动保留给用户,同时提供可访问的分页 URL,两者并存。
需要强调的是,渲染方案不是用来对付抓取的工具。如果给抓取工具返回一份内容,给用户返回另一份内容,或者把正文藏在用户看不到的位置,性质就变了。做法上应当保持两版内容一致,只是让内容更早出现。
改完之后怎么验证
改动上线后,别只看首页。挑几个不同类型的页面:栏目首页、带分页的列表页、内容详情页、标签聚合页。逐个请求源码,确认标题、正文、主要链接都在初始 HTML 中。同时对照访问日志,看抓取工具请求这些地址时的响应状态和返回体积是否正常,体积突然变小通常意味着内容又回到了脚本里。
另外记得检查渲染版本的样式和交互有没有因为改动而错位,尤其是服务端输出与前端接管之间的衔接部分。内容可见性和页面体验不是二选一,两个都要稳住。
把它纳入日常巡检
模板改动、前端框架升级、接口结构调整,都可能无意中让正文重新回到脚本里。可以在每次上线后固定抽查一两个页面,或者把「源码中是否包含正文关键词」做成简单的自动检查。这类问题发现得越早,处理成本越低。