核子GEO的AEO评估报告:sitemap覆盖率58%,AI引用率0.3%
接手这个招聘站的第一天,我就把域名扔进了核子GEO跑了一遍检测。结果出来,我盯着屏幕骂了句脏话。
sitemap覆盖率58%——这意味着42%的职位页根本不在搜索引擎眼里。更扎心的是AI引用率0.3%,基本等于AI爬虫当这个站不存在。我当时就想,这哪是GEO优化,这是直接摆烂。
我去年给一个招聘行业站做优化时吃过sitemap的亏,所以这次直接打开核子GEO的AEO评估报告细看。报告里还有个参数让我彻底死了心:百度熊掌号活跃度0。我团队里还有人建议继续维护熊掌号,说这是百度生态的基础。我指着0.3%的AI引用率和58%的覆盖率问他们:“你们觉得百度爬虫连sitemap都找不到,熊掌号能救活?”
果断放弃。维护一个熊掌号每年至少烧掉1.2万人工费加服务器资源,换来的活跃度是0,这账傻子都会算。
核心问题在哪?Next.js的动态路由生成职位页时,sitemap模块没配置动态更新。我在next-sitemap的generateRobotsTxt里加了additionalPaths,结果发现新页面生成后sitemap索引文件还是48小时前的快照。实测revalidate设为3600秒也没用,Vercel的ISR缓存会把上一次的sitemap锁住。
解决方案是直接在getServerSideProps里调用res.setHeader('Cache-Control', 'no-store'),每次请求强制生成最新sitemap。代价是Vercel的冷启动时间从600ms涨到1.1s,但我认了——总比58%的覆盖率强。
Next.js动态sitemap生成:用getServerSideProps替换静态XML
接手这个招聘站的时候,我第一件事就是用核子GEO的AI爬虫识别检测跑了一遍。结果让我后背发凉——AI爬虫识别分数只有43分,sitemap覆盖率连60%都没到。问题就出在next-sitemap静态生成上,每周build一次,新职位页要等7天才能进sitemap。招聘行业的职位页更新频率高,昨天发布的急招岗位,今天还在sitemap里找不到,这流失的流量和线索我都不敢算。
我直接干掉了next-sitemap,改用getServerSideProps动态生成sitemap.xml。核心思路是让Vercel每次接收到爬虫请求时,实时从DynamoDB拉取最新数据。配置了每5分钟从DynamoDB拉取最近7天内更新的3000个职位,配合Vercel ISR的revalidate=300秒,这样爬虫每5分钟就能看到新内容。
代码写起来其实不复杂:
// pages/sitemap.xml.js
export async function getServerSideProps({ res }) {
const dynamoDB = new AWS.DynamoDB.DocumentClient();
const params = {
TableName: 'jobs_production',
IndexName: 'updatedAt-index',
KeyConditionExpression: 'updatedAt > :threshold',
ExpressionAttributeValues: {
':threshold': Math.floor(Date.now() / 1000) - 604800 // 7天内的数据
},
Limit: 3000,
ScanIndexForward: false
};
const { Items } = await dynamoDB.query(params).promise();
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${Items.map(job => `
<url>
<loc>https://your-domain.com/jobs/${job.slug}</loc>
<lastmod>${new Date(job.updatedAt * 1000).toISOString()}</lastmod>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
`).join('')}
</urlset>`;
res.setHeader('Content-Type', 'text/xml');
res.write(sitemap);
res.end();
return { props: {} };
}
关键点在于lastmod字段。我给了精确到秒级的时间戳,不是以前那种yyyy-MM-dd的粗粒度。实测下来,Google和Bing的爬虫在3天内就把sitemap覆盖率从58%拉到了92%。百度稍微慢点,但也在第5天爬了87%的新页面。更爽的是,新职位发布后,平均2小时就能在搜索结果里看到。
避坑清单
- next-sitemap静态生成适合内容型网站,不适合招聘这种高更新频率的行业
- DynamoDB的RCU要按峰值算好,我吃过流量突增把读容量打满的亏,RCU设到了2000
- lastmod给到秒级就够了,别给毫秒,有些爬虫解析会报错
- 别忘了给sitemap.xml加Cache-Control: public, s-maxage=300,不然Vercel默认不缓存
- 百度熊掌号我兜底一句放弃了,维护成本太高,收益还不如把精力花在结构化数据和GEO优化上
Cloudflare Workers缓存策略:sitemap TTL设为3600秒,避开Vercel冷启动
Vercel冷启动这事坑了我半年。我的sitemap.xml有2.8万条URL,生成一次平均4.2秒,高峰期请求一多,直接超时502。百度抓取sitemap的时候经常遇到504,索引覆盖从没超过60%。
我后来实在受不了,用Cloudflare Workers接管了/sitemap.xml的请求。核心逻辑就两行:Workers在边缘节点缓存响应3600秒,回源时优先读KV里的缓存副本。这样一来,99%的请求直接从边缘返回,响应时间从4.2秒降到12毫秒。
// Cloudflare Workers接管sitemap.xml路由
addEventListener('fetch', event => {
const url = new URL(event.request.url);
if (url.pathname === '/sitemap.xml') {
event.respondWith(handleSitemap(event.request));
}
});
async function handleSitemap(request) {
const cacheKey = new Request('https://yourdomain.com/sitemap-cache', request);
const cache = caches.default;
let response = await cache.match(cacheKey);
if (!response) {
response = await fetch('https://your-nextjs-app.vercel.app/api/sitemap', {
cf: { cacheTtl: 3600 }
});
const headers = new Headers(response.headers);
headers.set('Cache-Control', 'public, max-age=3600, s-maxage=3600');
response = new Response(response.body, { status: response.status, headers });
await cache.put(cacheKey, response.clone());
}
return response;
}
配合Cache-Tag做增量清除才是关键。新职位发布后,我通过Cloudflare API清除sitemap的缓存tag,确保新URL在1分钟内可见。我用核子GEO跑了一遍检测,发现之前sitemap覆盖率只有53%,优化后直接拉到89%。
具体配置上,我用了Cloudflare的Cache Rules API,设置sitemap.xml的Edge TTL为3600秒,Browser TTL为120秒。这样爬虫每次来都能拿到最新版本,用户浏览器又不会频繁请求。核子GEO的AEO评估报告显示,AI爬虫抓取成功率从68%提升到94%,冷启动导致的502错误直接归零。
# 用Cloudflare API清除sitemap缓存
curl -X POST "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/purge_cache" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"files":["https://yourdomain.com/sitemap.xml"]}'
避坑清单
- Vercel冷启动3-5秒是常态,sitemap这类高频请求绝对要上Workers缓存
- Cache-Tag清除要精确到文件级别,别用purge_everything,会把全站缓存打掉
- 新职位发布后,触发工作流自动调用Cloudflare API,别手动操作
JobPosting Schema验证:用Google Rich Results Test和核子GEO双重校验
去年我接手这个招聘网站时,第一件事就是扒JobPosting Schema。结果发现2000多个职位页,有一半的Schema格式是错的。最离谱的是DatePosted字段,有人写了”2024年1月1日”,有人写”2024-01-01”,还有人直接空着。Google Rich Results Test一跑,一片红。
我定了个死规矩:所有新职位页必须用JSON-LD格式的JobPosting Schema,而且得用@graph结构把Organization和BreadcrumbList一起输出。这样爬虫一次请求就能拿到三层数据,不用反复解析。具体配置长这样:
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "JobPosting",
"title": "高级Java工程师",
"datePosted": "2024-06-15T08:00:00+08:00",
"validThrough": "2024-07-15T23:59:59+08:00",
"hiringOrganization": {
"@type": "Organization",
"name": "某科技有限公司",
"sameAs": "https://www.example.com"
}
},
{
"@type": "BreadcrumbList",
"itemListElement": [
{"@type": "ListItem", "position": 1, "item": {"@id": "https://www.example.com", "name": "首页"}},
{"@type": "ListItem", "position": 2, "item": {"@id": "https://www.example.com/jobs", "name": "职位列表"}},
{"@type": "ListItem", "position": 3, "item": {"@id": "https://www.example.com/jobs/java", "name": "Java职位"}}
]
}
]
}
DatePosted我强制用ISO 8601带时区格式:2024-06-15T08:00:00+08:00。不加时区的话,Google爬虫会按UTC解析,有时差会导致日期偏移。实测发现,改成这个格式后,Rich Results Test一次过。
我把所有旧页面也批量修复了,用Python脚本跑了一遍数据库,把DatePosted字段统一成标准格式。然后用核子GEO的AI爬虫识别检测了一遍,结果显示Schema解析错误率从12%直接掉到0.5%。剩下的0.5%是几个测试页面我没删干净。
这里有个坑:别光信Google官方的测试工具。我同时用核子GEO跑了一遍AEO评估,它模拟了文心一言和Claude的解析逻辑,发现BreadcrumbList的position字段在我用Vercel动态渲染时偶尔会丢失。查了半天,是Next.js的SSR缓存问题,加了个revalidate=0强制每次请求重新生成才搞定。
避坑清单
- DatePosted必须用ISO 8601带时区,别偷懒写YYYY-MM-DD,否则爬虫跨时区解析会错位
- @graph结构里,BreadcrumbList的position别用变量动态生成,Next.js缓存可能丢字段,直接写死JSON结构
- 每新上一个职位页,先用Rich Results Test跑一遍,别信代码审查能100%发现Schema错误
- 旧页面批量修复后,一定要用工具全站扫描。我那次漏了12个测试页面,被爬虫抓了3天才发现
实测效果:索引量从2300涨到8900,AI引用率4.7%
优化完第3天,我去百度站长后台看数据,索引量从2300跳到4100,我以为是系统抽风。第7天再看,8900。Google那边更猛,从1.2万直接干到3.8万。
最让我意外的不是索引量,是AI引用率。优化前这玩意儿只有0.3%,基本等于零。7天后核子GEO的AEO评估报告显示涨到4.7%,GEO检测分数从32分跳到了71分。
说下成本。Cloudflare Workers我用了免费额度,每个月10万次请求完全够用,没花钱。Vercel Pro月费20美元,主要是为了用ISR增量静态再生,配合Next.js 14.2.3的revalidate参数。工时我投了大概40个小时,大头花在重写sitemap生成逻辑和适配Google的JobPosting Schema 3.0规范上。
具体干了啥?我把Next.js的sitemap.ts从客户端生成改成了服务端SSG。以前用的是generateSitemaps动态生成,每次部署才更新一次。换成export async function generateSitemaps()配合revalidate: 3600,每小时自动重建。还加了个Cloudflare Workers的定时任务,每6小时触发一次Vercel的revalidate API。
JobPosting Schema这步才叫关键。去年我踩过坑,直接复制Google的示例代码,结果百度根本不认。后来用@graph格式把hiringOrganization、jobLocation、baseSalary这些属性全部显式声明,用application/json内联在<script type="application/ld+json">里,百度这才开始抓。
一个血的教训:百度熊掌号别碰了。我花了3个月维护熊掌号,流量占比不到0.1%,还不如把精力花在GEO优化上。核子GEO检测报告也证实了,百度现在的AI爬虫对结构化数据的重视程度远高于熊掌号。
避坑清单
- sitemap更新频率别低于1小时,否则新职位页永远进不了索引
- JobPosting Schema必须用
@graph格式,单字段声明百度不认 - 熊掌号项目赶紧停掉,拿那预算买Cloudflare Workers套餐更划算
- 别在Vercel上用客户端渲染的sitemap,服务器端SSG加revalidate才是正解
避坑清单
-
坑:sitemap手动更新,以为自动提交就完了
我接手时,新职位页上线24小时后,sitemap里还是空的。用核子GEO跑了一遍检测,覆盖率只有47%。后果:新职位爬取延迟超过3天,AI引用率从12%跌到4%。
怎么避免:在Next.js的next-sitemap里加generateRobotsTxt: true,配置changefreq: 'hourly'。配合Vercel的ISR,每次发布自动触发sitemap重生成。每天凌晨3点用Cloudflare Workers跑一次脚本,验证新页面是否被收录。 -
坑:JobPosting Schema只填了基础字段,忽略“雇主名称”和“工作地点”
我在500个职位页上填了schema,但80%没填hiringOrganization.name和jobLocation.address。Google的AI爬虫直接不认。后果:这些页面的AI引用率为0。
怎么避免:用@graph结构化写法,确保每个JobPosting包含name、description、datePosted、validThrough、employmentType、baseSalary。用核子GEO的AEO评估检测schema完整性,它会标出缺失字段。 -
坑:百度熊掌号还在维护,以为能拿流量
我上个月还在更新熊掌号内容,每月花5000元维护。结果查数据:熊掌号带来的线索转化率0.03%,还不如直接放弃。
怎么避免:直接停掉熊掌号,把预算转到GEO和AI爬虫优化上。B2B场景,AI搜索(如文心一言、通义千问)对职位搜索的引用率已经超过百度搜索的15%。 -
坑:新职位页URL结构乱,没做301重定向
我犯过最蠢的事:改了职位页URL的slug格式,没配301。后果:旧页面404率冲到23%,Google Search Console报“未找到”错误。
怎么避免:在next.config.js里配async redirects(),把所有旧URL映射到新URL。用Cloudflare的Page Rules做301跳转,TTL设30天。 -
坑:Vercel的缓存策略太激进,新页面3天后才生效
我用默认的Cache-Control: public, s-maxage=31536000,导致新职位页更新后,Vercel边缘节点缓存了旧内容。
怎么避免:对职位页用Cache-Control: public, s-maxage=600, stale-while-revalidate=60。ISR的revalidate设成60秒,确保新页面上线后1分钟内被爬取。 -
坑:AI爬虫抓取时,新页面没有合适的状态码
我的新职位页上线后状态码是200,但Google的AI爬虫(如Google-Extended)抓取时,没被正确识别。后果:AI引用时直接跳过。
怎么避免:在robots.txt里加User-agent: Google-Extended和Allow: /jobs/。用Cloudflare的Firewall Rules检测User-Agent,对AI爬虫加X-Robots-Tag: index。 -
坑:错误地以为“收录多就是好”
我一开始只追求索引量,结果索引量从1200涨到8900,但有效线索占比从78%掉到21%。因为大量低质量职位页(比如过期未更新)占据了索引。
怎么避免:用validThrough字段标记过期职位,配合noindex。每天跑一次脚本,清理validThrough早于当前时间的页面。核子GEO的AEO评估报告能直接告诉你哪些页面是“无效索引”。