蜘蛛并不理解页面内容,它首先认的是 URL 字符串。两个字符串只要有一个字符不同,在它眼里就是两个地址。于是同一份内容可能被请求很多次,抓取额度被摊薄,日志里也堆满了看起来相似却对不上的记录。
归一化要解决的问题就是:让同一个页面在站内、Sitemap、外链和日志里尽量只以一种形态出现。
蜘蛛是怎么看待 URL 的
在抓取阶段,蜘蛛主要做字符串层面的处理和去重。它不会自动帮你判断 /About 和 /about 是不是同一个页面,也不会因为参数顺序不同就认定它们是同一地址。只有当服务端返回跳转,或者页面上有明确的规范信号时,它才有可能把多种形态归拢到一起。
换句话说,归一化的第一道关口在服务端,第二道在内链输出,第三道才是 canonical 之类的页面级信号。
常见的归一分叉点
- 路径大小写:/About、/about、/ABOUT 在某些服务器上都能访问,于是变成三个 URL。
- 结尾斜杠:/list 与 /list/ 是否都返回 200,取决于服务器配置。
- 默认端口与协议:带 :80、:443 的写法,以及 http 与 https 并存。
- 主机名:example.com 与 www.example.com,以及大小写混写的主机名。
- 目录默认文件:/index.html 与 / 指向同一份内容。
- URL 编码:中文路径可能被编码成大写或小写的百分号形式;%2F 与 / 在部分环境下含义不同。
- 参数顺序:?a=1&b=2 与 ?b=2&a=1 是不同字符串。
- 空值与跟踪参数:?utm_source=xxx、?from=、?spm= 这类参数会在分享和投放中被不断追加。
- 片段标识:井号后的内容不会发给服务器,但带井号的链接如果被当成路径写入内链,就会产生新的字符串。
重复发现带来的实际问题
最直接的影响是抓取资源被分散。假设一个栏目有 200 个页面,但因为大小写和参数组合,实际被发现的 URL 有 1500 个,蜘蛛用在真正内容上的时间就少了很多。
其次是日志失真。做抓取分析时,如果按原始 URL 统计,很可能会得出栏目有大量页面从未被抓取的结论,而真实情况只是同一页面用了不同写法。
统一做法:从服务端到内链
- 确定唯一形态:先定一套规则,例如全小写路径、不带结尾斜杠、统一 https 加 www 或统一不带 www,然后全站按这套规则执行。
- 服务端做 301:把其他形态永久跳转到规范形态,跳转目标直接指向最终地址,不要串成多跳。
- 内链只输出规范形态:导航、面包屑、列表页、相关推荐里的链接统一写法,避免站内自己制造分叉。
- Sitemap 只放规范 URL:清单里出现非规范写法,等于主动把重复地址再喂给蜘蛛一次。
- 页面加自引用 canonical:规范页指向自己,参数页或分页页指向对应主地址,作为兜底信号。
- 跟踪参数单独处理:能去掉的在服务端重定向掉,必须保留的用 canonical 或 robots 规则控制抓取。
用日志验证是否生效
做法不复杂:把访问日志按路径聚合,再把查询参数按字典序排序后当作同一个键统计,看看同一路径下还剩多少种形态。如果某个栏目仍然出现几十种变体,说明还有入口在输出非规范链接。
也可以抽查一段时间内被抓取的 URL,挑出带参数的记录,人工判断哪些是有效筛选、哪些只是跟踪参数。这一步通常能很快定位到问题来源,比如某个分享组件、站内搜索框或者旧的外链。
归一化不是一次性配置,而是一个持续对账的过程。每次改版、换服务器、加投放参数之后,都值得回头看一眼日志里的 URL 形态有没有变多。
别走过头
有些参数确实承载内容,比如筛选、排序、分页,这类地址不该一律跳走,否则会误伤正常页面。同样,编码形式的不一致如果只出现在极少数旧链接上,做一次跳转就够了,不必为它改动整体结构。
判断标准可以简单一些:这个地址是否会被用户或外部链接用到?会,就保留并做跳转;不会,就让它自然消亡。