常见問题

蜘蛛池入口頁的連結由 JavaScript 動態插入,搜尋蜘蛛還能不能發現

蜘蛛池入口頁把連結交给 JS 動態生成,搜尋蜘蛛還能不能發現目标 URL?本文拆解抓取與渲染两段流程的差別,對比初始 HTML、内联脚本、异步注入三種寫法的實际表現,给出用源碼和日誌對照驗證的方法,以及把關键連結放回静態 HTML 的具体做法。

常见問题

蜘蛛池入口頁的連結由 JavaScript 動態插入,搜尋蜘蛛還能不能發現

不少蜘蛛池入口頁為了省事,會把連結列表交给 JavaScript 在浏览器里動態生成。這时一個很實际的問题就来了:搜尋蜘蛛訪問入口頁时,看到的是几乎是空壳的 HTML,它還會不會繼續去發現那些目标 URL?答案不是简單的“會”或“不會”,而是取决于這些連結最终出現在哪一個环节里。

一、抓取和渲染是两段流程,別当成一件事

主流搜尋引擎對 JavaScript 的處理通常是两段式:先用抓取程序拿到原始 HTML,把里面的連結和资源记下来;如果頁面被判定需要渲染,再排進渲染队列,由渲染服務执行 JS、拿到渲染後的 DOM,再做一次連結抽取。問题在于第二段是异步的,而且要排队。

這意味着两件事:

  • 連結如果只存在于 JS 执行之後,它的發現會被推迟,通常不是秒級,可能是小时級甚至更久。
  • 渲染队列不是所有 URL 都能進,優先級低的頁面可能長期只被“抓取”,而一直没被“渲染”。

二、三種常见寫法,實际差別很大

1. 初始 HTML 里就带連結

不管頁面外面套不套前端框架,只要服務器返回的 HTML 源碼里能看到 <a href="...">,抓取程序在第一次請求时就能抽到。這是最稳的一種做法。

2. 内联脚本同步寫入

比如在 <script> 里用 document.write,或者先拼好字符串再插入节点。部分渲染器會执行它,但仍然依赖渲染环节,不能指望抓取阶段就拿到這些連結。

3. 外部 JS 异步請求後再注入

先用 fetch 請求接口拿一份 JSON,再循环生成 DOM。這種最不稳定:既要有渲染能力,還要能执行外部脚本、請求接口,任何一步被 robots.txt、網絡抖動或超时挡住,連結就完全不可见。

三、怎么確認入口頁的連結有没有被真正發現

不要靠猜,用源碼和日誌来對照:

  1. 禁用 JS 抓一次入口頁,看返回源碼里有多少條目标 URL。這個數字就是抓取阶段能拿到的數量。
  2. 在浏览器里打開同一頁,用開發者工具看渲染後 DOM 里的連結數量。两者的差值,就是“只能靠渲染”的部分。
  3. 翻服務器日誌:入口頁被抓之後,目标 URL 有没有出現過来訪,間隔多久。如果入口頁天天被訪問、目标 URL 一條都不来,基本可以判断連結没進入發現流程。
  4. 做對比測試:同一批目标 URL 分別放在静態 HTML 和 JS 注入的位置,观察两邊日誌的差异。

四、想稳妥,就把關键連結放回初始 HTML

  • 入口頁優先做服務端渲染,或者干脆輸出静態 HTML,让連結在源碼里可见。
  • JS 只用来做样式、交互和統計,不要用来承载“唯一一份”連結列表。
  • 如果确實只能用 JS,至少在 <noscript> 里放一份普通連結,或者在頁脚补一组静態連結兜底。
  • 把重要的目标 URL 放在 HTML 前部,避免後半部分因為頁面体积過大被截断。
需要說明的是,让連結出現在初始 HTML 里,只是“有机會被發現”,並不等于會被抓取或被收錄。最终還要看目标 URL 本身的内容质量、服務器响應狀態和站点整体的抓取预算。

五、两個容易被忽略的细节

第一,有些入口頁用 JS 生成連結後,還會顺手加上 rel="nofollow",或者寫成 onclick 跳轉而不是真正的 href。這两者都會让連結在抽取阶段失效。跳轉請用可点击的 a 标簽,不要用 javascript:void(0) 或纯 onclick。

第二,連結的可见性和渲染完成度有關,但和渲染时机無關。如果你在日誌里看到入口頁被訪問的時間点,和渲染服務真正执行的時間点可能相差很遠,排查时不要只盯着抓取時間,把渲染队列的延迟也算進去。

總结一句:搜尋蜘蛛對 JavaScript 並非無能為力,但渲染是有代價、有排队的。蜘蛛池入口頁這類“連結搬运”性质的頁面,本身没有多少内容價值,更應该把鏈路做简單一点——源碼里能直接看到的連結,永遠比藏在脚本执行之後的連結更可靠。