蜘蛛访问一个 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 上花的力气,就能更多地落在真正需要抓的页面上。