不少站点的連結並不是寫在 HTML 里,而是由 JavaScript 在浏览器中生成。人看起来一切正常,点击顺畅、跳轉飞快,但對搜尋蜘蛛来说,URL 發現這件事可能被推迟,甚至被漏掉。這篇不讨论「能不能被抓」,只讨论当連結由脚本生成时,蜘蛛發現地址的节奏會發生什么變化,以及站点能做的調整。
抓取和渲染不是同一步
蜘蛛取回一個頁面时,先拿到的是服務器返回的原始 HTML。如果連結只存在于脚本执行之後的 DOM 里,這一轮它就看不到這些地址。
搜尋引擎通常會把這些頁面排進渲染队列,等资源允许时再执行脚本,渲染完成後才提取連結,並把新地址放進下一轮抓取。也就是说,連結從「被渲染出来」到「真正被訪問」,中間還隔着一次排队。頁面层級越深、站点越大,這個時間差越明顯。
連結由脚本生成时,通常會看到什么現象
- 新頁面發布後,日誌里迟迟没有抓取记錄,尤其是列表頁之後的二三层頁面;
- 首頁和主列表頁被抓得很勤,詳情頁數量增長却非常缓慢;
- 分頁、篩選、折叠面板里的地址,几乎不出現在抓取日誌中;
- 同一批老頁面反复被抓,新增 URL 却寥寥無几。
几種常见寫法與它們的代價
- 点击事件跳轉:用 div 或 span 绑定点击,地址寫在脚本里,HTML 中没有任何 href,蜘蛛没有可跟随的目标。
- 前端路由:靠 history 接口換地址,服務器對所有路径都返回同一個壳頁面,連結全部由脚本拼出。
- 無限滚動:内容随滚動加载,没有可翻頁的真實地址,蜘蛛很难走到列表深處。
- 懒加载区块:Tab、折叠面板里的連結只有交互後才插入 DOM,預設狀態下一片空白。
- href 為空或寫成脚本伪协议:看着像連結,實际没有可抓的目标地址。
把關键連結放回 HTML
- 首屏與主内容区尽量服務端渲染或静態生成,導航、面包屑、列表項輸出真實可点的連結。
- 分頁用真實 URL,並且這條地址要能在 HTML 源碼里被讀到,而不是只在点击时才生成。
- 無限滚動之外保留一條可翻頁的备用路径,比如「查看全部」或带頁碼的地址。
- 重要区块不要只放在預設隐藏的 Tab 里,考虑给它一條獨立地址或锚点入口。
- 预渲染可以作為過渡手段,但要让返回给蜘蛛的内容和真實頁面保持一致,避免形成两套内容。
怎么判断自己中招了
不需要复杂工具,几個對照就能看出端倪:
- 用禁用脚本的方式請求頁面,對比有無脚本时 HTML 里的連結數量;
- 看服務器日誌里是否存在渲染服務或第三方渲染来源的請求;
- 观察抓取統計中「已發現未抓取」的 URL 是否長期堆积、迟迟不動;
- 抽查几個深层頁面,確認它是否有来自 HTML 的入站連結。
渲染能帮蜘蛛看到更多内容,但它不是 URL 發現的捷径。能直接出現在 HTML 里的連結,永遠比等渲染更稳。
节奏上的取舍
並不是所有連結都必须塞進 HTML。導航、分類入口、核心内容這些值得;一些纯交互型的小组件可以接受被延迟發現。判断标准很简單:這個地址如果晚几天才被發現,會不會影响站点的主要收錄结构。會,就放回 HTML;不會,留在脚本里問题不大。
一個容易忽略的细节
即便連結已经在 HTML 里,如果它被埋在几百個同质連結之後,或者只出現在頁脚最末端,實际被走到的顺序依然靠後。把重要入口放在离首頁更近的位置,比單纯增加連結數量更有意义。