搜索抓取

页面靠 JavaScript 渲染时,蜘蛛的抓取路径会怎么走

当页面由 JavaScript 渲染时,蜘蛛拿到的初始 HTML 往往和用户看到的并不一样。渲染要排队、要加载资源,任何一步受阻,停在脚本里的链接就不会被发现。本文梳理蜘蛛从下载 HTML 到执行脚本的路径,并给出让内链在两种状态下都可见的做法。

搜索抓取

页面靠 JavaScript 渲染时,蜘蛛的抓取路径会怎么走

前端框架普及之后,服务器返回的 HTML 常常只剩一个空容器,正文和链接都要等 JavaScript 跑完才出现。蜘蛛在这方面比以前进步很多,但它走的顺序和用户不同:先下载 HTML,再去排队执行脚本,中间任何环节出问题,停在脚本里的链接就不会进入下一步。

第一份 HTML 决定第一次分叉

蜘蛛请求一个 URL 时,最先拿到的是服务端直接返回的源码。如果导航、栏目入口、详情页链接都写在这份源码里,路径在这一层就铺开了;如果它们全部由 JS 在浏览器端生成,第一份源码里就是空的,蜘蛛只能等渲染。等待不是问题,问题是等待有成本,而且不保证成功。

渲染是排队发生的,不是同步的

渲染阶段的执行依赖不少外部条件:

  • 渲染用的脚本和样式如果被 robots.txt 屏蔽,蜘蛛看不到完整页面;
  • 第三方统计、字体、地图等脚本加载慢或超时,会拖住整页的渲染;
  • 渲染任务有排队,页面越依赖脚本,真正拿到内容的延迟越大;
  • 需要登录、需要点击才出现的链接,基本不会进入抓取路径。

所以,一个在浏览器里看起来完全正常的页面,可能在蜘蛛那一侧只呈现出一个框架结构。

用 a 标签还是用点击事件

同样是跳转,写法不同,结果差别很大。写成 <a href="/detail/123">,蜘蛛在解析 HTML 时就能拿到链接;写成 span 加 onclick 跳转,或者靠 JS 绑定事件,链接对蜘蛛来说等于不存在。用 history.pushState 做客户端路由时也一样,地址栏变了,但 HTML 里没有对应的 href,蜘蛛没有可跟随的目标。

另一种常见情况是链接确实存在,但被包在条件判断里,比如只有鼠标悬停、只有滚动到可视区域才插入 DOM。蜘蛛的渲染不一定触发这些条件。

懒加载和无限滚动要留出口

图片懒加载问题不大,内容链接的懒加载就要留意。列表页如果只在滚动到底部时才追加下一页,蜘蛛很难走完。比较稳妥的做法是把分页做成带真实 URL 的链接,滚动加载只是给用户的补充,而不是唯一入口。

怎么确认蜘蛛真的走通了

  1. 用可以查看渲染结果的工具检查页面,对比初始 HTML 和渲染后的 HTML,看链接在哪个阶段出现。
  2. 在服务器日志里搜索子页面路径,确认有没有来自蜘蛛的请求,而不是只有首页的访问记录。
  3. 检查 robots.txt 是否挡住了渲染必需的 JS、CSS 资源。
  4. 排查脚本错误和超时,尤其是首屏依赖的第三方资源。
判断标准不是页面在浏览器里能不能打开,而是初始 HTML 或渲染结果里有没有可跟随的 href。

让两条路径都能走

关键导航、栏目入口、详情页链接尽量在服务端渲染输出,或者至少保证初始 HTML 中存在链接。对重内容页面,可以考虑服务端渲染或预渲染,把主体内容先给出去。链接统一用标准 a 标签承载,客户端路由只作为增强。这样无论蜘蛛走初始 HTML 还是走渲染路径,都能找到下一步。

抓取路径断在渲染阶段的信号

如果日志里首页和几个主要栏目页抓取正常,更深一层的 URL 却长期没有记录,而站点又是重度依赖 JS 的结构,那基本可以把排查方向放在渲染环节,而不是外链或权重。先把这个环节理顺,再谈抓取频率和收录,顺序会更顺一些。