网站收录

链接写在 JS 里:渲染型页面中的 URL 发现顺序

页面入口明明放好了,目标 URL 却迟迟没有动静,问题常常出在链接只存在于 JavaScript 渲染之后。本文梳理抓取与渲染两个阶段的差别、四种不易被发现的链接写法,以及从源码检查、渲染测试、日志核对到屏蔽排查的自查顺序,并给出为关键页面保留静态路径的兜底做法。

网站收录

链接写在 JS 里:渲染型页面中的 URL 发现顺序

很多做站点运营的人会遇到一个现象:导航里明明放了入口,页面也没有被屏蔽,但几个月过去,目标 URL 还停留在「已发现,尚未抓取」,或者干脆没出现在索引报告里。排查一圈 robots、sitemap、canonical 都没发现问题,最后发现症结在最基础的一环——链接根本没有以爬虫能看见的形式存在。

抓取和渲染是两步,不是一步

搜索引擎处理一个 HTML 页面时,通常先取回原始 HTML 源码,解析其中的 a 标签、图片地址等静态链接;之后才会安排渲染,执行页面上的 JavaScript,拿到渲染后的 DOM。

如果你的链接是 JS 动态加进去的,那它只在第二步之后才存在。第一步的解析结果里,这些 URL 是空白的。渲染是有成本的动作,不会对所有页面、所有时间点都无条件执行,所以纯 JS 生成的链接,被发现的时间点会明显靠后,甚至一直不出现。

这也是为什么「在浏览器里能看到入口」和「爬虫能发现入口」是两回事:你在浏览器里看到的,永远是渲染后的结果。

四种常见的不易发现写法

  • 点击后才生成。下拉菜单、选项卡里的链接写在 click 回调里,不点就不存在,爬虫不会替你点。
  • 滚动到底才加载。无限滚动、懒加载列表,第一屏 HTML 里没有任何指向后续内容的 a 标签。
  • 只用 pushState 路由。页面用 history API 切换视图,地址栏变了,但 HTML 里没有对应链接,爬虫找不到这些虚拟地址。
  • 链接由接口返回。列表数据来自 fetch,HTML 里只有一个空容器。

这几种写法本身没有对错,用户体验往往更好。问题在于它们把 URL 的发现完全交给了渲染,而渲染是你不完全可控的一环。

自查顺序

  1. 看源码,不看元素面板。在浏览器里右键查看网页源代码,搜索 href。开发者工具显示的是渲染后的 DOM,会掩盖问题。
  2. 用抓取测试工具跑一遍。多数站长平台都提供页面抓取或渲染测试,能看到原始 HTML、渲染后 HTML 以及被发现的链接列表,两者对比最直观。
  3. 看服务器日志里有没有渲染请求。有的渲染服务带特定 UA,有的来自不同的 IP 段。如果日志里完全没有相关请求,说明渲染这一环根本没有触发。
  4. 检查是否被技术手段挡住。robots 里屏蔽 JS、CSS 文件,或者对静态资源做了鉴权、按 UA 返回 403,都会让渲染失败,链接自然出不来。
  5. 确认没有互相打架的指令。比如页面本身可抓取,但 JS 文件被 robots 屏蔽,等于给爬虫送了一个残缺页面。

给关键 URL 留一条静态路径

渲染不该是 URL 发现的唯一通道。对真正希望被收录的页面,最省事的做法是至少保留一条静态可达路径:

  • 主导航、面包屑、页脚这类全站出现的区域,用原生 a 标签写死关键栏目和一批重要详情页。
  • 列表页尽量做成分页 URL,而不是纯无限滚动;或者在首屏之外保留「下一页」的静态链接。
  • 把重要页面按分组放进 sitemap。sitemap 是发现渠道,不是收录保证,但至少让 URL 有一个出口。
  • 对确实无法静态暴露的页面,先评估数量。几十个可以靠 sitemap 兜底,上万条就别指望这条路了。
判断标准很简单:把 JavaScript 全部关掉,看还能不能从首页走几步点到目标页面。能点到,发现就不成问题;点不到,就要靠渲染或 sitemap 补。

几个容易忽略的细节

一是锚点与 hash 路由。地址里 # 后面的内容不会作为独立 URL 参与抓取,靠 hash 区分的「页面」在抓取视角里属于同一个地址。

二是前端路由的返回状态。用 JS 做路由的站点,如果所有路径都返回 200 并渲染同一份骨架,容易让爬虫分不清哪些是真实存在的页面。服务端能区分的话,尽量给出准确的 HTTP 状态。

三是别为了发现而堆链接。把几千个链接塞进页脚、塞进隐藏容器,既影响体验,也不会因为数量多就更快被发现,反而可能让页面失去重点。

小结:URL 发现的第一步,是让链接以可解析的形式出现在 HTML 里,渲染只是补充手段。排查时按源码、渲染结果、日志、屏蔽规则这个顺序走,通常能比较快地定位到底是哪一环断了。