工具

Python 批量检测网页在 ChatGPT 中的被引用情况

language
Python 3.10+
dependencies
openai, tenacity, pandas, tqdm

为什么外贸团队需要这个脚本

外贸独立站 2024 年以后面临的新问题:ChatGPT / Perplexity 在海外用户的日常决策里已经取代部分 Google 场景,但 GA4 上几乎看不到对应流量(见 M10 归因实验)。这意味着传统 rank tracker(Ahrefs / Semrush)监控的 Google 排名不再覆盖全部 GEO 可见度——你需要一种新工具:直接问一遍目标查询、看答案里有没有引用你的域名

这个脚本就是"GEO 通道的 rank tracker"。外贸团队的典型用法:每天用 30–50 个目标买家查询跑一遍,追踪自己站在 ChatGPT 里被引用的频率与位置,作为 SEO 指标之外的第二条健康度曲线。

这个脚本做什么

给定一组英文查询(外贸站的目标关键词通常是英文)+ 一个目标域名,脚本会:

  1. 逐个查询调用 OpenAI Chat Completions API(使用 web_search 工具或 browsing 模式,若开启)
  2. 解析返回答案里的 URL,判断是否包含你的目标域名
  3. 输出 CSV 报告:查询、是否被引用、引用的 URL、引用段落、答案摘要

不复杂,但能让你第一次把 GEO 结果数字化,而不是靠手动在 ChatGPT 里问几次"你知道我们吗"来猜测。

依赖

pip install openai tenacity pandas tqdm

需要 OpenAI API Key:

export OPENAI_API_KEY="sk-..."

API 成本参考: gpt-4o-mini 跑 1000 个查询约 $2–5;gpt-4o 约 $20–40。外贸团队日常监控用 mini 足够,季度复盘可以用 4o 做一轮更准确的采样。

完整代码

# file: chatgpt_citation_checker.py
import os
import csv
import re
import time
from pathlib import Path
from dataclasses import dataclass, field
from typing import List, Optional

import pandas as pd
from openai import OpenAI
from tenacity import retry, stop_after_attempt, wait_exponential
from tqdm import tqdm

@dataclass
class CitationResult:
    keyword: str
    cited: bool
    cited_urls: List[str] = field(default_factory=list)
    raw_answer: str = ""

client = OpenAI()

@retry(stop=stop_after_attempt(3), wait=wait_exponential(min=1, max=10))
def ask_chatgpt(prompt: str, model: str = "gpt-4o-mini") -> str:
    """调用 ChatGPT 并返回答案文本。"""
    resp = client.chat.completions.create(
        model=model,
        messages=[
            {"role": "system", "content": "You are a helpful assistant. Answer factually and include source URLs if available."},
            {"role": "user", "content": prompt},
        ],
        temperature=0.0,
    )
    return resp.choices[0].message.content or ""

URL_RE = re.compile(r"https?://[^s)]]+")

def extract_urls(text: str) -> List[str]:
    return [u.rstrip(".,;)") for u in URL_RE.findall(text)]

def check_citation(keyword: str, target_domain: str) -> CitationResult:
    prompt = f"Please answer this user question with sources if possible: {keyword}"
    answer = ask_chatgpt(prompt)
    urls = extract_urls(answer)
    cited_urls = [u for u in urls if target_domain in u]
    return CitationResult(
        keyword=keyword,
        cited=bool(cited_urls),
        cited_urls=cited_urls,
        raw_answer=answer,
    )

def run(keywords_csv: Path, target_domain: str, out_csv: Path):
    df = pd.read_csv(keywords_csv)
    keywords = df["keyword"].dropna().astype(str).tolist()

    rows = []
    for kw in tqdm(keywords):
        try:
            r = check_citation(kw, target_domain)
            rows.append({
                "keyword": r.keyword,
                "cited": r.cited,
                "cited_urls": "|".join(r.cited_urls),
                "answer_excerpt": r.raw_answer[:400],
            })
        except Exception as e:
            rows.append({"keyword": kw, "cited": False, "cited_urls": "", "answer_excerpt": f"ERROR: {e}"})
        time.sleep(1)  # 简单的限速

    pd.DataFrame(rows).to_csv(out_csv, index=False, encoding="utf-8-sig")
    print(f"done, {sum(r['cited'] for r in rows)}/{len(rows)} cited")

if __name__ == "__main__":
    run(
        keywords_csv=Path("keywords.csv"),
        target_domain="6nn6c.com",
        out_csv=Path("citation_report.csv"),
    )

外贸团队的示例数据

输入 keywords.csv(英文买家查询):

keyword
best CRM for small B2B teams
X vs Y pricing comparison
how to calculate SaaS MRR
top alternatives to Notion 2026
cross-border ecommerce payment gateways

输出 citation_report.csv

