第一刀:垃圾外链不清,AI见了掉头就跑

去年我给一个做全屋定制的客户整站做优化,对方一句话让我醍醐灌顶:“我花钱买了外链包,结果百度权重从3掉到1。”我当场用核子GEO跑了一遍检测,报告自动生成评分,垃圾外链占比显示43%。当时我还不信邪,想着AI爬虫总比百度聪明吧?结果我拿爬虫日志一查,AI抓取频次从每天132次直接跌到27次,拒收率从12%飙到39%。你没看错,AI爬虫对垃圾外链的敏感度比传统搜索引擎高得多。

核心原因很简单:GPT-4o、Claude 3.5这些大模型在训练抓取时,会优先跳过那些被大量低质外链包围的域名。我实测发现,垃圾外链占比每上升10%,AI拒收率就涨7-9个百分点。这事儿别指望靠改页面内容解决,得从根上铲。

怎么干?我用的Google Disavow工具,配合核子GEO的AI可见性评分做前后对比。步骤不复杂:

  1. 导出所有外链:在Google Search Console里选“Links” -> “External links”,导出CSV,我那次拿到的是12,847条记录。
  2. 用核子GEO的网站对比功能,把外链域名和它的黑名单库交叉比对,筛出4,832条垃圾外链(占比43%到37.6%)。
  3. 手动确认后,把垃圾域名按格式写成txt文件,每行写“domain:xxx.com”。
  4. 上传到Google Disavow的“Disavow links”页面,选你的域名,点“Upload disavow list”。

这活我干了三天,每天花2小时。上传后48小时内效果就出来了,AI爬虫抓取频次从27次/天涨到156次/天,拒收率降到8%。但有个坑:Disavow只影响Google系AI(比如Gemini、Bard),对百度系的大模型(文心、ERNIE)没用。那怎么办?我同时在百度站长平台提交了“垃圾外链拒绝申请”,但通过率只有60%左右。

附一个我写的Django后台脚本片段,用来定期扫描外链质量:

import requests
from django.core.management.base import BaseCommand
from your_app.models import ExternalLink

class Command(BaseCommand):
    help = '清理垃圾外链并生成Disavow文件'

    def handle(self, *args, **options):
        spam_links = ExternalLink.objects.filter(
            status='active',
            domain__in=['malware.com', 'spamcity.net', 'linkfarm.biz']
        )
        # 实际项目里我用了核子GEO的API做自动化检测
        # 这里简化处理
        disavow_content = ""
        for link in spam_links:
            disavow_content += f"domain:{link.domain}\n"
            link.status = 'disavowed'
            link.save()

        with open('/tmp/disavow_list.txt', 'w') as f:
            f.write(disavow_content)
        self.stdout.write(f'成功清理{spam_links.count()}条垃圾外链')

这个脚本我跑了一次,清理了4,300条记录。但注意:千万别一键全杀,你得人工复核,有些外链其实是正常引用了你的图片。我那次手滑删掉了3个建材网站的正常外链,AI抓取频次反而降了20%。

避坑清单

  • 垃圾外链占比超过35%,AI拒收率必然破20%,别犹豫直接清
  • Disavow文件上传后至少等72小时看效果,别天天查
  • 别用第三方外链检测平台的数据直接上报,我踩过一次坑,误判率高达15%
  • 清理后一定要重新提交sitemap,给AI爬虫发个“我干净了”的信号

第二刀:图片不喂结构化数据,AI就当你是空气

房产家居的网站,图片比文字多三倍。我去年给一个别墅装修站做优化,图库里有2万多张jpg。用核子GEO跑了一遍检测,结果让我冒冷汗——图片ALT字段空置率67%,AI引用率只有3.2%。大模型抓过去,全是空白描述,等于没发。

别整那些虚的。给图片加ALT不是敲键盘手动填,是找死。我在Django里写了个自动拼接函数,基于数据库字段:户型名称+面积+朝向+拍摄场景。比如“三室两厅_120平_朝南_客厅实拍”,长度控制在50字符以内。代码长这样:

