搜尋抓取

源碼里的連結和屏幕上的連結:蜘蛛走的是哪一份

在浏览器里点得動的卡片、按钮和分頁,源碼里可能只是一段脚本。蜘蛛先解析 HTML,再决定要不要渲染,連結不在源碼里,URL 發現這條路就断了。這篇梳理連結消失的几種常见寫法,以及用服務端渲染、静態内鏈和 Sitemap 把路径补回来的做法。

搜尋抓取

源碼里的連結和屏幕上的連結:蜘蛛走的是哪一份

打開開發者工具,頁面上是一排排可以点的卡片和分頁按钮;查看網頁源代碼,這些連結却一個都找不到。對用戶来说没差別,對蜘蛛来说,這是两條不同的路。

蜘蛛先看源碼,再决定要不要渲染

抓取大体分两步:第一步下载 HTML 並解析,第二步在需要时执行脚本、渲染頁面。第一步便宜且稳定,第二步更贵,也更不确定。

  • 寫在 a 标簽 href 属性里的地址,第一步就能進入待抓取队列。
  • 只在脚本执行後才出現的連結,要等渲染完成才可能被發現,而渲染並不是每次都會發生。

所以問题往往不是“蜘蛛不抓 JS 頁面”,而是連結從源碼里消失了,URL 發現少了一條稳定入口。

連結“消失”的几種常见寫法

  • 用脚本跳轉代替連結:元素上只绑了点击事件,跳轉由脚本里的地址赋值完成。没有 href,第一步就看不到目标地址。
  • 前端路由:單頁應用通過 history 接口改寫地址栏,源碼里的列表項没有 href。
  • 資料来自接口:列表由接口返回的 JSON 渲染,目标地址也寫在 JSON 里。
  • 外面套了容器:内容放在 iframe 里,源碼中看不到内部連結。
  • 只在交互後加载:点击“展開更多”才把下一批連結插入頁面。

這些寫法本身没有错,問题在于它們把 URL 發現完全押在渲染這一步上。

让連結回到源碼里:几個层級的做法

首選:服務端渲染或静態生成

列表頁、詳情頁、分頁導航在服務端就把 a 标簽和 href 輸出到 HTML 里,蜘蛛第一步就能拿到。分頁用真實的下一頁連結,而不是一個按钮。這样即使後續脚本出错,抓取路径依然完整。

次選:预渲染與動態渲染

對已知的抓取 UA 返回渲染後的 HTML,是可行但需要持續维護的方案。要留意几点:

  • 渲染後的 HTML 與普通用戶看到的應保持一致,不要返回明顯不同的内容。
  • 中間若有缓存层,缓存键要能区分不同版本,避免把空壳頁缓存给蜘蛛,或把渲染版塞给普通用戶。
  • 渲染服務要纳入监控,長時間超时或报错會让蜘蛛拿到不完整的頁面。

兜底:Sitemap 與静態内鏈

如果短期内改不了前端,至少把 URL 清單交给 Sitemap,並在頁脚、主導航、面包屑這類静態輸出的位置补上通往重要頁面的連結。這样即便渲染环节失敗,蜘蛛仍有別的入口到達這些地址。

渲染服務不稳时會發生什么

渲染依赖服務端资源,出問题时常见两種表現:

  1. 返回 200,但頁面是空壳。蜘蛛拿到一個几乎没有正文和連結的 200 頁面,容易影响它對這批 URL 的後續抓取意愿。
  2. 超时或返回 5xx。蜘蛛會稍後重试,短期内這片路径的發現能力下降。

因此,渲染失敗率、平均耗时、空内容比例都值得進监控,而不是只盯着首頁能不能打開。

抓取路径断掉时,站点通常不會报错,只是新頁面迟迟不出現。检查源碼,比反复提交 Sitemap 更直接。

怎么自查

  • 用命令行請求頁面,看返回的 HTML 里有没有目标連結。
  • 浏览器禁用脚本後再看一遍,確認主導航和列表仍能走通。
  • 在服務器日誌里筛蜘蛛的請求路径,看它是否只停在首頁和少數入口頁。
  • 對比源碼版本與渲染版本,確認連結是否只在渲染後才出現。

小结

蜘蛛走的是它拿到的那份 HTML。把關键連結寫回源碼,是让抓取路径稳定的省事做法;前端渲染並非不能用,但要清楚它把 URL 發現的责任從 HTML 轉移到了渲染服務上,而這一步更容易出错。