Python自动化脚本处理SEO批量数据实战教程:从关键词清洗到页面审计,新手也能跟做

loong
2026-05-31 / 0 评论 / 5 阅读 / 正在检测是否收录...

欢迎来到本教程,今天我们将学习如何用 Python 自动化脚本处理 SEO 批量数据。

如果你做过关键词整理、页面标题检查、Meta Description 缺失排查,应该很熟悉这种场景:几千行 CSV 数据摆在面前,Excel 能做,但做着做着就开始卡;筛选条件一多,公式复制错一格,结果就不可信;下周再来一批新数据,又要重复一遍。

坦白讲,SEO 数据处理最烦人的不是难,而是重复、琐碎、容易出错。Python 的价值就在这里:它不替你做 SEO 判断,但可以把清洗、合并、去重、分类、检测、导出报告这些机械动作稳定地跑完。

本教程适合初级到中级学习者。你不需要成为 Python 工程师,只要能看懂基础代码,就可以跟着这个步骤做出一个可复用的 SEO 批量数据处理脚本。

你将学会什么

完成本教程后,你会得到一个完整的小项目,能够处理常见 SEO 数据:

  • 批量读取关键词 CSV、页面抓取 CSV、排名数据 CSV
  • 清洗关键词空格、大小写、重复项
  • 识别标题过长、标题缺失、描述缺失等页面问题
  • 根据关键词意图做简单分类
  • 合并多份 SEO 数据,生成可阅读的 Excel 报告
  • 把脚本整理成以后可以反复使用的工具

这里有个重要提醒:自动化脚本不是魔法。它能帮你提升效率,但判断某个页面是否值得优化、关键词是否有商业价值,仍然需要你的 SEO 经验。我们要做的是把时间从重复劳动里拿回来,留给真正需要判断的部分。

前置准备:确保你已经装好这些工具

开始之前,你需要准备:

  • Python 3.10 或更高版本
  • 一个代码编辑器,推荐 VS Code
  • 基础命令行操作能力
  • 几份 CSV 文件,例如关键词表、URL 抓取表、排名表

如果你还没有安装依赖,打开终端,在项目文件夹里执行:

pip install pandas openpyxl

本教程主要使用 pandas。它是处理表格数据非常常用的 Python 库,适合 CSV、Excel、批量清洗、数据合并等任务。

建议你创建这样的项目结构:

seo-python-demo/
├── data/
│   ├── keywords.csv
│   ├── pages.csv
│   └── rankings.csv
├── output/
└── seo_batch_report.py

你可以把 data 理解成原始数据区,output 理解成结果区,seo_batch_report.py 是我们要编写的脚本。

示例数据应该长什么样

为了方便学习,我们先约定三份文件的字段。你不一定要完全一样,但字段名越规范,脚本越容易维护。

keywords.csv:关键词数据

keyword,volume,difficulty
python seo,500,35
seo automation,300,42
python seo,500,35
SEO Python Tutorial,150,28

pages.csv:页面抓取数据

url,title,meta_description,h1,status_code
https://example.com/python-seo,Python SEO Guide,Learn Python SEO automation,Python SEO,200
https://example.com/old-page,,Old content page,Old Page,200
https://example.com/error-page,Error Page,,Error,404

rankings.csv:排名数据

keyword,url,position
python seo,https://example.com/python-seo,8
seo automation,https://example.com/python-seo,15
python tutorial,https://example.com/python-tutorial,22

真实工作里的数据通常更乱:字段名不统一、URL 带参数、关键词前后有空格、大小写混在一起。下一步很关键,我们先把这些脏数据清洗干净。

步骤一:读取 CSV,并做基础检查

在 seo_batch_report.py 中写入下面的完整代码。先不要急着加复杂逻辑,第一步只做读取和检查。

from pathlib import Path
import pandas as pd

BASE_DIR = Path(__file__).resolve().parent
DATA_DIR = BASE_DIR / 'data'
OUTPUT_DIR = BASE_DIR / 'output'
OUTPUT_DIR.mkdir(exist_ok=True)

keywords_path = DATA_DIR / 'keywords.csv'
pages_path = DATA_DIR / 'pages.csv'
rankings_path = DATA_DIR / 'rankings.csv'

keywords_df = pd.read_csv(keywords_path)
pages_df = pd.read_csv(pages_path)
rankings_df = pd.read_csv(rankings_path)

print('关键词数据:', keywords_df.shape)
print('页面数据:', pages_df.shape)
print('排名数据:', rankings_df.shape)

print(keywords_df.head())

运行:

python seo_batch_report.py

