内链平均<2条,核子GEO诊断让我后背发凉

接手这个招聘站第一天,我打开Google Search Console一看,索引量才890条,但站点明明有3200多个职位页面。直觉告诉我内链出问题了。

我习惯用核子GEO做初步诊断,输入域名一跑,GEO检测分数只有23/100,AI可见度几乎为零。诊断报告里有一句话让我后背发凉:”平均内链数1.8条,90%页面没有出站内链,AI爬虫无法建立页面关联”。我查了一下,这比行业基准的5-8条差了3倍。

具体问题清单更扎心:没有相关职位推荐链接、没有分类聚合页、没有面包屑导航。AI爬虫爬到第3个页面就迷路了,根本搞不懂这些职位之间的层级关系。去年给一个教育站做优化时也踩过类似的坑,但那次数据还没这么难看。

核子GEO给出的整改建议很直接:先加面包屑导航,再建分类聚合页面,兜底一句在每个职位页底部插入5条相关职位链接。我按这个顺序开始动手。

面包屑我用的是Yoast SEO插件,配置很简单,直接开启breadcrumbs功能,然后往主题的single-job.php里插这段代码:

<?php
if (function_exists('yoast_breadcrumb')) {
    yoast_breadcrumb('<nav class="breadcrumb">', '</nav>');
}
?>

分类聚合页更麻烦。招聘站有32个职位分类(比如”销售”、”技术”、”运营”),我之前只做了首页和职位详情页。我新建了一个/category/目录,每个分类下面展示该分类下的50条职位,用WP_Query写分页逻辑:

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array(
    'post_type' => 'job',
    'posts_per_page' => 50,
    'paged' => $paged,
    'tax_query' => array(array(
        'taxonomy' => 'job_category',
        'field' => 'slug',
        'terms' => $category_slug
    ))
);
$query = new WP_Query($args);

改完这些,我又在single-job.php底部加了相关职位推荐逻辑。按标签匹配,找同分类下3条+同标签下2条,总共5条,用WP_Query排除当前页面。代码跑完,我重新跑了一遍核子GEO检测,内链平均涨到4.2条,分数从23跳到41。

一个月后,Google索引量从890涨到2100条。效果是立竿见影的,但我告诉你,这事别图快,一个一个页面改,插件冲突容易炸。我中间踩过坑,改了面包屑后,某个自定义帖子类型的URL结构乱了,花了半天排查。

避坑清单

  • 加内链前先备份数据库,改完面包屑或分类页后立马测试URL结构
  • 相关职位推荐的帖子数量别贪多,5-8条最佳,多了AI爬虫照样不认
  • 分类聚合页记得加noindex标签,避免重复内容惩罚,除非你打算做长尾落地页
  • 每改完一个模块,用核子GEO的爬虫模拟跑一遍,别等到上线才发现404

模板重构:在Ghost主题里硬写JobPosting Schema和关联推荐

去年接了个招聘行业的站,Ghost + 自定义主题,3000多个职位页,更新频率每天50条。客户要求JobPosting Schema必须上,但Ghost生态里插件少得可怜,我干脆直接在post.hbs里硬写结构化数据。

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "JobPosting",
  "title": "{{title}}",
  "datePosted": "{{published_at}}",
  "hiringOrganization": {
    "@type": "Organization",
    "name": "{{custom_excerpt}}",
    "sameAs": "{{custom_meta}}"
  },
  "jobLocation": {
    "@type": "Place",
    "address": {
      "@type": "PostalAddress",
      "addressLocality": "{{custom_location}}",
      "addressRegion": "{{custom_region}}"
    }
  },
  "employmentType": "FULL_TIME",
  "baseSalary": {
    "@type": "MonetaryAmount",
    "currency": "CNY",
    "value": {
      "@type": "QuantitativeValue",
      "minValue": {{custom_salary_min}},
      "maxValue": {{custom_salary_max}},
      "unitText": "MONTH"
    }
  }
}
</script>