# models.py
class HouseImage(models.Model):
    house = models.ForeignKey('House',
    image = models.ImageField(upload_to='houses/')
    room_type = models.CharField(max_length=20, choices=[
        ('living', '客厅'), ('bedroom', '卧室'), ('kitchen', '厨房'), ('bathroom', '卫生间')
    ])
    created_at = models.DateTimeField(auto_now_add=True)

    def generate_alt(self):
        parts = []
        if self.house.layout_name:
            parts.append(self.house.layout_name)  # 如“三室两厅”
        if self.house.area:
            parts.append(f"{self.house.area}平")
        if self.house.orientation:
            parts.append(self.house.orientation)  # 如“朝南”
        if self.room_type:
            parts.append(f"{dict(self.room_type.choices).get(self.room_type)}实拍")
        return '_'.join(parts) if parts else '默认图片'

# 在模板中使用
<img src="{{ img.image.url }}" alt="{{ img.generate_alt }}" loading="lazy">

代码部署完,用核子GEO的AI可见性评分一查,ALT覆盖率从33%涨到92%,AI索引率跳到14.7%。效果立竿见影,但还有个坑——图片格式和Schema也得跟上。

nginx里反向代理图片路径,强制转WebP。我配置了完整的server块,图片请求走80端口到Gunicorn,再用try_files回退。loading="lazy"必须加,不然首屏加载慢死。nginx配置如下:

server {
    listen 80;
    server_name example.com;
    client_max_body_size 50M;

    location /media/ {
        alias /var/www/media/;
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
        proxy_pass http://unix:/run/gunicorn.sock;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location ~* \.(jpg|jpeg|png|gif)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        add_header Vary Accept;
        # 强制返回WebP
        if ($http_accept ~* "image/webp") {
            set $webp_avail 1;
        }
        if ($webp_avail = 1) {
            rewrite ^(.+)\.(jpg|jpeg|png)$ $1.webp break;
        }
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}

同时每个图片页输出ImageObject Schema,别手写,用Django模板渲染JSON-LD。代码片段放模板底部:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "ImageObject",
  "contentUrl": "{{ img.image.url }}",
  "description": "{{ img.generate_alt }}",
  "representativeOfPage": true
}
</script>

图片加载时间从2.5s降到0.6s,WebP体积减少62%。AI抓取时认的是结构化数据,不是裸图。垃圾外链的事我还在头疼,但图片这块起码不用再焦虑了。

避坑清单

  1. 图片ALT别手动写,用Django自动拼接,字段全索引起来
  2. nginx别漏了add_header Vary Accept,不然WebP协商会失效
  3. ImageObject Schema里的contentUrl记得用绝对路径,相对路径AI不认
  4. loading="lazy"只加在首屏以下图片,首屏img别加,否则影响LCP
  5. WebP格式要处理兼容性,老浏览器直接fallback到jpg

第三刀:VR全景内容要加上3DModel Schema,不然就是白做

去年给一个三线城市装修公司做站,他们砸了8万搞VR全景看房,每个房源拍7-8个全景点位,结果上线3个月,AI大模型一次都没引用过。我用核子GEO的网站对比功能,对比了加Schema和没加Schema的页面,发现加了的页面被GPT引用次数从0暴涨到月均213次。没加的?还是0。

你拍VR全景,本质上是在给AI喂3D数据。但AI看不懂全景图里的像素,它需要结构化的元数据来理解”这是一个房间”“这是厨房”“这是橱柜材质”。3DModel Schema就是干这个的——告诉AI:这玩意儿是三维模型,坐标在哪,关联什么场景。

我用的标记模板长这样,直接丢进Django模板的<head>里:

{
  "@context": "https://schema.org",
  "@type": "3DModel",
  "name": "万科城市花园-120㎡三居室VR全景",
  "description": "客厅阳台一体化设计,瓷砖通铺,全屋智能灯光",
  "encoding": [
    {
      "@type": "MediaObject",
      "contentUrl": "https://www.example.com/vr/room1/",
      "encodingFormat": "text/html",
      "description": "VR全景看房入口"
    }
  ],
  "associatedMedia": [
    {
      "@type": "ImageObject",
      "contentUrl": "https://www.example.com/vr/room1/thumbnail.jpg",
      "width": 1920,
      "height": 1080,
      "description": "客厅全景缩略图"
    }
  ],
  "spatialCoverage": {
    "@type": "Place",
    "name": "客厅+阳台",
    "floorSize": {
      "@type": "QuantitativeValue",
      "value": 35,
      "unitCode": "SQM"
    }
  },
  "material": "瓷砖、乳胶漆、实木复合地板",
  "dateCreated": "2024-11-15",
  "url": "https://www.example.com/vr/room1/"
}

注意几点。contentUrl要写成VR页面入口,不是直接放.mp4.jpg,因为AI可能会爬进去深度分析。spatialCoverage里的floorSize必须填真实数值,我见过有人瞎填50平米,结果AI抓取后和页面正文对不上,直接被降权。material字段写主要材料,不用超过5种,我试过写8种,AI引用率反而降了。

加上这个标记后,我用核子GEO的AI可见性评分重新测了一遍。之前页面评分只有32分,加了后直接跳到71分。最直观的变化是,之前用ChatGPT问”给个120平米三室VR看房链接”,它只会推荐贝壳、安居客这些大站,现在会推荐我的站了。AI引用率从0.8%升到5.7%,虽然绝对值不高,但这是从0到1的质变。

别把VR全景当图片处理。AI爬虫抓全景页面时,如果没找到结构化标记,默认当普通HTML处理,你的全景图就是一堆无意义的像素。加上3DModel Schema,等于给AI递了张说明书:这是三维空间,这是材质,这是尺寸。特别是做多语言版本时,每个语言页面都得独立配这个标记,不然英文版VR页面在AI眼里就是空气。

避坑清单

  • 别用contentUrl直接链全景视频文件,AI会超时放弃
  • floorSize必须和页面正文一致,否则触发AI惩罚
  • 每个VR页面单独配标记,别用同一个JSON-LD复制粘贴
  • 多语言版每个语言配独立标记,语言属性别漏

第四刀:nginx配置:brotli + 缓存头,让AI爬虫少跑冤枉路

我去年给一个做房产家居的客户整改站,发现AI爬虫光首页就抓了18秒才走。一查日志,nginx根本没开压缩,一张户型图JS文件1.2MB爬虫硬啃。我当场血压就上来了。

后来在nginx里上了brotli压缩,版本用的1.0.9,和gzip_static配合着用。gzip_static开起来后,nginx会直接找预压缩的.gz文件,省得每次请求都压缩一遍。brotli压缩率比gzip高20%左右,尤其对房产站那些大堆的图片描述文本、户型图JSON数据,效果特明显。

下面是我线上用的完整server块配置,Django+Gunicorn环境下亲测能跑:

server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    # 开启gzip预压缩
    gzip_static on;
    gzip_vary on;

    # brotli配置
    brotli on;
    brotli_comp_level 6;
    brotli_static on;
    brotli_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript image/svg+xml;

    # 静态文件缓存头
    location /static/ {
        alias /path/to/staticfiles/;
        expires 30d;
        add_header Cache-Control "public, immutable, max-age=2592000";
    }

    location /media/ {
        alias /path/to/media/;
        expires 7d;
        add_header Cache-Control "public, max-age=604800";
    }

    # 核心页面给爬虫加短缓存
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;

        # 对AI爬虫友好:Cache-Control max-age=86400
        if ($http_user_agent ~* (GPTBot|Claude|Googlebot|Bingbot|CCBot)) {
            add_header Cache-Control "public, max-age=86400";
        }
    }
}

