现在很多页面的正文不是一次性吐出来的:图片滚到位置才加载,列表往下拉才续上,评论区点开才出现。对用户来说这是体验优化,对蜘蛛来说,如果这些交互没有对应的 HTML 兜底,就等于把一部分 URL 藏在了一条需要执行脚本才能走通的路径后面。抓取本身不判断内容好不好,它先要能看见链接。
懒加载:图片和链接的处理并不一样
图片懒加载通常把真实地址放在 data-src 一类自定义属性里,等进入视口再写回 src。图片能不能被抓到,主要影响的是图片搜索和页面完整性,对 URL 发现的冲击相对有限。真正需要注意的是正文里的链接:如果列表项、卡片、相关阅读都是脚本注入的 a 标签,那么在未渲染的抓取下,页面可能只是一个空容器。
判断方法很直接:把浏览器 JS 关掉,重新打开这个页面,看看还剩多少文字、多少可点的链接。如果导航、列表、正文链接都还在,说明你的 HTML 结构本身是完整的;如果只剩一个加载动画,那就要考虑服务端渲染或预渲染这条路。
无限滚动:滚动条后面的 URL 有没有出口
无限滚动最常见的问题不是内容抓不到,而是后续批次的 URL 没有稳定入口。用户滚一下,脚本请求下一批数据并插入 DOM,地址栏不变,也没有可点击的分页链接。蜘蛛不会一直滚动,它更依赖页面里已经存在的 href。
比较稳妥的做法是保留可访问的分页地址,比如 /list/?page=2 这样的形式,同时在首屏的“查看更多”上给出真实链接;用 history API 更新地址栏也可以,但那更多是给用户和分享用的,不能替代 HTML 里的链接。
折叠、选项卡和弹窗
用 CSS 隐藏的内容,比如 display:none 的折叠面板,文字通常仍在 HTML 源码里,抓取时一般能读到。麻烦的是“点击后才请求”的那类:选项卡切换时用 Ajax 拉一段 HTML 插进来,弹窗里的详情链接只在点击后生成。这部分内容对蜘蛛来说,取决于它是否渲染以及渲染的程度。
如果这些内容本身对应独立 URL,尽量让每个面板有可直接访问的地址,或者至少在初始 HTML 中保留关键链接和摘要文字。把重要链接只放在点击事件里,等于给 URL 发现加了一道不必要的关卡。
渲染、压缩与缓存各管一段
服务端渲染、预渲染和客户端渲染的差别,最终体现在首屏 HTML 里有什么。压缩、缓存、CDN 解决的是传输快慢,不会改变内容是否写在源码里——文件传得再快,链接不在里面也读不到。反过来说,HTML 结构清晰、链接齐全的页面,即使传输层普通一些,抓取路径通常也不会有大问题。
可以照着做的几项检查
- 禁用 JS 打开页面,看导航、列表和正文链接是否仍然存在
- 给无限滚动列表保留可访问的分页地址,而不是只留滚动加载
- 懒加载图片保留 noscript 或真实 src 兜底,避免整块内容为空
- 折叠面板、选项卡里的关键链接不要只存在于点击后的请求结果中
- 翻抓取日志,确认蜘蛛确实访问到了这些分页和面板地址
- 对改造过的栏目页,隔一段时间复查一次,别让新模板悄悄改回纯脚本加载
能被抓到的前提是先被看到。交互可以让体验更好,但不要让它成为 URL 发现的唯一入口。
这类调整不需要一次性推翻现有前端方案,多数情况下只要在关键位置补一条静态链接、保留一个分页入口,就能让抓取路径重新变得连贯。做完之后用日志核对一遍实际访问情况,比单看页面效果更可靠。