结论先放前面:JavaScript 动态插入的链接,搜索蜘蛛有概率发现,但发现率不稳定,延迟也更高。把 URL 发现完全押在 JS 上,通常不是好选择。
搜索蜘蛛处理页面有两条路径
搜索蜘蛛拿到的第一份内容,是服务器返回的原始 HTML。它会先解析这份 HTML 里的 a href 链接、sitemap、canonical 等信号。至于页面加载后由 JavaScript 改写出来的 DOM,需要进入渲染环节,也就是用浏览器内核把页面跑一遍,再重新抽取链接。
两条路径的区别很实际:前者是默认动作,后者要排队、要消耗额外的抓取资源。入口页越多、页面越重,进入渲染队列的机会就越往后排。所以渲染后才有链接的页面,被发现的速度普遍比静态页面慢。
几种写法的风险差异
风险最高:请求返回后再插入
比如页面先加载,再用 fetch 或 XHR 去接口取一批 URL,成功回调里用 createElement 或 innerHTML 拼进列表。这种链路要等网络请求完成、脚本执行成功,而且渲染时接口还得是活的。任何一环出问题——接口超时、跨域被拦、渲染超时被截断——链接都不会出现。
中等风险:脚本里写死数组、页面加载即插入
URL 直接写在脚本的数组常量里,页面一加载就循环生成链接。它不依赖额外请求,比上一种稳一些,但依然要等渲染。如果这段脚本被放在需要滚动、点击或懒加载才触发的位置,风险又会明显上升。
相对稳:服务端渲染或预渲染
让链接出现在服务器返回的 HTML 里,是风险最低的做法。服务端渲染、构建时预渲染,或者干脆用模板直接输出链接,都能让搜索蜘蛛在第一份 HTML 里就拿到目标 URL。
自查方法:先看源代码,再看 DOM
浏览器里右键「查看网页源代码」看到的是服务器原始返回内容,右键「检查」看到的是执行 JavaScript 之后的 DOM。把这两份内容对比一下,就能判断链接到底属于哪一类。
- 源代码里有目标 URL:属于静态链接,发现路径顺畅。
- 源代码里没有、DOM 里有:依赖渲染,稳定性打折。
- 两份都没有:先查有没有别的脚本动态注入,或者链接压根没渲染出来。
更直接的办法,是在服务器日志或搜索蜘蛛的抓取统计里,看目标 URL 有没有被抓取记录。只看入口页被访问、却不看目标 URL 的抓取情况,很容易误判。
让发现更稳的几个做法
- 把关键链接写进初始 HTML。哪怕页面主体是 JS 渲染的,也可以在底部加一块服务端输出的链接区。
- 减少渲染依赖。不依赖接口返回、不依赖点击或滚动就能出现的链接,成功率更高。
- 同步放进 sitemap。sitemap 是独立的发现通道,不受渲染影响,可作为补充。
- 控制单页链接数量。链接过多会分散抓取注意力,重点 URL 反而容易被淹没。
- 保持入口页可访问、响应快。渲染本身就很耗资源,入口页再慢,被抓取和被渲染的机会都会减少。
常见误区
有几种判断经常出错,值得单独提一下。
- 在浏览器里能看到链接,就以为搜索蜘蛛也能看到。你看到的是渲染结果,不代表原始 HTML 里有。
- 用 JS 生成链接,同时又给入口页加了 noindex,却期待链接被跟进。这两件事的目的通常是冲突的。
- 链接写在按钮点击事件里,靠用户交互才生成,这种基本不会被主动触发。
- 把带 # 的地址当作独立 URL 去提交,井号后面的部分通常不会被当成独立地址处理。
把 JS 渲染当作锦上添花,而不是唯一通道,页面的 URL 发现会更可控:能在 HTML 里写清楚的链接,就不要留给脚本去生成。
小结
JavaScript 动态插入的链接不是完全没机会,但它把发现这件事变得不确定:要排队渲染、要脚本执行成功、要渲染时数据源可用。想验证,就对比源代码与 DOM,并去抓取记录里确认目标 URL 的实际状态。想稳妥,就把关键链接放回服务器返回的 HTML,同时用 sitemap 做补充通道。发现之后能不能被收录,还要看目标页本身的质量与可访问性,这部分并不在入口页的控制范围内。