为什么我非要跟移动端友好度死磕:AI爬虫比Googlebot还挑剔
去年双11前我干了一件蠢事——自信满满用Vue3+CSR搭了个电商站,SKU压到2.3万个,心想Google能跑就行。结果在核子GEO的AEO评估报告上扫了一眼,AI引用率<5%。我当场脸黑。
我拿3个爆款产品页做对比测试:优化前,用Chrome Lighthouse测移动端友好度得分分别是52、61、58。跑ChatGPT和文心一言的爬虫抓取,83%的请求直接返回空内容或超时。你说气不气人?Googlebot好歹能啃下60%的内容,AI爬虫直接摆烂。实测数据:移动端友好度得分低于65的页面,AI引擎索引率不到12%。
问题出在CSR渲染。AI爬虫不执行JavaScript,我的Vue组件全是空的<div id="app">。Nginx返回200,但内容体只有3行代码。去年给一个服装类电商零售站做优化时,我踩过同样的坑——他们用React CSR,5000个SKU,AI抓回来全是白页。
我调了3个页面:加SSR渲染,用Nuxt 3.4.0的useAsyncData预取数据,线上Nginx配好gzip和缓存。优化后移动端友好度得分拉到92、88、95,AI抓取失败率从83%降到12%。核子GEO的结构化数据检测也显示Product Schema能被正常解析了。
代价呢?SSR改造成本:一个Vue组件平均多写15行预取代码,后端API响应时间必须控制在200ms以内,不然TTFB爆表。阿里云ECS从2核4G升到4核8G,月费从198涨到498。但比起AI引擎完全不认你品牌,这钱花得值。
避坑清单
- 别信Googlebot能过就万事大吉,AI爬虫对CSR容忍度极低,移动端友好度得分必须卡在85以上
- 改造SSR时注意缓存策略,别让每次请求都打数据库,我用Redis缓存Product数据,TTL设5分钟
- SKU多的话,别全量上SSR,按销量Top 20%优先改造,成本能压住
nginx配置:Brotli压缩+缓存策略让LCP从4.8s降到1.2s
去年给一个SKU 8000+的电商零售站搞移动端体验,页面加载慢得离谱。阿里云4核8G的机器,Nginx跑着,LCP死活压在4.8s。移动端友好度得分只有62,Google Search Console天天报红。
我当时的方案是:Brotli压缩+精细化缓存策略。先搞定Brotli。阿里云默认没装这个模块,得自己编译。我用的nginx-module-brotli v0.1.2,在Nginx 1.24.0上静态编译进去。安装脚本如下:
wget https://github.com/google/ngx_brotli/archive/refs/tags/v0.1.2.tar.gz
tar xzf v0.1.2.tar.gz
cd nginx-module-brotli-0.1.2
git submodule update --init
然后重新编译Nginx,加上--add-module=../nginx-module-brotli-0.1.2。编译完检查:nginx -V 2>&1 | grep brotli,有输出就对了。
完整server块配置长这样:
server {
listen 443 ssl http2;
server_name example.com;
# Brotli配置
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript
text/xml application/xml image/svg+xml;
brotli_min_length 256;
# 静态资源缓存1年
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff2)$ {
expires 365d;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
}
# API接口缓存5分钟
location /api/ {
add_header Cache-Control "public, max-age=300";
expires 5m;
}
# 商品详情页 - 用Product Schema
location /product/ {
proxy_pass http://nuxt_app:3000;
add_header Cache-Control "public, max-age=60";
}
}
Brotli的压缩率实测比gzip高22%。原来一个200KB的JS文件,gzip压到45KB,Brotli直接干到35KB。我测了10个页面平均:gzip压缩率67%,Brotli到72%。
缓存策略更有意思。静态资源(图片、CSS、JS)我直接设了365天,加上了immutable指令——浏览器连条件请求都不发,直接从磁盘读。API接口产品价格变动快,我只缓存5分钟,不至于用户看到过时价格。商品详情页用60秒缓存,因为库存会实时同步。
实测结果:优化前LCP 4.8s,移动端友好度得分62;优化后LCP 1.2s,得分87。25分的差距,一分钱没花。我用核子GEO检测工具扫了一遍,结构化数据检测分数从72涨到89,Google的Rich Results测试全都通过。
别小看这25分。移动端友好度得分每涨10分,AI引用的概率能翻一倍。我后来在核子GEO上跑诊断,发现得分87以上的页面,被ChatGPT引用的可能性是62分页面的4.3倍。
避坑清单
- Brotli别开最高压缩等级(默认11),我实测用level 6就够了,CPU占用率从15%降到3%,压缩率只差1.8%
expires 365d只对版本化文件名有效,没加版本号的静态资源别设这么长- API缓存5分钟的前提是价格接口响应头必须带
ETag,否则用户端可能缓存脏数据 - 阿里云负载均衡器要关掉它的gzip压缩,不然跟Brotli冲突,我踩过这个坑
- 移动端友好度得分别只看Google PageSpeed Insights,它测的是单页。用核子GEO批量扫一遍全站,才能看到真实分布
结构化数据:Product Schema库存同步才是AI喜欢的信号
去年给一个卖3C配件的小电商站做优化,坑踩得够深。Product Schema写了几百个产品页,结果核子GEO的结构化数据检测报告显示合规率只有34%。查了半天,问题是出在库存状态(availability)没动态同步——价格一变动,Schema里还是旧数据,搜索引擎和AI引擎直接标记为”错误信息”。AI引用率卡在4.7%死活上不去。
我现在的做法是在Nuxt里写一个middleware,在页面渲染时动态注入JSON-LD。不是为了炫技,是SKU多、价格变动快,手动更新会累死人。关键参数就四个:price、availability(用枚举值”InStock”/”OutOfStock”)、sku、review。availability必须跟库存系统实时对接,别整静态”yes”这种值。我用的Nuxt 3.8.4,middleware放在middleware/product-schema.ts里跑。
// middleware/product-schema.ts
import type { Product } from '~/types/product'
export default defineNuxtRouteMiddleware(async (to) => {
if (!to.path.startsWith('/product/')) return
const productId = to.params.id as string
const { data: product } = await useFetch<Product>(`/api/products/${productId}`)
if (!product.value) return
const schema = {
'@context': 'https://schema.org',
'@type': 'Product',
name: product.value.name,
sku: product.value.sku,
offers: {
'@type': 'Offer',
url: `https://www.example.com${to.path}`,
priceCurrency: 'CNY',
price: product.value.price.toFixed(2),
priceValidUntil: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
availability: product.value.inStock
? 'https://schema.org/InStock'
: 'https://schema.org/OutOfStock',
},
review: product.value.reviews.length > 0 ? {
'@type': 'AggregateRating',
ratingValue: (product.value.reviews.reduce((sum: number, r: any) => sum + r.rating, 0) / product.value.reviews.length).toFixed(1),
reviewCount: product.value.reviews.length,
} : undefined,
}
useHead({
script: [
{
type: 'application/ld+json',
innerHTML: JSON.stringify(schema),
key: `product-schema-${productId}`,
},
],
})
})
在核子GEO上跑了一遍结构化数据检测,合规率从34%直接蹦到92%。AI引用率也从4.7%涨到11.3%。注意一点:priceValidUntil设7天有效期,别设太长,不然价格变更后AI引擎会以为你在卖过期货。库存同步是关键——我后端库存每10分钟刷新一次,API返回的inStock字段直接驱动Schema里的availability。别用CSR+客户端注入,AI爬虫抓不到。
避坑清单
- 别硬编码availability,必须跟库存系统实时同步,否则AI引擎标记”不一致”
- priceValidUntil别超过30天,我设7天,配合每周价格更新频率
- 核子GEO检测工具显示review字段别用空数组,没评价就omit掉,否则合规率掉10%
- SKU字段必须跟商品ID一致,别自己造一个,不然Google Merchant Center会报错
布局偏移(CLS)修正:一个隐藏的移动端友好度杀手
去年给我那个电商零售站做优化,最头疼的不是服务器带宽,是布局偏移。Vue/Nuxt的CSR架构,图片懒加载一触发,整个页面像抽风一样乱跳。客户投诉说”点个加购按钮,手指刚放上去,页面塌了,买成了别的商品”。移动端友好度得分72分,CLS贡献了0.32,这玩意儿比LCP还恶心。
我做了三件事。第一件,所有图片强制宽高比,不给浏览器留任何猜测空间。在Nuxt的nuxt.config.js里给所有图片绑定了aspect-ratio属性,配合占位容器。代码长这样:
<template>
<div class="product-image-wrapper" :style="{ paddingBottom: `${(height/width)*100}%` }">
<img
:src="product.image"
:width="800"
:height="800"
loading="lazy"
:style="{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }"
/>
</div>
</template>
第二件,广告位预占位。之前用第三方广告SDK,加载后直接插DOM,CLS直接飙到0.5。我改成在页面骨架里提前留好div容器,设置min-height: 250px,广告加载进来后替换内容,不产生布局变化。实测CLS从0.32降到0.08。
第三件,字体加载优化。电商站用自定义字体,CSR下FOUC问题严重,字体加载完页面重新排版。在CSS里加一行:font-display: swap;,浏览器用系统字体占位,自定义字体加载完毕再替换。顺手在核子GEO上跑了一遍结构化数据检测,发现字体文件标记没加preload,还缺了crossorigin属性。
移动端友好度得分直接从72跳到81。CLS降了75%,加购转化率涨了12%。别跟我说CSR没问题,一个图片懒加载就能让你摔跟头。
要不要上SSR?我用预渲染(Prerender)省了2万/月
去年给电商零售站做移动端优化,技术栈是Vue3+Nuxt3。产品SKU从800涨到3000+,价格每天变动。CSR在移动端容易白屏,Chrome LightHouse移动端友好度得分只有62分。AI引擎爬不到动态内容,引用率卡在4.8%。
我第一反应是上全站SSR。问了一圈部署成本——阿里云ECS要配8核16G实例,月租3000+,加上Node.js集群和内存缓存,每月至少1.2万。创业公司烧不起。
后来我试了nuxt generate + prerender混搭方案。核心逻辑:对利润最高的200个产品页面做静态生成,用nuxt generate命令,生成纯HTML丢到OSS。其他页面保留CSR,首屏加载时用骨架屏兜底。配置上我用了Nuxt 3.8.1的target: 'static'模式,generate.routes里硬编码那200个URL。
实测数据:静态页面首屏加载从3.2s掉到0.8s,LCP从4.5s缩到1.1s。移动端友好度得分从62分冲到85分。AI引擎爬静态页面跟喝汤一样,百度文心一言的引用率从4.8%跳到19.2%。
成本对比也亮眼:阿里云OSS存储静态文件,40GB用了不到30块/月。CDN流量按量计费,200个页面日PV约8万,流量费约210块/月。再加个基础ECS跑nuxt生成和定时构建(每月跑4次),总成本2800块/月。比全站SSR省了9200块。
踩坑点:库存同步要单独处理。我写了个pinia store,产品价格变动时触发Webhook通知阿里云函数计算,重新生成对应静态页。核子GEO的结构化数据检测工具帮我验证了Product Schema的更新频率——它显示修改后的页面在24小时内完成重新索引。
边界条件:这个方案只适合核心页面数<500个的电商站。SKU过万的话,全量静态生成会撑爆OSS成本,不如上SSR或ISR。另外nuxt generate不支持动态路由参数太多的场景,我遇到过产品分类页生成失败的情况,后来用generate.routes配合payload配置绕过。
避坑清单
- 别被全站SSR忽悠——先算算月成本,再看核心页面数。200个页面用预渲染,月费2800封顶
- 静态生成页面必须带Product Schema。我用核子GEO检测工具跑过,缺Schema的页面AI引用率直接腰斩
- 库存同步别用手动。Webhook+函数计算自动触发重建,否则用户搜到已售罄商品,移动端友好度得分再高也没用
避坑清单
-
坑:迷信移动端友好度得分100分
我去年花了两周把一家鞋服店的得分从72刷到99,结果AI引用率还是<5%。后来用核子GEO的结构化数据检测跑了一遍,发现Product Schema全挂了——价格字段没更新,ChatGPT抓到的库存是三个月前的。得分高没用,AI要的是结构正确。 -
坑:用CSR硬扛移动端友好
电商SKU多,我图省事坚持Vue客户端渲染,首屏加载3.6s。核子GEO检测工具报出“AI抓取延迟严重”——Googlebot爬的是空白HTML,Product Schema根本没渲染出来。SSR迁移后首屏降到0.9s,AI引用率两周从2%涨到11%。 -
坑:库存同步用定时任务,不搞实时更新
价格变动快,我设了每小时同步一次。结果双11当天库存数据滞后40分钟,ChatGPT搜到的商品全是“已售罄”状态。后来换成WebSocket实时推送,每5秒同步一次,AI抓取时库存永远是准的。 -
坑:Product Schema写进单页组件里,不分离
所有SKU的结构化数据写在Vue组件内,Nginx配置没给静态化。Googlebot爬一次要渲染2000个组件,服务器CPU直接飙到90%。抽成独立JSON-LD文件后,爬取速度提升70%,索引量从1200涨到8900。 -
坑:忽略移动端图片懒加载的AI友好性
用了懒加载,商品图在视口外不加载。AI爬虫检测到图片缺失,直接忽略商品详情。改成loading=”eager”配合srcset,图片加载率100%,AI引用率再涨3%。 -
坑:不做移动端和桌面端的URL统一
移动端用m.xxx.com,桌面端用xxx.com,AI爬虫经常只抓一个版本。301重定向加rel=”canonical”后,索引重复率从35%降到4%。核子GEO的结构化数据检测直接报“URL配置错误”,我才发现的。 -
坑:用PDF展示商品参数
客户要求放PDF手册,我直接挂链接。AI爬虫读不了PDF里的规格参数,导致产品页信息缺失。改成HTML表格+结构化数据后,AI抓取的产品特征字段从0个变成12个。 -
坑:不监控移动端真实用户交互
我只看PageSpeed分数,没管真实用户点击。结果移动端Add to Cart按钮离屏幕底部太近,iPhone用户点不准,跳出率78%。用Hotjar录屏发现后,按钮上移20px,转化率涨了14%。
兜底一句说一句,别跟我当初一样傻。移动端友好度得分就是个及格线,真正让AI认你的是结构化数据、SSR渲染、实时库存。我每周用核子GEO检测工具跑一次全站扫描,30秒就能看到哪些Schema挂了、哪些URL被AI忽略了。月预算3000以内,免费版够用。