2026年用Python做关键词聚类:把1000个关键词自动分成内容选题(附完整代码)

2026年用Python做关键词聚类:把1000个关键词自动分成内容选题(附完整代码)

作者: QAssistant

发布时间: 2026-09-18

标签: SEO、关键词研究、语义聚类、内容规划、Python、实战工具、Embedding

阅读时长: 约 16 分钟

难度: 中级


先说一个内容人每天都在受的罪

你导出了 1000 个关键词,然后呢?

  • 手动一个个看,分不清哪些是同一个主题
  • 凭感觉分组,分出来的东西没法直接变成选题
  • 关键词之间的语义关系(同义、上下位、长尾)全靠脑子记

结果就是:关键词表躺在那,内容规划还是拍脑袋。

今天写一个 关键词聚类工具 ------用 Embedding(词向量)把关键词按语义相似度自动分组,一个聚类 = 一个内容选题,直接输出可执行的内容规划表。


一、工具思路

复制代码
关键词表(CSV / TXT)
   ↓
向量化:sentence-transformers 编码成高维向量
   ↓
聚类:层次聚类(Agglomerative)按余弦距离分组
   ↓
自动命名:每个簇选"最靠近中心"的词作为主题标签
   ↓
输出:内容规划表(cluster_id / 主题 / 关键词 / 搜索量)

为什么用 Embedding 而不是关键词匹配?

因为语义聚类能识别"SEO 工具 "和"优化软件推荐 "是一类,"外链建设 "和"发外链的方法 "是一类------即使它们字面完全不同。这是传统分组做不到的。

依赖:

bash 复制代码
pip install sentence-transformers scikit-learn numpy

二、完整代码:keyword_cluster.py

python 复制代码
"""
keyword_cluster.py
关键词语义聚类工具:把关键词表自动分组为内容选题
依赖:pip install sentence-transformers scikit-learn numpy
"""
import csv
import numpy as np
from sentence_transformers import SentenceTransformer
from sklearn.cluster import AgglomerativeClustering


# 中文关键词推荐用中文/多语言模型;英文可用 all-MiniLM-L6-v2
MODEL_NAME = "BAAI/bge-small-zh-v1.5"


def load_keywords(path: str) -> list:
    """
    读关键词表。支持两种格式:
      - 每行一个词(TXT)
      - CSV:第一列=关键词,第二列(可选)=搜索量
    返回 list[(keyword, volume)]
    """
    items = []
    if path.endswith(".csv"):
        with open(path, "r", encoding="utf-8-sig") as f:
            for row in csv.reader(f):
                if not row or not row[0].strip():
                    continue
                if row[0].lower() in ("keyword", "关键词"):
                    continue  # 跳过表头
                vol = 0
                if len(row) > 1:
                    try:
                        vol = int(float(row[1]))
                    except ValueError:
                        vol = 0
                items.append((row[0].strip(), vol))
    else:
        with open(path, "r", encoding="utf-8") as f:
            items = [(ln.strip(), 0) for ln in f if ln.strip()]
    return items


def cluster_keywords(items: list, distance_threshold: float = 0.45):
    """
    对关键词做层次聚类。
    distance_threshold 越小 → 簇越多越细;越大 → 簇越少越粗。
    0.4~0.55 是中文关键词的常用区间。
    """
    keywords = [k for k, _ in items]
    volumes = {k: v for k, v in items}

    print(f"🔢 编码 {len(keywords)} 个关键词...")
    model = SentenceTransformer(MODEL_NAME)
    # 归一化后,余弦距离=欧氏距离,聚类更稳定
    embeddings = model.encode(
        keywords, normalize_embeddings=True, show_progress_bar=True
    )

    print("🧩 层次聚类中...")
    clustering = AgglomerativeClustering(
        n_clusters=None,
        distance_threshold=distance_threshold,
        metric="cosine",
        linkage="average",
    )
    labels = clustering.fit_predict(embeddings)

    # 按簇聚合
    clusters = {}
    for kw, label in zip(keywords, labels):
        clusters.setdefault(int(label), []).append(kw)

    # 为每个簇命名:选最靠近簇中心的词
    named = []
    for cid, kws in clusters.items():
        idxs = [keywords.index(k) for k in kws]
        vecs = embeddings[idxs]
        centroid = vecs.mean(axis=0)
        # 距离中心最近的词 = 主题代表
        sims = vecs @ centroid
        label_kw = kws[int(np.argmax(sims))]
        total_vol = sum(volumes.get(k, 0) for k in kws)
        # 簇内按搜索量排序
        kws_sorted = sorted(kws, key=lambda k: -volumes.get(k, 0))
        named.append({
            "cluster_id": cid,
            "topic": label_kw,
            "size": len(kws),
            "total_volume": total_vol,
            "keywords": kws_sorted,
        })

    # 按总搜索量降序(优先做高价值主题)
    named.sort(key=lambda x: -x["total_volume"])
    return named