如果你能看到每份数据的行数和列数,说明读取成功。

完成这一步后,你已经建立了自动化处理的入口。很多新手一上来就想写复杂功能,结果报错后不知道哪里出了问题。我的建议是:每一步都先确认数据读进来了,再继续往下做。

步骤二:清洗关键词,避免后续统计失真

关键词清洗是 SEO 批量数据处理中最容易被低估的一步。

比如:

  • python seo
  • Python SEO
  • python seo 后面带一个空格

人眼看起来差不多,但程序会把它们当成不同值。关键词去重、排名合并、分组统计都会被影响。

接着往下做,我们添加一个清洗函数:

def clean_keyword(value):
    if pd.isna(value):
        return ''
    return str(value).strip().lower()

keywords_df['keyword_clean'] = keywords_df['keyword'].apply(clean_keyword)
rankings_df['keyword_clean'] = rankings_df['keyword'].apply(clean_keyword)

keywords_df = keywords_df[keywords_df['keyword_clean'] != '']
keywords_df = keywords_df.drop_duplicates(subset=['keyword_clean'])

print('清洗后的关键词数量:', len(keywords_df))

这里做了三件事:

  • 把空值转成空字符串,避免报错
  • 去掉前后空格,并统一转成小写
  • 根据 keyword_clean 去重

注意这个细节:我们没有直接覆盖原始 keyword 字段,而是新增 keyword_clean。这样做更安全,因为原始数据还能保留,后面检查问题时不容易说不清楚。

步骤三:规范 URL,减少重复页面

URL 也是 SEO 数据里的重灾区。同一个页面可能出现这些形式:

https://example.com/page
https://example.com/page/
https://example.com/page?utm_source=test

是否要完全合并,取决于具体场景。对于基础审计,我们可以先做一个温和版规范化:去掉首尾空格,去掉末尾斜杠,但不强行删除参数。因为有些网站参数页确实需要单独分析。

def clean_url(value):
    if pd.isna(value):
        return ''
    url = str(value).strip()
    if url.endswith('/'):
        url = url[:-1]
    return url

pages_df['url_clean'] = pages_df['url'].apply(clean_url)
rankings_df['url_clean'] = rankings_df['url'].apply(clean_url)

pages_df = pages_df[pages_df['url_clean'] != '']
pages_df = pages_df.drop_duplicates(subset=['url_clean'])

我不建议新手一开始就写太激进的 URL 规则,比如直接删除所有查询参数、统一 http 和 https。那样确实看起来干净,但可能把本来不同的页面合并掉。SEO 自动化最怕的不是慢一点,而是悄悄把数据处理错。

步骤四:检测页面 SEO 基础问题

现在我们来做页面审计。先从最常见、最容易自动化判断的项目开始:

  • 状态码是否为 200
  • Title 是否缺失
  • Title 是否过长
  • Meta Description 是否缺失
  • H1 是否缺失

把下面的函数加入脚本:

def text_length(value):
    if pd.isna(value):
        return 0
    return len(str(value).strip())

pages_df['title_length'] = pages_df['title'].apply(text_length)
pages_df['description_length'] = pages_df['meta_description'].apply(text_length)
pages_df['h1_length'] = pages_df['h1'].apply(text_length)

pages_df['issue_status'] = pages_df['status_code'].apply(lambda x: '非200状态' if x != 200 else '')
pages_df['issue_title_missing'] = pages_df['title_length'].apply(lambda x: 'Title缺失' if x == 0 else '')
pages_df['issue_title_long'] = pages_df['title_length'].apply(lambda x: 'Title可能过长' if x > 60 else '')
pages_df['issue_description_missing'] = pages_df['description_length'].apply(lambda x: 'Meta描述缺失' if x == 0 else '')
pages_df['issue_h1_missing'] = pages_df['h1_length'].apply(lambda x: 'H1缺失' if x == 0 else '')

issue_columns = [
    'issue_status',
    'issue_title_missing',
    'issue_title_long',
    'issue_description_missing',
    'issue_h1_missing'
]

pages_df['issues'] = pages_df[issue_columns].apply(
    lambda row: ';'.join([item for item in row if item]),
    axis=1
)

pages_df['has_issue'] = pages_df['issues'].apply(lambda x: '是' if x else '否')

关于 Title 长度,很多教程会给一个固定标准。这里我更愿意说得谨慎一点:60 个字符只是常用参考,不是绝对规则。搜索结果展示会受像素宽度、语言、设备影响。脚本的作用是帮你筛出“可能需要检查”的页面,而不是替你下最终结论。

