在蜘蛛池入口頁里放目标連結时,有时會顺手带上锚点,比如 example.com/article#part2,或者單頁應用的 example.com/#/detail/123。這種带 # 的 URL,搜尋蜘蛛會怎么處理,會不會因此抓不到目标地址,是不少人問過的問题。先说结论:大多數情况下,搜尋蜘蛛會把 # 及其後面的内容当作頁面内的定位标记,而不是一個新的 URL。
# 後面的内容不會發给服務器
HTTP 請求本身就不包含片段标识符(fragment)。浏览器訪問 example.com/page#section2 时,實际發给服務器的請求只是 example.com/page,服務器看不到 #section2 這一截。搜尋抓取器遵循同样的規則,它發出的請求里不會带 # 後面的部分。所以只要入口頁里的連結去掉片段後指向同一個地址,抓取器請求到的就是那個真實资源。
同頁不同片段會被合並成一個 URL
在 URL 归一化环节,片段通常會被剥离。可以這样理解:
- example.com/page、example.com/page#a、example.com/page#b 一般被视為同一個 URL;
- 入口頁里把這三條連結都放一遍,不會让目标地址被多抓两次;
- 抓取预算也不會因為你多寫了几個 # 就多分出来。
想靠给同一個地址加不同 # 来“多引几次蜘蛛”,基本是無效操作,反而让入口頁顯得杂乱。
真正會出問题的是 hash 路由
如果目标地址是單頁應用,靠 # 切換路由,例如 example.com/#/list 或 example.com/#/detail?id=9,情况就不一样了:
- 服務器收到的請求仍然只是站点根路径,返回的通常是同一份 HTML 外壳;
- 正文由前端 JS 在浏览器端渲染;
- 抓取器能否拿到渲染後的内容,取决于它是否执行 JS、渲染是否成功、内容是否在首屏可见。
這时入口頁里放带 # 的連結,抓取器确實會去請求,但拿到的很可能是一個空壳,這些内容也不會被当成獨立頁面来處理。
确實要用 hash 路由的站点怎么办
- 優先改成 history 模式,让每篇内容有獨立的可請求地址;
- 短期無法改造时,為關键内容补一份静態 HTML 或服務端渲染版本,让抓取器至少能讀到正文;
- 在入口頁里同时提供几條指向静態地址的普通連結,不要只依赖 hash 地址。
入口頁寫法上的几個建议
- 連結直接寫最终要被抓取的那個地址,不要為了好看額外加锚点;
- 需要锚点跳轉时,把带 # 的連結当作站内導航使用,別指望它带出新 URL;
- 同一個目标地址在入口頁出現一次就够了,重复堆叠没有額外收益;
- 投放前先確認目标頁面在無脚本环境下是否有可讀内容。
想知道連結到底有没有被真正請求,看服務器訪問日誌最直接——你會發現日誌里從来没有 # 後面的部分。
怎么驗證
- 查看訪問日誌里請求的完整路径,和入口頁寫的連結做對比;
- 用抓取工具或日誌分析脚本模拟請求,观察返回内容是否為空壳;
- 對單頁應用,用“查看網頁源代碼”而不是開發者工具,確認 HTML 里是否真的有正文。
小结:# 片段在抓取层面基本是透明的,它既不會帮你多要一次抓取,也不會打断對真實地址的請求。真正需要警惕的是把内容完全交给 hash 路由的站点结构——那種情况下,問题不在入口頁寫不寫 #,而在目标地址本身能不能被当作一個可獨立請求、可獨立阅讀的頁面。