懒加载和无限滚动本来是为了让页面更快、更省流量:先加载首屏,剩下的等用户往下滚再取。问题是,搜索蜘蛛不滚动页面,也不点击按钮。它拿到的往往只是首屏那一份 HTML,后面被“省下来”的内容,如果没有别的入口,就很难进入抓取队列。
蜘蛛看到的是初始响应,不是滚动后的页面
蜘蛛请求一个地址时,拿到的是服务器返回的 HTML,以及它能执行的脚本渲染结果。滚动、点击、悬停这类交互行为不在它的动作清单里。所以判断一个页面能不能被完整抓到,关键不是用户能不能看到,而是不滚动、不点击时,内容和链接在不在。凡是必须靠交互才会出现的链接,都要默认它处于不可抓取的状态。
懒加载的两种写法,结果差别很大
原生懒加载属性
img 标签上的 lazy 属性只是推迟加载时机,地址本身仍在 HTML 里,蜘蛛读源码时能看到 src 或 srcset。这类写法对抓取基本没有影响,最多是图片资源本身稍晚被取走。
把地址放在脚本里,滚动时再插入
另一种写法是先用占位符,等滚动到视口附近,再用脚本把真实地址写进 img 或容器。如果页面没有预渲染,蜘蛛在脚本执行完之前读到的就是空占位符。文字内容被这样注入时风险更大:它可能既不进正文,也不产生链接。
无限滚动:地址不变,内容却在换
无限滚动通常不会为新出现的内容生成新 URL,或者只在浏览器地址栏里用脚本改一下。对蜘蛛来说,一个地址对应一份内容,它不会“往下滚”去看后面的条目。
- 所有内容挤在同一个 URL 里,后面的条目很难被单独发现和评估;
- 用脚本拼出的分页地址,如果没有静态链接指向,等于不存在;
- 即使用 History API 改了地址,直接访问该地址能否返回同样内容,也要单独验证。
“加载更多”尽量做成真实链接
按钮最容易踩的坑是写成 button 加 onclick。视觉上没问题,但对蜘蛛来说页面里根本没有可跟随的地址。更稳妥的做法是把它做成一个普通的 a 标签,href 指向下一页的真实地址,再用脚本拦截点击、改成局部加载。
顺序很重要:先保证 HTML 里有可抓取的链接,再考虑用脚本优化体验。反过来做,蜘蛛看到的就是一个没有出口的页面。
给深层内容补一条可抓取的路径
交互体验不必改,但需要另外铺设几条给蜘蛛走的路径:
- 在列表页提供常规分页链接,指向 /list/2、/list/3 这类静态可达的地址;
- 把深层条目按栏目或时间归档,生成一批可遍历的聚合页;
- 在 Sitemap 里列出这些分页与聚合地址,并保证每个地址直接访问都有稳定内容;
- 重要条目在相关正文里用内链指向,形成不依赖脚本的路径。
这几种方式不冲突,可以同时存在。差别只在于谁先被蜘蛛发现,以及服务器要为抓取多承担多少请求。
自查:把脚本关掉,再看一遍页面
最直接的办法是禁用 JS 打开页面,看是否还能读到主要内容和链接,或者用抓取工具对比源码与渲染后的结果。另外可以翻一翻服务器日志:如果某个分页或聚合页很久没有蜘蛛访问记录,多半说明它在 HTML 里缺少入口,而不一定是内容本身的问题。
懒加载本身不是问题,把内容的可达性完全交给用户交互才是问题。让每一层内容至少有一条不需要点击就能走到的地址,抓取路径才不容易断在首屏。