網站收錄

連結寫在 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 里,渲染只是补充手段。排查时按源碼、渲染结果、日誌、屏蔽規則這個顺序走,通常能比較快地定位到底是哪一环断了。