蜘蛛訪問一個 URL,服務器回了一個 301,它不會就此結束,而是顺着 Location 头繼續訪問下一個地址。每一次跳轉,都是一次額外的請求。鏈條短一点無所谓,鏈條長起来,問题就慢慢顯現:蜘蛛花在同一個頁面上的請求變多,真正需要抓的新 URL 拿到的机會變少。
一次跳轉,蜘蛛要額外做几件事
表面上看,跳轉只是把用戶带到新地址。對蜘蛛来说,流程是這样的:請求舊地址、讀到狀態碼與目标地址、把目标地址放進待抓队列、再次請求、最後拿到 HTML。如果這條鏈有三跳,同一個目标頁面就要消耗四次請求才能拿到内容。
這带来三個直接後果:
- 抓取次數被重复占用,尤其在被跳轉的 URL 數量很多时。
- URL 發現被拉長,新頁面進入抓取队列的時間可能被推後。
- 連結信号的归属變模糊——外鏈指向的是舊地址,最终呈現的却是新地址。
跳轉鏈太長,通常是這几種情况叠出来的
- 协议與域名叠加:http 跳到 https,再跳到带 www 的 https,最後再补一次尾斜杠。
- 歷史遗留:早年改過一次目錄结构,舊路径没有一次性替換干净,變成二級甚至三級跳。
- CDN 與源站各管一段:邊缘节点做了一次規范化跳轉,源站又做了一次。
- 語言或地区判断:根據 IP 或 Accept-Language 再跳一次到具体語言目錄。
- 登入與權限:未登入狀態下被跳到登入頁,登入頁又跳回列表頁。
301、302、307,蜘蛛的理解並不一样
301 表示永久迁移,蜘蛛會倾向于把舊地址替換成新地址,後續直接抓新地址。302 和 307 表示临时跳轉,蜘蛛一般會繼續保留舊地址,並按一定频率回来复查——如果這個“临时”持續了几個月,等于让蜘蛛長期多跑一趟。
實际维護中常见的失誤,是把一次永久性的结构調整寫成了 302。蜘蛛不會立刻把抓取目标切過去,舊地址仍然占着队列位置。確認是長期變更的,用 301;只是活動頁、临时分流,才用 302 或 307。
鏈條末端才是那個真正被收錄的 URL
這一点直接影响 Sitemap 和内鏈的寫法。蜘蛛最终抓取、最终判断内容归属的,是跳轉鏈末端那個返回 200 的地址。因此:
- Sitemap 里應该寫末端地址,而不是中間那個會跳轉的地址。
- 站内連結直接指向末端地址,別让每個内鏈都先跳一次。
- canonical 标簽也用末端地址,避免出現“頁面说自己規范到 A,A 又跳到 B”的分裂。
- 外鏈如果拿不到修改權,至少保證舊地址能一跳到達,不要让它经過中轉頁。
一個简單的判断标准:從任意一個對外公開的地址出發,到達最终内容頁面,最好不超過一次跳轉。超過一次,就值得回头看看是谁多加了一层。
几種容易漏掉的跳轉
- meta refresh 與 JS 跳轉:返回 200 的空壳頁,几秒後才用脚本跳走。蜘蛛對這類跳轉的處理不如服務端 301 明确,容易出現空頁面被抓的情况。
- 按 UA 判断的跳轉:服務端识別到蜘蛛 UA 就跳到別的地址,這類規則一旦寫错,蜘蛛看到的和用戶看到的不是同一套頁面。
- HSTS 與强制 HTTPS:浏览器层面會自行升級,但蜘蛛仍然可能先訪問 http 地址,多一次請求。
- 分頁與篩選參數:參數被規范化後跳回無參地址,數量一多,跳轉請求會明顯堆积。
排查跳轉鏈的常規做法
- 用命令行或抓取工具查看完整跳轉鏈,记錄每一跳的狀態碼和目标地址。
- 從服務器日誌里筛出 301、302 狀態碼較多的路径,看是否集中在某几個目錄。
- 抽查 Sitemap 中的样本 URL,確認它們返回的是 200,而不是一连串跳轉。
- 把内鏈模板里的舊地址统一替換成末端地址,减少站点范围内的重复跳轉。
- 改完之後保留一段過渡期,舊地址繼續 301,但不再让它參與内鏈分發。
跳轉本身没有問题,問题是鏈條太長、方向不一致、末端地址和 Sitemap 说的不是同一個。把這三件事理顺,蜘蛛在同一批 URL 上花的力气,就能更多地落在真正需要抓的頁面上。