结论先放前面: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 做补充通道。發現之後能不能被收錄,還要看目标頁本身的质量與可訪問性,這部分並不在入口頁的控制范围内。