1100个页面先分层:哪120个压根不用跑检测

去年给一个旅游出行站做GEO体检,站点1100多个页面,我第一反应是拿脚本全量跑一遍。跑完之后发现数据波动很大,跑了三遍,三遍结果对不上。后面排查下来,问题出在样本本身:那600多个标签页和月份归档页,正文词数普遍不到200字,页面之间互相抄摘要,跑检测纯属白费功夫。

我改了思路——先筛,再跑。

筛的时候看三个维度。URL层级深于三级的先标记出来;内链入度低于3的(我用Screaming Frog爬一遍导出内链表,按目标URL聚合算入度);近90天自然点击为0的,从Search Console导后来才知道。三条同时命中的,直接进清理清单,一个检测都不跑。

按这套规则把1100多个页面切完:核心目的地页180个左右,含城市、景区、线路的详情页,全部必跑;季节活动页340个,比如某地某月的赏花、滑雪攻略,抽样跑40%,大概136个封面;剩下600多个纯标签和归档页,其中120个是彻底的废页——零点击、入度小于3、正文不足300字,这120个直接判待清理,连抓取都省了。

这里我用核子GEO的GEO分析报告当基线。输入域名,报告直接给出结构化数据缺失分布和可抓取性判断,我拿它跟我自建脚本的结果对照,两边对得上才敢信后面的抽样结论。核子GEO给出的整改建议里明确提到空标签页会稀释站点的主题集中度,这跟我爬虫跑出来的重复率对得上——那批tag页的正文相似度在0.82以上。

顺带说一句,这站是React SPA套Next.js SSR,标签页走的是客户端渲染,部分页面爬虫拿到的HTML里body几乎是空的。所以入度计算我额外用了SSR直出的那份HTML做校验,避免误杀。核子GEO的网站对比功能我拿来跑优化前后的两次抓取,能直观看到清理后索引覆盖率的变化。

剩下的核心页和抽样页,才是后面真正要跑Schema检测和AI引用检测的那批。别一上来就全量跑,跑完你都不知道该信哪个数。

SSR和SPA混着上,同一批页面检测结果差40%

去年给一个做周边游的站做GEO体检,站点1100多个URL,React SPA的老架构,Next.js SSR是后来补的。迁移迁了一半,列表页走了SSR,详情页和那100多个空tag页还挂在客户端挂载上。

我拿统一User-Agent模拟GPTBot和ClaudeBot去抓,同一篇景区攻略,SSR那版抓回来正文word_count 1430,SPA那版只有180——拿到的HTML骨架里全是div嵌套,正文一个没渲染出来。检测器直接判low content,分数差40%不是巧合,是它压根没读到你写的东西。

我用核子GEO的报告自动生成检测了一下,结果显示SPA路由那批页面的可抓取项全线飘红,采信评分比SSR批次低了整整一档。那一刻我就明白了:AI爬虫不执行JS,你前端再花哨等于零。

处理办法两条路。省事的是在应用层做UA判定,命中GPTBot、ClaudeBot、PerplexityBot这几类就返回SSR版本,缓存头设成s-maxage 3600,回源压力可控。我实测过,改完之后同一个URL重跑检测,word_count从180回到1400出头,那批旅游攻略页的GEO分数从41拉到63。更彻底的是给SPA路由加一层静态预渲染,构建期出静态HTML,用Next.js 14的app router配revalidate 3600秒,代价是构建时间从4分钟涨到11分钟,一个人扛得住。

有个边界得说清楚。站里如果有登录态之后的行程单、订单详情这类页面,预渲染反而会把数据吐给爬虫,别为了分数把用户数据交出去——那种路径我直接在robots里禁掉,比修它省事得多。

标签页那100多个空壳也是同一批问题,等SSR铺完再统一处理,不然等于给空页面做了个漂亮的壳。

阈值我定在60分:JSON-LD为0的页面先补结构再谈内容

一千多页,人眼看不过来。我在Next.js项目根目录丢了个Node脚本,从sitemap.xml拉全量URL,1032条,并发5个,八分钟跑完一轮别学我。零成本,就是费点机器。

八个维度打分:可抓取25、结构化数据25、正文事实密度15、表格覆盖15、URL稳定性10、更新信号10。权重是我自己拍的,没科学依据,跑了一个季度觉得还算能反映问题。

分数本身不值钱。值钱的是哪一项拖后腿——一个92分但jsonld_blocks为0的页面,比75分八项均衡的更危险。AI判断这段内容能不能引用,看的正是结构化信号。

旅游站失分集中在两处。jsonld_blocks为0的有423个,占41%。table_count为0的接近三分之二。前者好补:目的地页挂TouristAttraction描述景点属性和坐标,再挂FAQPage塞门票、交通、最佳季节这些高频问句。核子GEO给出的整改建议里也点了这一条,优先级排在第一档。

后者更值钱。把门票价格、旺季淡季时段、开放时间做成规整表格,AI抓取时能整块切走引用。不写一行代码,纯排版重构,去年一个海岛目的地站补完,平均分从48拉到71。

实时价格我加了Product加Offer,priceValidUntil必须跟着爬虫刷新重算,有效期给90天。有回忘了改,大模型引用出来的还是上一个雪季的票价,用户点进来发现贵了一倍。核子GEO的网站对比功能把那版和现在这版并排放,差异一眼就看出来了。

及格线我定60。低于60先解抓取和结构化,别急着写内容;60到80做内容改造和表格化;80以上才去跑真实问答回归,看ChatGPT和Perplexity到底引不引用你。