步骤五:给关键词做简单意图分类

关键词意图分类可以做得很复杂,也可以先做一个够用的基础版。对于新手,我建议从规则分类开始,因为它透明、可解释,出错了也容易调整。

比如我们可以按词根判断:

  • 包含 how、tutorial、guide,归为信息型
  • 包含 price、cost、buy,归为交易型
  • 包含 best、vs、review,归为对比型
  • 其他归为待判断
def classify_intent(keyword):
    kw = clean_keyword(keyword)

    informational_words = ['how', 'tutorial', 'guide', 'what', 'why']
    transactional_words = ['buy', 'price', 'cost', 'discount', 'coupon']
    comparison_words = ['best', 'vs', 'review', 'compare']

    if any(word in kw for word in transactional_words):
        return '交易型'
    if any(word in kw for word in comparison_words):
        return '对比型'
    if any(word in kw for word in informational_words):
        return '信息型'
    return '待判断'

keywords_df['intent'] = keywords_df['keyword_clean'].apply(classify_intent)

这套规则对英文关键词更直接。如果你处理中文关键词,可以换成中文词根,例如:

  • 怎么、如何、教程、方法:信息型
  • 价格、多少钱、购买、优惠:交易型
  • 哪个好、对比、评测、推荐:对比型

没有绝对答案。关键词意图和行业、页面类型、搜索结果页形态都有关系。我们先用脚本做初筛,再人工复核重点词,这才是更稳妥的工作流。

步骤六:合并关键词、排名和页面数据

进入下一环节,我们把三份数据串起来。这个步骤非常实用:你可以看到某个关键词对应哪个 URL、排名是多少、页面本身有没有 SEO 基础问题。

keyword_ranking_df = rankings_df.merge(
    keywords_df[['keyword_clean', 'volume', 'difficulty', 'intent']],
    on='keyword_clean',
    how='left'
)

full_report_df = keyword_ranking_df.merge(
    pages_df[['url_clean', 'title', 'title_length', 'meta_description', 'description_length', 'h1', 'status_code', 'issues', 'has_issue']],
    on='url_clean',
    how='left'
)

这里的 how='left' 很重要。它表示以排名数据为主,即使关键词表或页面表里找不到对应记录,也保留排名数据。

你可能会问:为什么不直接用 inner join,只保留匹配成功的数据?

因为在 SEO 排查中,“匹配不上”本身就是线索。比如排名工具里有 URL,但抓取工具没有抓到,可能是抓取范围不完整,也可能是 URL 规范化规则不一致。保留这些异常,后面才有机会发现问题。

步骤七:生成 Excel 报告,而不是只导出一个 CSV

CSV 适合机器继续处理,Excel 更适合人查看。我们可以把不同结果放到不同 Sheet:

  • full_report:关键词、排名、页面问题总表
  • page_issues:存在 SEO 问题的页面
  • keyword_summary:按意图统计关键词数量

继续添加:

page_issues_df = pages_df[pages_df['has_issue'] == '是'].copy()

keyword_summary_df = keywords_df.groupby('intent').agg(
    keyword_count=('keyword_clean', 'count'),
    avg_volume=('volume', 'mean'),
    avg_difficulty=('difficulty', 'mean')
).reset_index()

output_file = OUTPUT_DIR / 'seo_batch_report.xlsx'

with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
    full_report_df.to_excel(writer, sheet_name='full_report', index=False)
    page_issues_df.to_excel(writer, sheet_name='page_issues', index=False)
    keyword_summary_df.to_excel(writer, sheet_name='keyword_summary', index=False)

print('报告已生成:', output_file)

运行脚本后,打开 output 文件夹,你应该能看到 seo_batch_report.xlsx。

这一步完成后,你已经拥有一个基础但完整的 SEO 批量数据自动化脚本。它不花哨,但可维护、可扩展、能落地。

完整脚本汇总:可以直接复制运行

为了方便你对照,这里放一份完整版本。你可以先跑通,再根据自己的字段名调整。

from pathlib import Path
import pandas as pd

BASE_DIR = Path(__file__).resolve().parent
DATA_DIR = BASE_DIR / 'data'
OUTPUT_DIR = BASE_DIR / 'output'
OUTPUT_DIR.mkdir(exist_ok=True)

keywords_path = DATA_DIR / 'keywords.csv'
pages_path = DATA_DIR / 'pages.csv'
rankings_path = DATA_DIR / 'rankings.csv'

def clean_keyword(value):
    if pd.isna(value):
        return ''
    return str(value).strip().lower()

