翻站点日志时经常会看到这样的画面:同一篇文章的 URL 以好几种形态出现,蜘蛛挨个抓了一遍,返回的都是 200,正文也几乎一样。表面上看抓取次数很漂亮,实际上被覆盖的页面并没有增加,只是把有限的抓取次数摊薄在了重复地址上。URL 去重属于那种平时没人管、出问题时又很难一眼看出来的基础工作。
蜘蛛按 URL 区分页面,不按内容
抓取系统排队、判重、分配回访频率,第一步依据的都是 URL 字符串。只要字符串不同,它就是两个待抓地址;至于打开之后内容是否相同,那是抓回来之后才判断的事。所以对服务器来说,凡是能返回 200 的地址,都会被当成一个独立页面去消耗抓取资源。真正需要做的,是让同一篇内容在对外暴露的地址上尽量只有一个。
常见的重复来源
- 域名层:带 www 与不带 www、http 与 https 同时可访问,且没有强制跳转。
- 大小写:/Article/123 与 /article/123 都能打开,部分服务器环境确实区分大小写。
- 结尾斜杠:/list 与 /list/ 返回同一页。
- 默认文件:/about 与 /about/index.html 并存。
- 端口号:外链里混进了 :80、:443 这类默认端口写法。
- 跟踪参数:?utm_source=、?from=、?spm= 等,同一篇文章被外部转发出多个地址。
- 排序与筛选:列表页的 ?order=、?sort= 组合出大量内容相近的页面。
- 会话与临时 ID:URL 里带 sessionid、随机 token。
- 分页:?page=1 与不带参数的第一页内容一致。
这些情况单独看都不严重,凑在一起就足以让一个中小站点多出几倍的待抓地址。
先确认是不是真重复,再决定怎么处理
不要只凭 URL 长得像就动手合并。先抓下来对比三样东西:标题、主要正文、对外声明的规范地址(canonical)。如果正文主体完全不同,那它是独立页面,不该被 301;如果只是参数不同、正文一致,才属于要去重的对象。比较稳妥的方式是拿日志里出现频次最高的那批地址,人工抽几十条核对一遍,再决定规则。
处理顺序:从源头到兜底
- 先统一下发的链接。站内导航、面包屑、列表页、Sitemap 里输出的地址必须是同一个形态。内链是蜘蛛最主要的入口,内链自己就不统一,后面怎么补救都费劲。
- 用 301 做强制归一。把 http 跳 https、非 www 跳 www、大写跳小写、带默认端口跳标准形态。跳转要一步到位,不要串成多级跳转。
- canonical 做兜底。对于参数页、打印页这类不方便直接 301 的地址,用 canonical 指向主地址,帮助判重。注意 canonical 与 301 的指向要一致,否则等于给蜘蛛两个相反的答案。
- Sitemap 只放规范地址。站点地图里混入重复地址,等于主动把重复 URL 送到蜘蛛面前。
- 参数处理要克制。排序、筛选参数如果确实产生了有价值的独立页面,就让它正常被抓;如果只是同一批内容换了个顺序,考虑限制其抓取,而不是全部 301 回首页。
几个容易踩的坑
- 把所有参数页 301 到首页或栏目首页,容易被当成不当跳转,反而影响判断。
- 301 链太长:A 跳 B、B 跳 C,蜘蛛每跳一次都要重新发起请求,成本叠加。
- 只改内链不做跳转:老地址仍能从外链、历史快照、用户收藏进入,重复地址依然存在。
- 把 robots.txt 屏蔽重复地址当作去重手段。屏蔽只是不让抓,地址仍然存在,也不利于权重传递,不如老老实实做跳转。
- CDN 或反向代理层做了大小写归一,源站没有,两边规则不一致时会来回跳。
去重的目标不是让日志里的 URL 变少,而是让每一个被抓的地址都对应一个真实、独立的页面。
怎么确认有没有做干净
改完之后隔一段时间回到日志里看两件事:一是同一路径下大小写、斜杠、参数的变体请求量是否明显下降;二是 301 是否集中在少数几条规则上。如果仍然有大量变体被以 200 返回,说明源头还没堵住——多半是内链或者外部引用仍在往外吐旧形态的地址。内链统一、跳转到位、Sitemap 干净,这三件事做完,抓取次数才算花在了该花的地方。