def export_plan(clusters: list, path: str = "content_plan.csv"):
    """导出内容规划表:每行一个关键词,标注所属主题"""
    with open(path, "w", newline="", encoding="utf-8-sig") as f:
        w = csv.writer(f)
        w.writerow(["主题ID", "主题(代表词)", "关键词", "簇规模", "簇总搜索量"])
        for c in clusters:
            for i, kw in enumerate(c["keywords"]):
                w.writerow([
                    c["cluster_id"],
                    c["topic"] if i == 0 else "",   # 主题只写一次,方便阅读
                    kw,
                    c["size"] if i == 0 else "",
                    c["total_volume"] if i == 0 else "",
                ])
    print(f"✅ 内容规划表已导出:{path}")


def print_summary(clusters: list, top_n: int = 20):
    print("\n" + "=" * 62)
    print(f"📊 共聚出 {len(clusters)} 个主题簇(按总搜索量排序)")
    print("=" * 62)
    for c in clusters[:top_n]:
        head = ", ".join(c["keywords"][:6])
        more = f" ...等{c['size']}个" if c["size"] > 6 else ""
        print(f"\n[{c['cluster_id']}] 主题「{c['topic']}」"
              f"({c['size']}词 / 总搜索量{c['total_volume']})")
        print(f"    {head}{more}")


if __name__ == "__main__":
    import sys
    src = sys.argv[1] if len(sys.argv) > 1 else "keywords.csv"
    items = load_keywords(src)
    clusters = cluster_keywords(items, distance_threshold=0.45)
    print_summary(clusters)
    export_plan(clusters)

三、运行 & 输出示例

输入 keywords.csv

csv 复制代码
keyword,volume
seo工具,4800
免费seo工具,2200
seo优化软件,1600
关键词挖掘工具,1300
外链建设,2400
怎么发外链,980
高质量外链资源,760
独立站seo,3100
外贸独立站优化,1500
网站收录慢,890

输出(节选):

复制代码
==============================================================
📊 共聚出 4 个主题簇(按总搜索量排序)
==============================================================

[0] 主题「seo工具」(4词 / 总搜索量9900)
    seo工具, 免费seo工具, seo优化软件, 关键词挖掘工具

[1] 主题「独立站seo」(2词 / 总搜索量4600)
    独立站seo, 外贸独立站优化

[2] 主题「外链建设」(3词 / 总搜索量4140)
    外链建设, 怎么发外链, 高质量外链资源

[3] 主题「网站收录慢」(1词 / 总搜索量890)
    网站收录慢

一瞬间,1000 个乱词变成了 N 个清晰的选题方向。


四、怎么用这个结果做内容规划

一个规律:一个簇 = 一篇内容 / 一个栏目

主题 内容动作
0 seo工具 写一篇《2026最好用的N款SEO工具横评》,内部覆盖"免费""优化软件""关键词挖掘"长尾
1 独立站seo 写《外贸独立站SEO从0到1》(你的核心业务词)
2 外链建设 写《外链建设实战:怎么发高质量外链》
3 网站收录慢 写问答型《网站收录慢怎么办?5个排查方向》