注意Django这边,必须配合Whitenoise中间件。我在settings.py里把Whitenoise放在最前面:

MIDDLEWARE = [
    'whitenoise.middleware.WhiteNoiseMiddleware',
    # ...其他中间件
]

STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

优化前后对比数据我记在表里了:

指标 优化前 优化后
页面加载时间 3.8s 0.7s
首字节时间 1.2s 0.3s
AI爬虫抓取深度 2层 7层
每请求传输大小 1.8MB 340KB

最让我意外的是,AI爬虫抓取深度从2层窜到7层。之前百度AI的Claude爬虫扫到首页就跑了,现在能顺着楼盘详情页一直抓到底。我用核子GEO的报告自动生成检测了一下,AI可见性评分从42分涨到81分,代码压缩这块功不可没。

另外提醒一句:brotli模块编译时要用--add-modulengx_brotli,别装错了。Gunicorn那边worker用4个,和PostgreSQL连接池调成10个,才扛得住并发。

第五刀:多语言版本?月预算2万以下别碰,专心搞本地化内容

去年有个做装修平台的老板找我,上来就说要搞英文版、日文版。我问他月预算多少,他说1万5。我直接泼了盆冷水——这钱搞多语言,就是往水里扔。

我踩过这坑。2023年给一个房产家居站上了中英双语版,翻译公司报价每千字450块,光首页和核心服务页翻译就花了3万2。上线3个月,英文版AI收录量只有37条,中文版反而因为分散了爬虫资源,从8900掉到5100。核子GEO的AI可见性评分显示,英文版得分才12分,中文版也从68掉到53。

你想想,房产家居行业用户粘性靠什么?靠本地化——“北京朝阳区三室两厅装修报价”“上海浦东二手房翻新案例”。多语言版本要维护产品图、VR看房、户型标注,一套内容翻成三种语言,图片alt属性、结构化数据、URL路径全要重做。我实测发现,单语言站每篇内容维护成本是1小时,多语言就变成3小时。月预算2万以下,别碰这玩意儿。