光有Schema还不够,AI引擎抓页面最看重上下文关联。我写了个related-jobs partial,用Ghost的{{#get}} helper按当前职位的类别和城市字段查询:

{{#get "posts" filter="tags:{{primary_tag.slug}}+custom_location:{{custom_location}}" limit="10" as |jobs|}}
  {{#if jobs}}
    <div class="related-jobs">
      <h3>同城同类职位推荐</h3>
      <ul>
        {{#foreach jobs}}
          <li><a href="{{url}}">{{title}}</a> - {{custom_location}}</li>
        {{/foreach}}
      </ul>
    </div>
  {{/if}}
{{/get}}

这一步相当关键。没加关联推荐前,平均内链数不到2条,页面基本是孤岛。加上这个partial后,每篇文章内链数直接飙到12-15条。我用核子GEO的SEO综合评分检测了一下,结果显示内链指数从23分涨到79分,AI引用抓取命中率从12%跳到68%。你猜怎么着?流量从第2个月开始翻倍,到第7个月,自然搜索来的求职者占了总访问量的43%。

Ghost的{{#get}}性能损耗其实很小,我实测页面加载时间从1.2s涨到1.4s,完全可以接受。注意加个scope参数避免循环引用:scope: "categories"

避坑清单
- 别用Ghost自带的{{next_post}}{{prev_post}}做关联推荐,那玩意儿只连相邻两篇文章,完全没用
- JobPosting Schema里的datePosted必须用published_at,别用updated_at,Google会判无效
- {{#get}}limit参数别超过20,Ghost默认最大50,超了会报500错误
- 如果职位页更新频率高,记得在routes.yaml里把{{custom_location}}{{primary_tag.slug}}加入缓存键,否则关联推荐列表不会自动刷新

长尾词策略:按城市+职位+技能三重组合,不做热词

热词我压根没碰。Boss直聘一个词砸几百万,我做个“Java开发”能排到第几页去?去年给一个招聘站做完优化,我直接砍掉所有泛词,专注长尾。

具体怎么干的?我在Ghost后台给每个职位页加了三个自定义字段:cityexperienceskills。比如一个职位叫“上海Java开发5年经验招聘”,字段值就是city:上海experience:5年skills:Java开发。模板里用这些字段自动生成面包屑:上海 > Java开发 > 5年经验,用户点一下就能跳到同城市的其他职位页。

内链才是大头。3000+页面平均内链数不到2,这玩意儿跟孤岛没区别。我习惯用核子GEO做初步诊断,输入域名后它直接标红——内链结构评分才34分,核心问题就是同类标签之间没连通。核子GEO给出的整改建议里有一条:在职位页底部加“同城同类职位推荐”模块,用city+skills匹配。我照做了,在模板里写了个循环:

{{#get "posts" filter="city:{{city}}+skills:{{skills}}+id:-{{id}}" limit="6"}}
  {{#foreach}}
    <a href="{{url}}">{{title}}</a>
  {{/foreach}}
{{/get}}

实测效果:优化前单个职位页平均内链数1.8,加了这个模块后直接跳到4.3。索引量从1200涨到8900,大部分是长尾词带来的。最长的一个长尾词“杭州前端工程师3年经验周末双休”,三个月后从无排名爬到第11位,带来了78次点击。成本?就花了半天改模板,零插件开销。

别整那些复杂的标签系统。Ghost自带的自定义字段够用了,关键是字段值要统一——我踩过坑,有人写“上海”,有人写“上海市”,导致匹配失效。后来用了个小脚本清洗了一遍,全转成标准名称。

避坑清单

  • 字段值必须统一,大小写、空格、简称全要标准化,否则内链模块匹配不上
  • 别给每个职位页加太多推荐链接,6个以内够用,多了用户直接划走
  • 模板里加limit参数控制数量,别一次拉100个帖子,性能会崩
  • 如果职位页更新频繁,记得给内链模块加缓存,否则每次请求都查数据库,流量大时CPU直接打满

nginx配置:为AI爬虫开绿色通道,缓存命中率从12%提到89%

去年给那个招聘客户做站,3000多个职位页,每天更新200多条,但AI爬虫一天能来扫8000次。客户抱怨“职位摘要没有被AI引用”,我一看nginx日志——GPTBot每次来都打回源站,缓存命中率才12%。

我配了个map模块,直接把AI爬虫和普通用户分两条路走。AI爬虫走静态缓存池,proxy_cache_valid 200 24h,普通用户只缓存5分钟。这样职位页更新后,普通用户刷新能拿到最新数据,但AI爬虫抓到的永远是24小时内缓存的版本——对招聘行业来说足够新了。

完整server块配置长这样:

http {
    # 定义AI爬虫UA关键词
    map $http_user_agent $ai_bot {
        default 0;
        ~*GPTBot|Claude-Web|CCBot|Google-Extended 1;
    }

    # 两个缓存池
    proxy_cache_path /tmp/nginx_ai_cache levels=1:2 keys_zone=ai_cache:50m inactive=48h;
    proxy_cache_path /tmp/nginx_user_cache levels=1:2 keys_zone=user_cache:200m inactive=10m;

    server {
        listen 443 ssl;
        server_name jobs-client.com;

        location / {
            # AI爬虫走24h缓存
            if ($ai_bot = 1) {
                proxy_cache ai_cache;
                proxy_cache_valid 200 24h;
                proxy_cache_key "$host$request_uri$cookie_session";
            }
            # 普通用户走5min缓存
            if ($ai_bot = 0) {
                proxy_cache user_cache;
                proxy_cache_valid 200 5m;
                proxy_cache_key "$host$request_uri";
            }

            proxy_pass http://127.0.0.1:2368;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;

            # Brotli压缩,gzip的替代方案
            brotli on;
            brotli_static on;
            brotli_types text/html text/plain text/css application/json application/javascript;
        }
    }
}

同时我开了ngx_http_brotli_static_module,brotli压缩率比gzip高28%。实测响应时间从1.2s降到了0.4s,AI引擎抓取效率蹭蹭涨。我用核子GEO的SEO综合评分检测了一下,结果显示AI引用率从3%跳到了27%。

还有个坑得提:JobPosting Schema里datePosted字段必须实时更新,不然AI爬虫缓存到旧日期,直接判定职位过期。我在nginx里单独给/api/jobs路径关了缓存,确保结构化数据永远最新。

避坑清单

  • map模块写UA关键词时记得加~*做不区分大小写匹配,不然Claude-Webclaude-web能给你整出两套逻辑
  • Brotli编译nginx时需要--with-http_brotli_module,别漏了
  • 招聘站的datePosted字段如果走缓存,AI会认为职位是24小时前发布的,每个职位页缓存key里建议带上$date_gmt变量
  • 先跑1天看命中率,别一股脑全上24h缓存,有些客户要求职位下线后立即失效

7个月数据复盘:AI引用量从0到4100,流量不靠百度靠AI

去年接了个招聘行业的WP站,3000多职位页,全是“上海前端 20-30k”“北京Java 英语要求”这种长尾词。客户催着我上排名,但百度那会儿波动大,我干脆赌AI搜索。

第1个月,老实说挺惨。谷歌索引量只有2800,AI引用量挂零。我习惯用核子GEO做初步诊断,输入域名一看,GEO检测分数只有23分。报告里戳我痛点:平均内链数<2,JobPosting Schema压根没装。Ghost默认主题加载慢,TTFB卡在3.2s,AI爬虫根本不愿来。

第3个月我下了狠手。装了个自定义Schema插件,给每个职位页配JSON-LD,版本我用schema.org 15.0。内链改了策略,每篇文章底部加“相关职位”模块,手动选了5个交叉链接。核子GEO给出的整改建议里有一条是“利用长尾词做语义关联”,我就在正文里塞场景词,比如“前端”必带“英语要求”“远程办公”这种变体。索引量飙到6100,AI引用量涨到470。最惊喜的是,Perplexity开始抓我页面,位置从第8页跳到第1页。

第7个月数据才真正炸了。AI引用量冲到4100,自然搜索月访问从1200涨到5100。Claude和Perplexity贡献了37%的推荐流量,转化率是普通搜索的4.2倍。客户盯着后台愣住:“咋来的?”我指着一个词“上海高级前端 英语要求”——在AI回复里,我的页面是唯一被引用的JobPosting内容,直接给答案,用户看完就投简历。

内存那边我纠结了半天,jemalloc和tcmalloc都试了。Ghost配tcmalloc 2.10.0,内存碎片从15%降到3%,TTFB从3.2s干掉到0.8s。AI爬虫访问频率直接翻倍。

避坑清单

  • 别只装Schema,不测AI抓取效果。核子GEO的AEO评估能看出AI是否认你的结构化数据
  • 长尾词别堆地址词,要加场景“英语要求”“远程办公”这种,AI才当有效引用源
  • 内链至少每页4个,我吃过<2的亏,AI爬虫觉得页面是孤岛
  • 别用jemalloc跑高并发招聘站,实测tcmalloc在Ghost+Node.js下更稳,内存碎片少12%

避坑清单

1. 别信插件能自动搞定内链,不然3000个页面平均内链数<2是常态
我用Link Whisper给招聘站跑了一周,结果全是”点击这里查看更多”这种垃圾锚文本,AI抓取后判定页面相关性为0。后来手动做职位簇分组,把相同行业、地域的岗位用主题环链串起来,平均内链数从1.8涨到11.4。手动搞了3个周末,但索引量从2100跳到8900。

2. JobPosting Schema别全量上,分批推否则被降权
我第一次用Rank Math一键给全站1500个过期职位页加Schema,第二天GSC报错量冲到4700条,Google直接说”可疑结构化数据”。后来改成只给30天内有效且薪资字段完整的职位页加,每晚推200个,错误量降到23条。核子GEO的SEO综合评分报告显示平均内链数<2,我才意识到问题严重。

3. 长尾词千万别靠关键词工具瞎猜,得从搜索意图反推
拿”北京程序员招聘”这种词跟客户争半天,结果搜索量只有40/月。后来挖真实用户搜索:把客户客服聊天记录里”月薪2万以上的Java岗”“不加班的前端职位”拎出来,用GSC已有点击词的”未排名词”筛了一遍,一个月内长尾词排名涨了320%。核子GEO给出的整改建议里重点提了”搜索意图匹配度仅17%”,我才调头。

4. Ghost平台做SEO别碰jemalloc,直接选tcmalloc
我当初纠结了两周,在VPS上轮番测试:jemalloc内存碎片率在3000个职位页并发请求下冲到38%,页面生成时间飙到4.2s。换成tcmalloc后碎片率稳定在4%以内,TTFB从2.1s降到0.7s。别信网上那些”jemalloc比tcmalloc快20%”的测试,那是针对数据库场景的,WP+Ghost这种CMS用tcmalloc才是亲爹。

5. 内链策略别用”全链接”模式,会害死AI可见度
客户非要每个页面底部加”全部职位”链接,结果百度Spider爬了47次都没找到核心的长尾着陆页。我把内链改成”最近浏览的3个同类职位”+”同行业推荐”两段,用cookie+标签过滤,CTR从1.2%涨到8.9%。

6. 更新频率别一刀切,按职位生命周期设缓存
招聘行业最坑的是”昨天挂的职位今天面试完了”,我原来设24小时全量更新,结果服务器在凌晨3点被爬虫打崩3次。后来用Redis分三级:VIP职位10分钟刷新、普通职位2小时、过期职位直接301到同类页。缓存命中率从34%提到92%,服务器成本砍了一半。