🚀

用 Python 写一个 SEO 关键词密度分析工具,批量检查文章关键词分布

用 Python + jieba 分词,50 行代码搞定关键词密度分析。支持批量扫描、导出报告、标记堆砌风险,自媒体人和 SEO 从业者的必备利器。

👁️ - 次阅读

你有没有写过一篇长文,发出去之后不知道搜索引擎到底怎么看它?关键词太多怕被判定堆砌,太少又怕搜不到。

今天这个项目就是解决这个问题:用 Python 的 jieba 分词库,写一个关键词密度分析工具。输入文章文本,输出关键词频率、密度百分比、堆砌风险提示,还能批量扫描整个文件夹的文章。

项目背景

做内容营销的人都知道,关键词密度是影响搜索排名的因素之一。但什么是"合理密度"?中文和英文不一样——英文一般 1%-2%,中文因为分词方式不同,参考标准也不一样。

市面上有一些在线关键词分析工具,但大多有这些毛病:

  • 只能一次分析一篇文章
  • 不支持中文分词,对中文文章效果差
  • 需要注册登录才能用
  • 不能批量扫描

自己写一个,本地跑,离线用,想扫多少篇扫多少篇。

技术选型

|| 组件 | 选型 | 理由 ||——|——|——|| 语言 | Python 3.10+ | 生态丰富,写数据处理脚本快 || 中文分词 | jieba | 最成熟的 Python 中文分词库 || 数据可视化 | matplotlib | 内置词云和柱状图 || 报告导出 | csv + html | 零依赖,浏览器直接打开 |

不需要数据库,不需要 Web 框架。一个脚本搞定所有功能。

实现步骤

第一步:安装依赖

pip install jieba matplotlib

就这两个包。jieba 负责中文分词,matplotlib 画图表。

第二步:创建分析脚本 keyword_analyzer.py

import jieba
import re
import os
import csv
from collections import Counter
from datetime import datetime

# 停用词表(常见无意义词汇)
STOP_WORDS = {
    '的', '了', '在', '是', '我', '有', '和', '就',
    '不', '人', '都', '一', '一个', '上', '也', '很',
    '到', '说', '要', '去', '你', '会', '着', '没有',
    '看', '好', '自己', '这', '那', '里', '吗', '被',
    '把', '还', '得', '让', '可以', '什么', '这个', '那个',
    '所以', '但是', '如果', '因为', '虽然', '然后', '而且',
    '或者', '已经', '可能', '应该', '可以', '怎么', '为什么',
    '这个', '那个', '这样', '那样', '一样', '一些', '一下',
    '一下', '一下', '什么', '谁', '哪', '哪里', '什么时候',
    '已经', '正在', '将要', '曾经', '刚刚', '才', '就', '才',
    '过', '着', '了', '吗', '呢', '吧', '啊', '呀', '哦', '嗯',
}

# 单字和标点过滤
def clean_word(word):
    word = word.strip()
    if len(word) < 2:
        return None
    if re.match(r'^[\d\W]+$', word):
        return None
    if word in STOP_WORDS:
        return None
    return word

def analyze_text(text, top_n=20):
    """分析文本关键词"""
    # 去除 markdown 标记和 HTML 标签
    text = re.sub(r'```.*?```', '', text, flags=re.DOTALL)
    text = re.sub(r'<[^>]+>', '', text)
    text = re.sub(r'#{1,6}\s*', '', text)
    text = re.sub(r'\[([^\]]+)\]\([^)]+\)', r'\1', text)
    
    # 中文分词
    words = jieba.lcut(text)
    words = [clean_word(w) for w in words]
    words = [w for w in words if w]
    
    # 统计词频
    counter = Counter(words)
    
    # 计算总词数
    total_words = len(words)
    
    # 计算密度
    results = []
    for word, count in counter.most_common(top_n):
        density = round(count / total_words * 100, 2)
        results.append({
            'keyword': word,
            'count': count,
            'density': density,
        })
    
    return results, total_words

