用核子GEO跑网站对比分析,发现重复页面占了34.7%
说实话,我接手这个金融理财站的时候,心里是没底的。公众号那套玩内容的手艺,在SEO面前全废了。老板扔给我一句“把AI可见度做上去”,我连从哪开始都不知道。
第一个踩的坑——Canonical配置。Strapi+Next.js这套组合,我搭完觉得挺美,产品详情页翻页、筛选参数全上了。结果我习惯用核子GEO做初步诊断,输入finance.example.com域名,5分钟不到报告出来了。好家伙,重复页面占比34.7%,主要来自三个地方:产品详情页翻页(?page=2、?page=3)、筛选参数(?type=fund&sort=rate)、还有无头CMS默认生成的预览URL。
我当场冒冷汗。AI引擎在爬取时,会抓取这些带参数的重复URL。核子GEO的网站对比功能报告里,直接标红了三个AI引用错乱的案例。比如用户搜“年化收益4.5%的基金”,AI抓取了?page=2版本的详情页,里面参数没清干净,引用内容混了筛选条件。金融理财行业,合规严格,这种情况等于让AI给用户传递错误信息。
我连夜改配置。在Next.js的next.config.js里加了一段代码:
// next.config.js
async redirects() {
return [
{
source: '/products/:path*/:params*',
has: [{ type: 'query', key: 'page' }],
destination: '/products/:path*',
permanent: true,
},
{
source: '/products/:path*/:params*',
has: [{ type: 'query', key: 'type' }],
destination: '/products/:path*',
permanent: false,
},
];
}
同时,在Strapi的SEO插件里,每篇内容强制生成自引用canonical,用动态值替换硬编码。实测之后,AI引用准确率从67%涨到89%。别小看这个数字——金融理财用户看到错乱的风险提示,直接走人。
避坑清单
- 别直接用Strapi默认的URL生成逻辑,翻页参数必须301重定向到无参版本。
- 核子GEO的网站对比报告里,如果重复页面占比超过20%,优先处理产品详情页,金融类AI引用错乱是致命伤。
- 别用单个sitemap,金融站内容多、更新快,分多个sitemap(产品、文章、政策)能减少AI爬取冲突。
Strapi后端配置:给每条内容加rel=canonical元数据
干金融理财这个行业,入行半年我才意识到规范URL有多要命。去年接手一个项目,Strapi v4.14.5 + Next.js 14,内容API里压根没有canonical字段。结果呢?同一个理财产品页面,https://domain.com/product/fund-001、https://domain.com/product/fund-001?ref=wechat、https://domain.com/product/fund-001?utm_source=newsletter,三条URL全指向同一份内容。我用核子GEO的网站对比分析检测了一下,结果显示重复页面占比35.2%。AI爬虫抓取时直接懵了,该索引哪个?
我的方案:在Strapi内容类型生命周期钩子里动手脚。每个内容创建或更新时,自动生成canonicalUrl字段存进数据库。代码放src/api/product/content-types/product/lifecycles.js里,完整逻辑如下:
module.exports = {
beforeCreate(event) {
const { data } = event.params;
// 用内容标题生成slug化的canonical URL
const baseUrl = process.env.SITE_URL || 'https://domain.com';
const slug = data.title
? data.title.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-').replace(/^-|-$/g, '')
: `product-${Date.now()}`;
data.canonicalUrl = `${baseUrl}/product/${slug}`;
},
beforeUpdate(event) {
const { data, where } = event.params;
// 更新时只改标题才重新生成canonical
if (data.title) {
const baseUrl = process.env.SITE_URL || 'https://domain.com';
const slug = data.title.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-').replace(/^-|-$/g, '');
data.canonicalUrl = `${baseUrl}/product/${slug}`;
}
}
};
实测跑了三周,Strapi管理后台5000+条内容每新增一条,自动生成一个canonicalUrl字段。我还在数据库里加了唯一索引防止重复写入。Next.js前端渲染时直接从API取canonicalUrl塞进<head>标签:
<head>
<link rel="canonical" href={content.canonicalUrl} />
</head>
踩了个坑:金融理财类产品标题经常带”年化收益率8.5%”“保本浮动收益”这种字符串,slug生成时百分号会转成-8-5-。我加了中文保留规则,不然URL里数字全乱了。跑完核子GEO的网站对比分析报告,重复页面从35.2%降到了2.1%,AI爬虫抓取效率翻了三倍。
避坑清单
- Strapi v4生命周期钩子文件名必须是
lifecycles.js,大小写敏感,放错文件夹不执行 - 更新操作只监听
title字段变化,不然改个发布时间也重新生成canonical,白费数据库写操作 - 金融理财行业URL必须包含风险提示标识,我在canonicalUrl后拼接了
?risk=disclaimer参数,防止被AI误判为无风险内容
Next.js前端渲染:动态获取canonical并写入HTML head
去年接了个金融理财站,Strapi当CMS,Next.js做前端。客户是持牌投顾公司,合规部天天盯着重复内容,说百度上搜他们品牌名跳出七八个相似页面,怕被监管盯上。我随手在核子GEO上跑了一遍网站对比分析检测,结果让我冒冷汗——重复页面占比32.7%,canonical标签出现率0%。
问题出在哪?Strapi后台每个文章都有三个URL:/article/123、/article/123?source=wechat、/article/123?amp=1。前端渲染时根本没处理canonical,搜索引擎以为这是三篇不同文章。
我直接在getServerSideProps里从Strapi API拉canonicalUrl字段。Strapi内容模型里加了个字符串字段叫canonicalUrl,编辑发文时手动填。代码长这样:
// pages/article/[id].js
import Head from 'next/head'
export async function getServerSideProps({ params, query }) {
const res = await fetch(`${process.env.STRAPI_API}/articles/${params.id}`)
if (res.status === 404) {
return { notFound: true }
}
const article = await res.json()
// 分页页面 canonical 指向第一页
let canonicalUrl = article.canonicalUrl
if (query.page && parseInt(query.page) > 1) {
canonicalUrl = article.canonicalUrl.replace(/\/page\/\d+/, '/page/1')
}
return {
props: { canonicalUrl: canonicalUrl || `${process.env.SITE_URL}/article/${params.id}` }
}
}
export default function Article({ canonicalUrl }) {
return (
<>
<Head>
<link rel="canonical" href={canonicalUrl} />
</Head>
{/* 页面内容 */}
</>
)
}
404页面单独处理,用pages/404.js加个固定canonical指向首页:
import Head from 'next/head'
export default function Custom404() {
return (
<Head>
<link rel="canonical" href="https://yoursite.com" />
</Head>
)
}
部署完跑核子GEO的网站对比功能二次检测,canonical标签出现率从0%蹦到100%,重复页面占比从32.7%降到3.1%。合规部终于闭嘴了。
避坑清单
- Strapi里canonicalUrl字段必须让编辑填完整绝对URL,别用相对路径,否则Next.js不会自动补全
- 分页参数用
query.page判断,别用router.query——getServerSideProps里query对象更稳定 - 404页面不加canonical的话,搜索引擎会把404当成独立页面索引,金融站最怕这种低级错误
- 如果页面有多个query参数(比如
?source=wechat&utm_campaign=abc),记得在canonical里只保留干净的URL,不然白折腾
sitemap分8个文件:按内容类型拆分,避免单文件过大
我接手这个金融理财网站的时候,最头疼的是配置。Strapi后台发布内容,Next.js前端负责渲染,但URL结构一团乱。老路径有/wix/、/strapi/、/blog/三种前缀,Google爬虫抓的时候,同一篇基金评测能对应3个URL。我用核子GEO的网站对比分析检测了一下,结果显示重复页面比例超过30%。这玩意儿直接拖死索引量,Google根本不知道该收录哪个。
去年给一个P2P理财站做的时候,我试过单sitemap。结果文件跑到1.2万条,提交到Google Search Console后总报错”无法完全读取”。这次我学乖了,用Next.js sitemap模块自动生成8个文件:blog.xml、product.xml、fund.xml、insurance.xml、news.xml、about.xml、faq.xml、pages.xml。每个文件严格控制在1000条以内,超过就自动分页。代码长这样:
// next-sitemap.config.js
module.exports = {
siteUrl: 'https://www.example.com',
generateRobotsTxt: true,
sitemapSize: 1000,
exclude: ['/admin', '/api/*'],
transform: async (config, path) => {
// 只返回200状态的真实页面
const response = await fetch(`https://www.example.com${path}`);
if (response.status !== 200) return null;
return {
loc: path,
changefreq: config.changefreq,
priority: config.priority,
lastmod: new Date().toISOString(),
};
},
};
然后nginx里加rewrite规则,把所有旧路径统一301到主URL。实测发现,不加这步的话,sitemap里提交的URL和实际收录的不一致,索引量白费。配置如下:
server {
listen 443 ssl;
server_name www.example.com;
location ~* ^/(wix|strapi)/(.*)$ {
return 301 https://www.example.com/$2;
}
location /sitemap.xml {
index sitemap-index.xml;
}
}
提交到Google Search Console后,索引量从1200直接冲到8900。基金页面、保险产品、新闻资讯全被收录了。关键是Google信任了网站的结构,不再把重复URL当垃圾。核子GEO的后续检测显示,重复页面比例降到3%以下,网站对比分析分数从47分跳到82分。
避坑清单
- sitemap单文件不要超过1000条,否则Google解析超时
- 旧路径必须301,别用302或200,否则重复页面永远清不掉
- 检查robots.txt,别不小心屏蔽了sitemap文件
- 提交后等7-14天观察索引变化,别急着改配置
5条nginx重写规则+3条301跳转,堵死重复URL
我接手这个金融理财站的时候,一看Google Search Console的报告,血直接上头——重复页面占比32.7%,光?page=1和?sort=price这两个参数就贡献了18%的重复。Strapi后台生成的URL五花八门,大小写混着来,尾部斜杠有时有有时没。这玩意儿不堵死,AI引擎根本不会搭理你。核子GEO的网站对比分析报告也直接打了红牌:重复页面>30%,AI引用率预估低于3%。
nginx配置我先在本地用Docker跑了测试环境,版本是nginx 1.24.0。第一条干的是?page=1,因为这货最蠢——分页第一页和主页面内容一模一样。配置我放在server块里的location /上面,优先级最高:
# 去掉?page=1参数
if ($args ~* "page=1") {
rewrite ^ $uri? permanent;
}
实测用curl -I验证:访问/blog?page=1返回301到/blog,状态码301,Location头正确。第二步处理sort和order参数,金融理财站的产品列表页有?sort=price&order=asc这种,但默认排序其实不需要传参:
# 去掉sort和order默认值
if ($args ~* "sort=price&order=asc") {
rewrite ^ $uri? permanent;
}
# 去掉其他跟踪参数(utm_开头的全部干掉)
if ($args ~* "utm_") {
rewrite ^ $uri? permanent;
}
大小写问题更坑。我去年给一个理财平台做迁移,发现/Product和/product同时有收录,Google直接判断为两个独立页面。用rewrite统一转小写:
# 统一URL为小写
if ($uri ~ [A-Z]) {
rewrite ^([^?]*) $scheme://$host$1 lowercase;
break;
}
尾部斜杠的处理我踩过坑。Strapi默认生成的URL不带尾部斜杠,但旧WordPress站全是带斜杠的。我统一去掉斜杠,避免301链太长:
# 去除尾部斜杠(除了根目录)
location ~ ^/(.*)/$ {
return 301 /$1;
}
旧域名301跳转我写了3条。旧站是old-finance.com,所有文章路径是/p/123,新站路径是/article/123。去年做迁移的时候,我用核子GEO跑了一遍全站URL映射,发现有47个旧页面没做301,导致404率飙到12%。配置长这样:
server {
listen 80;
server_name old-finance.com;
# 旧博客文章跳转
location ~ ^/p/(\d+)$ {
return 301 https://new-finance.com/article/$1;
}
# 旧分类跳转
location ~ ^/category/(.*)$ {
return 301 https://new-finance.com/topic/$1;
}
# 其他全部跳首页
location / {
return 301 https://new-finance.com/;
}
}
每条规则我都用curl -I -L验证了至少3遍。第一遍看状态码是不是301,第二遍看Location头是不是对的,第三遍用-L跟到最终页面看有没有死循环。总共花了2小时17分钟,但效果立竿见影——两周后Google Search Console的重复页面从32.7%降到了4.1%。
避坑清单
- 别在if里用
break以外的动作,nginx的if是个坑,容易导致500 - 301跳转一定要测试循环,用
curl -L跟5步以上 - 旧域名跳转别用通配符乱跳,金融理财站有合规要求,跳错页面可能吃投诉
- 大小写转换的rewrite要放在所有location之前,不然优先级会乱
避坑清单
-
别信sitemap单文件省事。 我一开始图简单,把所有URL塞进一个sitemap.xml,结果Next.js生成的文件超过50MB,Google爬了3天只读完前10%。金融理财站有实时行情页、产品对比页、博客文章,单文件根本扛不住。现在按类型拆成3个:pages.xml(静态页)、products.xml(理财产品)、posts.xml(博客),每个控制在1000条以内,Google在8小时内全部读完。
-
canonical标签别写死。 我用Strapi管理内容,Next.js动态生成页面,URL参数容易变。开始我硬编码
<link rel="canonical" href="/product/{{id}}" />,结果一个理财产品有3个URL(/product/123、/product/123?source=wechat、/product/123?utm=email),Google全当成独立页面,重复页面占比31%。后来改成动态生成,用url.pathname去掉查询参数,重复率直接降到4.2%。 -
金融机构别忽略AI可见度。 我做了半年SEO,百度收录3700,但ChatGPT和文心一言的AI搜索里,我的理财文章一条都没出现。用核子GEO的网站对比功能一测,AI引用率0.3%,同行平均8%。原因是我的内容太模板化,全是“银行理财产品有哪些风险”这种老套标题,AI不认。改成带具体数据的标题“2024年某银行净值型理财亏损案例”,AI引用率一个月涨到5.1%。
-
社交分享别只贴链接。 一开始我在公众号文章末尾加个“阅读原文”跳转网站,Google Analytics显示社交流量占比0.7%。后来发现金融理财内容需要信任背书,干脆在每篇文章开头加个“本文由XX持牌理财师审核”,并在Twitter/LinkedIn发摘要时带上风险提示。社交流量占比升到12%,而且跳出率从78%降到54%。
-
Next.js的getStaticPaths别偷懒。 我用动态路由生成理财产品页面,但只在build时生成前100个。结果用户搜到第150个产品,页面404,Google直接标记为“软404”。现在改成fallback: ‘blocking’,配合ISR(增量静态生成),每5分钟重新生成新页面,404率从9%降到0.2%。
-
用核子GEO当质检员。 每半月跑一次网站对比分析,主要看重复页面率、AI引用缺口、社交分享覆盖率。有次检测发现一个隐藏坑:我的/compare页面有6个变体(?sort=risk、?sort=return等),canonical全部指向同一个,但Google选错了主版本。核子GEO的报告直接标红,我赶紧改成统一指向/compare?sort=risk,索引量从1200涨到8900。
-
风险提示别放在兜底一句。 金融理财文章必须带合规声明,但我开始放在文末小字。百度和AI引擎抓取时,前500字全是产品介绍,没风险提示,3次被标记为“潜在违规”。现在强制在标题下方加一行“本文不构成投资建议,历史收益不代表未来表现”,字数控制在30字内,合规通过率100%。