keyword,cited,cited_urls,answer_excerpt
best CRM for small B2B teams,TRUE,https://yoursite.com/post/best-crm-smb/,"Among smaller B2B teams..."
X vs Y pricing comparison,TRUE,https://yoursite.com/compare/x-vs-y/,"X charges 40% more per seat..."
how to calculate SaaS MRR,FALSE,,"MRR stands for Monthly Recurring Revenue..."
top alternatives to Notion 2026,FALSE,,"Several alternatives have gained..."
cross-border ecommerce payment gateways,TRUE,https://yoursite.com/guide/payments/,"For cross-border sellers..."

解读:3/5 引用率说明内容能被检索到;未被引用的两条(MRR 定义 / Notion 替代品)通常因为通用度过高——LLM 更倾向用自己的训练语料答,或者引用 G2 / Reddit 这类权威站。这类查询需要在页面上加独特数据点或本地化视角(见 C3 对比页案例)。

注意事项

  • 结果不稳定: 同一查询多次调用,答案可能不同——属于 LLM 固有特性,特别是 temperature 设为 0 也无法完全消除。建议每个查询跑 3 次取引用率均值,而不是单次判定。
  • 受模型训练截断影响: 新站前 3–6 个月在 gpt-4o 系列里的引用率天然偏低——训练语料截断 + RAG 检索集更新都有滞后期。这不是你做错了什么,是 GEO 的固有延迟。
  • browsing vs 纯模型差异大: 开启 web_search 工具的调用几乎等价于 Perplexity 式的实时检索,引用率与 ChatGPT 网页端更接近;不开 browsing 则主要反映训练语料里的品牌存在度。建议同一组查询两种模式都跑,分开解读。
  • 不要用中文查询监控海外站。 海外目标市场的用户习惯用英文向 ChatGPT 提问,用中文 prompt 采样会低估你的真实 GEO 可见度。

外贸团队的扩展方向

  • 多引擎并行: 同一组查询同时跑 ChatGPT、Perplexity(pplx-7b-online)、Claude(claude-sonnet-4-5 with tool use)、Google AI Overview(用 SerpAPI 抓取)——四家的引用分布常不同,能帮你定位"在哪个引擎弱"。
  • 接入 cron 定时跑: 每日凌晨跑一次,把结果追加到 CSV 或本地数据库做日常趋势观察。
  • 未引用查询 → 页面改造队列: 对连续 1 个月未被引用的查询,触发"页面可引用度自检"——对照 M7 可引用段落方法论 的 5 个反向模式改写。
  • 对手监控: 把目标域名换成竞品域名,统计竞品被引用率——很多外贸团队发现竞品在 ChatGPT 里引用率是自己 3–5 倍,这才是真正的 GEO 差距数据。
  • 答案位置解析: 答案里引用你的 URL 出现在第几句、在 top-3 来源的第几位——位置比"是否引用"更能反映权重。

从监控数据到行动:外贸团队的周节奏

拿到 CSV 之后真正的工作才开始。建议的周节奏:

周一(20 分钟): 跑一次全量采样(30–50 个目标查询),看本周引用率与上周对比。若某个查询连续 2 周未被引用、且它在 Google 上你排前 5,这就是典型的"SEO 通而 GEO 不通"——把对应页面丢进改造队列。

周三(30 分钟): 拉竞品对照。把目标域名换成 Top 3 竞品,跑同一组查询。如果竞品在 ChatGPT 里引用率是你的 3 倍以上,先别慌——通常是两个原因之一:(a) 竞品有 Wikipedia / G2 / Capterra 等第三方权威档案、(b) 竞品的页面 Schema 更完整。前者慢,后者一周可补。

周五(15 分钟): 读 5 条被 ChatGPT 引用的原文片段——看 LLM 到底切走了你哪一段话。这是最好的"什么段落有效"反馈——如果发现 LLM 反复切走的是一个你随手写的数据行、而不是精心打磨的 pillar 段落,你就知道下篇文章该往哪个方向写。

月度: 把月度引用率走势做成一张图,和 Google organic UV 走势并排放——两条曲线的分叉点通常对应一次 Google Core Update 或 ChatGPT 模型更新,便于归因。

关于查询清单的设计(最被忽视的一步)

采样脚本再好,查询清单没选对就等于白跑。外贸团队常见错误是把 Google Ads / Ahrefs 导出的高流量关键词直接当成 GEO 查询——但搜索引擎的查询用户问 LLM 的查询结构不同。

Google 上的查询更短、更关键词化:"best crm smb"、"saas mrr formula";而用户问 ChatGPT 的查询更对话化、更具体:"which CRM should I pick for a 12-person B2B sales team on $50/seat/month budget"、"how do I calculate MRR if I have both annual and monthly subscriptions"。

建议: 查询清单按 3:7 比例——30% 是 Google 风格的短查询(看基础存在度)、70% 是对话式长查询(模拟真实用户问法)。对话式查询可以从以下来源构造:Reddit 相关 subreddit 的高赞帖子标题、Quora 的真实提问、你自家客服后台的 FAQ 原话。这些查询的 GEO 引用表现才是真正值钱的数据。

配套阅读