AI爬虫读不到你的正文?132个独立站首页有28个是空壳
本文目录
- 抓下来的字节里,到底有多少字
- 测量口径怎么定的
- 211个域名,最后剩下132个
- 为什么先量"有没有字",而不是先量结构
- 正文长度的分布长什么样
- 另一头也值得看一眼
- 五兆的HTML里一个字都没有,这可能吗?
- 零字符俱乐部的成员名单
- 这五兆字节到底装了什么
- 体积和内容的关系被彻底切断了
- 顺手记一个细节:这些页面的响应都很快
- 脚本数量也不站在你这边
- 这28个站是怎么走到这一步的
- 空壳页到底给机器留了什么?
- 先说清楚这张表是怎么比的
- 门面全在,正文全无
- 这说明了什么
- noscript那一栏为什么是最关键的一栏
- 结构化数据比正文长92倍的那个站
- 为什么这种做法会流行起来
- 无障碍树是什么,它凭什么跟抓取有关?
- 先把这棵树说清楚
- 那为什么它跟机器读页面扯上了关系
- 状态那一层,很多人根本没意识到它存在
- 可访问名是怎么算出来的
- 怎么在没有浏览器的情况下量这一层
- 页面上那个按钮,在机器眼里叫什么名字?
- 原生按钮的情况
- 为什么偏偏是这几类按钮
- 图标是重灾区
- 用div假装按钮的那批
- 链接这一层的数字被一个站带偏了
- 一张图没有alt,和alt写成空字符串,差别在哪?
- 三种状态,三个意思
- 72%这个数字该怎么看
- 那361张没有属性的图,都是些什么图
- 那24%的空alt里,有多少是真的装饰图
- 写alt的一条实用判据
- 表单里那个输入框,谁告诉机器它是干什么的?
- 四分之一的输入框没有标签
- 为什么偏偏是表单最差
- 视觉上不想要标签,该怎么办
- 一个反例说明这不是做不到
- 邮件订阅框是第二个
- 搜索框是最该优先修的那一个
- 标题层级跳一级,机器会怎么理解?
- h1的分布
- 跳级的比例是45.5%
- 那些被写成div的标题
- 地标区域的情况
- 主动把内容藏起来的那几个站
- main标签有一个被低估的用途
- 那次尺子失效是怎么被发现的?
- 第一版的数字
- 发现问题的过程
- 问题出在哪
- 三种尺子失效,三种不同的病
- 修正之后的对比
- 那一版差点就发出去了
- 为什么这类错误特别难被发现
- 这条教训该怎么用
- 那条1200字符的线是怎么划的?
- 先看数据自己怎么说
- 边界上那几个站
- 如果换一个口径
- 把这条线用在自己站上
- 怎么判断一个缺失是真缺,还是只是没渲染?
- 三步判断法
- 第三步的三种结果
- 两种情况的修法是相反的
- 一个具体的分诊例子
- 关于执行脚本这件事的现状
- 有个说法要澄清一下
- 怎么估自己站受影响的程度
- 如果短期内改不了渲染方式
- 这套自查要花多久,从哪一步开始?
- 第一个动作:三分钟
- 第二个动作:十分钟
- 第三个动作:半小时
- 如果要把它变成常态检查
- 一个容易被跳过的动作:换个身份再抓一次
- 把这次的数字存下来
- 把结果说给不同的人听
- 不建议做的事
- 把无障碍当成SEO手段,这条线该画在哪
- 顺序不能颠倒
- 那这篇文章的立场是什么
- 顺便说一个容易被忽略的事实
- 一个现实的建议
- 最后回到那个五兆的页面
- 常见问题解答
- 我的站是单页应用,是不是一定有问题?
- Google能渲染脚本,那我是不是不用管?
- 那我把内容塞进结构化数据是不是就行了?
- alt到底该写多长?
- placeholder能不能代替label?
- 首页测完了,其他页面要不要都测?
- 为什么无名按钮的比例只有8.2%,但受影响的站有37%?
- svg没名字算不算错?
- 这套检查多久做一次?
- 团队里这件事该归谁?
- 我该先修哪一项?
- 权威参考资料
摘要:用一台普通服务器,把211个国际化独立站的首页各抓了一次,拿到132份能分析的HTML。里面有28份的正文可读字符不到1200个,其中14份是整整0个字符。最夸张的一份传了5146465字节,一个字都读不出来。这些页面并不是不管机器——93%写了标题,82%写了描述,57%放了结构化数据,只有1个站在noscript里留了正文。它们知道机器会来,只是没给机器留内容。文章后半段把无障碍树这一层也量了一遍,并记下一次尺子失效:把空壳页混进样本,无地标区域的比例会从3.6%虚高到22.9%。
先说一件反直觉的事。你打开一个独立站首页,满屏商品、导购文案、促销标语,看着热闹得很。同一个地址,我用命令行抓一次,得到2109539字节的HTML。把标签、脚本、样式全部剥掉,剩下的可读文字是:零。
不是少,是零。2兆的字节,一个字都没有。
这个站不是什么小作坊,是一个消费电子大牌。它的首页在浏览器里工作得很好,因为浏览器会执行那几十个脚本,然后把内容画出来。问题是,来读这个页面的不只有浏览器。
2026年8月,行业里有两条新闻在同一周出现,看着毫不相干。一条是内容分发网络的爬虫开关被一键关掉,两周流量归零;另一条是一篇讲无障碍树的技术文章,说AI代理读网页读的不是你的视觉设计,而是浏览器构建的那棵语义树。保哥把这两条并排放了几天,发现它们说的其实是同一件事的两个方向:你以为你发布了内容,其实你只是发布了一份让浏览器去生成内容的说明书。
说明书这个比喻可以再往下走一步。你把说明书交给一个会照着做的人,他能做出一桌菜;交给一个只会念字的人,他念完只知道有这么一份说明书。这两个人拿到的是同一份东西,得到的结果差着一整桌菜。
过去十年,来读你页面的基本都是"会照着做"的那种。这两年名单变了,而且新加进来的那批,大多数只会念字。
这篇文章只干一件事:把"东西到底在不在"这个问题,从感觉变成可以数出来的数字。前面是211个站的实测明细,中间是无障碍树这一层的量法,后面是一次尺子失效的完整复盘——同一批数据,混进错误样本之后,某个结论虚高了6.4倍,另一个虚高了11倍。
需要先说明一句:这套测量只看服务端交付的那一份字节,不看渲染之后的结果。所以下面所有"没有"的准确含义都是"在交付的那一刻没有"。这个边界很重要,文中会反复提到它。
抓下来的字节里,到底有多少字
先把测量方法交代清楚,因为这篇文章所有结论的可信度都挂在这一段上。方法说不明白,后面那些百分比就只是一堆漂亮的数字。
有些地址连head都没有,接口和feed拿什么说自己不想被收录是相邻的盲区。
测量口径怎么定的
样本是211个国际化独立站的域名,覆盖服饰、家居、消费电子、美妆、户外、母婴几个大类,绝大多数是有独立品牌、面向多国市场的品牌自营站。这批域名不是随机抓的,是按"有多语言版本、有独立品牌、体量在中大以上"三个条件筛出来的,所以它们代表的是行业里做得比较认真的那一批,不是平均水平。这一点在读后面的数字时要记住:这些不是随便找的小站,它们是很多人拿来当参照对象的站。
剥标签数字符这个动作,用现成的HTML转纯文本工具也能做,不必自己写脚本。
请求方式是最普通的一次GET,用桌面版Chrome的用户代理串,跟随跳转,开启压缩,超时30秒,不执行任何脚本。整个过程用二十条并发跑完,全部211个域名在同一个时间窗内完成,避免出现"这个站是早上抓的、那个是晚上抓的"这种时间偏差。
拿到HTML之后的处理只有三步:剥掉script和style的成对标签及其内容,剥掉noscript,然后去掉所有剩余标签,把连续空白压成一个空格。剩下的字符数,就是这一页"直接给出来的可读文字"。
这个口径故意定得很窄,窄到有点不近人情。它不认脚本里的JSON数据,不认结构化数据块,不认属性值里藏的文案,也不认注释里的东西。理由很简单:它模拟的不是浏览器,是一个只会读字节、不会执行代码的读者。这类读者今天有很多,而且这两年正在快速变多。
要给这个口径挑毛病也很容易。它会冤枉那种"内容在页面上但被写进了属性"的写法,也会把一些正当的懒加载算成缺失。但它有一个别的口径都没有的好处:任何人拿同样的三步,在任何一台机器上,都能得到同一个数字。做横向对比的时候,这个性质比精确更值钱。
211个域名,最后剩下132个
211个域名里,返回200并且正文超过3000字节的有132个。其余的要么连不上,要么撞上人机验证页,要么直接403。这79个的去向本身是另一篇文章的题目,这里先按下不表——只强调一点:后面所有的百分比都算在这132个身上,因为只有它们证明了自己愿意对一次普通请求给出一个真页面。
用什么身份去请求会改变结果,这份爬虫识别与UA分类把各家的串列全了。
这一步很重要,重要到值得多说两句。如果把连不上的站也算进分母,任何"缺失率"都会虚高,而且虚高的原因跟被测的东西毫无关系——一个站因为防护策略把我拒之门外,跟它首页有没有写标题是两回事。混在一起算,得到的数字既不能说明防护,也不能说明结构。
把基线定在数据内部、不从外面拍脑袋,是这一整套测量能站住的前提。这个原则在本文后半段还会再出现一次,而且那一次的教训要贵得多。
为什么先量"有没有字",而不是先量结构
做技术审计的人有个通病,喜欢从精细的项目查起:结构化数据对不对、标题层级顺不顺、图片有没有替代文本。这些都该查,但顺序错了。
从粗到细的顺序,企业网站SEO审计框架里也是这么排的,先抓取后内容。
顺序应该是从粗到细,而且每一层都是下一层的前提。正文都不在,讨论标题层级毫无意义,就像检查一个空信封的折叠是否规整。本文后面那次尺子失效,根子就在于第一遍跑的时候没把这个顺序摆对。
所以整套检查的第一个问题永远是同一个:这次交付的字节里,有没有字。答案是"有",才轮得到第二个问题。
正文长度的分布长什么样
| 可读正文字符数 | 站点数 | 占132个的比例 |
|---|---|---|
| 0到99 | 18 | 13.6% |
| 100到499 | 7 | 5.3% |
| 500到1199 | 3 | 2.3% |
| 1200到2999 | 16 | 12.1% |
| 3000到5999 | 32 | 24.2% |
| 6000到11999 | 38 | 28.8% |
| 12000到24999 | 14 | 10.6% |
| 25000以上 | 4 | 3.0% |
正文字符和HTML字节是两件事,46个电商站的体积实测量的是后一件。
这张表最刺眼的不是中间那一大坨,是最上面那一行:18个站的首页,可读正文不到100个字符。一百个字符是什么概念?大概就是这句话本身的长度。
把不到1200字符的都算成"空壳",一共28个,占132个的21.2%。这个1200的线不是随手划的,后面有一节专门讲它是怎么来的、以及划在别处会发生什么。
另一头也值得看一眼
表的最下面两行是另一个极端:14个站正文超过12000字符,其中4个超过25000。
内容铺太多也有上限,Googlebot的2MB抓取限制就卡在这里。
两万五千个字符的首页是什么样子?基本上是把整个商品目录、所有分类说明、全部页脚导航铺在一页上。这类页面在字节层面当然没有"内容不在"的问题,但它们有另一个问题:内容太多,重点在哪不清楚。
这就是为什么main标签和标题层级在后面会单独讲。当一页只有八百个字的时候,机器不用分区也能看明白;当一页有两万五千个字的时候,"哪一块是这页真正要说的事"就成了一个必须回答的问题,而回答它的方式只有语义标记。
内容太少和内容太多,需要的是同一套东西的两端:前者需要把内容交出来,后者需要把内容组织好。中间那一大坨表现正常的站,两件事都做对了,所以它们在后面的检查里通常也表现更好——这个相关性在数据里挺明显。
五兆的HTML里一个字都没有,这可能吗?
可能,而且不止一个。把这28个站按可读字符数从少到多排开,前14个是同一个数字:0。
字节多少还牵着首字节时间,多层缓存对性能与抓取的双向影响算过这笔账。
零字符俱乐部的成员名单
| 域名 | HTML字节数 | 可读正文 | 结构化数据字节 |
|---|---|---|---|
| burrow.com | 5146465 | 0 | 710 |
| govee.com | 3198168 | 0 | 401 |
| quince.com | 2577494 | 0 | 363 |
| eufy.com | 2444733 | 0 | 415 |
| harrys.com | 2231979 | 0 | 725 |
| anker.com | 2109539 | 0 | 649 |
| soundcore.com | 1993145 | 0 | 736 |
| boohoo.com | 1936893 | 0 | 620 |
| nomadgoods.com | 1919826 | 0 | 596 |
| kotn.com | 1781118 | 0 | 241 |
| columbia.com | 1574364 | 0 | 1110 |
| prose.com | 47071 | 0 | 0 |
| sostrenegrene.com | 38027 | 0 | 0 |
| uniqlo.com | 6413 | 0 | 0 |
这批站多数跑现代前端框架,渲染模式选错就抓成空壳讲的正是这个成因。
注意这张表里的两种零。上面11个是"很大的零":字节以兆计,内容为空。下面3个是"很小的零":整个文件才几万字节甚至6千字节,摆明了就是一个跳转壳或者加载器。
很小的零是诚实的,很大的零才是麻烦的。6413字节的文件,任何工具扫一眼都知道有问题;5兆的文件在体积报表里排在最前面,看上去像是个内容极其丰富的重量级页面,实际上一个字都读不出来。
打个不太恰当的比方:这就像收到一个巨大的包裹,拆开是十七层气泡膜,中间什么都没有。你不能说人家没发货,运单上的重量是实打实的。
这五兆字节到底装了什么
既然不是文字,那总得是点什么。把这几个大文件拆开看,主要是三类东西:内联的样式表、内联的脚本代码、以及大段大段的状态数据——通常是一个巨大的JSON对象,里面装着这一页需要的所有商品信息,等着脚本把它渲染出来。
压缩只解决体积不解决内容,免插件压缩HTML的做法能减掉一部分冗余。
内容在标签里还是在变量里差别很大,语义化HTML对抓取的实际影响做过样本实测。
最后这类东西最有意思。商品名、价格、文案,其实全在这五兆字节里,只是它们被装在一个引号里,而不是装在一个标签里。一个不执行脚本的读者,理论上不是拿不到,是它没有义务去猜你那个JSON的结构。
这一点值得给做技术的同事说清楚,因为它经常引起争论。争论的焦点通常是"数据明明在HTML里"。数据确实在,但HTML是一个有语义的格式,标签就是语义。把内容放进一个属性值或者一个脚本变量,等于把它从有语义的部分挪进了无语义的部分。在有语义的地方它是内容,在无语义的地方它只是字符。
体积和内容的关系被彻底切断了
把28个空壳页和104个正常页的HTML体积中位数放在一起比,结果是这样:空壳页335662字节,正常页586994字节。
想快速量体积,抓取体积检查器能直接给出这一页有多大。
正常页确实更大,但只大了不到一倍。体积这个指标,在判断"有没有内容"这件事上,已经完全失效了。过去做技术优化,页面体积是个万能的粗筛指标——太大就是有问题。现在它只能告诉你传了多少字节,不能告诉你传的是什么。
保哥自己踩过这个坑。早年间审站,习惯先看一列体积排序,从大的往下看。这个习惯在服务端渲染的年代很好用,因为体积大基本等于内容多,排在最前面的往往就是那些堆了太多东西的页面。现在这个相关性断了,还按老习惯看,注意力会被系统性地引到错误的地方去。
更麻烦的是,体积这个指标还在各种报表里活得好好的,页面性能工具会报它,抓取诊断工具会报它,看板上通常有一格给它。一个已经失去解释力的指标,如果还挂在显眼的位置,比没有这个指标更糟——它会持续地把注意力吸走。
顺手记一个细节:这些页面的响应都很快
抓取的时候顺带记了每个请求的耗时。有点意外的是,这28个空壳页的响应速度普遍不慢,有几个还比正常页快。
想想也合理。服务端不用查数据库、不用套模板、不用拼字符串,直接把一份构建好的静态文件甩出来,当然快。所有的活都推给了浏览器,而浏览器那边的耗时不会出现在服务器的响应时间里。
这条值得记一笔,因为它意味着响应时间这个指标同样不能用来判断内容有没有交出去——跟体积一样,又一个看着很相关、实际毫无解释力的指标。
脚本数量也不站在你这边
还有一个更反直觉的对照:空壳页的script标签数中位数是22个,正常页是70个。
脚本多少还牵着首屏速度,关键渲染路径优化把阻塞机制讲透了。
正常页的脚本反而多三倍。原因不难想——那些正常吐HTML的站大多跑在成熟的电商平台上,平台自带的追踪、客服、评价、推荐插件一堆,脚本自然多。而空壳页往往是自研的单页应用,脚本少但每一个都是重量级的:一个框架运行时,一个应用包,一个状态数据块,齐活。
所以"脚本多的站更可能是空壳"这个直觉,方向是反的。这类反直觉的地方特别值得记一笔,因为它们正是经验会骗人的位置。凭直觉排查,你会先去查那些脚本一大堆的平台店,而它们恰恰是这一项上表现最好的。
顺着这条线还能得到一个更实用的判断:用自研前端的站,出这个问题的概率明显高于用成熟电商平台的站。不是因为自研团队水平差,恰恰相反,是因为自研团队有能力选择渲染方式,而选择往往发生在没有人代表机器读者说话的那个会议上。
这28个站是怎么走到这一步的
没有一个团队会在某次会上决定"我们不给爬虫留内容"。这件事是一步一步走过来的,每一步都很合理。
单页应用被AI爬不到的完整链路,SPA站被跳过的真相有四种渲染模式对比。
第一步,前端选了一个现代框架,因为它开发效率高、交互体验好、招人也容易。这个决定几乎没有争议。
第二步,框架默认是客户端渲染,服务端渲染需要额外搭一层服务、额外一套部署、额外的缓存策略。评估之后决定先不做,等有需要再说。这个决定当时也是对的,因为当时的"需要"确实还没出现。
第三步,站上线,搜索表现看着还行——因为主流搜索引擎会渲染。这一步进一步确认了第二步的判断。
第四步,两三年过去,读页面的程序名单变了。而没有人会在这个时候回头去复查第二步那个决定,因为那个决定当时被验证过是对的,而且验证的证据现在还在——搜索流量确实没出问题。
问题不在任何一步,问题在于没有一个环节负责在前提变化时重新审视旧结论。这个模式在技术决策里非常普遍,本文这28个站只是它一个特别容易量化的例子。
空壳页到底给机器留了什么?
如果这28个站是完全不管机器的,事情反而简单——那就是一个纯粹的技术选型问题。但数据不是这么说的。
平台站的字段入口分散,Shopify的128种结构化数据类型怎么选给了对照。
先说清楚这张表是怎么比的
下面这张表把28个空壳页和104个正常页放在一起,逐项比"页面里有没有这样东西"。要注意的是,这里比的是有无,不是好坏——一个只写了三个字的标题也算有。
之所以这么比,是因为想回答的问题很具体:这些站是不是压根没考虑过机器读者。要回答这个,看有没有就够了,写得好不好是下一层的问题。
还有一点要说明:这几项全部位于HTML的头部,是服务端直接输出的,不受渲染方式影响。所以它们在两组之间的差距,反映的是意识差距,不是技术差距。这一点很关键,也是这张表能说明问题的前提。
门面全在,正文全无
| 页面里有什么 | 28个空壳页 | 104个正常页 |
|---|---|---|
| 有title标签 | 26个(93%) | 102个(98%) |
| 有meta description | 23个(82%) | 96个(92%) |
| 有og标签 | 19个(68%) | 90个(87%) |
| 有结构化数据 | 16个(57%) | 77个(74%) |
| noscript里有文字 | 1个(4%) | 17个(16%) |
头部信息的完备度可以批量体检,Meta标签检测器的加权评分一次跑完整页。
这张表是整篇文章里保哥最想让你盯着看的一张。
头部信息的完备度,空壳页和正常页几乎没差别。标题93%对98%,描述82%对92%,结构化数据57%对74%。这些东西全都写在head里,全都是静态输出的,一个都没落下。
只有一行例外,而且例外得非常干净:noscript里有文字的,空壳页28个里只有1个。
这说明了什么
说明这些站完全知道有机器会来读它们。知道要给标题,知道要给描述,知道要给社交分享的卡片图,甚至知道要给结构化数据。这些工作没有一样是给人做的,全都是给机器做的。
中间那条缝要靠协作填,前端工程师SEO协作的7个动作点给了具体分工。
然后,在"要不要给这些机器留一份能读的正文"这个问题上,它们的答案是不留。
这不是疏忽,这是一个默认值。前端框架默认就是这么工作的,没人主动选择过它。团队里做SEO的那个人负责了标题和描述,做前端的那个人负责了渲染方式,两件事各自都做得挺对,中间那条缝没有人的名字写在上面。
这个判断有一条很硬的旁证:头部信息的完备度跟正文有没有输出,几乎不相关。如果这些站是"不重视机器",那标题和描述也该一起烂掉。事实是它们的头部信息只比正常站低几个百分点,而正文的差距是从6539掉到14。一个指标掉了几百倍,相邻的指标纹丝不动,这只能说明它们由两拨人、两套流程负责。
noscript那一栏为什么是最关键的一栏
表里最后一行看着不起眼,其实是全表信息量最大的一行。
不执行脚本的读者拿到什么,CSR与SSR的引用率实测给过一组对照数字。
noscript这个标签的作用就一个:告诉不执行脚本的读者,这里有一份备用内容。它存在的唯一理由就是照顾那类读者。一个站在noscript里写了正文,等于明确表过态:"我知道有人不执行脚本,这是给他们的。"
28个空壳页里,表过这个态的有1个。
而正常页里有17个(16%)写了noscript内容。有意思的是,正常页本来就不太需要它——正文已经在字节里了。该写的那批没写,不太需要写的那批反而写了。这个错位不是巧合,它说明noscript的使用跟"是否意识到有非浏览器读者"高度相关,而空壳页的团队恰恰是最没意识到这件事的那批。
结构化数据比正文长92倍的那个站
有两个例子值得单独拿出来。awaytravel.com的首页可读正文是145个字符,同一份HTML里的结构化数据是13423字节。avocadogreenmattress.com正文36个字符,结构化数据5159字节。
结构化数据到底有多大用,Schema对AI搜索的官方说法加实测说得比较克制。
这两个站给机器准备的专用数据块,比给所有人准备的正文长几十倍到近百倍。它们不是没为机器着想,它们只为机器准备了一份精装的名片,然后忘了带上要谈的事。
这个比例本身就是个很好的自查指标:把你首页的结构化数据字节数除以可读正文字符数,如果这个比值超过1,基本可以断定正文没有被服务端输出。这个指标的好处是不需要判断"多少字算够",它是个相对值,任何品类任何规模的站都能用。
还要多说一句,这种配比本身在规范上就有风险。结构化数据的通行要求是它描述的内容要在页面上真实存在、用户看得到。当结构化数据里写着商品名和价格,而同一份字节里的正文是空的,这个对应关系严格说是断的。实际执行中很少有人因此被处理,但把它当成一个可以长期依赖的做法,并不稳妥。
为什么这种做法会流行起来
值得花两句话说说它的来路,因为理解来路才知道该怎么劝人改。
哪些类型值得做,Schema官方公开的全网使用数据比凭感觉堆类型靠谱。
过去几年,行业里关于结构化数据的讨论极其密集,各种指南、各种工具、各种检测器,都在告诉你"把这些字段填全"。填全之后工具会给你一个绿色的对勾,非常有成就感。而"页面上有没有正文"这件事,没有任何工具会给你一个红色的叉。
于是就形成了一个很自然的行为模式:大家都在做有反馈的那件事,没反馈的那件事没人做。这跟人的水平没关系,跟工具塑造的注意力有关系。
所以劝人改的时候,讲道理效果一般,给他看数字效果好得多。把他自己站的那个比值算出来——结构化数据多少字节,可读正文多少字符——这个数字一出来,通常不需要再多说什么。本次实测里那两个比值超过90倍的站,只要有人把这个数摆到会上,事情大概率就推动了。
无障碍树是什么,它凭什么跟抓取有关?
到这里为止讲的都是"有没有字"。接下来这一层更细:字有了,但字和字之间的关系在不在。
先把测量框架想清楚,别急着埋事件是同一个顺序问题。
先把这棵树说清楚
浏览器拿到HTML之后会构建两棵树。一棵是文档对象模型,也就是常说的DOM,它管的是元素怎么排布、样式怎么套用。另一棵叫无障碍树,它管的是每个元素"是什么、叫什么、现在什么状态"。
智能体读的到底是什么,AI浏览器读无障碍树而不是页面截图这篇讲得更细。
读屏软件用的是第二棵。一个盲人用户用读屏软件浏览你的站,软件念给他听的不是DOM,是无障碍树上的节点:这是一个按钮,它叫"加入购物车",它现在可用。
这棵树的存在意义从一开始就跟搜索毫无关系。John McAlpin在2026年8月那篇讲无障碍树用例的文章里专门用一整段强调了这件事:这棵树存在的目的是让残障人士能用网络,SEO上的好处只能当作把无障碍做对之后的副作用,不能反过来当成设计的驱动力。这句话保哥完全同意,而且觉得应该抄一遍贴在工位上。
那为什么它跟机器读页面扯上了关系
因为一个不带眼睛的读者,和一个带眼睛但只能读结构的读者,需要的东西高度重合。
无障碍改造的完整清单,18个改动的实操指南可以直接照着走。
读屏软件需要知道"这个圆形图标是干什么的",AI代理也需要知道。读屏软件需要知道"这一坨文字里哪块是主内容、哪块是导航",抓取程序同样需要知道。无障碍树本来就是一份"把视觉信息翻译成语义信息"的产物,而所有不靠视觉理解页面的读者,用的都是同一份翻译。
这也是为什么这套检查特别值得做:它同时服务两拨人,而且其中一拨是法律和道德意义上你本来就该服务的。
状态那一层,很多人根本没意识到它存在
名字和角色比较好理解,状态这一项容易被忽略,但它在交互页面上出问题的概率最高。
折叠面板里的内容算不算数,内容折进标签页手风琴的处理有官方口径。
举个具体的:一个折叠面板,点一下展开,再点一下收起。视觉上一目了然,因为箭头会转、内容会出来。而在无障碍树上,这个"现在是展开还是收起"是靠一个属性表达的——aria-expanded,值是true或false。
最常见的缺陷是这个属性写死了。初始状态写了false,面板打开时脚本没有把它改成true。视觉上一切正常,树上永远是"收起"。对读屏软件用户来说,他点了展开,系统告诉他还是收起的,内容就在那儿但没人通知他。
这一层没法从静态HTML里查,因为它的错误恰恰发生在"应该变而没变"这个动作上。要查它只能真的去点一下,然后看树。所以本文的量化部分完全没有覆盖这一层——这不是漏了,是这个方法从原理上就够不着。把方法的边界说清楚,比多给几个数字重要。
可访问名是怎么算出来的
树上每个节点有三样东西:角色、名字、状态。角色是"这是个什么",比如按钮、链接、标题;状态是"它现在怎么样",比如展开还是收起、选中还是未选中;名字就是"它叫什么"。
名字来源里alt占很大比重,图片alt与属性的批量体检能一次扫完整页。
名字这一项有一套明确的计算顺序,不是随便取的:先看aria-labelledby指向的内容,再看aria-label属性,再看元素本身该用的原生属性(比如图片的alt、表单的关联label),再看元素内部的文字,最后才是title属性。
这个顺序有个很实用的推论:越靠前的方式优先级越高,也越容易把后面的盖掉。给一个已经有文字的按钮再加一个aria-label,实际生效的是aria-label,按钮上那行字反而不算数了。这是个常见的错误来源——两个人各写了一半,结果只有一半生效。
怎么在没有浏览器的情况下量这一层
严格说,无障碍树只有浏览器能构建,因为它依赖渲染后的最终状态。但上面那套计算顺序里,绝大多数来源是HTML里静态写着的:aria-label、aria-labelledby、alt、label的for关联、元素内部的文字。这些东西在字节里就能看到。
字节和渲染后的差异,渲染对比器能直接把两份结果摆在一起。
所以可以退一步:不去构建整棵树,只检查"这个元素有没有可能拿到名字"。一个button标签,里面没有文字,也没有aria-label,也没有aria-labelledby,也没有title,也没有带alt的图片子元素,那它渲染成什么样都不会有名字——除非脚本在运行时给它补一个。
"除非脚本补一个"这句是这套方法唯一的缺口,必须承认。所以下面所有数字的准确说法是:这些元素在服务端交付的那一刻是无名的。它们后来有没有被补上,只有真浏览器能回答。但对一个不执行脚本的读者来说,"后来"不存在。
本次量的是170份可解析首页快照。为了不让空壳页污染结果,先把它们剔掉了——这一步的重要性,后面有一整节专门讲,而且是这篇文章里最贵的一段教训。
页面上那个按钮,在机器眼里叫什么名字?
剔掉空壳页之后剩110个站,下面所有比例都算在这110个身上。
弹窗上的关闭按钮尤其常见,侵入式插页的真相与豁免说明了什么情况会出问题。
原生按钮的情况
110个站的首页一共有4876个button标签,其中401个(8.2%)拿不到任何名字。这401个分布在41个站上,也就是说每10个站里差不多有4个,首页上至少有一个按钮对机器来说是无名的。
这类结构短板可以批量扫,页面结构分析工具的六维体检覆盖H1层级和语义标签。
最集中的几个:philips.com的58个按钮里46个无名,allbirds.com的79个里41个,peakperformance.com的121个里34个,ritual.com的65个里30个,chubbiesshorts.com的62个里30个,dreametech.com的60个里27个。
这些按钮在浏览器里当然有样子——它们是购物车、搜索、菜单、关闭、上一张下一张。人一眼就认得出,因为人认的是图形。机器认的是名字,而名字这个字段是空的。
为什么偏偏是这几类按钮
把无名按钮挨个看过去,会发现它们高度集中在几个位置:轮播的左右箭头、弹窗的关闭叉、菜单的汉堡图标、搜索的放大镜、数量增减的加减号。
图标库的用法差别不小,Font Awesome各版本的语法与SVG渲染影响的正是这一层。
这几个位置有一个共同点:它们的含义完全靠一个约定俗成的图形来传达,而这个约定只存在于人的经验里。一个向右的三角,全世界的人都知道是下一个,但这个知识不在HTML里,它在你脑子里。
还有一个共同点更现实:这些控件通常来自组件库,是同一份代码在页面上重复了几十次。所以一个站的无名按钮数量往往不是"错了几十次",而是"错了一次,用了几十次"。philips那46个,多半来自不到十种组件。
这是个好消息。它意味着修复成本跟数量不成正比。四十六个问题可能只对应五处改动,而且改完之后新写的页面自动就是对的。
图标是重灾区
把内联的svg单独拎出来数:110个站里有3906个svg,既没有aria-label,也没有内嵌title,也没有被标记成装饰性元素。87个站有这个问题,占79.1%。
图标这件事从来不只一处,Favicon生成器给出的十个文件真正生效的只有一张。
这个数字大到有点吓人,但要说句公道话:svg没名字不一定是错。如果它外面包着一个有名字的按钮,那这个图标本来就该被标成装饰性的,不该有自己的名字。这3906个里有相当一部分属于这种情况。
真正确凿的问题是另一种:图标是唯一的内容,外面那层也没名字。本次数据里,纯图标且拿不到名字的链接有264条。这264条是硬伤,因为它们对机器来说就是264个"点这里",去哪里不知道。
用div假装按钮的那批
还有一类:给div或者span加上role="button"来模拟按钮。110个站里有171处这种写法,分布在32个站上,其中13处连名字都没有。
该用什么标签有明确答案,8类语义标签对SEO的真实影响逐个做过拆解。
这个写法本身不算错,但它是一个信号。能用button标签的地方用了div,通常意味着这个团队在按视觉需求组织标签,而不是按语义需求。顺着这个信号往下查,一般还能查出别的。
更值得注意的是它的近亲:直接给div绑点击事件,连role都不加。这种写法110个站里有115处,分布在10个站上。加了role的至少还告诉了机器"这是个按钮",什么都不加的那种,在树上就是一段普通文字,只不过点它会有反应。键盘用户按Tab永远走不到它,读屏软件也不会提示它可以点。
链接这一层的数字被一个站带偏了
链接的整体数字是这样:110个站一共28747条链接,其中2359条(8.2%)拿不到可访问名。
内链本身也能被标记,用结构化数据标注重要内链是另一条思路。
但这个8.2%要打个折扣看,因为其中1855条来自同一个站。parachutehome.com的首页有2343条链接,其中1855条没有名字,占它自己的79%。一个站贡献了全样本无名链接的四分之三还多。
把它拿掉重算,剩下109个站的无名链接是504条,占比降到1.9%。两个数字都是真的,区别在于它们回答的问题不同:8.2%是"这批站的链接整体质量",1.9%是"一个典型的站大概是什么水平"。
遇到这种被单个样本主导的指标,最好的做法是两个数都给出来,并且说清楚差在哪。只给8.2%会让人以为这是普遍问题,只给1.9%又会漏掉那个真正出了大事的站。保哥见过太多报告在这种地方偷偷选一个对自己论点有利的口径,这是很不体面的做法。
顺便说一句,一个站首页放2343条链接本身也值得看一眼。这个数量远超样本中位数,多半是把整个商品目录铺在了首页上。
一张图没有alt,和alt写成空字符串,差别在哪?
这是个特别容易被工具搞混的地方,而两者的含义正好相反。
同一份内容给人和给机器的写法可以不同,正文本地化而结构化数据写国际格式是个好例子。
三种状态,三个意思
| 写法 | 机器怎么理解 | 数量 | 占9459张的比例 |
|---|---|---|---|
| alt里有文字 | 这张图有内容,内容是这些字 | 6814 | 72.0% |
| alt="" | 这张图是装饰,忽略它 | 2284 | 24.1% |
| 完全没有alt属性 | 不知道该怎么办 | 361 | 3.8% |
alt写过头也有风险,图片alt关键词堆砌的新规解读附了处罚实例。
中间那一行是很多人误会的地方。alt=""不是"没写alt",它是一句明确的话:这张图不承载信息,跳过去。装饰性的分割线、渐变背景、纯视觉的图形,就该这么写,HTML标准里关于替代文本的那一章把什么时候该写空字符串讲得比多数教程都细。写空的alt是尽责,不是偷懒。
最后那一行才是问题。没有alt属性意味着没有人表过态——它可能是重要商品图,也可能是背景纹理,读的一方只能自己猜。本次样本里有361张,涉及36个站,占110个站的32.7%。
72%这个数字该怎么看
72%的图有文字alt,听起来不算差。但这个数字是按图片张数算的,而首页上的图片张数分布极不均匀——一个站可能有200张,另一个只有15张。张数多的站会把整体比例拉向它自己的水平。
文件名、alt、WebP与懒加载怎么配合,图片SEO的完整落地讲得比较全。
所以更该看的是站的口径:110个站里有36个,首页上至少有一张图没有alt属性。这36个站不是alt写得不好,是这一项根本没进他们的检查流程。
这两个口径的差距,是所有横向审计都要面对的问题。个数口径回答"整体质量怎么样",站数口径回答"这个问题普不普遍"。汇报的时候用站数口径,排期的时候用个数口径。反过来用,要么把问题说得太轻,要么把工作量估得太大。
那361张没有属性的图,都是些什么图
把这361张挨个看过去,来源比想象的集中。
最多的一类是脚本生成的图。购物车里的商品缩略图、推荐位里的商品图、评价区里的用户上传图,这些都是运行时插进来的,插的时候只带了地址没带说明。写这段脚本的人手上根本没有替代文本这个数据——后台的商品字段里没有这一栏。问题不在前端,在数据模型。
第二类是第三方嵌入的图。支付方式的标志、物流公司的标志、认证徽章、社交平台的图标,这些通常是从别人给的代码片段里复制过来的,原样贴上,没人会去改。这一类有个特点:它们往往集中在页脚,一排排挨着,缺一起缺。而支付方式那一排恰恰是转化路径上很关键的信任信号,读不出来等于这份信任没传达到。
第三类才是真正的疏忽:模板里手写的图,写的时候忘了。这一类数量最少,通常也最好改,因为它们就在模板文件里摆着,一个个补过去就行。
有意思的是,很多团队的注意力恰恰全放在第三类上——因为它最好找、最好改、改完最有成就感。而占比最大的第一类,因为要动后台字段、要拉上运营和产品,往往就一直挂在那儿。这个模式在技术优化里到处都是:先做完的总是最容易的那一件,不是最要紧的那一件。
知道来源之后,处理方式就清楚了:第一类要去后台加字段,第二类可以批量补上,第三类改模板。三件事的负责人不是同一个,工作量也差着量级。上来就说一句"我们有361张图缺替代文本",谁也不知道该干什么。
第一类值得多说一句,因为它是最容易被误判的。前端同事看到这个问题,第一反应通常是"我加个默认值就行",于是所有商品图的替代文本都变成了同一句"商品图片"。这确实让缺失率归零了,但信息量还是零,只是从"没表态"变成了"表了个没用的态"。真要解决,得让运营在上架时把那一栏填上,而那需要后台先有那一栏。
那24%的空alt里,有多少是真的装饰图
这个问题没法用抓取的方式回答,必须人看。保哥随手抽了几个站翻了翻,感觉大体是对的——那些空alt多数落在分割线、渐变块、图标背景这类元素上。
alt是不是排名因素,这个说法的真相跟很多人想的不一样。
但也确实见到写错的:有的商品列表里,商品主图的alt是空的,旁边一个装饰性的角标反而写了文字。这种颠倒比全部留空更麻烦,因为它会让读的一方得到一个错误的信息层次:装饰被当成了内容,内容被当成了装饰。
所以这一项没法完全自动化。能自动化的部分是"有没有表态",表得对不对,还得人看。好在需要人看的量不大——把首屏那十几张图看一遍就够了,剩下的多半是同一套模板出来的。
写alt的一条实用判据
跟SEO没关系但很好用:如果这张图去掉之后,你需要用一句话补上它说的事,那句话就是alt。如果去掉之后什么都不用说,那就写空字符串。
非拉丁字母的站更麻烦,文件名和alt要用两套字母写同一个词是实测结论。
这条判据的好处是它自然地控制了长度。补一句话通常十几到三十几个字符,不会写成一段。见过最离谱的alt是把整段商品描述塞进去,那不是替代文本,那是把正文藏进了属性里。而藏进属性里的文字,前面刚说过,在语义上是不算数的。
表单里那个输入框,谁告诉机器它是干什么的?
表单这一项的数字,是整套检查里最糟糕的。
留邮箱那个框最典型,邮件弹窗的时机字段与合规把这一步拆开讲了。
四分之一的输入框没有标签
把隐藏域、提交按钮这类排除掉,110个站的首页一共有1192个真正需要用户输入的字段。其中291个(24.4%)拿不到任何形式的标签:没有label关联,没有aria-label,没有aria-labelledby,也没有title。
表单控件选错的代价,下拉框如何悄悄吃掉询盘是个很具体的例子。
受影响的站有44个,占40%。也就是说每5个站里有2个,首页上至少有一个输入框,机器不知道它要填什么。
为什么偏偏是表单最差
因为占位符太好用了。
首屏那一块的设计取舍,导航、主Banner到分类区的排布决定了标签放不放得下。
设计稿上一个干干净净的输入框,框里灰色小字写着"请输入邮箱",视觉上非常清爽,不需要额外一行标签文字。前端照着实现,用placeholder属性,一切正常。
问题是placeholder不是标签。它是提示,是示例,是可以随时消失的东西——用户一开始打字它就没了。把它当标签用,等于把一块随时会掉的牌子挂在门上。
这件事的坏处不只在机器那边。用户填到第四格的时候想回头确认第二格填的是什么,看到的是一串已经输入的文字,但那一格要求填什么已经不在屏幕上了。这是个纯粹的可用性缺陷,跟搜索、跟AI、跟任何技术指标都没关系,它就是不好用。
本次数据里几个典型:ritual.com的22个输入框全部无标签,mejuri.com的14个全部无标签,allbirds.com的13个全部无标签,awaytravel.com的8个全部无标签。这种"全军覆没"的形态几乎可以断定是同一套组件出来的,改一处就能全好。
视觉上不想要标签,该怎么办
这是个真实的设计诉求,不能光说"你得加标签"就完事。实际有三种做法,各有适用场景。
视觉隐藏靠的是样式类,CSS的美化压缩与性能账顺带讲了这类工具链。
第一种,把标签留在HTML里但视觉上隐藏。用一个专门的样式类把它移出可视区域,而不是用display:none——后者会把它从无障碍树上一起拿掉,等于白写。这是最常用也最稳妥的做法,几乎所有成熟组件库都提供了这个类。
第二种,给输入框加aria-label,值就是那句标签文字。这种做法更简洁,适合搜索框这类只有一个输入框、上下文很明确的场景。
第三种,浮动标签——用户没输入时标签显示在框里,开始输入后缩小移到框上方。这种做法视觉效果好,标签也一直在,是这几年比较流行的方案。缺点是实现复杂,而且要注意别把标签做成一个纯视觉的div,那样又回到原点了。
三种做法的共同点是:标签这个东西一直存在,只是被安排到了不同的位置。而用placeholder代替,是让它彻底不存在。
一个反例说明这不是做不到
casetify.com的首页有591个输入字段,是全样本最多的,多半是筛选器和批量表单撑起来的。其中无标签的是121个,比例20.5%,低于平均。同一份HTML里有375个带for属性的label。
筛选器多的站字段自然多,分面导航的抓取预算治理是配套的另一半。
一个字段数量最多的站,标签覆盖率反而高于平均。这说明这件事跟站的复杂度没关系,只跟有没有把它写进组件规范有关。
反过来看那几个"全军覆没"的站,字段数都在十几到二十几个,规模小得多。不是因为难所以没做,是因为量小所以没人觉得需要立规矩。二十二个输入框,手写就手写了,等到有一天变成两百二十个,那套没有标签的写法已经复制了两百遍。
邮件订阅框是第二个
排在搜索框后面的是邮件订阅框,理由类似但不完全一样。
它同样出现在几乎每一页的页脚,同样是一个明确的转化动作,同样极少有人给它配标签——因为设计上那一块通常就是一行输入框加一个按钮,加一行标签文字会显得很笨重。
不一样的地方在于后果。搜索框填错了,用户马上知道,因为结果不对。订阅框填错了,用户什么都不知道,他以为自己订阅成功了。本次样本里有几个站,页脚同时有订阅邮箱和搜索两个输入框,都没有标签,光看字节完全分不出哪个是哪个。
顺带说一句,这一块的按钮也常常是无名的——很多站的订阅按钮就是一个箭头图标。一个没有名字的输入框,配一个没有名字的按钮,这个组合在树上就是两个匿名节点并排站着。
搜索框是最该优先修的那一个
如果只能改一个输入框,改搜索框。理由有三条。
搜索框值得单独设计,从入口到结果的四层拆解把这个高转化入口讲透了。
第一,它几乎在每一页上都有,一处改动全站受益。第二,它是站内转化路径上最短的一条——用户用搜索找东西,意图最明确、转化率通常最高。第三,它恰恰是最容易只写占位符的那一个,因为设计上大家都不想在搜索框旁边再摆一行"搜索"两个字。
本次样本里,无标签输入框里搜索框占了相当一部分。一个每页都出现、承担高价值动作、又系统性缺标签的控件,投入产出比高得不像话。这种机会在技术优化里不多见,通常一件事要么便宜要么有效,很少两者兼得。
标题层级跳一级,机器会怎么理解?
标题这一层的结论比较微妙,需要分开说。
改标题会不会掉排名,改动本身不被罚改错内容才掉澄清了这个担心。
h1的分布
110个站里,首页没有h1的有28个(25.5%),有且只有一个的58个(52.7%),有多个的24个(21.8%)。
标题本身怎么写,10个技巧加5类高点击公式是内容侧的功课。
关于h1数量的争论已经吵了十几年,这里不想再吵。只说一个事实:h1有几个不重要,重要的是有没有一个标题告诉读者这一页是关于什么的。那28个没有h1的站里,多数是有h2的,视觉上也确实有个大标题——只是那个大标题被写成了div加大字号。
跳级的比例是45.5%
这个数字比想象的高。110个站里有50个,标题层级出现过跳级:h2下面直接接h4,或者h1下面直接接h3。
层级关系也体现在面包屑上,四种类型与结构化数据实操可以对照着看。
跳级的实际危害没有很多文章渲染的那么大,机器不会因为你跳了一级就读不懂。但它是一个非常好的信号:层级跳了,说明标题是按字号选的,不是按结构选的。而按字号选标题的页面,一般还会有别的结构问题。
保哥审站的时候有个偷懒办法:只把页面所有h标签的数字按顺序列成一串。本次实测里抓下来的几串长这样——一个站是"2322322233",另一个是"333333333333231222222232",还有一个是"41323232333333333334"。
第一串是正常的:二级下面挂三级,起伏有规律。第二串一看就不对:十二个三级排在最前面,一个上级都没有,说明这一大片内容在结构上是悬空的。第三串更乱,四级开头,然后一二三四轮着来,基本可以断定是几套模板拼在一起的。
这一串数字不需要任何工具,看一眼就知道这页的结构是设计出来的还是长出来的。保哥现在审站基本都是先看这一串,比跑任何评分工具都快,而且它给的是结构的形状,不是一个分数。
那些被写成div的标题
110个站里有9个站用了role="heading",一共117处。这个属性的意思是"这个元素虽然不是h标签,但请把它当标题看"。
标题标签在AI时代的作用变了,8类骨架加实体信号的实战给了新的写法。
用它不算错,但它的存在本身说明了一件事:这9个站里有117个位置,视觉上是标题、标签上不是标题,只好用属性补一句。而这只是那些补了的。没补的有多少,从抓取数据里看不出来——一个被写成div加大字号的标题,在字节里跟一段普通文字长得一模一样。
这就是本文那句"视觉标题"问题的真实形态。它是所有结构问题里最难自动检测的一个,因为判断它需要同时知道"看起来像什么"和"标记成了什么",而抓取只能知道后者。目前唯一可靠的查法是人打开页面,把每个看起来像标题的东西点开看一眼标签。好在这活量不大,一页十几处顶天了。
地标区域的情况
地标区域是给页面分区的:header、nav、main、footer这几个标签,或者对应的role属性。它们的作用是让不靠视觉的读者知道"从这里开始是正文"。
分区之上还有整站结构,架构搭错爬虫找不到产品页讲的是更大的一层。
110个站里,四个齐全的76个(69.1%),有main的94个(85.5%),有nav的97个(88.2%),有footer的101个(91.8%),一个都没有的4个(3.6%)。
这一项的表现明显好于其他项,原因大概是这些标签写起来最省事——用header替代div不需要额外工作量,反而更短。凡是"做对不比做错麻烦"的事,行业整体表现就不会太差。这个规律在别的地方也成立,可以当成排优先级时的一条经验:那些需要额外动作才能做对的项,才是真正需要靠流程去保证的。
还有个细节:94个有main的站里,有7个不是用main标签,而是给一个div加了role="main"。这个写法完全有效,但它通常意味着这套模板的年纪比较大,是在语义标签普及之前写的,后来打了补丁。看到role属性替代原生标签,可以顺手估一下这套代码的年龄,往往能解释别处的一些奇怪写法。
主动把内容藏起来的那几个站
还有一个属性值得单独说:aria-hidden。给一个元素加上这个属性并设为true,等于告诉所有不靠视觉的读者"这块跳过,别读"。
跳过渲染也可能藏掉内容,content-visibility的机制实战说明了边界在哪。
它的正当用途很多——装饰图形、重复出现的图标、已经被别处描述过的内容,都该这么标。110个站里这个属性一共出现了4652次,绝大多数属于正当使用。
但有8个块不太一样:它们各自藏起了超过300个字符的纯文字。分布在5个站上。三百多个字符是什么概念?大概是一段完整的商品介绍,或者一条完整的促销说明。
这种情况通常有两个来源。一个是弹窗或者抽屉式导航——它在关闭状态下被整体标为隐藏,这是对的,但如果脚本在打开时忘了把这个属性改回来,那它就永远是隐藏的。另一个是某次为了解决读屏软件重复朗读的问题,粗暴地把一整块标了隐藏,把该读的一起带走了。
这一项特别值得查,因为它的性质跟别的都不一样:别的项是忘了给信息,这一项是明确下令不要读。一条主动发出的错误指令,比一个被动的遗漏危害大得多,而且它绝对不会出现在任何"缺失项"的报表里——从任何自动化工具的角度看,这块内容有标签、有文字、结构完整,一切正常。
main标签有一个被低估的用途
main这个标签除了给读屏软件分区,还有一个越来越重要的用途:它是"正文从哪开始"的最明确的一句声明。
让AI读得懂引得出,GEO技术端的抓取渲染提取三步把这条链讲全了。
任何一个想从你页面里提取内容的程序,都要先解决一个问题——满页的导航、页脚、推荐位、弹窗里,哪一块是这一页真正要说的事。没有main标签,它只能靠猜,常用的猜法是找文字最密集的那个块。有main标签,这个问题就没有了。
这是本文所有检查项里,成本最低、说明力最强的一个。加一个标签,把一个需要推断的问题变成一个可以直接读的事实。85.5%这个数字已经不低,剩下那16个站补上,是半天的活。
那次尺子失效是怎么被发现的?
现在讲这篇文章里最该被记住的一段。上面所有关于无障碍树的数字,第一版全是错的。
样本边界决定结论边界,调研数据里没有非会员结论却写给非会员是同一个病。
第一版的数字
第一次跑完170个站,结果是这样:一个地标区域都没有的占22.9%,没有h1的占47.1%,连一个标题标签都没有的占30.6%。
没有对照组就会虚高,74%的差异补上对照后只剩2.2%是同一类教训。
这三个数字,任何一个单独拿出来都够写一篇标题很吓人的文章了。三成的独立站首页连一个标题标签都没有,听着像行业末日。
发现问题的过程
保哥的习惯是在写结论之前,把最极端的那批样本逐个打开看一眼。这次打开的是"一个标题标签都没有"那52个,第一个是aesop.com,第二个是aliexpress.com,第三个是anker.com。
翻明细是唯一的防线,Google抓取报告里五类问题URL的排查顺序也强调这一点。
看到第三个的时候就不对劲了。anker.com刚刚在前半篇里出现过——它是那个2兆HTML零个字符的站。它当然没有标题标签,它连一个字都没有。
再往下扫,52个里有一大半是同一批空壳页。
问题出在哪
问题不在尺子的算法,算法是对的:这些页面确实没有h1,确实没有地标。问题在于这把尺子被用在了它不该量的对象上。
想知道谁真的来过,日志分析一步步挖真相比任何推断都实在。
量一个页面的语义结构,前提是这个页面有内容。一个还没渲染的空壳,它的语义结构不是"差",是"还不存在"。把它算成"结构差",等于批评一张白纸排版难看。
这个错误跟以前踩过的坑都不一样。以前的失效都是判据本身写错了——词表分不清、基准没定好。这次判据完全正确,错的是样本边界。一把准确的尺子用在错误的对象上,产生的错误数据比一把不准的尺子更难发现,因为每一条记录单独看都是对的。
三种尺子失效,三种不同的病
把这几年踩过的坑摆在一起,形态其实很清楚:
判断力比工具重要,只会蛮力的SEO为什么被淘汰说的是同一件事。
| 失效形态 | 错在哪 | 怎么才能发现 |
|---|---|---|
| 判据写错 | 规则本身理解偏了 | 回原文核对措辞 |
| 基准缺失 | 用了绝对判断,而规则是相对的 | 问一句"多出来的,是相对什么多" |
| 样本越界 | 判据对,但对象不该被量 | 翻最极端的那十几条明细 |
三种病的共同点是它们都让问题看起来更严重,从来没有一次是让问题看起来更轻的。这个方向性很值得琢磨。
保哥后来想明白了:因为尺子是奔着"找问题"做的,它的每一处模糊地带,默认都会倒向"这是个问题"。写规则的时候没有人会故意留一条"拿不准就算通过"的分支,于是所有拿不准的情况都堆到了"不通过"那一边。
所以有一条实用的自查:跑完一把新尺子,先看它有没有弃权的能力。一把只会说"通过"和"不通过"的尺子,一定在某个地方虚高。一把在没把握的时候会说"这个我判断不了"的尺子,才可能是诚实的。本次这把改完之后,空壳页就是它的弃权区——不是判它差,是判它不适用。
修正之后的对比
| 结论 | 混入空壳页(170个) | 剔除空壳页(110个) | 虚高倍数 |
|---|---|---|---|
| 一个地标区域都没有 | 22.9% | 3.6% | 6.4倍 |
| 连一个标题标签都没有 | 30.6% | 2.7% | 11.3倍 |
| 首页没有h1 | 47.1% | 25.5% | 1.8倍 |
| 四个地标区域齐全 | 45.3% | 69.1% | 被压低 |
被广泛相信的数字未必成立,重复内容惩罚这个说法其实从来不存在。
最夸张的一条虚高了11倍。而且注意最后一行:好的结论被同样的机制压低了,方向相反,幅度也不小。
那一版差点就发出去了
说句实话:那三个虚高的数字,当时已经写进初稿了,而且写得挺顺手——三成的独立站首页连一个标题标签都没有,这句话既有冲击力又有数据支撑,读起来毫无破绽。
拦下它的不是任何工具,也不是复核流程,是一个习惯:在写结论之前,把最极端的那一批样本逐个打开看一眼。这个习惯很笨,很花时间,一次要看十几二十个页面,而且绝大多数时候什么问题都看不出来。
但它是唯一有效的。所有自动化的检查,检查的都是"计算过程对不对",而这类错误发生在计算开始之前——发生在决定"哪些东西进入这次计算"的那一步。没有任何一个程序会质疑你给它的输入名单,它只会认认真真地把错误的输入算得一丝不苟。
这也是为什么保哥每次量完东西,都要留一节专门讲量的过程。不是为了显得严谨,是因为一篇只给结论不给口径的文章,读者没有任何办法判断它有没有犯这个错。而这个错,从数字表面是绝对看不出来的。
为什么这类错误特别难被发现
因为它没有任何异常特征。
看着整齐的高比例最该警惕,76%改写率那个数字也得看它怎么算出来的。
一把算错的尺子,通常会露马脚:某个站的数字大得离谱,某个分类一条都没有,某两项互相矛盾。这些都是可以被察觉的。而这次的每一条记录单独看都完美无缺——anker.com的地标数量确实是零,这个记录没有一个字段是错的。
错误不在任何一条记录里,错误在"这条记录该不该出现在这张表里"。而这个问题,表本身回答不了。
更麻烦的是,这类错误的方向是系统性的,不是随机的。随机误差会互相抵消,越多样本越准。系统性偏差不会——空壳页在每一项上都会算成"最差",样本越多,偏差越稳定地把结论往一个方向推。看到一个特别整齐、特别符合预期、特别适合当标题的数字,反而应该警惕。
这条教训该怎么用
提炼成一句可操作的:在跑任何结构类审计之前,先问一句"这批样本里,有多少个根本不该被这把尺子量"。
回到基本盘,抓取、索引、排名三步是判断任何前提的起点。
判断方法也简单,跟这篇文章前半段是同一个动作:先量每个页面的可读正文长度,把明显不到线的挑出来单独成一组。它们不该被算成"结构差的站",它们该被算成"另一个问题的站"。
再往上提一层,这其实是一条通用的经验:任何一把尺子都有一个默认前提,而这个前提一般不写在文档里。量结构的尺子默认页面有内容,量转化率的尺子默认流量是真人,量停留时长的尺子默认用户没开着标签页去吃饭。用尺子之前把这个默认前提找出来,然后去数有多少样本不满足它——这个动作花不了十分钟,但它是保哥吃过好几次亏之后唯一留下的防线。
那条1200字符的线是怎么划的?
上面反复用到"空壳"这个分类,判据是可读正文小于1200字符。这个数怎么来的,得交代一下,不然整篇文章的地基是虚的。
首页铺太多也会牵出URL问题,筛选器URL不爆炸的系统方案给了八步做法。
先看数据自己怎么说
把132个站的正文字符数排序,会看到一个非常明显的双峰:一堆挤在0到500之间,另一堆从1200往上一直铺到两万多,中间500到1200这一段只有3个站。
分布怎么看,服务器日志分析工具给了现成的分桶方式。
这条线不是我划的,是数据自己裂开的地方。1200这个数落在那道缝里,往左移到500或者往右移到2000,被分类的站只会变动两三个。一个稳健的阈值就该是这样——挪一挪结果不怎么变。
边界上那几个站
紧挨着线右边的几个:joolz.com正文1262字符,ecoflow.com 1464,nespresso.com 1503,peakdesign.com 1682。
边界情况最容易漏,抓取速率被调低却一条错误都没有就是这么发生的。
这几个都被算成了"正常页",但说实话它们也没正常到哪去。1262个字符对一个电商首页来说,大概就是导航加页脚的量,商品区多半还是靠脚本画的。
所以这条线的正确读法不是"过线就没事",而是"过线之后要看的是别的问题"。分类的作用是把不同性质的问题分开处理,不是发及格证。
如果换一个口径
值得说一句:如果不用字符数,改用"首屏商品名有没有出现在HTML里"这类内容级判据,分类结果会更贴近实际,但可复现性会大幅下降——不同品类的首页放什么根本不一样,一个家具站和一个美妆站的首屏完全没有可比的元素。
口径要能复现,一个尾逗号就让整页结构化数据失效说明细节有多要紧。
字符数这个口径粗,但它对所有站一视同仁,而且任何人拿同样的方法都能复现出同样的数字。在做横向对比的时候,可复现性比精确性重要。
这条原则值得展开一句,因为它经常被误解成"糙一点没关系"。不是的。它说的是:当你要比较很多个对象的时候,一把所有人都能拿到同样读数的粗尺子,胜过一把只有你能用好的精细尺子。因为横向对比的价值全在"可比"这两个字上,尺子一旦因人而异,所有排名都失去意义。
换成自己站的纵向监测,结论就反过来了:这时候没有可比性问题,用越贴近业务的判据越好。横向用粗尺子,纵向用细尺子,这是两种完全不同的测量任务,经常被混为一谈。
把这条线用在自己站上
如果你要照着这套方法量自己的站,1200这个数不要直接搬。它是从这批国际化独立站首页的分布里长出来的,换一批样本,那道缝的位置会变。
一个站两套技术栈很常见,插件和主题冒出两套标记怎么归一是同源问题。
正确的做法是:把你自己站上各类页面各抓十几个,量出正文字符数,画一下分布。如果分布是连续的,说明你的站在这件事上是一致的,那就不需要分类;如果出现明显的双峰,那道缝就是你的线。
多数站的结果是第一种——同一套模板出来的页面,输出方式是一样的。出现双峰通常意味着站上有两套技术栈,比如商品页是服务端渲染的老系统,而某个新做的活动频道是纯前端的。这种情况在做过几次改版的站上很常见,而且往往没人记得还有这么一块。
怎么判断一个缺失是真缺,还是只是没渲染?
这是整篇文章最实用的一节,因为两种情况的修法完全不同。
有一整类抓取器规则不同,Google不看robots.txt的那类抓取器值得单独了解。
三步判断法
第一步,把页面用命令行抓下来,看可读正文有多少。这一步决定了后面所有检查有没有意义。如果正文接近零,别的都不用查了,先解决输出问题。
抓取和渲染分几步,看懂才知道哪里丢内容把流程拆开了讲。
第二步,如果正文正常,那就在字节里找那个具体的东西。找按钮的名字,找图片的alt,找main标签。找得到就是有,找不到就是没有,不需要争论。
第三步,只有在字节里找不到、但你确信页面上有的时候,才需要区分"是不是渲染后才有"。这时候打开浏览器的开发者工具,在元素面板里找无障碍相关的那个窗格,把整页的无障碍树打开看,重点看这个节点在树上叫什么。
第三步的三种结果
第三步会得到三种结果,对应三种完全不同的处理方式。
调试这类问题的工具链,JSON格式化与结构化数据调试是常用的一环。
第一种,树上有名字。那说明脚本在运行时补上了。这种情况下,问题只对不执行脚本的读者存在,要不要处理取决于那类读者对你重不重要。这是唯一一种可以"知情之后选择不处理"的情况。
第二种,树上也没有名字。那就是确凿的缺陷,跟渲染没关系,读屏软件用户此刻正在遭遇它。这种要修,而且优先级不低。
第三种最有意思:树上有名字,但名字是错的。比如按钮上明明写着"加入购物车",树上的名字却是"button-4",或者是一串组件生成的编号。这种情况多半是有人给元素加了aria-label,而那个值是从代码里带出来的、不是给人看的。这一类比没有名字更糟——没有名字至少还能靠周围的上下文猜,一个错误的名字会把猜的路也堵死。
两种情况的修法是相反的
如果字节里就没有,那是内容交付问题,要动的是渲染方式——服务端渲染、预渲染、或者至少给一份能读的降级内容。这件事的成本按项目算,不按页面算。
JS渲染抓不到该从哪查起,这几种情况的排查顺序是现成的路线。
如果字节里有、渲染后反而没了,那是脚本把它改坏了,要动的是那段脚本。这件事的成本按缺陷算,通常改一处就好。
把这两件事搞混,最典型的后果是拿改缺陷的力气去解决交付问题,改了三个月发现指标一动不动。
反过来搞混也很常见,而且更浪费:把一个几行代码就能修的缺陷,当成架构问题上报,于是它进了一个需要评审、需要排期、需要跨部门协调的流程,半年之后还在待办列表里。判断成本高低的第一个动作,就是先分清它是哪一类。
一个具体的分诊例子
假设你发现商品页上的"加入购物车"按钮,在抓下来的HTML里找不到名字。接下来怎么走?
分诊之后怎么排优先级,从AI爬虫到无障碍的42步实战给了一份完整清单。
先看同一份HTML里有没有商品名和价格。如果有,说明这一页整体是服务端输出的,只有这个按钮出了问题——那就是个组件缺陷,去找那个组件,加一个名字,改动量大概一行。
如果连商品名都找不到,那这个按钮没有名字只是表象,真正的问题是整页都没输出。这时候去改按钮组件是白费力气,因为改完之后那个按钮照样不在字节里。
同一个现象,同一句"按钮没名字",背后是两个成本差三个数量级的问题。区分它们只需要多看一眼旁边有没有商品名,十秒钟的事。这十秒钟省下来的力气,比这篇文章里任何一条建议都多。
关于执行脚本这件事的现状
需要说清楚一个事实边界:主流搜索引擎的抓取程序是会执行脚本的,这一点官方文档写得很明确,只是执行有排队、有资源上限,不保证每次都完整。而当下大量新出现的读取程序——各类AI训练与检索用的抓取器——多数不执行脚本,只读原始字节。
要不要拦这些程序,robots加UA加WAF的三层选型框架给了决策路径。
读你页面的名单变了多少,AI爬虫抓取量已超Googlebot 3.6倍有实测数据。
所以同一个空壳首页,对不同读者是两个完全不同的结论。这不是"要不要为SEO做服务端渲染"的老问题,这是"你的读者名单变长了"的新问题。名单变长的部分,恰好都是不执行脚本的那种。
这个变化的时间点很值得注意。服务端渲染这个话题在2016年前后吵得最凶,那时候的结论大致是"搜索引擎已经能渲染了,不必过度紧张",这个结论在当时是对的。之后这件事就淡出了很多团队的检查清单,新一批前端工程师入行时,它已经不是一个需要讨论的问题了。
结论没变,前提变了。当年那个结论成立的前提是"读你页面的只有会渲染的搜索引擎",这个前提在最近两年悄悄失效了,而失效的过程没有任何一次公告。这就是为什么值得重新量一遍——不是因为出了新规则,是因为老结论的地基被换掉了。
有个说法要澄清一下
经常听到一种说法:既然那些程序不执行脚本,那它们本来也读不好网页,不用太在意。
这个说法把因果搞反了。它们不执行脚本,不是因为技术做不到,是因为不划算。执行一整套前端脚本的成本,是纯读字节的几十倍,还要维护一整套浏览器环境。当抓取量以亿为单位的时候,这个差价决定了谁能活下来。
换句话说,这不是一个会随时间自动改善的问题。成本结构不变,行为就不会变。指望对方升级,比自己多输出一份HTML要难得多。
还有一种说法是"重要的内容它们会想办法拿到"。这个也不太站得住。对一个批量抓取的程序来说,判断哪一页重要本身就需要先读懂这一页,而读不懂的页面连进入这个判断的资格都没有。它不是把你排在后面,是根本没把你放进队列。
怎么估自己站受影响的程度
不用猜,日志里有答案。把最近一个月的访问日志按用户代理串分组,把那些明确自报家门的抓取程序挑出来,看它们各自的请求量占比。
日志里怎么分类,8类UA实测与22周访问账本给了可照搬的方法。
然后做一个简单的判断:这些程序里,有多少是会执行脚本的。搜索引擎的主抓取程序会,绝大多数其他的不会。把不会的那部分请求量加起来,除以总抓取量,就是你这个空壳问题的实际影响面。
这个比例在不同行业差别很大。内容型站点通常高,因为它们的文字更容易被这类程序盯上;商品型站点低一些,但也在涨。关键是这个数字你自己算得出来,不需要相信任何人的估计。
如果短期内改不了渲染方式
把整站改成服务端渲染,是一个按季度算的工程,很多团队短期内确实做不了。这种情况下有几件成本低得多的事可以先做,效果不如根治,但比什么都不做强很多。
预渲染这条路怎么走,Speculation Rules API的机制实战是相邻的技术选项。
第一件,把最重要的那几类页面单独做预渲染。首页、主要分类页、销量最高的那批商品页,加起来可能就几百个地址。预渲染只需要在构建时把这些页面跑一遍存成静态文件,不需要改运行时架构。这件事通常是一两周的量。
第二件,用noscript留一份精简正文。这个做法有点土,但它诚实、有效、几乎零成本。里面不需要放完整页面,放清楚"这一页是什么、有哪些主要内容、去哪能看到"就够了。本次样本里只有1个空壳站这么做了,说明这条路基本没人走——不是因为不好用,是因为没人想起来。
第三件,检查一下你的站点地图和结构化数据有没有把这些空壳页当成正常页在推。如果一个页面在字节层面是空的,把它推给更多程序去抓,只是让更多程序确认了它是空的。先把内容补上,再谈推广。
这三件事有个共同点:都不需要动前端架构,都可以由做技术优化的人独立推动。在等待架构排期的那几个月里,它们能把损失控制在一个可接受的范围内。
这套自查要花多久,从哪一步开始?
把上面所有东西收成一个能在一个下午跑完的清单。
批量打开页面手工看一眼,网址批量打开工具的实测说明了它能和不能做什么。
第一个动作:三分钟
用命令行抓一次你自己的首页,把标签剥掉数字符。如果这个数小于1200,后面的检查全部暂停,先去开会讨论渲染方式。
把HTML转成可读文本,Markdown与HTML双向转换也能顺手完成这一步。
如果这个数正常,顺手再抓一个商品页和一个分类页。首页往往是全站最特殊的一页,别拿它代表全站。这个教训保哥在别的检查里反复吃过。
第二个动作:十分钟
在HTML里数四样东西:有没有main标签,h标签的数字序列长什么样,有多少img没有alt属性,有多少input拿不到标签。
同一趟还能顺手查结构化数据,一次扒清五种格式的字段缺漏省一遍功夫。
这四样都能用最朴素的方式数出来,不需要任何工具。数出来之后跟本文的数字对一下,下面这张表可以直接当参照:
| 检查项 | 本次110个站的水平 | 你比它差就该做 |
|---|---|---|
| 四个地标区域齐全 | 69.1%的站做到了 | 缺哪个补哪个,半小时 |
| 有main标签 | 85.5%的站做到了 | 优先补,成本最低 |
| 首页至少有一张图缺alt属性 | 32.7%的站中招 | 按模板批量补 |
| 首页至少有一个输入框无标签 | 40.0%的站中招 | 查组件,一处全好 |
| 首页至少有一个按钮无名字 | 37.3%的站中招 | 查图标类组件 |
| 标题层级出现跳级 | 45.5%的站中招 | 危害小,改版时顺手 |
你比这几个数好,说明这一项不是你的优先项;比它差,说明这是个能低成本拉平的地方。注意这批站是行业里做得比较认真的一批,所以这些数字更像是及格线而不是优秀线。
第三个动作:半小时
打开浏览器开发者工具,把首页的完整无障碍树导出来看一遍。重点看四个位置:主要的行动按钮有没有描述性的名字,导航有没有被包在导航地标里,主内容区在树上是不是可读的文本,以及有没有大块内容被标成了隐藏。
想边改边看效果,三栏实时预览的HTML编辑器比来回刷新快得多。
这一步是唯一需要真浏览器的,也是唯一能看到"渲染后真相"的。前两步可以排除大部分问题,这一步用来确认剩下的。
看的时候有个小技巧:不要顺着树从上往下读,那样很容易被结构带着走。换个方式——先在页面上挑五个你最不想让用户点错的元素,比如加入购物车、结算、提交、切换规格、关闭弹窗,然后逐个到树上去找它们叫什么。五个都对,这一页基本没大问题;有一个叫不出名字,那多半是一整类组件的问题。
如果要把它变成常态检查
上面三个动作是一次性的排查,做完能知道现状。要让它不再退化,得挑一两项做成自动的。
常态检查还该包含链接健康,改版后全站404与重定向链的排查是配套项。
推荐做成自动的只有两项:关键页面的可读正文字符数,和关键控件的可访问名。前者用一个定时抓取加字符统计就够,掉到阈值以下告警。后者需要在自动化测试里加一条断言,把首页的无障碍树快照存下来,之后每次改动跟它比一下,有节点丢了名字就报出来。
其余各项不建议做成自动检查。它们的误报率高到会让人很快学会忽略告警,而一个被忽略的告警比没有告警更糟——它会让所有人以为这件事已经被监控了。
一个容易被跳过的动作:换个身份再抓一次
上面三个动作都是用普通浏览器的身份去请求的。有一件事值得顺手做:把请求的身份换成一个抓取程序的标识,再抓一次,看两次拿到的字节是不是一样。
这个动作的成本几乎为零,就是加一个参数。但它能查出一类前三步完全看不见的问题:你的服务器或者前面那层防护,可能对不同身份给出了不同的答案。本次实测里确实有站是这样,而且差异大到不可能是偶然。
如果两次结果不一样,接下来要判断的是哪一边不对。给浏览器的多、给程序的少,那是内容没交出去;反过来给程序的多、给浏览器的少,那通常是某种为抓取做的特殊处理,风险更大一些。
这件事跟本文主题只沾了一半的边——它查的不是"东西在不在",而是"东西有没有被送到",那是另一层问题。但既然抓都抓了,多抓一次几乎不费什么事,顺手排除掉一整类可能性。
把这次的数字存下来
做完前三步,一定要把结果存成一份带日期的记录,哪怕就是一个表格文件。这一步经常被跳过,但它决定了这次排查有没有长期价值。
记录要带时间,从sitemap的lastmod到结构化数据日期都得靠时间戳对齐。
原因很实际:这些指标的绝对值意义有限,变化才有意义。你的首页正文有5800个字符,这个数好不好?不知道。但如果三个月后变成了1200,那就是一件必须立刻查清楚的事,而且几乎可以肯定跟某次改版有关。
存的时候记得连口径一起存——用了什么用户代理串、哪一天抓的、剥标签的规则是什么。半年后重跑一次,如果口径变了,两次的数字就没法比,这份记录也就白存了。保哥吃过这个亏,翻出一份两年前的审计表,数字都在,但当时怎么算的一个字都没写,只能从头再来。
还有一个小建议:把行业参照值也记在同一份表里。这样下次看的时候,不用再去翻文章找那几个百分比。
把结果说给不同的人听
这套检查跑完,会得到三堆完全不同性质的问题,而它们需要说给三拨人听,说法还不能一样。
沟通方式也是能力的一部分,给SEO人的个人审计五步法里有相关的提醒。
正文输出问题要说给做技术决策的人听,因为它涉及架构选择和排期,说法应该是"我们有多少页面对不执行脚本的读者是空白的,这些读者占抓取量的多少"。不要说"我们没做服务端渲染",那是手段不是问题。
组件层的问题——按钮名字、表单标签——要说给做前端的人听,说法应该是具体的组件名和具体的改法。这类问题的沟通成本最低,因为它们是明确的、可验证的、改完立刻能确认的。
内容层的问题——图片替代文本写得对不对——要说给做内容和设计的人听,而且要给判据不要给清单。给清单会得到一堆敷衍的填空,给判据才会得到能用的文字。
不建议做的事
不建议一上来就跑一个综合评分工具,然后照着分数改。这类工具会把上面说的三层问题混在一起给一个总分,而三层的修法完全不同、成本差几个数量级。先分类,再打分,顺序反了会浪费很多力气。
综合评分工具的局限,AMP验证器的八大类规则是个可对照的例子。
也不建议把这些检查项变成一张需要人工填写的上线检查表。人工检查表的寿命通常是三个月,之后它会变成一个所有人都勾但没人看的仪式。能自动检测的就自动检测,检测不了的就写进组件默认值,两条路都走不通的才写进检查表。本文这些项里,前两类能覆盖绝大部分。
把无障碍当成SEO手段,这条线该画在哪
最后必须说一段立场,因为前面全篇都在用"机器读不读得到"当理由,这个理由本身是有边界的。
动机和后果要分开谈,AI写的内容会被惩罚吗也是在澄清因果。
顺序不能颠倒
无障碍这套东西的存在理由是残障人士的使用权,这一点跟搜索、跟AI、跟流量都没关系。它在很多国家和地区是法律要求,在所有地方都是基本的产品责任。
无障碍不止网页,PDF的标签结构与阅读顺序是同一套思路在另一种格式上。
因为机器读得到所以去做无障碍,这个动机会在某一天失效——某天机器变强了,能靠视觉理解页面了,按这个逻辑就该不做了。而那一天到来的时候,需要读屏软件的人一个都没有减少。
那这篇文章的立场是什么
是这样:这些检查项你本来就该做,做了之后顺带会让机器也读得懂。顺序是"做对了,所以机器也能读",不是"机器要读,所以做一下"。
把内容当结构来生产,内容工程这套新手艺说的是流程而不是清单。
实际操作上这两个顺序的产出会不一样。按第一个顺序做,会把整个流程改掉,组件规范里加上标签要求,以后新写的页面自动就是对的。按第二个顺序做,会挑几个重要页面手工补一遍,三个月后新上的页面又是老样子。
差别的根源在于覆盖范围。为机器做,只需要覆盖那些机器会去的页面;为人做,得覆盖所有页面。前者的终点是一份清单,后者的终点是一套默认值。而只有默认值才不会退化。
顺便说一个容易被忽略的事实
需要无障碍支持的人,比多数人想象的多得多,而且不只是完全失明的用户。
看不见的流失最难发现,那排标签让用户没法把两块信息放进同一屏也是这一类。
视力低下需要放大、色觉有差异需要靠文字而非颜色区分、手部不便只能用键盘、在嘈杂环境里只能看不能听、临时性的比如手上打着石膏或者抱着孩子只能单手操作——这些人在任何一个电商站的日活里都占着相当可观的一块,而且他们中的绝大多数不会告诉你他们遇到了困难,他们只会离开。
一个没有名字的按钮不会产生任何一条报错,也不会出现在任何一张转化漏斗的报表上。它只会表现为某一小撮用户在那一步的流失率略高一点,而那一点会被淹没在噪声里。这可能是本文所有内容里,唯一一条跟机器完全无关、但比所有机器相关的理由都更该被听见的。
一个现实的建议
如果你在一个把商业指标看得很重的团队里,很难只靠"这是应该做的"推动这件事,那么本文这些数字可以当成一个补充论据,不是唯一论据。用它去争取排期,别用它去定义目标。
排期时需要一份完整的说法,GEO从AI搜索到结构化数据的实施策略可以当框架用。
这两者的区别在验收的时候会显出来。用它定义目标,验收标准会变成"无名按钮数降到多少以下",团队会去做那些数字上最划算的改动,而真正影响用户的那几个控件可能一个都没动。用它争取排期,验收标准还是"这些控件能不能被读屏软件正常使用",数字只是排期时的说服材料。
如果站点规模大,或者所在行业有明确的无障碍法规要求,请找专业的无障碍顾问,别拿这篇文章当验收标准。这篇文章量的只是那些能从字节里看出来的部分,它离一次真正的无障碍审计还差很远——真正的审计要看键盘能不能走通全流程、对比度够不够、动效能不能关掉、读屏软件实际念出来是什么,这些都不是抓一次HTML能回答的。
最后回到那个五兆的页面
写到这里,可以把开头那个例子的完整含义说清楚了。
把地基打对,实体主页与品牌身份的搭法是这套思路的另一面。
那个站传了两兆多字节,一个字都读不出来,同时它写了标题、写了描述、放了结构化数据。这不是一个不专业的站,恰恰相反,它每一样单独看都做得挺规范。
问题出在没有人问过那个最笨的问题:我们发出去的东西里,到底有没有字。所有人都在检查各自负责的那一项,没有人负责检查这些项加起来是不是构成了一个能读的页面。
这篇文章从头到尾其实只在推荐一个动作:抓一次,剥掉标签,数一下。三分钟,不需要工具,不需要权限,不需要跟任何人商量。三分钟之后你会知道,接下来该讨论的是哪一层的问题。
常见问题解答
我的站是单页应用,是不是一定有问题?
不一定,关键看有没有做服务端渲染或者预渲染。单页应用只是描述前端架构,不决定输出什么字节。本次样本里跑单页框架但正常输出HTML的站不少,也有用传统模板引擎却把内容全塞进脚本的。架构名词说明不了任何事,字节能。判断方法只有一个:抓一次,数字符。这个动作三分钟,比在群里讨论半小时有用得多。
PWA也有类似问题,8类抓取与索引影响的实战可以对照判断。
Google能渲染脚本,那我是不是不用管?
如果你的目标只有搜索引擎,风险确实小一些,但也不是零——官方明确说过渲染有排队、有资源限制,不保证每一页都能完整执行。页面越多、更新越频繁的站,排到的概率越不确定。
渲染要排队,抓取预算优化的12项实操解释了资源是怎么分配的。
而现在来读你页面的不止搜索引擎,各类AI检索与训练用的抓取器大多不执行脚本。所以这个问题的答案在这两年变了:以前是"影响有限",现在是"影响取决于你在乎哪些读者"。要把这个问题变成一个可以决策的问题,去日志里数一下不执行脚本的那类请求占多少。
那我把内容塞进结构化数据是不是就行了?
不行,这是本次数据里最明显的一个误区。有几个站的结构化数据比正文长几十倍,看起来很努力,但结构化数据的作用是描述实体和关系,不是承载正文。它是目录,不是书。
结构化数据该怎么配合,Schema的落地方式与常见避坑说得比较清楚。
而且这么做在规范上是有风险的:结构化数据描述的内容通常要求在页面上真实可见。当结构化数据里写着商品名和价格,同一份字节里的正文却是空的,这个对应关系严格说是断的。实际执行中很少有人因此被处理,但把它当成长期依赖的做法并不稳妥。
alt到底该写多长?
写到"这张图去掉之后你需要补的那句话"为止,通常十几个到三十几个字符。太短的问题是没信息量,比如写"图片"、"banner"、"product";太长的问题是变成了正文,那些话该写在正文里。
文字进图片这件事也有坑,OG图生成器把emoji切成方块是个具体教训。
装饰性的图直接写空字符串,这是明确表态,不是偷懒。本次数据里24.1%的图是空alt,这个比例本身很健康。需要警惕的是另一种情况:商品主图空着、旁边的装饰角标反而写了字,那是信息层次被写反了。
placeholder能不能代替label?
不能。placeholder在用户开始输入的那一刻就消失了,它是提示不是标签。用户填到第三个字段忘了这一格填什么,只能全部删掉重看一眼——这个体验问题跟机器读不读得到无关,它本身就是个缺陷。
这类细节的收益常被低估,被低估的9个反直觉杠杆收集了不少类似的。
如果设计上确实不想显示标签文字,正确做法是保留label但在视觉上隐藏它,或者给输入框加aria-label。本次样本里有好几个站是整套表单组件全部无标签,ritual.com的22个、mejuri.com的14个、allbirds.com的13个都是这种形态。整齐的全军覆没说明它是组件层面的选择,改一处就能全好。
首页测完了,其他页面要不要都测?
不用全测,但一定要测不同类型的各一个:商品页、分类页、内容页各取一个。首页在很多站上是最特殊的一页,用的模板跟别的页面完全不同,往往还是改版时最先被重做的那一个。
分类页最容易被忽略,用户点进来那一屏没有一个字写着他在哪就是实例。
更值得测的是那些"不太起眼但流量不小"的页面:搜索结果页、筛选后的分类页、专题活动页。这几类最容易由不同的人在不同的时期用不同的方式做出来,也最容易游离在所有检查流程之外。
为什么无名按钮的比例只有8.2%,但受影响的站有37%?
因为分母不同。8.2%是按按钮个数算的,37.3%是按站算的——只要一个站有一个无名按钮就计入。这两个数不矛盾,它们回答的是两个问题:整体质量怎么样,和这个问题普不普遍。
口径这件事在别处也一样,13种Schema类型该怎么选同样要先分清对象。
用哪个口径取决于你要干什么。做横向对比、判断一件事值不值得关注,看站的口径;给自己的站排改进优先级,看个数的口径。本文所有指标都同时给了两个口径,就是因为这两个问题经常被混在一起问。
svg没名字算不算错?
要看它在哪。如果外面包着一个有名字的按钮或者链接,那这个svg本来就该被标成装饰性的,没名字是对的,甚至可以说是正确做法——图标和它所在的控件不该各有一个名字,那会被读两遍。
图形处理的基本功,8种按比例缩放的前端方案是相邻的实务。
如果它是唯一的内容、外层也没名字,那就是硬伤。本次数据把这两类分开数过:前一类数量很大(3906个)但多数无害,后一类264条是确凿的问题。汇报的时候只报后一类,报前一类会被技术同事当场问倒,而且他们是对的。
这套检查多久做一次?
触发式比定期式实用。换模板、上新的组件库、大改导航、迁移前端框架,这四件事之后各做一次。它们是结构问题最容易被批量引入的时机——一次组件改动能同时影响几十个页面上的几百个元素。
配置每次都通过不代表没事,每8次抓取有1次撞在301上是同类的隐形退化。
如果一定要个周期,配合改版节奏走就行,为它单独排期通常排不上。更省事的办法是把最粗的那一项——正文字符数——做成一个定时任务,掉到线以下就告警,剩下的靠触发。
团队里这件事该归谁?
这是本次数据背后最真实的一个问题。标题和描述归做搜索的人,渲染方式归做前端的人,两边各自都做得对,中间那条缝没人负责。本次那张头部信息完备度的表,实际上就是这条缝的照片。
设计侧也有对应的动作点,从IA到Figma落地的7个协作动作能补上另一半。
比较务实的做法是把几条检查写进组件规范和自动化检测,让它变成默认行为,而不是靠某个人记得去查。靠人记得的事,撑不过一次人员变动。
我该先修哪一项?
按成本和影响排:正文输出问题排第一,它决定别的检查有没有意义;表单标签排第二,因为它一般是组件级的、改一处全好,而且直接影响真实用户;图片alt排第三,工作量大但可以分批做,而且可以跟内容更新一起做;标题层级和地标排最后,它们的实际危害最小,通常在改版时顺手就修了。
排优先级要看影响面,URL结构与slug的9个细节也是这么权衡的。
如果只有半天时间,就做两件事:给搜索框加标签,给页面加main标签。这两件加起来不到一小时,覆盖的是所有页面。
权威参考资料
本文标题:《AI爬虫读不到你的正文?132个独立站首页有28个是空壳》
本文链接:https://zhangwenbao.com/html-shell-page-readable-text-audit.html
版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0
← 上一篇
一个词值不值得单开一页,87个站的站点地图先替你答了一半下一篇 →
没有了