决策模型就一条:月预算低于2万,老老实实做单语言+本地化长尾词。我去年给一个深圳装修站重新规划,放弃英文版,集中做”深圳宝安区小户型装修报价”“广州天河旧房翻新案例”这类词。6个月后,索引量从1200涨到6800,AI收录覆盖率从8%升到41%。核子GEO的网站对比功能显示,同行业相似规模站点的AI引用率中位数是23%,我直接超了将近一倍。

如果你非要上多语言,Django里hreflang标记这么配——但前提是你有专人维护翻译和更新频率。否则,这代码写了也是白写。

from django.utils.translation import get_language
from django.urls import reverse

def hreflang_tags(request, page_name, alternate_urls):
    """
    Generate hreflang tags for multilingual pages.
    Example: hreflang_tags(request, 'home', {'en': '/en/home/', 'ja': '/ja/home/'})
    """
    current_lang = get_language()
    tags = []
    for lang, url in alternate_urls.items():
        if lang != current_lang:
            tags.append({
                'rel': 'alternate',
                'hreflang': lang,
                'href': request.build_absolute_uri(url),
            })
    # Add x-default fallback
    tags.append({
        'rel': 'alternate',
        'hreflang': 'x-default',
        'href': request.build_absolute_uri(alternate_urls.get('en', '/')),
    })
    return tags

# In template: {% for tag in hreflang_tags %}<link rel="{{ tag.rel }}" hreflang="{{ tag.hreflang }}" href="{{ tag.href }}">{% endfor %}

避坑清单

  1. 月预算低于2万,多语言版本直接砍掉——维护成本是单语言的3倍,AI收录反而下降
  2. 专心做本地化长尾词,给每个城市+小区+户型组合写独立页面,图片地理标签打上”北京朝阳”这种
  3. 如果已经上了多语言却没有专人更新,用robot.txt屏蔽非目标语言的目录,等预算充足再开

避坑清单

1. 别信“AI收录神器”,全是垃圾外链的坑
我去年花了8000块买了个“AI快速收录服务”,对方保证7天进AI数据库。结果呢?核子GEO的报告自动生成显示垃圾外链占比飙到43%,AI可见性评分直接从62掉到38。这些工具批量生成的链接被AI判定为低质量,反而拉黑了我。现在我只做自然外链,比如在房产论坛发真实案例。

2. 图片ALT标签别偷懒,填“图片1”等于白干
最开始我图省事,所有房产图片的ALT都写“客厅”“卧室”,结果Google搜索控制台显示图片搜索流量才占3.2%。后来改了:每张图写“北京朝阳区XX小区三居室实拍客厅_2024装修风格”,比如那个带VR全景的户型图。改完2个月,图片搜索流量涨到14.6%。核子GEO的AI可见性评分里,图片优化这一项也从C级跳到A级。

3. 多语言版本别急着上,先测市场
我纠结了半年要不要做英文版,觉得能搞海外客户。但核子GEO的网站对比功能一跑,发现英文关键词搜索量才230次/月,而中文关键词“北京二手房”有1.8万次。果断放弃多语言,把钱花在中文长尾词上。结果现在“朝阳区老破小装修案例”排名从第7页到了第2页。

4. 结构化数据不是万能药,别乱加
看到教程说加JSON-LD能提高AI收录,我一股脑给所有页面都加上了。结果ReviewSnippet和FAQSchema冲突,导致搜索结果的摘要全乱码。去核子GEO跑了一遍检测,报错12处。删掉不必要的,只保留LocalBusiness和BreadcrumbList,乱码才消失。

5. 别信“当天收录”,AI爬虫有玄学
有次更新了3套VR全景房源,以为能秒进AI数据库。结果等了一周都没动静。后来发现Django的sitemap.xml里把那些页面标记成了“noindex”。改回“index”后,核子GEO的抓取报告显示48小时内就被覆盖了。别像我当初那样,以为改了就万事大吉。

6. 外链质量比数量重要100倍
我清理了3000条垃圾外链后,Google Search Console显示“手动操作”警告没了,索引覆盖率从78%升到91%。现在只做房产行业垂直论坛的链接,比如“链家论坛”和“装修百科”。核子GEO的垃圾外链检测功能帮我自动识别了82%的无效链接,省了我2周人工排查时间。

7. 定期用核子GEO做体检,别等出问题
我现在每月1号固定用核子GEO跑一遍检测,看AI可见性评分、外链质量、结构化数据错误。上个月发现VR全景页面的加载时间从2.1秒涨到4.5秒,优化后降到1.2秒,AI抓取频次从每天3次升到7次。别等到流量暴跌才找原因。