def clean_url(value):
    if pd.isna(value):
        return ''
    url = str(value).strip()
    if url.endswith('/'):
        url = url[:-1]
    return url

def text_length(value):
    if pd.isna(value):
        return 0
    return len(str(value).strip())

def classify_intent(keyword):
    kw = clean_keyword(keyword)

    informational_words = ['how', 'tutorial', 'guide', 'what', 'why']
    transactional_words = ['buy', 'price', 'cost', 'discount', 'coupon']
    comparison_words = ['best', 'vs', 'review', 'compare']

    if any(word in kw for word in transactional_words):
        return '交易型'
    if any(word in kw for word in comparison_words):
        return '对比型'
    if any(word in kw for word in informational_words):
        return '信息型'
    return '待判断'

keywords_df = pd.read_csv(keywords_path)
pages_df = pd.read_csv(pages_path)
rankings_df = pd.read_csv(rankings_path)

keywords_df['keyword_clean'] = keywords_df['keyword'].apply(clean_keyword)
rankings_df['keyword_clean'] = rankings_df['keyword'].apply(clean_keyword)

keywords_df = keywords_df[keywords_df['keyword_clean'] != '']
keywords_df = keywords_df.drop_duplicates(subset=['keyword_clean'])
keywords_df['intent'] = keywords_df['keyword_clean'].apply(classify_intent)

pages_df['url_clean'] = pages_df['url'].apply(clean_url)
rankings_df['url_clean'] = rankings_df['url'].apply(clean_url)

pages_df = pages_df[pages_df['url_clean'] != '']
pages_df = pages_df.drop_duplicates(subset=['url_clean'])

pages_df['title_length'] = pages_df['title'].apply(text_length)
pages_df['description_length'] = pages_df['meta_description'].apply(text_length)
pages_df['h1_length'] = pages_df['h1'].apply(text_length)

pages_df['issue_status'] = pages_df['status_code'].apply(lambda x: '非200状态' if x != 200 else '')
pages_df['issue_title_missing'] = pages_df['title_length'].apply(lambda x: 'Title缺失' if x == 0 else '')
pages_df['issue_title_long'] = pages_df['title_length'].apply(lambda x: 'Title可能过长' if x > 60 else '')
pages_df['issue_description_missing'] = pages_df['description_length'].apply(lambda x: 'Meta描述缺失' if x == 0 else '')
pages_df['issue_h1_missing'] = pages_df['h1_length'].apply(lambda x: 'H1缺失' if x == 0 else '')

issue_columns = [
    'issue_status',
    'issue_title_missing',
    'issue_title_long',
    'issue_description_missing',
    'issue_h1_missing'
]

pages_df['issues'] = pages_df[issue_columns].apply(
    lambda row: ';'.join([item for item in row if item]),
    axis=1
)
pages_df['has_issue'] = pages_df['issues'].apply(lambda x: '是' if x else '否')

keyword_ranking_df = rankings_df.merge(
    keywords_df[['keyword_clean', 'volume', 'difficulty', 'intent']],
    on='keyword_clean',
    how='left'
)

full_report_df = keyword_ranking_df.merge(
    pages_df[['url_clean', 'title', 'title_length', 'meta_description', 'description_length', 'h1', 'status_code', 'issues', 'has_issue']],
    on='url_clean',
    how='left'
)

page_issues_df = pages_df[pages_df['has_issue'] == '是'].copy()

keyword_summary_df = keywords_df.groupby('intent').agg(
    keyword_count=('keyword_clean', 'count'),
    avg_volume=('volume', 'mean'),
    avg_difficulty=('difficulty', 'mean')
).reset_index()

output_file = OUTPUT_DIR / 'seo_batch_report.xlsx'

with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
    full_report_df.to_excel(writer, sheet_name='full_report', index=False)
    page_issues_df.to_excel(writer, sheet_name='page_issues', index=False)
    keyword_summary_df.to_excel(writer, sheet_name='keyword_summary', index=False)

print('关键词数据:', keywords_df.shape)
print('页面数据:', pages_df.shape)
print('排名数据:', rankings_df.shape)
print('报告已生成:', output_file)

实践练习:把脚本改成适合你的网站

现在我们来做几个练习。不要只复制代码,真正掌握自动化脚本的方法,是把它改成你的工作流。

练习一:增加 Title 过短检测

很多页面 Title 不缺失,但只有一两个词,也可能不够清晰。你可以增加规则:小于 15 个字符标记为 Title 可能过短。

参考写法:

pages_df['issue_title_short'] = pages_df['title_length'].apply(lambda x: 'Title可能过短' if 0 < x < 15 else '')