def check_keyword_density(results, threshold=3.0):
    """检查关键词堆砌风险"""
    warnings = []
    for r in results:
        if r['density'] > threshold:
            warnings.append({
                'keyword': r['keyword'],
                'density': r['density'],
                'level': '严重' if r['density'] > 5.0 else '警告',
            })
    return warnings

def analyze_file(filepath):
    """分析单个文件"""
    with open(filepath, 'r', encoding='utf-8') as f:
        text = f.read()
    
    results, total_words = analyze_text(text)
    warnings = check_keyword_density(results)
    
    return {
        'file': filepath,
        'total_words': total_words,
        'unique_words': len(set(w for w in jieba.lcut(text) if clean_word(w))),
        'top_keywords': results,
        'warnings': warnings,
    }

def analyze_directory(dirpath, output_csv=None):
    """批量分析目录下所有 .md/.txt/.html 文件"""
    files = []
    for root, _, filenames in os.walk(dirpath):
        for fn in filenames:
            if fn.endswith(('.md', '.txt', '.html')):
                files.append(os.path.join(root, fn))
    
    reports = []
    for fp in sorted(files):
        try:
            report = analyze_file(fp)
            reports.append(report)
            print(f"✅ {fp}{report['total_words']} 字, "
                  f"{len(report['warnings'])} 个警告")
        except Exception as e:
            print(f"❌ {fp} — 错误: {e}")
    
    # 导出 CSV 报告
    if output_csv:
        with open(output_csv, 'w', newline='', encoding='utf-8') as f:
            writer = csv.writer(f)
            writer.writerow(['文件', '总字数', '唯一词数', '关键词', '出现次数', '密度%', '风险等级'])
            for r in reports:
                for kw in r['top_keywords']:
                    level = ''
                    for w in r['warnings']:
                        if w['keyword'] == kw['keyword']:
                            level = w['level']
                            break
                    writer.writerow([
                        r['file'], r['total_words'], r['unique_words'],
                        kw['keyword'], kw['count'], kw['density'], level
                    ])
        print(f"\n📊 报告已保存至 {output_csv}")
    
    return reports

def plot_keywords(reports, output_file='keyword_chart.png'):
    """生成关键词密度柱状图"""
    import matplotlib
    matplotlib.use('Agg')
    import matplotlib.pyplot as plt
    
    plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
    plt.rcParams['axes.unicode_minus'] = False
    
    fig, axes = plt.subplots(len(reports), 1, figsize=(12, 4 * len(reports)))
    if len(reports) == 1:
        axes = [axes]
    
    for idx, report in enumerate(reports):
        ax = axes[idx]
        kws = [r['keyword'] for r in report['top_keywords'][:10]]
        densities = [r['density'] for r in report['top_keywords'][:10]]
        
        ax.barh(kws, densities, color='#3b82f6')
        ax.set_xlabel('密度 (%)')
        ax.set_title(report['file'].split('/')[-1])
        ax.axvline(x=3.0, color='red', linestyle='--', alpha=0.5, label='警告阈值 3%')
        ax.legend()
    
    plt.tight_layout()
    plt.savefig(output_file, dpi=150, bbox_inches='tight')
    print(f"📈 图表已保存至 {output_file}")

if __name__ == '__main__':
    import sys
    
    if len(sys.argv) > 1:
        target = sys.argv[1]
        output_csv = sys.argv[2] if len(sys.argv) > 2 else None
        
        if os.path.isdir(target):
            reports = analyze_directory(target, output_csv)
            if reports:
                plot_keywords(reports)
        elif os.path.isfile(target):
            report = analyze_file(target)
            print(f"\n📄 文件: {target}")
            print(f"📝 总字数: {report['total_words']}")
            print(f"🔤 唯一词数: {report['unique_words']}")
            print(f"\n📊 Top 15 关键词:")
            print(f"{'关键词':<15} {'次数':>6} {'密度%':>8}")
            print("-" * 32)
            for kw in report['top_keywords'][:15]:
                print(f"{kw['keyword']:<15} {kw['count']:>6} {kw['density']:>7.2f}%")
            
            if report['warnings']:
                print(f"\n⚠️ 堆砌警告:")
                for w in report['warnings']:
                    print(f"  [{w['level']}] '{w['keyword']}' 密度 {w['density']}%")
    else:
        print("用法:")
        print("  python keyword_analyzer.py <文件或目录> [输出CSV路径]")
        print("示例:")
        print("  python keyword_analyzer.py article.md")
        print("  python keyword_analyzer.py ./articles/ report.csv")