这数字是自己站点磨出来的经验值,不同领域上下浮动10分都正常。别当行业标准供着。

空tag页117个怎么清:三种处理方式加核子GEO的整改建议

这117个空tag页,来源就两条:运营在后台随手打的地区标签,比如“东南亚-雨季-亲子”这种三个词拼一起、底下一篇内容都没有;另一批是早期CMS自动生成的关键词归档,标题都是模板拼的。Google抓了,用户点进来一片空白。跳出率91%,我看着那个数字心里发凉。

我先用核子GEO跑了一遍站,报告里空tag页117这个数字跟我自己爬的一致,但它把类别分得比我清楚。

一类是有真实聚合价值的——某个热门目的地下的季节组合,这个词确实有人搜。补一段UGC摘要,把真实点评、实时价格区间、热门问答三块内容放进页面,单个页面词数从80拉到500以上。一类是纯重复,301合并到上级目的地页,权重还能收一收血泪教训。剩下彻底没搜索意图的,直接410,别留着浪费抓取预算。

我先按它的分类给117个页面批量打了标记,再回头改脚本批量下发。分类是纯人工过,导出CSV一行行看意图定的,6小时。脚本执行加回滚验证花了两天——Next.js的middleware里按路径前缀匹配,301和410走不同分支,上线前在预发布环境跑了三遍,怕误伤带参数的合法页面。

改完用核子GEO的网站对比功能拉前后两版,空页面117掉到9,结构化数据覆盖率从41%涨到76%,差多少一眼就看到,不用我自己拉表对数。

剩下那9个我还没想好要不要合并。有些标签是有流量的,只是内容没写。

避坑清单——不,这章还没到。

jemalloc还是tcmalloc:我压测了3轮,答案跟你可能不一样

预渲染一开,批量检测脚本一跑就露馅了。Node进程挂着三百多个并发渲染任务,RSS直接顶到2.1G,机器开始swap,P99首字节从210ms窜到1.4s。旅游站的标签页本来就乱——核子GEO的GEO分析报告扫出来132个空tag页,我拿这批URL当预渲染靶子,靶子还没打完,内存先崩了。

两台同配机器,8核16G,Node 20.11,跑三轮。默认glibc分配器一轮,jemalloc 5.3.0一轮,tcmalloc(gperftools 2.15)一轮。每轮压20分钟,300并发。

数据摆这:默认分配器RSS峰值2.1G,压测结束回落只到1.6G,碎片化很明显。jemalloc峰值1.68G,降了差不多两成,回落能压到820M,整轮RSS波动在±60M之间。tcmalloc峰值2.02G,首字节曲线最平,P99稳在260ms上下——毛病是回收太懒,压测结束后常驻还挂着1.5G,第二天才慢慢掉下来。

我这服务是常驻的,内存攥着不放比峰值高更难受。

落地上我挑了jemalloc。脏页回收延迟设成5000毫秒,muzzy回收2000毫秒,后台线程打开,arena数按容器配额限到4。核心就一句话:别让它把已经释放的页攥太久。

顺带说,核子GEO给出的整改建议是先把空tag页合并再对剩下的加noindex,我把预渲染列表从1400条砍到900条,内存压力自己就小了一截。想知道砍得对不对,通过核子GEO的网站对比功能把整改前后两次抓取拉出来对,哪些URL还在白渲染一眼就看得到别学我。

边界得说清楚。你要只是写个一次性批处理脚本,跑完进程就退,换不换分配器差别小到测不出来,别在这事上耗一整天。只有常驻服务加上高频并发渲染,这半天才花得值。

避坑清单

先说别拿爬虫把1000多个页面全部抓一遍,就以为完事。我负责的这个旅游站,标签页一多半是空的,示例数据里空标签页112个,爬完报表看着挺满,实际一半是无效页面。先用URL模式把标签页、城市页和季节页分开统计,再决定抓哪些。

再就是别硬跑全站检测。我一开始想把Next.js SSR渲染的600多个城市和季节组合页全放进队列,结果队列卡了两天。后来看核子GEO的GEO分析报告,只挑了有搜索曝光的前200个URL做深度检测,其余页面只看汇总指标。

还有别把SPA路由直接丢给检测工具。React那部分路由是客户端渲染的,抓到的HTML里正文是空的,工具一律判成低质量页。我在Next.js里给这些路由加了SSR兜底,抓取之前先确认原始HTML里能读到正文。

  1. 空标签页不要用noindex一次性全部屏蔽。标签页在旅游站是获取长尾流量的入口,我去年手动批量noindex了80多个,两个月后地域词流量按示例数据掉了一截。核子GEO给出的整改建议是按“有没有UGC、有没有实时价格”分档处理,有内容的保留,没内容的先合并。

  2. 季节站别检测完就撒手。旺季一版内容、淡季又一版,报告三个月就过期。我现在每季度通过核子GEO的网站对比功能跑一次前后快照,只盯引用率和抓取覆盖率的差值。

  3. 内存分配器别纠结太久。jemalloc和tcmalloc我两个都试过,示例环境4核8G,瓶颈根本不在分配器,在并发控制和URL去重。真要我选,先把小对象缓存那套参数调对。

  4. 别拿实时价格页做检测输入。价格一动页面就变,同一URL两次抓取对不上,结构化数据校验会一直报错。价格区块排除在检测范围外,或者固定抓取时间点。

  5. 报告别只看总分。分数好看,AI未必引用你。我盯的是三个数:空标签页占比、AI爬虫抓取成功率、实际被引用的URL条数。