记得把 issue_title_short 加入 issue_columns。

练习二:识别排名在 11 到 20 的关键词

排名 11 到 20 的词通常值得重点看,因为它们已经接近第一页,但还没拿到足够曝光。你可以这样筛选:

near_page_one_df = full_report_df[
    (full_report_df['position'] >= 11) &
    (full_report_df['position'] <= 20)
].copy()

然后把它导出到新的 Sheet:

near_page_one_df.to_excel(writer, sheet_name='near_page_one', index=False)

练习三:给页面问题设置优先级

并不是所有问题都同等重要。404 页面、非 200 页面通常比 Title 过长更值得优先处理。你可以添加一个优先级字段:

def get_priority(row):
    if row['status_code'] != 200:
        return '高'
    if row['issue_title_missing'] or row['issue_description_missing']:
        return '中'
    if row['issues']:
        return '低'
    return '无'

pages_df['priority'] = pages_df.apply(get_priority, axis=1)

这就是自动化脚本真正有用的地方:它不只是列问题,还能帮你排序,让你知道先处理什么。

检查验收:跑完后你应该看到什么

完成所有步骤后,请按下面的清单检查:

  • output 文件夹中生成了 seo_batch_report.xlsx
  • full_report Sheet 中能看到关键词、URL、排名、页面标题、问题字段
  • page_issues Sheet 中只保留存在问题的页面
  • keyword_summary Sheet 中按意图统计了关键词数量
  • 脚本重复运行不会报错,旧报告会被覆盖
  • 原始 CSV 文件没有被修改

如果你做到这些,恭喜你完成了一个可复用的 Python SEO 自动化基础项目。

常见报错与处理方法

报错:No such file or directory

通常是文件路径不对。检查 data 文件夹是否和 seo_batch_report.py 在同一级目录,CSV 文件名是否完全一致。

报错:KeyError: keyword

这说明 CSV 里没有 keyword 这个字段。打开文件检查表头,可能是 Keyword、关键词、keywords。你可以统一改 CSV 表头,也可以在代码里适配字段名。

中文乱码怎么办

如果 CSV 是从某些工具导出的,可能需要指定编码:

pd.read_csv(keywords_path, encoding='utf-8-sig')

如果还是不行,可以尝试 gbk,但不要盲目修改。先确认你的文件实际编码。

Excel 打不开或文件损坏

常见原因是脚本运行时 Excel 文件正处于打开状态。关闭 Excel 后重新运行脚本。

FAQ:关于 Python 自动化处理 SEO 数据的几个真实问题

需要学到什么程度才能用于 SEO 工作?

不需要学完整个 Python 体系。你先掌握文件读取、pandas 表格处理、条件筛选、数据合并、Excel 导出,就足够覆盖很多 SEO 日常任务。

Excel 已经能做,为什么还要用 Python?

如果只是几十行数据,Excel 更快。如果是几千行、几万行,或者每周都要重复同样流程,Python 更稳定。关键不是炫技,而是减少重复劳动和人为错误。

这个脚本能不能直接用于大型网站?

可以作为起点,但大型网站还需要考虑更多因素,比如分页抓取、Canonical、robots、重定向链、日志文件、索引状态、模板聚类等。不要一口吃成胖子,先把基础数据流跑顺。

是否可以接入 Ahrefs、Semrush、Search Console 数据?

可以。只要能导出 CSV 或通过 API 获取数据,就可以用类似思路处理。建议新手先用 CSV 练熟,再接 API。API 会多出鉴权、限流、字段变化等问题。

下一步怎么学更稳

如果你已经跑通这个教程,下一步可以沿着三条线继续扩展:

  • 数据源扩展:加入 Search Console 查询词、点击、展示、CTR 数据
  • 页面审计扩展:检查 Canonical、图片 Alt、内链数量、重复标题
  • 报告自动化:按日期生成文件名,定时运行,自动发送邮件

我认为学习 Python 自动化 SEO,最好的路径不是先啃厚书,而是围绕真实任务一点点加功能。今天先清洗关键词,明天合并排名,后天生成报告。每完成一个小脚本,你对 SEO 数据的掌控感都会更强。

到这里,你已经完成了从数据读取、清洗、检测、合并到报告导出的完整流程。接下来,把示例 CSV 换成你的真实数据,仔细按照步骤调整字段名和规则。真正的学习,会从你第一次处理自己的脏数据开始。

赏金: 1.99 缘

⚠ 温馨提示: 完成赞赏后 可能有彩蛋哟~

赞赏后可读区
0