蜘蛛池知识

蜘蛛池入口页的 JS 渲染与跳转:内容藏在脚本里,蜘蛛能读到多少

不少入口页把跳转和正文都交给 JavaScript,日志里蜘蛛明明来过,目标页却始终没被读到。这篇梳理搜索引擎抓取页面时 HTML 获取与渲染两个阶段的关系,拆开纯 JS 跳转、脚本注入内容、懒加载三种常见用法的风险,并给出用访问日志和无 JS 抓取对比来验证蜘蛛实际读到什么的做法。

蜘蛛池知识

蜘蛛池入口页的 JS 渲染与跳转:内容藏在脚本里,蜘蛛能读到多少

做入口页的人常有一个错觉:浏览器里打开一切正常,蜘蛛看到的应该也一样。但搜索引擎抓取页面通常分两步走——先按原始 HTML 拿一遍,再排队用渲染服务执行页面里的 JavaScript。两步之间有时间差,能力也不完全对等。如果入口页的关键内容或跳转全靠脚本,蜘蛛可能只拿到一个空壳。

蜘蛛读页面,往往要分两次

第一次抓取拿到的是服务器返回的原始 HTML。这时候由 JS 动态写入的文本、链接和跳转指令都还不存在。搜索引擎随后会把这些 URL 放进渲染队列,用无头浏览器再跑一遍,才可能看到脚本生成的内容。

渲染队列是有成本和延迟的:站点权重低、页面重复度高、入口页数量庞大的时候,很多 URL 可能等不到渲染那一步,或者渲染出来的结果和第一次抓取对不上。蜘蛛池入口页往往数量多、结构相似,正好属于渲染资源容易被压缩的类型。

三种常见 JS 用法,风险不一样

纯 JS 跳转

用 window.location 之类的方式把访客带向目标页,是入口页最常见的做法。问题在于:这条跳转指令写在脚本里,第一次抓取拿到的 HTML 中并没有对应的链接,蜘蛛既看不到目标 URL,也判断不出这一步跳转的含义,它大概率把入口页当场处理完,不会跟进。

相比之下,服务端返回的 301 或 302,以及写在 HTML 里的 meta refresh 再加一个普通 a 标签链接,至少在原始 HTML 层面是可读的。

内容靠脚本注入

有些入口页把正文、内链、分页都交给前端框架渲染。如果服务端不做预渲染,原始 HTML 里只剩一个空容器和几个 script 标签。这种做法对入口页尤其不划算——入口页本身承担的就是让蜘蛛看到链接和上下文的功能,内容后置等于把最关键的部分藏起来。

懒加载与无限滚动

图片懒加载影响相对小,因为蜘蛛主要关心链接和文本。但列表、内链如果也做懒加载,或者靠滚动才触发加载,情况就不同了:蜘蛛不会主动滚动页面,滚动区之后的内容和链接通常拿不到。

怎么确认蜘蛛到底读到了什么

  • 看日志里的资源请求。真实的渲染抓取通常会伴随一批 CSS、JS、图片请求,并且 UA 与主文档抓取一致。如果某个入口页只有一次 HTML 请求、之后再无动静,大概率没有被渲染。
  • 对比有 JS 和无 JS 的结果。关掉 JS 打开入口页,看还剩多少正文和链接。如果几乎为空,就要假设蜘蛛第一次抓取时同样是空的。
  • 看原始响应而不是最终 DOM。直接看服务器返回的 HTML 源码,而不是浏览器开发者工具里渲染完的页面结构,两者的差别往往比想象中大。
  • 观察内链的后续抓取。入口页上指向目标页的链接如果长期没有对应的访问记录,说明蜘蛛根本没读到那些链接。

几条实务上的取舍

  1. 能放在原始 HTML 里的,就别放到脚本里。跳转、正文主干、指向目标页的链接,优先由服务端输出。
  2. 必须依赖 JS 渲染时,考虑做服务端渲染或预渲染,保证第一次抓取就有可读内容。
  3. 跳转尽量用服务器端状态码,或 meta refresh 配合可见链接,不要只留一行 location 赋值。
  4. 入口页的列表和分页避免无限滚动,改成可点击的分页链接。
  5. 上线一批入口页后,隔几天翻一次日志,确认蜘蛛是否只停留在 HTML 那一层。
渲染是搜索引擎额外付出的成本,不是入口页的默认待遇。把关键信息放在第一次抓取就能读到的地方,才不用去赌渲染队列什么时候轮到自己。

需要说明的是,即使原始 HTML 完全可读,也不代表蜘蛛一定会跟进每一条链接、一定会抓取目标页——抓取预算、页面质量、重复度都会影响结果。JS 这一层只是最容易排查、也最容易改掉的一个问题。