关键收益:

  • 避免关键词互相打架(cannibalization) :同一簇的词,用一篇内容承接,而不是分散成 5 篇互相内耗
  • 选题优先级一目了然 :按 total_volume 排序,先做高价值主题
  • 内容结构自然生成:主题词 = 文章标题,簇内长尾 = 文章各小节

五、关键参考链接

主题 链接
sentence-transformers 文档 https://www.sbert.net/
BGE 中文向量模型 https://huggingface.co/BAAI/bge-small-zh-v1.5
scikit-learn 聚类算法 https://scikit-learn.org/stable/modules/clustering.html
Google 内容质量指南 https://developers.google.com/search/docs/fundamentals/creating-helpful-content
关键词堆砌(要避免) https://developers.google.com/search/docs/essentials/spam-policies

六、进阶玩法

6.1 用搜索量加权,优先做高价值簇

代码里 total_volume 已经把整簇搜索量加总。你还可以这样排:"总搜索量 ÷ 簇规模 "得到"平均词价值",优先做高价值且竞争集中的主题。

6.2 调整聚类粒度

python 复制代码
# 想要更细的选题 → 调小阈值
cluster_keywords(items, distance_threshold=0.35)

# 想要更粗的主题栏目 → 调大阈值
cluster_keywords(items, distance_threshold=0.55)

先跑 0.45,看结果再微调,通常两次就能找到你满意的粒度。

6.3 接入 GSC 真实数据做"意图聚类"

把 Search Console API 拉来的已有展示词 (见前文《用 Search Console API 自建排名监控》)和候选新词一起聚类,就能看出:哪些簇你已经在排名、哪些是内容空白------直接定位增长点。

6.4 结合 GEO:一簇 = 一个"事实密度单元"

GEO 时代,AI 需要结构化的、单一主题清晰 的内容。一个聚类正好是一个主题单元,写成一篇事实密集的文章,既利于传统排名,也利于被 AI 引用------一举两得。


七、总结

关键词不是用来"堆"的,是用来"组织"的。

这个工具的价值:

  • Embedding 语义聚类,识别字面不同但意思相同的词
  • 全自动分组 + 自动命名,1000 词几秒钟出结果
  • 输出可直接执行的内容规划表
  • 顺带解决关键词打架、选题混乱、长尾浪费三大痛点

把"看关键词表发呆"的时间,换成"按主题批量产出高质量内容"。


你那 1000 个关键词,聚出来几个主题?评论区晒一下主题数量,我帮你看有没有漏掉的高价值簇。


📮 想要本文完整代码包 + 更多 SEO/GEO 实战工具合集?评论区留言或私信我即可,看到都会回。

相关推荐
拾光师1 小时前
MapReduce Join 操作:大表关联小表用 Map 端,大表关联大表用 Reduce 端
大数据
tedcloud1231 小时前
emilkowalski/skills:让 AI 写出来的网页更有“设计感”
服务器·人工智能·开源·音视频·ai编程
卷无止境1 小时前
Jev来了,一个不会说话的AI模型正在改写自动化的规则
人工智能·后端
SatanII1 小时前
容器运行时Containerd完整学习笔记|原理、安装、ctr/nerdctl/crictl实操全梳理
运维·docker·华为云·containerd
爱上纯净的蓝天1 小时前
自包含推理一体机四层架构拆解:128G 统一内存、256K 上下文与实测口径
人工智能·大模型·私有化部署·agent·大模型部署
一心同学1 小时前
Hermes架构拆解之Agent Loop
人工智能·agent·loop·hermes
DevNo1 小时前
我用AI工具辅助看盘的三段记录
人工智能
IT_陈寒1 小时前
React的useEffect依赖项居然骗了我三年
前端·人工智能·后端
HRaitest1 小时前
【架构拆解】从“外挂插件”到“原生基座”:2026 新一代全链路 AI 招聘系统底层技术演进
人工智能·ai·求职招聘