很多站点把導航、列表、分頁都交给前端框架渲染,HTML 源碼里只剩一個空容器和一串脚本。對用戶来说頁面正常,但對蜘蛛来说,第一次抓取拿到的文档里可能没有任何可跟随的連結。這不是说蜘蛛一定發現不了,而是 URL 發現的路径變長、變不确定。
抓取和渲染不是同一步
搜尋蜘蛛處理頁面时,通常先做一次 HTTP 抓取,拿到服務器返回的 HTML,再解析其中的連結、文本和标簽。對于需要执行 JavaScript 才能出現的内容,部分搜尋引擎會把頁面放進渲染队列,用無头浏览器再跑一遍。這里有两個關键点:渲染队列有延迟,不是抓完立刻执行;不同引擎對 JS 的执行能力、执行时長和资源限制也不一样。
所以,如果連結只存在于 JS 执行之後,蜘蛛能不能看到、多久看到,取决于它是否愿意渲染、渲染时脚本是否成功執行、以及接口資料是否返回。把 URL 發現押在這條鏈上,風險比放在静態 HTML 里高。
首轮 HTML 里没有出鏈,會發生什么
最直接的影响是抓取队列扩展變慢。蜘蛛抓到一個頁面,如果解析不到新的 a 标簽,就没有新的 URL 可以排队。頁面可能仍然被渲染,連結随後被發現,但發現時間會晚于预期。如果渲染阶段失敗——脚本报错、接口超时、资源被 robots.txt 挡住——這些連結可能一直不出現。
另一種情况是頁面本身有連結,但寫法让蜘蛛無法识別。例如用 onclick 绑定跳轉、用 button 加 JS 事件、用 JS 路由只改 URL 不产生真實 a 标簽。這些對用戶是点击,對解析器不是連結。
几種高風險寫法
- 纯 JS 路由:点击後通過 history API 改變地址,源碼里没有對應的 href。
- 動態插入連結:等接口返回資料後才用 JS 建立 a 标簽,首轮 HTML 為空。
- 依赖用戶交互:需要滚動、点击“加载更多”才出現的内容和連結。
- 伪連結:用 span、div 加 onclick 代替 a 标簽,蜘蛛不會把它当作連結。
- 登入後才渲染:未登入抓取时拿不到導航或列表連結。
让連結在首轮 HTML 里就可用
目标很简單:蜘蛛第一次請求时,返回的 HTML 里就包含可抓取的 href。常见做法有:
- 服務端渲染或预渲染關键導航、列表和分頁連結,至少保證主要路径有静態 a 标簽。
- 把“加载更多”改成真實的分頁 URL,每一頁都能獨立訪問,而不是只靠 JS 拼接。
- 用 a 标簽承载跳轉,href 指向真實地址,JS 只做增强,不替代連結。
- 重要入口放在全局導航或頁脚,减少對前端异步接口的依赖。
- 如果确實只能靠 JS,至少用 Sitemap 或静態内鏈把重要 URL 补進發現路径。
Sitemap 和内鏈的兜底
Sitemap 不能替代頁面内鏈,但它能在首轮 HTML 没有出鏈时,给蜘蛛一份可讀的 URL 清單。對于分頁較深、篩選頁較多、或前端渲染為主的站点,把重要 URL 放進 XML Sitemap,並在静態頁面里提供分類入口和面包屑,能减少對渲染队列的依赖。注意 Sitemap 里的 URL 應该是可返回正常内容的地址,不要放重定向鏈或大量參數變体。
怎么確認蜘蛛拿到了連結
- 用搜尋引擎提供的 URL 检查工具,查看“已抓取的 HTML”里有没有目标連結。
- 查看服務器日誌,確認蜘蛛是否請求了那些只由 JS 生成的 URL。
- 在關閉 JavaScript 的情况下打開頁面,看是否還能看到主要導航和列表連結。
- 對比 Sitemap 中的 URL 與日誌中被抓取的 URL,找出長期没有出現的部分。
把連結放在首轮 HTML 里,本质是降低蜘蛛發現 URL 的不确定性。渲染可以补,但不應该成為唯一的路。
總结一下:蜘蛛抓取和渲染有先後,JS 生成的連結不一定不能被處理,但發現會更晚、更容易受脚本和资源影响。對站点运营来说,能静態輸出的連結尽量静態輸出,再用 Sitemap 和内鏈结构兜底,URL 發現會更稳。