SEO爬虫报的死链和Googlebot抓的,从来不是同一批URL
本文目录
- 同一份HTML,为什么爬虫和浏览器数出来的链接不一样?
- 尾斜杠一个字符,能把整页链接指向别的地方吗?
- 十九条链接,十三条会变
- 为什么这件事比听起来严重
- 双斜杠入口更狠
- 兜底路由和相对链接凑一块会发生什么?
- 每深一层,链接跟着深一层
- 缺一不可
- 浏览器在解析href之前先做了什么?
- 那一行才是真正的杀手
- 为什么空格反而不剥
- 两套URL标准到底差在哪?
- 一百五十二格判决矩阵
- 差在哪几条
- 连“指向自己”都能算出两个答案
- 基准地址越畸形,两边差得越远
- Googlebot用的是哪一套?
- 现网到底有多少页面会踩这个?
- 但那9.5% 是满格伤害
- 顺手把自家站也测了
- 资源引用比链接更干净
- 那base标签为什么几乎没人用了?
- 怎么让四个裁判给出同一个答案?
- 第一条几乎解决全部问题
- 三条自查
- 保哥的判断
- 常见问题解答
- 我的死链检测工具报了一批404,站内却找不到这些链接,是怎么回事?
- 纯相对链接和根相对链接到底差在哪?
- href里的换行和制表符真的会出问题吗?浏览器不是会自动处理吗?
- 该不该给站点加base标签来统一基准地址?
- Googlebot到底按哪套标准解析链接?
- 两套URL标准并存,以后会统一吗?
- 协议相对链接(以 // 开头)现在还能用吗?
- 权威参考资料
摘要:把一份写着
href="api"的HTML原封不动挂在两个都能返回200的地址下,浏览器算出来的目标链接不是同一个——十九条链接里有十三条会变。再往下拆,同一串字符要经过四道判决才变成一个可抓取的地址:HTML解析器先剥掉里面的换行和制表符,然后URL解析器按标准还原,而现在世面上跑着两套互不兼容的标准,实测一百五十二格判决矩阵有五十一格给出不同答案。最扎眼的一条是htt<TAB>ps://example.com/x:浏览器把它读成一个跨站的绝对地址,而任何按属性原值取链接的爬虫都会把它当成本站的一个相对路径。谷歌自己声明按RFC 3986处理地址,渲染却跑在Chrome里,而Chrome用的是那套明确说要废弃RFC的标准。
上一篇同一个页面11种URL写法都返回200,做SEO查重复内容时一条都不会报数的是入口:一份内容到底有多少种地址能敲开服务器的门。这一篇数的是另一头——这些多出来的入口,会不会把页面上的链接也一起改掉。
结论提前说:会,而且比例高得不像话。
同一份HTML,为什么爬虫和浏览器数出来的链接不一样?
先把问题摆正。<a href="api"> 里的 api 不是一个地址,它是一个相对引用——一段需要配合“当前在哪儿”才能算出结果的字符串。从这段字符串到一个真正可以去抓的绝对地址,中间要过四道手:
| 顺序 | 裁判 | 它干什么 | 谁在用 |
|---|---|---|---|
| 一 | HTML解析器 | 把属性值从字节流里取出来,顺手剥掉某些字符 | 浏览器、渲染型爬虫 |
| 二 | URL解析器 | 把相对引用和当前地址合成绝对地址 | 所有人,但用的标准不同 |
| 三 | 基准地址 | 决定“当前在哪儿” | 取决于这个页面是用哪个地址打开的 |
| 四 | 服务器归一化 | 请求到达后再改一次路径 | nginx及各类web服务器 |
四道手里,只有第四道是上一篇讲过的。前三道全在客户端,而你的SEO工具和Googlebot在这三道上未必是同一套实现。
下面逐道拆,每一道都用实测说话。
尾斜杠一个字符,能把整页链接指向别的地方吗?
从第三道开始讲,因为它最容易验证,后果也最大。
上一篇实测出来,现网57.1% 的站尾斜杠两种写法都返回200,而且字节完全相同。也就是说 /docs/guide 和 /docs/guide/ 很可能是同一份HTML的两个入口。
那么问题来了:这两个入口打开的同一份HTML,里面的链接指向哪儿?
十九条链接,十三条会变
我准备了一份包含十九种常见href写法的页面,分别用两个基准地址去解析,用的是Node 24内置的URL解析器(和浏览器同一套标准):
| href写法 | 基准带尾斜杠 /docs/guide/ | 基准不带 /docs/guide |
|---|---|---|
api | /docs/guide/api | /docs/api |
./api | /docs/guide/api | /docs/api |
../api | /docs/api | /api |
api/ | /docs/guide/api/ | /docs/api/ |
./ | /docs/guide/ | /docs/ |
.. | /docs/ | / |
?x=1 | /docs/guide/?x=1 | /docs/guide?x=1 |
#frag | /docs/guide/#frag | /docs/guide#frag |
/api | /api | /api(不变) |
//example.net/api | https://example.net/api | 同(不变) |
https://example.org/api | https://example.org/api | 同(不变) |
完整矩阵十九条,其中十三条的解析结果不同,占68.4%。
规则本身很简单:尾斜杠决定了“当前目录”是哪个。有尾斜杠时,当前目录就是 /docs/guide/;没有尾斜杠时,最后一段被当成文件名,当前目录退回 /docs/。相对引用是相对目录算的,所以整体平移了一层。
为什么这件事比听起来严重
把上一篇的数字接上来就明白了:
- 57.1% 的站,两种尾斜杠写法都能返回200;
- 这两个地址下发的是同一份HTML,字节级相同;
- 可里面的相对链接,有68.4% 会解析到不同的地方。
于是同一份HTML在两个入口下,长出了两套不同的出边。爬虫从哪个入口进来,接下来走的就是完全不同的一条路——而且其中一条路上的地址多半是不存在的。
这解释了一类很常见但很难查的现象:站点地图里的页面收录得好好的,某些页面却总有一批来路不明的404,而你在站内怎么找都找不到那些链接。因为它们不在HTML里,是解析出来的。而当这些算错的地址又反过来占掉内部权重的流向时,就成了内链结构会自己烂掉:你辛苦攒来的权重正在漏进分页和重定向链里讲的那种慢性失血。
好在这个坑现网踩得不多,原因下面第六节会给数字——但踩上的那几个,是满格伤害。
双斜杠入口更狠
上一篇还测出21.9% 的站接受开头双斜杠 //a/b。这个入口对相对链接的杀伤力比尾斜杠更大:十九条里有十二条解析结果和规范入口不同,而且形态很难看——https://ex.com//docs/guide/api 这种带着双斜杠的地址会一路传染下去,因为它算出来的下一跳还是带双斜杠的。
上一篇讲过服务器为什么会收这种地址,配置侧的处置也在那篇的收敛表里。
兜底路由和相对链接凑一块会发生什么?
上一篇实验台上还有一条配置,当时只说了它造出无限个入口,没说这些入口拿来干嘛:
location / { try_files $uri $uri/ /app.html; }这是前后端分离和单页应用的标准写法——文件找不到就交给应用。实测结果是任意深度、任意内容的路径全部返回200,而且是同一份字节。
现在把相对链接放进这份HTML里,两件事就咬合了。
每深一层,链接跟着深一层
同一份写着 href="api" 的HTML,在越来越深的路径下被打开:
| 页面被哪个地址打开 | href="api" 解析成 |
|---|---|
/docs/guide/ | /docs/guide/api |
/docs/guide/anything | /docs/guide/api |
/docs/guide/anything/deeper/still | /docs/guide/anything/deeper/api |
最后一行是关键:这个新算出来的地址,在兜底路由下同样返回200,同样是那份HTML,于是它又能解析出下一个更深的地址。
循环就此闭合。爬虫每走一步,就从当前页面拿到一个更深的地址;每一个更深的地址又都能打开、又都含着同一条相对链接。这就是老资料里说的“无限空间”,只不过它的成因通常被含糊地写成“动态生成的URL”,而实际上它是两个再普通不过的配置撞在一起的产物。
缺一不可
值得说清楚的是,这两个条件必须同时成立:
- 只有兜底路由、没有相对链接:无限个地址确实存在,但没人给爬虫喂第一个,它们永远不会被发现;
- 只有相对链接、没有兜底路由:算错的地址第二跳就撞404,爬虫走一步就停了,最多留下几条死链。
所以真正危险的是交集。好消息是这个交集在现网很小:兜底路由把不存在路径当200的站占3.8%,首页含纯相对链接的站占9.5%,两个条件同时踩上的概率不高。
但这也解释了为什么这类事故一旦发生就特别难查——它不是某一处配置写错了,是两处各自都合理的配置凑在了一起。单独审查任何一处都看不出问题,日志里则是一大片深度递增、从未见过的路径。服务器日志分析工具教程:读懂Googlebot抓取与预算浪费里讲的那种“抓取量涨了但收录没动”的形态,有一类源头就在这儿。
浏览器在解析href之前先做了什么?
现在回到第一道手。很多人默认“属性值里写的是什么,链接就是什么”,这个假设在有空白字符的时候会翻车。
我在真实Chrome里跑了一组:构造 <a href="...">,然后分别读两个东西——getAttribute('href')(属性原值)和 .href(浏览器解析后的绝对地址)。基准地址是 https://example.com/docs/guide/。
| 属性里写的 | getAttribute 拿到 | 浏览器实际去抓 |
|---|---|---|
api | api | /docs/guide/api |
a\npi(中间一个换行) | a\npi | /docs/guide/api |
a\tpi(中间一个制表符) | a\tpi | /docs/guide/api |
a\rpi(中间一个回车) | a\npi(回车被换成换行) | /docs/guide/api |
/foo\n/bar | /foo\n/bar | /foo/bar |
htt\tps://ex.com/x | htt\tps://ex.com/x | https://ex.com/x |
a pi(中间一个空格) | a pi | /docs/guide/a%20pi |
两列一对照,问题就出来了:属性原值和浏览器真正去抓的地址,是两个不同的字符串。
那一行才是真正的杀手
倒数第二行值得单拎出来。htt<TAB>ps://ex.com/x 这串东西,分成两种读法:
- 浏览器:先把制表符剥掉,得到
https://ex.com/x,这是一个指向另一个站的绝对地址; - 按属性原值处理的爬虫:看到的是
htt\tps://ex.com/x,它不以http://或https://开头,也不以斜杠开头,于是被归类成本站的一个相对路径,拼出来是https://example.com/docs/guide/htt\tps://ex.com/x。
同一行HTML,一个判成外链,一个判成站内死链。这已经不是“数字有偏差”了,是分类完全反了。
这个行为在WHATWG URL标准里写得明明白白:
If input contains any ASCII tab or newline, invalid-URL-unit validation error. Remove all ASCII tab or newline from input.
注意它的措辞:先报一个校验错误,然后照样把字符剥掉继续解析。所谓“校验错误”不是拒绝,只是记一笔,流程一步不停。
为什么空格反而不剥
最后一行的对照很说明问题:中间的空格没被剥掉,而是编码成了 %20。标准里剥的只有制表符和换行,以及首尾的空白,中间的空格属于“非法但要保留并编码”的一类。
所以这不是“浏览器会自动清理脏数据”这么简单的规律,它剥哪些、留哪些,是一张需要照着查的表,凭直觉猜必错。这类“看着是同一件事、实际分了好几档”的坑,在URI编解码器怎么用?中文URL编码、UTM参数转码与GSC乱码网址还原里还有一批。
顺带提醒一句:换行和制表符跑进href里,最常见的来源不是手写,是模板引擎。为了让生成的HTML好看一点而在属性值里换行缩进,浏览器毫无察觉,而你的链接审计报告可能已经炸了。
两套URL标准到底差在哪?
第二道手是重头戏。现在世面上并存着两套URL规范:
- RFC 3986(也就是IETF STD 66),2005年的老规范,绝大多数服务端语言的标准库按它实现——Python的
urljoin、Java、Go、各类SEO爬虫框架; - WHATWG URL Standard,浏览器实际在用的那套,Chrome、Firefox、Safari、Node的
new URL()都是它。
两套不是“新版旧版”的关系。WHATWG在自己的目标里写得很不客气:
Align RFC 3986 and RFC 3987 with contemporary implementations and obsolete the RFCs in the process.
直白说就是要把那两份RFC废掉。但RFC并没有被撤销,服务端生态还在按它跑。于是同一串字符,两边算出不同结果。
一百五十二格判决矩阵
我拿八个基准地址乘十九种href写法,共一百五十二格,同时跑Python的 urljoin(RFC 3986)和Node的 new URL()(WHATWG),逐格比对:
| 范围 | 格数 | 不一致 | 比例 |
|---|---|---|---|
| 全部写法(含刻意构造的怪招) | 152 | 51 | 33.6% |
| 只算日常会写出来的常规写法 | 104 | 17 | 16.3% |
就算只看日常写法,也有六分之一对不上。
差在哪几条
| href | RFC 3986算出 | WHATWG算出 | 差别性质 |
|---|---|---|---|
\api | /docs/guide/\api | /api | 一个当普通字符,一个当斜杠 |
a\b | /docs/guide/a\b | /docs/guide/a/b | 凭空多出一层目录 |
%2e%2e/api | /docs/guide/%2e%2e/api | /docs/api | 编码的点段被还原成父目录 |
api␣(尾部空格) | /docs/guide/api␣ | /docs/guide/api | 一个保留一个剥掉 |
第一行的落差最大:\api 在RFC那边是当前目录下一个名字带反斜杠的文件,在WHATWG那边直接跳到网站根目录。一个在三层深处,一个在最顶层,中间隔着整个站。
反斜杠这条在标准里也是“报错但照做”:
If c is U+005C (\), invalid-reverse-solidus validation error.
报完错,接着按斜杠处理。这个行为是为了兼容那些手滑把Windows路径分隔符写进href的历史页面,属于现实倒逼标准的典型。
连“指向自己”都能算出两个答案
有一组写法特别值得留意,因为它们看起来根本不该有分歧:href=""(空字符串,规范里表示“当前页面”)、href="?x=1"(只换查询串)、href="#frag"(只跳锚点)。这三种都是“还在这一页”的意思。
可只要当前页面是用一个含点段的地址打开的,比如 /docs/./guide/,两边就分家了:
| href | RFC 3986算出 | WHATWG算出 |
|---|---|---|
"" | /docs/./guide/ | /docs/guide/ |
?x=1 | /docs/./guide/?x=1 | /docs/guide/?x=1 |
#frag | /docs/./guide/#frag | /docs/guide/#frag |
差别在于WHATWG在解析阶段就把点段消掉了,而RFC 3986的合成算法在这几种“不改路径”的分支上直接沿用基准地址的原样路径,点段留在里面。
后果是:一个页面上指向自己的链接,在两套标准下指向两个不同的地址——其中一个还带着点段。而按上一篇的实测,带点段的地址在16.2% 的站上照样返回200。分页导航、语言切换、排序按钮这类控件大量使用 ?x=1 这种写法,一旦页面是从含点段的地址进来的,整组控件的目标地址就集体偏移。
这也是为什么把地址收敛干净是上游动作:基准地址一旦是规范形态,下游这些分歧全部消失。
基准地址越畸形,两边差得越远
按基准地址拆开看,不一致率不是均匀分布的:
| 基准地址 | 十九格中不一致 |
|---|---|
/docs/guide/(规范形态) | 4 |
/docs/guide(无尾斜杠) | 4 |
/DOCS/GUIDE/(大写) | 4 |
/docs/./guide/(含点段) | 7 |
//docs/guide/(开头双斜杠) | 12 |
/docs//guide/(路径内双斜杠) | 12 |
规范形态下只有4格分歧,而双斜杠入口下飙到12格。原因是RFC那边会把多余斜杠归一化掉,WHATWG原样保留——而上一篇实测,21.9% 的站恰好接受这种双斜杠入口。
两篇的数据在这里合上了:服务器多开的那扇门,正好是两套标准分歧最大的那个位置。
Googlebot用的是哪一套?
这个问题的答案有点分裂,而分裂本身就是答案。
谷歌在URL结构文档里明确表过态:
Like any other HTTP client following IETF STD 66, Google Search's URL handling is case sensitive.
IETF STD 66就是RFC 3986。谷歌自称按RFC 3986处理地址。
但另一边,谷歌的渲染是跑在Chromium里的——网页被真实加载、执行JavaScript、构建DOM,然后从DOM里取链接。而Chromium的URL解析用的是WHATWG那套。
所以合理的推断是:抓取调度那一层按RFC 3986的语义处理地址(比如大小写敏感),而渲染阶段从页面里提取出来的链接,是Chromium按WHATWG算出来的。这个推断我没法直接验证——谷歌没有公开渲染管线取链接的实现细节,这里必须说清楚是推断而不是实测。
但对干活的人来说,可操作的结论是确定的:
凡是你用服务端爬虫(Screaming Frog之外的自研脚本、Python写的批量检查、CI里的链接校验)算出来的链接集合,都要假设它和渲染型爬虫算出来的不完全一样。
这不是说工具不能用,是说报告里那些“莫名其妙的404”和“找不到来源的链接”,第一嫌疑人是解析差异,不是站点真的坏了。关于死链报告该怎么分诊、哪些必须修哪些可以放,修复死链对SEO到底有没有用?哪些必须修、哪些纯属白费功夫里有一套优先级;本文补的是它上游的那一步——先确认这条死链是不是工具自己算出来的。
现网到底有多少页面会踩这个?
讲了半天机制,得给个现实的量。我抓了181个站的首页,其中116个返回200且含链接,一共17988条 <a href>,按形态分类:
| 形态 | 条数 | 占比 | 受基准地址影响吗 |
|---|---|---|---|
根相对 /path | 8965 | 49.8% | 否 |
绝对 https://… | 8218 | 45.7% | 否 |
片段 #x | 303 | 1.7% | 否 |
纯相对 path | 280 | 1.6% | 是 |
协议相对 //host/path | 176 | 1.0% | 否(但会跨域) |
真正受基准地址影响的纯相对链接,只占1.6%。按站看,116个站里只有11个(9.5%)首页含至少一条纯相对链接。
这个数字得诚实地讲:行业整体已经用根相对和绝对地址把这个坑绕过去了。写这篇之前我预期会看到一个更吓人的比例,实测没有。
但那9.5% 是满格伤害
相对链接的分布极度不均。中位数是0.0%,也就是一半以上的站一条都没有;可一旦有,往往是整站风格:
| 站点 | 纯相对链接占比 | 数量 |
|---|---|---|
| mixpanel.com | 72.4% | 223 / 308 |
| nginx.org | 66.0% | 35 / 53 |
这两个站首页上七成左右的链接是纯相对的。对它们来说,前面讲的所有解析差异全部生效,而且一次影响几百条链接。
结论因此是二元的,不是渐变的:绝大多数站完全不用管这件事,少数站需要当成头等大事。判断成本极低——打开首页源码,搜一下 href=" 后面第一个字符不是 / 也不是 h 的有多少条,一分钟出结果。
顺手把自家站也测了
写到这儿总得拿自己的站过一遍秤,不然只是在说别人。保哥这个站首页459条链接,形态是这样的:
| 页面 | 链接总数 | 绝对形态 | 纯相对 | <base> | href含换行或制表符 |
|---|---|---|---|---|---|
| 首页 | 459 | 458 | 0 | 无 | 0 |
| 术语表页 | 328 | 297 | 0 | 无 | 0 |
剩下的几十条是页内锚点。也就是说本站在这篇讲的每一个坑上都是零风险——不是因为特意治理过,而是因为模板一开始就是拿绝对地址拼的。这类问题的分布就是这样:要么一条都没有,要么满屏都是,中间地带很窄。
资源引用比链接更干净
顺手统计了 img、script、link 这三类标签的11542条引用:绝对地址67.0%、根相对26.2%、协议相对3.0%,纯相对只有0.5%。
比 <a> 还干净三倍,不过协议相对的比例反过来更高(3.0% 对1.0%),那是全站HTTPS之前留下的历史习惯。想把自家站的链接结构整体扒一遍,内链外链分析器使用教程:一次扒清链接结构与SEO扣分项里那套统计口径可以直接照搬。合理——资源加载一旦出错是肉眼可见的白屏或者裂图,早就被修掉了;而链接指错只是多一个404,页面看起来一切正常。会立刻挨骂的问题总是修得更彻底,这条规律在哪儿都成立。
那base标签为什么几乎没人用了?
<base href> 是HTML里专门用来改基准地址的标签。理论上它能一劳永逸解决尾斜杠问题:不管页面被哪个地址打开,相对链接一律按 <base> 里写的算。
实测116个站里用了它的有两个,占1.7%。而这两个的用法都挺有意思:
| 站点 | <base href> 的值 | 问题 |
|---|---|---|
| php.net | https://www.php.net/index.php | 指向一个具体文件,当前目录退回站根 |
| angular.dev | / | 值本身是相对的,还得先解析一次 |
第二个尤其绕:<base> 的作用是给别人当基准,可它自己的值又是个需要基准才能解析的相对地址。规范对这种情况有明确处理(拿文档地址来解析它),但读代码的人很容易看岔。
<base> 用得少不是因为它没用,而是因为它是个全局开关:一旦写上,页面里所有相对引用——链接、图片、脚本、表单提交地址——全部改基准。改对一个的同时可能改坏五个。相比之下,把链接写成根相对地址是局部的、可控的,代价也更低。
这也是为什么现网49.8% 的链接是根相对形态:它是唯一一种既省字数又完全不受基准地址影响的写法。
怎么让四个裁判给出同一个答案?
治理动作按投入产出排,从便宜到贵:
| 动作 | 成本 | 解决什么 | 适用 |
|---|---|---|---|
| 链接一律写根相对或绝对 | 低 | 基准地址的全部影响 | 所有站,首选 |
| 尾斜杠301收敛到一种 | 低 | 入口分裂的根源 | 57.1% 的站需要 |
| 模板检查href里的换行缩进 | 低 | 解析器分歧 | 模板生成的页面 |
| canonical写成绝对地址 | 低 | 兜底,现网100% 已这么做 | 所有站 |
| 审计工具换成渲染型 | 中 | 两套标准的差异 | 相对链接占比高的站 |
用 <base> | 高 | 基准地址 | 基本不推荐 |
第一条几乎解决全部问题
值得强调:把 href="api" 改成 href="/docs/guide/api",这一个动作就让前三道裁判全部失效。根相对地址不依赖当前目录,尾斜杠怎么变都不影响它;也不存在点段要不要消除的分歧。
现网49.8% 的链接已经是这么写的,这不是什么前卫做法,是主流。顺带一提,同一份普查里116个站有98个写了canonical,形态百分之百是绝对地址,一个用相对写法的都没有——大家在这件事上早就达成共识了,只是没把同样的共识推到 <a href> 上。
三条自查
# 1. 首页有多少条纯相对链接(不以 / 和 h 开头)
curl -s https://你的域名/ | grep -o 'href="[^"/h][^"]*"' | wc -l
# 2. href 属性值里有没有换行或制表符
curl -s https://你的域名/ | grep -Pc 'href="[^"]*[\t\n][^"]*"'
# 3. 尾斜杠两个写法是不是都 200(是就要收敛)
curl -s -o /dev/null -w '%{http_code} %{size_download}\n' https://你的域名/某页面
curl -s -o /dev/null -w '%{http_code} %{size_download}\n' https://你的域名/某页面/想省事也可以直接用现成的工具对照一遍,渲染对比器怎么用?揪出爬虫和用户看到的页面不一样讲的就是把两侧结果摆在一起看。
第一条如果结果是0,恭喜,这篇文章讲的坑你一个都踩不到,可以直接跳到最后。第三条两行如果状态码和字节数都一样,那就回上一篇看收敛配置。
顺带一提,相对路径算错这件事不只发生在HTML里。llms.txt校验器亮绿灯时,5条链接可能全是死的那篇碰到的是同一个毛病换了个文件格式:校验器只检查结构合不合法,不检查相对地址解析出来还在不在。
保哥的判断
这个话题很容易写成“你的工具全是错的、赶紧换渲染型爬虫”,但实测数据不支持这个结论。91% 的站首页一条纯相对链接都没有,对它们来说四个裁判永远一致,换工具纯属浪费预算。
真正值得做的是那个一分钟的自查:先确认自己在9.5% 里还是在90.5% 里,再决定要不要往下投入。技术SEO里最贵的浪费,从来不是没做优化,而是把资源投在了一个自己压根不存在的问题上。顺便说,那两个纯相对链接占比七成的站,一个是做用户行为分析的,一个是写出本文实验台那个服务器的——可见这事和团队水平无关,只和历史包袱有关。
常见问题解答
我的死链检测工具报了一批404,站内却找不到这些链接,是怎么回事?
先查两件事。一是这些地址是不是比正常路径少一层或者多一层目录,如果是,多半是尾斜杠导致的基准地址错位——同一个页面有带斜杠和不带斜杠两个入口,工具从其中一个进来解析相对链接,算出来的地址整体平移了一层。二是原地址里有没有反斜杠或者奇怪的空白,那属于两套URL标准的分歧。两种情况下站点本身都没坏,坏的是链接是怎么算出来的。
纯相对链接和根相对链接到底差在哪?
href="api" 是纯相对,结果取决于当前页面的地址,尾斜杠变一下结果就变。href="/docs/api" 是根相对,只依赖域名,当前页面在哪儿都不影响。现网49.8% 的链接用根相对,纯相对只有1.6%。如果你只想记一条规则,就记这个:href的第一个字符是斜杠,你就安全了。
href里的换行和制表符真的会出问题吗?浏览器不是会自动处理吗?
浏览器确实会剥掉它们,WHATWG标准明确要求“Remove all ASCII tab or newline from input”。问题出在按属性原值取链接的工具上——它拿到的是没剥过的字符串,于是算出一个完全不同的地址。最极端的例子是制表符落在协议名里,浏览器读成跨站绝对地址,工具读成本站相对路径,分类直接反了。中间的空格则两边都不剥,会编码成 %20。
该不该给站点加base标签来统一基准地址?
一般不建议。它是全局开关,会同时影响页面里所有相对引用,包括图片、脚本和表单提交地址,改对链接的同时容易改坏别的。现网116个站里只有2个在用。把链接改写成根相对地址是更便宜也更可控的做法,效果完全一样。
Googlebot到底按哪套标准解析链接?
谷歌文档里明确说自己的URL处理遵循IETF STD 66,也就是RFC 3986,这解释了它为什么大小写敏感。但渲染阶段跑在Chromium里,而Chromium用的是WHATWG那套。合理推断是两层各用各的,不过谷歌没公开渲染管线取链接的实现细节,这一条是推断不是实测。干活时按最保守的假设来:不要指望自研脚本算出的链接集合和渲染型爬虫完全一致。
两套URL标准并存,以后会统一吗?
短期看不会。WHATWG在自己的目标里写着要让那两份RFC作废,但RFC 3986并没有被正式撤销,服务端语言的标准库还在按它实现,而且改动它会破坏大量既有系统。更现实的做法是承认分歧存在,在会出问题的位置(相对链接、反斜杠、编码的点段)主动避开,而不是等标准统一。
协议相对链接(以 // 开头)现在还能用吗?
能用,但没必要。它在全站HTTPS之前有意义——让资源跟随当前页面的协议。现在所有站都上了HTTPS,直接写 https:// 更清楚。它本身不受基准地址影响,所以不属于本文讲的这类问题,但它有另一个坑:// 开头的地址会跳到另一个主机,一旦域名写错就是跨域,而这个错误在代码审查里看着特别像一个普通的路径。
权威参考资料
本文标题:《SEO爬虫报的死链和Googlebot抓的,从来不是同一批URL》
本文链接:https://zhangwenbao.com/relative-url-resolution-crawler-googlebot-broken-link-seo.html
版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0