蜘蛛抓取时拿到的,是服務器在那一瞬間返回的响應。這條响應可能已经被 Cookie、地域判断、设备识別或 A/B 測試改寫過。一旦改寫後的版本里少了導航、少了列表連結,抓取路径就會随之變窄,URL 發現也會跟着慢下来。
為什么同一個 URL 會返回不同内容
分流本身不是错誤,很多站点确實需要它。問题在于分流经常在爬虫不知情的情况下發生,而且是按“有没有带 Cookie”“請求從哪個区域進来”這類蜘蛛不具备的條件来判断。
- Cookie 與同意彈窗:首次訪問返回一個带遮罩层的版本,用戶点過之後才寫入 Cookie。蜘蛛没有這個 Cookie,每次拿到的都是遮罩版,若遮罩把首屏連結一起挡在客戶端渲染之外,内鏈就等于不存在。
- 地域與語言跳轉:按 IP 或 Accept-Language 跳到某個語言站。蜘蛛的出口 IP 與用戶分布不同,可能被反复送到同一個版本,其他語言站的 URL 就長期缺少入口。
- User-Agent 分流:给移動端和桌面端返回不同的 HTML 骨架。如果其中一版的導航依赖脚本後置注入,蜘蛛從中拿不到可跟随的連結。
- A/B 測試與灰度:随机把訪問者分到實驗组。蜘蛛每次抓到的可能都是不同分支,連結结构不稳定,抓取结果也就不稳定。
- 登入或會員门槛:未登入狀態只给一個极简首頁,站内大部分 URL 没有對外暴露的路径。
這些分流怎样影响 URL 發現
URL 發現依赖可见的、可跟随的連結。当蜘蛛拿到的版本是一份“瘦身版”,它並不是抓取失敗,而是把這份瘦身版当成了頁面的真實样子:里面有多少連結,就顺着多少連結往下走。结果是站点里有内容的頁面長期没人訪問,日誌里只看到首頁反复被請求。
判断标准很朴素:在不带 Cookie、不模拟登入、不設定特殊 UA 的情况下請求一次,看看返回的 HTML 里能不能找到通向主要栏目的連結。找不到,就是發現路径被切断了。
缓存层會把問题放大
CDN 和反向代理按缓存键决定返回哪一份内容。如果缓存键里包含 Cookie,同一 URL 會被拆成很多份副本,命中率下降,回源增多;如果响應带上了 Vary: Cookie 或 Vary: User-Agent,缓存會把不同請求者当成不同對象,蜘蛛抓到的那一份可能恰好是某個邊缘节点上残留的實驗版本。反過来,如果缓存键過于简單,先被缓存的實驗版或遮罩版又會被分發给後續所有請求者,包括蜘蛛。
排查與治理的常規做法
- 用全新會话、不带任何 Cookie 的請求抓一次首頁和几個栏目頁,检查返回 HTML 中的連結數量。
- 分別用桌面與移動 UA 請求同一 URL,比對可跟随連結的差异。
- 检查响應头里的 Vary、Cache-Control 與缓存键設定,確認蜘蛛與普通用戶是否可能落到不同副本。
- 把導航、面包屑、主要列表這類關键連結做成服務端直出的静態 HTML,不依赖脚本後置注入。
- 確認彈窗、跳轉、同意层不會阻断連結的抓取路径,必要时對爬虫請求返回不含遮罩的基礎版本。
- 如果确實需要多語言或多地域版本,确保每個版本都有稳定、獨立的 URL,並互相之間有可跟随的連結。
把版本差异控制在無害范围内
理想狀態不是消灭所有分流,而是让分流只影响样式、推荐位這類非關键内容。左侧導航、頁脚、面包屑、分頁連結這些承载發現功能的元素,最好在任何版本里都保持一致,並且是服務端就能輸出的。這样即便蜘蛛抓到的是實驗分支、地域版本或未登入版本,它依然能顺着同一套連結繼續走,URL 發現的节奏不會被局部改動打乱。
做這類检查不需要复杂工具,一份不带 Cookie 的响應加上一次日誌比對,通常就能看出問题出在哪一层。