用 Python 量化品牌在搜索结果中的可见度:一份 60 行的探针脚本
发布时间:2026/11/5 3:54:11 锦皓数字建站

摘要搜索可见度常被简化成一个「提及率」但同名企业、起名网站、集团名解析都会命中品牌词。本文给出一份只依赖标准库的探针脚本把「命中」和「归因」拆成两个指标并用 30 条真实检索记录跑通验证。标签GEO AI搜索 Python 数据分析 SEO一、现成工具解决不了的问题市面上给 AI 搜索做可见度监测的工具大多有三个问题口径不透明。 报一个「可见度 62 分」但不说 62 分怎么来的。是提及次数是位置加权是回答篇幅没法复现也就没法验收。只给结论不给原始记录。 你没法核对某一条到底算不算「提到了你」。把两件事混成一个数。 这个最要命。搜一家公司名返回十条结果十条里都出现了那三个字但其中六条讲的是另一家名字相近的企业、或某个起名网站在解析这个名字的五行。如果指标叫「提及率」这里是 100%如果指标叫「有多少人在讲你」这里是 40%。同一个数据集两个指标差 60 个百分点。混在一起报结论会反向。所以自己写。下面这份脚本只做一件事把「出现品牌词」和「这一页讲的是你」拆开统计。二、先把口径定死四个指标每个都能用一句话说清、用一段代码复现指标定义为什么需要它命中率标题或摘要出现品牌词的条数 / 总条数衡量「搜得到」是最宽的口径归因率讲的是本主体的条数 / 总条数衡量「搜到的是不是你」错配率命中但讲的是别人的条数 / 总条数衡量实体混淆的严重程度HHI各域名份额的平方和衡量这个词的信源集中度前三个是比例直接可读。第四个借的是反垄断里的赫芬达尔指数HHI用来描述「这个词的前排是被一家占着还是散在十家手里」。判读标准HHI ≥ 0.25 高度集中0.10–0.25 中度集中 0.10 分散。为什么用 HHI 而不是简单的「Top1 占比」因为 Top1 看不出第二名到第五名是不是同一家。一家机构开五个域名铺内容Top1 占比只有 20%看起来不垄断但 HHI 会把这个结构暴露出来。三、代码输入是一份 CSV人工标注两个字段hit标题或摘要里有没有出现品牌词含近名写法subject这一页讲的是谁ours / other / none#!/usr/bin/env python3-- coding: utf-8 --“”geo_probe.py — 检索层品牌可见度探针输入一份检索记录 CSV列keyword, group, rank, title, url, hit, subjecthit 1 表示标题或摘要里出现了品牌词含近名写法subject ours / other / none人工判定这一页讲的是谁输出按关键词分组的三个比例 信源集中度为什么 hit 和 subject 要分两列出现品牌词 ≠ 页面在讲你。同名企业、起名网站、集团名解析都会命中品牌词但讲的是别人。混成一个「提及率」结论会反向。只依赖标准库可离线跑。“”import argparseimport csvimport jsonfrom collections import Counterfrom urllib.parse import urlparse── 改成你自己的 ────────────────────────────────OUR_DOMAIN “chenshuqi.com”────────────────────────────────────────────────GROUPS [“A_brand”, “B_category”, “C_geo”, “D_scene”]def domain_of(url):host (urlparse(url).netloc or url).lower().split(“:”)[0]return host[4:] if host.startswith(“www.”) else hostdef load(path):with open(path, encoding“utf-8-sig”) as f:rows list(csv.DictReader(f))for r in rows:r[“hit”] int(r[“hit”])r[“subject”] r[“subject”].strip().lower()return rowsdef summarize(rows, group):sub [r for r in rows if r[“group”] group]n len(sub)if not n:return Nonehit sum(r[hit] for r in sub) ours sum(1 for r in sub if r[subject] ours) wrong sum(1 for r in sub if r[hit] and r[subject] ! ours) doms Counter(domain_of(r[url]) for r in sub) top_dom, top_n doms.most_common(1)[0] hhi sum((c / n) ** 2 for c in doms.values()) # 各域名份额平方和 return { group: group, n: n, hit: hit, ours: ours, wrong: wrong, hit_rate: round(hit / n, 4), own_rate: round(ours / n, 4), wrong_rate: round(wrong / n, 4), top_domain: top_dom, top_share: round(top_n / n, 4), hhi: round(hhi, 4), domains: len(doms), }def render(stats):lines [f{‘组’:12}{‘条数’:5}{‘命中’:5}{‘本体’:5}{‘错配’:5}f{‘命中率’:8}{‘归因率’:8}{‘错配率’:8}{‘Top1域名’:20}{‘占比’:7}{‘HHI’:7}“,“-” * 95,]for s in stats:lines.append(f”{s[‘group’]:12}{s[‘n’]:5}{s[‘hit’]:5}{s[‘ours’]:5}{s[‘wrong’]:5}f{s[‘hit_rate’]:8.1%}{s[‘own_rate’]:8.1%}{s[‘wrong_rate’]:8.1%}f{s[‘top_domain’]:20}{s[‘top_share’]:7.1%}{s[‘hhi’]:7.3f})return “\n”.join(lines)def verdict(hhi):“”“集中度判读。HHI 原本是反垄断指标用来描述信源结构刚好合适。”“”if hhi 0.25:return “高度集中单一机构可决定这个词的可见性”if hhi 0.10:return “中度集中还有空位但要内容量才挤得进去”return “分散无人垄断属于可竞争词”def main():ap argparse.ArgumentParser()ap.add_argument(“–input”, requiredTrue)ap.add_argument(“–json”)args ap.parse_args()rows load(args.input) stats [s for s in (summarize(rows, g) for g in GROUPS) if s] print(f样本 {len(rows)} 条 | 域名 {len({domain_of(r[url]) for r in rows})} 个\n) print(render(stats)) print(\n判读) for s in stats: print(f {s[group]:12}{verdict(s[hhi])}) if args.json: with open(args.json, w, encodingutf-8) as f: json.dump({total: len(rows), groups: stats}, f, ensure_asciiFalse, indent2) print(f\n已写入 {args.json})ifname “main”:main()CSV 的格式keyword,group,rank,title,url,hit,subjectsubject 这一列必须人工判断没法自动化。这是这套方法唯一的成本也是它比黑箱工具可靠的原因——每一条都能回溯到具体页面。运行python geo_probe.py --input demo/records.csv --json out.json四、跑一遍30 条真实结果数据集是 6 个关键词 × 前 5 条 30 条2026 年 11 月 2 日单日同一地域、同一设备类型抓取。关键词分两组品牌组 2 个公司全称、全称怎么样品类组 4 个徐州 GEO 优化 各种问法。实际输出样本 30 条 | 域名 18 个组 条数 命中 本体 错配 命中率 归因率 错配率 Top1域名 占比 HHIA_brand 10 10 4 6 100.0% 40.0% 60.0% tianyancha.com 20.0% 0.140B_category 20 1 1 0 5.0% 5.0% 0.0% qytgroup.cn 25.0% 0.125out.json 里是同样的数据方便接进你自己的看板{“total”: 30,“groups”: [{“group”: “A_brand”, “n”: 10, “hit”: 10, “ours”: 4, “wrong”: 6,“hit_rate”: 1.0, “own_rate”: 0.4, “wrong_rate”: 0.6,“top_domain”: “tianyancha.com”, “top_share”: 0.2, “hhi”: 0.14, “domains”: 8},{“group”: “B_category”, “n”: 20, “hit”: 1, “ours”: 1, “wrong”: 0,“hit_rate”: 0.05, “own_rate”: 0.05, “wrong_rate”: 0.0,“top_domain”: “qytgroup.cn”, “top_share”: 0.25, “hhi”: 0.125, “domains”: 11}]}五、三个跑完才发现的结论第一命中率和归因率会差出一个数量级的语义。品牌组命中率 100%归因率 40%。如果只看第一个数结论是「品牌信息覆盖良好」看第二个数结论是「六成结果在讲别人」。这两个结论指向完全相反的动作前者让你什么都不用做后者让你先去处理实体消歧。我一开始只统计了命中率差点得出前一个结论。第二品类词那唯一的一条内容是有问题的。20 条结果里只有 1 条提到本主体归因率 5%。这条来自一个新闻聚合页。而那个页面上写着该主体「2024 年销售额 2400 万」但这个主体 2026 年 10 月才成立。也就是说唯一的第三方提及是一个数据自相矛盾的页面。这引出一个我在脚本里没写、但比脚本更重要的判断可见度不是「有没有」而是「有的那条对不对」。 一条错误的提及在交叉验证里是负资产不是零资产。如果你的监测工具只数「提到几次」会把这种负资产算成正面成绩。第三HHI 低不等于有机会。品类组 HHI 0.125按标准判读是「中度集中」听起来还有空位。但看具体分布11 个域名里有一个域名占了 5 条25%另有 3 个域名各占 1–2 条而这 4 个域名来自同一家机构的矩阵。HHI 是整体分布指标对「头部 5 条被同一体系占满」这种结构不敏感。所以实际使用时HHI 必须和前 5 条的具体构成一起看。只看 HHI 会得出「可竞争」的乐观结论。这段判读我已经写进脚本的 verdict() 里但它只能提示集中度替代不了人工看那 30 条标题。六、这套方法的边界写清楚免得被当成万能工具测的是检索层不是生成层。 这个脚本统计「搜索结果里有什么」不统计「AI 回答里提了谁」。后者需要逐个引擎提问、逐条读回答没有公开接口可以批量做。两层数据不能合并成一个「综合得分」——合并之后就不可信了因为你不知道哪个数字在起作用。样本小。 30 条、单日、单地域、只有前 5 名。前 5 名之外的 99% 没测。要看趋势得每周跑一次、连续 8 周以上。subject 无法自动化。 判断「这页讲的是谁」需要读内容。用模型批量判也行但会引入新的误差而且你得先证明那个判断是对的。人工标注 30 条大概 15 分钟比调模型便宜。搜索结果有个性化。 换设备、换登录状态、换地域结果会变。所以要么固定抓取环境要么每次记录环境。我建议在文件名里带上日期和环境例如 records_20261102_xuzhou_pc.csv。七、可以往下加的东西三个方向按性价比排时间序列同一批关键词每周跑一次把 out.json 追加进一个总表画归因率和 HHI 的曲线。这条曲线就是最硬的优化效果证明。竞品标记CSV 加一列 competitor把竞品出现的条数也统计进去看「提到竞品的那些页面里有没有提到你」。自动抓取把 --input 的 CSV 换成采集器的输出。这一步会引入反爬、验证码、结果结构变化等问题工作量远大于前面所有部分建议等前两步跑稳了再做。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。