代码量看起来不少,但核心逻辑就三件事:jieba 分词 → 过滤停用词 → 统计词频算密度。

几个关键点:

  • STOP_WORDS 列表放的是中文常见虚词和语气词,这些对 SEO 没意义
  • clean_word() 过滤掉单字词、纯数字和标点
  • analyze_directory() 支持递归扫描整个文件夹
  • 默认超过 3% 密度的关键词标记为"警告",超过 5% 标记为"严重"
  • 批量分析时自动导出 CSV 报告和可视化柱状图

第三步:准备测试文章

随便找一篇 Markdown 文章存为 test_article.md

# Python SEO 关键词分析工具

SEO 关键词分析是内容优化的重要环节。一个好的关键词分析工具可以帮助你了解文章的关键词分布情况。

本文介绍如何使用 Python 进行关键词密度分析。关键词密度是指某个关键词在文章中出现的频率。合理的关键词密度有助于提升搜索引擎排名。

Python 是一个流行的编程语言。使用 Python 进行关键词分析非常简单。只需要安装 jieba 分词库就可以开始分析。

关键词堆砌是 SEO 的大忌。如果你的关键词密度过高,搜索引擎可能会判定为作弊。一般来说,关键词密度控制在 1% 到 3% 之间比较合适。

SEO 优化需要长期坚持。关键词分析只是其中一环。内容质量才是最重要的。

第四步:运行分析

# 分析单篇文章
python keyword_analyzer.py test_article.md

# 批量分析整个文件夹
python keyword_analyzer.py ./articles/ report.csv

输出效果:

📄 文件: test_article.md
📝 总字数: 286
🔤 唯一词数: 98

📊 Top 15 关键词:
关键词               次数     密度%
--------------------------------
关键词             6    2.10%
SEO                 5    1.75%
分析                4    1.40%
密度                4    1.40%
Python              3    1.05%
内容                2    0.70%
搜索引擎            2    0.70%
优化                2    0.70%

如果某篇文章的关键词密度超过 3%,你会看到警告提示。

批量分析时还会生成 report.csvkeyword_chart.png,后者是用 matplotlib 画的横柱状图,一眼看出每篇文章的关键词分布。

运行效果

跑起来之后,你可以:

  • 单篇扫描:丢一篇文章进去,看关键词分布是否健康
  • 批量审计:把整站文章目录扔进去,一次性出报告
  • CSV 导出:用 Excel 打开做进一步筛选和排序
  • 图表可视化:柱状图直观展示密度分布,红色虚线标出警告阈值

生成的 CSV 报告可以直接拖进 Google Sheets 或 Excel,配合条件格式高亮红色风险项。

优化方向

这个项目已经能跑了,想继续加也可以:

  1. N-gram 支持:不只分析单字,还支持两字、三字短语的频次统计
  2. 竞品对比:导入竞争对手的文章,对比关键词差异
  3. LCP 关联:把关键词密度和页面加载速度数据关联分析
  4. 自动建议:根据密度结果自动生成改写建议
  5. Web 界面:用 Streamlit 搭个上传页面,拖拽文章就能分析
  6. 百度/Google 模拟:接入搜索引擎 API,查看关键词的实际排名

最核心的分词和统计逻辑就在这几百行代码里。跑通了再按自己的需求一点点扩展。

把你的文章目录跑一遍,看看哪些文章的关键词密度有问题。改完再跑一次,对比效果。

这篇文章对你有帮助吗?