你是不是也遇到过这样的场景:月底要汇总几十张 Excel 报表,复制粘贴到手指发酸;领导临时让你把一份 Word 通知批量改成 20 个不同部门;又或者每周都要做一份格式一模一样的 PPT 周报,光是调字体和占位符就耗掉半天。
其实这些活,Python 都能做,而且做起来很快。我之前也是从“只会打开 Excel 手动操作”的阶段过来的,直到有一天被一堆重复性的文档整理工作压到崩溃,才开始认真用 Python 写脚本。今天这篇文章,我把自己实际用过的 Python 操作 Excel、Word、PPT 的思路整理成了一套完整教程,不是只贴接口文档,而是带你从背景概念、环境搭建、实战代码到最终运行效果完整走一遍。
本文适合下面几类读者:
- 工作里经常和 Office 三件套打交道,想提升效率的职场人;
- 刚刚学完 Python 基础,想知道一行行代码到底能解决什么实际问题的同学;
- 被 Excel 函数、Word 宏、PPT 模板折磨过,想换一种更可控的自动化方案的开发者。
读完之后,你可以掌握:用 Python 实现对 Excel 的批量读写与统计、对 Word 文档的批量生成与内容替换、对 PPT 的自动化创建与版式修改,并学会封装脚本的方法。
1. Python 办公自动化到底能帮你做什么
先不急着写代码,我们来理清一个概念。
所谓的“Python 办公自动化”,指的是使用 Python 作为控制工具,操作常见的办公文件格式,比如 Excel 工作簿、Word 文档、PPT 演示文稿,把原来需要在 Office 软件里手动完成的重复操作通过代码自动执行。它不是说让你用 Python 写一个 Office 软件,只是通过代码完成“读写内容、调整格式、批量生成、汇总计算”这一类文档处理动作。
1.1 办公自动化的常见应用场景
我身边比较常见的场景大致有下面几类:
首先是批量格式整理。比如几十个 Excel 表都设置了不同字体、列宽、边框,而汇总方要求统一格式。这种情况下,手动打开每一份文件再调整,不仅慢还容易漏。用 Python 遍历文件,统一设置样式,几秒就能完成。
其次是数据汇总与统计。这也是最刚需的场景。各分店发来销售明细表,需要合并到一张总表里,并且按产品类别或门店名称汇总求和,Python 里的 pandas 处理这种二维表是最顺手的。
然后是批量生成文档。比如给不同客户生成不同合同模板、给不同员工生成录用通知书。这类工作往往是同一个 Word 模板,只有称呼、项目名称、金额、日期等少数字段不一样。用 Python 读取外部数据源,然后循环替换模板里的占位符,就可以批量输出 Word 文件。
还有数据看板与汇报材料生成。从 Excel 读取统计数据后,直接在 PPT 中生成可视化图表页面,或者把关键数据填入固定版式的 PPT 模板页,省掉手工复制数据、重新做图表的时间。
1.2 常用工具库梳理
Python 能处理 Office 文件,依赖的是社区提供的大量第三方库。不同文件类型有对应的核心库:
| 文件类型 | 主要操作库 | 能做什么 |
|---|---|---|
| Excel | openpyxl / pandas / xlsxwriter | 读写 xlsx、批量汇总、格式设置、图表生成,xlsxwriter 适合大量写操作 |
| Word | python-docx | 读取 docx 文本、创建段落、设置字体、插入图片和表格,还可以处理模板占位符替换 |
| PPT | python-pptx | 打开已有 pptx 模板、添加幻灯片、写入文本、设置版式、插入图片和图表 |
| CSV | csv / pandas | 读写逗号分隔或自定义分隔符的文本表格数据 |
| pdfplumber / PyPDF2(新版推荐 pypdf) | 读取 PDF 文字、合并拆分 PDF、提取表格 |
注意一个版本问题:老代码里常见的xlrd在新版本中已经不再支持 xlsx 格式,只支持 .xls,所以现在读取 .xlsx 建议使用openpyxl或pandas格式读写由后端解析引擎完成。
1.3 没有基础能学会吗
我能理解有些读者看到“编程”两个字就头大,但实际上,办公自动化脚本的门槛并不高。你不需要啃很深的数据结构和算法,只需要掌握最基本的语法:变量、列表、字典、for 循环、if 条件、函数定义,然后学会把 Office 操作的 API 按照官网示例“抄下来改一改”。
我把这篇文章写成了一套“照着做”的教程。遇到不懂的地方,你动手跑一遍,多看打印输出,慢慢就能建立起“文件对象—读取方式—写入操作”的完整心智模型。
2. 环境准备与基础配置
工欲善其事,必先利其器。在写自动化脚本之前,先要把 Python 环境和依赖库准备到位。
2.1 安装 Python 解释器
如果你的电脑里还没有 Python,可以先到 Python 官网下载安装包。如果你的操作系统在 Windows 上用,安装时记得勾选最下方的“Add Python to PATH”,这样在命令行中直接输入python才能找到解释器。
安装完成后打开命令行(Windows 下是 CMD 或 PowerShell,macOS / Linux 下是终端),输入下面命令验证:
python --version如果输出类似Python 3.13.x的信息,说明安装成功。
有些朋友电脑上安装过 Anaconda,那里面自带了 Python 和常用的数据分析库,也可以用。
2.2 安装第三方依赖库
本文的示例需要用到这三个核心库:
- openpyxl:处理 Excel .xlsx 文件;
- python-docx:处理 Word .docx 文档;
- python-pptx:处理 PowerPoint .pptx 文件。
使用 pip 安装,这里建议使用国内镜像加速下载:
pip install openpyxl python-docx python-pptx -i https://pypi.tuna.tsinghua.edu.cn/simple如果想做复杂的数据统计,还可以再安装 pandas:
pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple如果你的项目要通过 pip 管理依赖,也可以把库名记录到 requirements.txt 中:
openpyxl==3.1.5 python-docx==1.1.2 python-pptx==1.0.2 pandas==2.2.3然后统一执行:
pip install -r requirements.txt这里的版本号只是举例,实际安装时请以你自己环境中的最新兼容版本为准。依赖版本更新较快,安装时报错时优先检查版本兼容性和网络源是否可用。
2.3 建议使用的开发环境
命令行直接写小脚本没有问题,但如果你要调试批量处理代码,个人还是推荐用一个开发工具,这样能看到变量的实时变化,比如:
- VS Code + Python 插件;
- PyCharm Community Edition;
- Jupyter Notebook(适合练习语法和逐步分析数据表内容)。
我平时最常用的是 VS Code,轻量且免费。创建项目后,建议保持这样的目录结构:
office_auto/ ├── data/ # 存放原始 Excel、Word、PPT 文件 ├── output/ # 存放脚本生成的结果文件 ├── templates/ # 存放模板文件 ├── scripts/ # 存放 Python 脚本 └── requirements.txt # 依赖列表统一把输入文件和输出路径分开管理,后面写脚本时不容易因路径问题混淆。
3. Python 操作 Excel:从打开工作簿到批量汇总统计
Excel 是办公自动化里应用最广的领域。接下来我们先用 openpyxl 从最基础的操作讲起,然后通过一个多文件汇总的案例,把日常办公的真实场景体现出来。
3.1 openpyxl 基础概念
openpyxl 操作 Excel 时分三个层次:
- Workbook:工作簿,对应一个 .xlsx 文件;
- Worksheet:工作表,也就是 Excel 底部一个个 Sheet 标签页;
- Cell:单元格,由行号和列号决定,比如 A1、C3。
常见的打开方式有两种。一种是读取现有文件:
from openpyxl import load_workbook wb = load_workbook("data/sales.xlsx") ws = wb.active # 获取当前活动工作表 print(ws["A1"].value) # 读取 A1 单元格内容如果打开时源 Excel 带格式,并且你没有修改格式的需求,可以加data_only=True读取公式计算后的值:
wb = load_workbook("data/sales.xlsx", data_only=True)另一种方式是新创建一个文件:
from openpyxl import Workbook wb = Workbook() ws = wb.active ws.title = "汇总表" ws["A1"] = "门店名称" ws["A2"] = "华东一店" wb.save("output/新建文件.xlsx")这里的save()代表保存到磁盘,如果目标文件已存在,会被覆盖。写代码时注意,对已有的文件做修改后也必须执行save(),否则不会生效。
3.2 需求描述:多 Excel 合并统计
为了贴近实际场景,我这里设计一个案例:
假设你是一家连锁零售公司的运营助理,公司在华东区有 5 家门店。每个月,每家门店会发来一份销售明细表,列结构统一为:门店名称、商品类别、销售额、销售日期。你的任务是:把这 5 张表合并到一张总表,并统计每个商品类别的总销售额,把结果写入一个新的 Excel 文件。
为了演示方便,我们先写一个脚本自动生成 5 份模拟数据,保存在data/sales/目录下:
# 文件路径:scripts/gen_sales_data.py import os from openpyxl import Workbook os.makedirs("../data/sales", exist_ok=True) stores = ["华东一店", "华东二店", "华东三店", "华东四店", "华东五店"] categories = ["手机", "电脑", "家电", "配件"] samples = [ ["华东一店", "手机", 35000, "2025-12-01"], ["华东一店", "电脑", 78000, "2025-12-02"], ["华东一店", "家电", 21000, "2025-12-03"], ["华东二店", "手机", 22000, "2025-12-01"], ["华东二店", "配件", 8500, "2025-12-02"], ["华东三店", "电脑", 56000, "2025-12-01"], ["华东三店", "家电", 12000, "2025-12-02"], ["华东四店", "手机", 18200, "2025-12-01"], ["华东四店", "电脑", 43000, "2025-12-02"], ["华东五店", "家电", 9900, "2025-12-01"], ] for idx, store in enumerate(stores, start=1): wb = Workbook() ws = wb.active ws.title = "销售明细" ws.append(["门店名称", "商品类别", "销售额", "销售日期"]) for row in samples: if row[0] == store: ws.append(row) elif idx == 3 and row[0] == "华东三店": # 给其中一份文件加几行示例数据 pass # 为了让示例文件空一点,这里直接每个文件写 5 行统一数据,最后保留完整测试数据 # 重新按门店循环写入 ws.delete_rows(1, ws.max_row) header = ["门店名称", "商品类别", "销售额", "销售日期"] ws.append(header) for row in samples: ws.append(row) wb.save(f"../data/sales/{store}_销售明细.xlsx") print("模拟数据生成完成")上面的脚本逻辑其实有一点重复:先写入再删除,只是为了展示delete_rows的使用方式。如果你自己写生成脚本,可以更简洁:
for store in stores: wb = Workbook() ws = wb.active ws.append(["门店名称", "商品类别", "销售额", "销售日期"]) for row in samples: ws.append(row) wb.save(f"../data/sales/{store}_销售明细.xlsx")无论如何,最终我们应该得到 5 个结构一致的数据文件。这非常重要——只有当输入文件的列结构一致时,合并脚本才不需要做额外字段映射。
3.3 编写 Excel 汇总脚本
真正干活的脚本,可以拆成三步:
- 遍历目标目录下所有 .xlsx 文件;
- 用 openpyxl 逐个读取 Sheet 中从第 2 行开始的数据;
- 把数据添加到总表,然后使用字典按“商品类别”累加销售额。
完整代码如下:
# 文件路径:scripts/merge_sales.py import os import glob from openpyxl import load_workbook, Workbook SALES_DIR = "../data/sales" OUTPUT_DIR = "../output" def get_all_sales_files(): pattern = os.path.join(SALES_DIR, "*.xlsx") return glob.glob(pattern) def merge_sales(): os.makedirs(OUTPUT_DIR, exist_ok=True) all_rows = [] category_sum = {} files = get_all_sales_files() for file_path in files: wb = load_workbook(file_path, data_only=True) ws = wb.active # 从第二行开始读取,跳过表头 for row in ws.iter_rows(min_row=2, values_only=True): store_name, category, amount, date_text = row if category is None: continue all_rows.append([store_name, category, amount, date_text]) # 统计商品类别销售额 category_sum[category] = category_sum.get(category, 0) + amount wb.close() # 写入合并明细 wb_out = Workbook() ws_detail = wb_out.active ws_detail.title = "合并明细" ws_detail.append(["门店名称", "商品类别", "销售额", "销售日期"]) for row in all_rows: ws_detail.append(row) # 写入统计结果 ws_summary = wb_out.create_sheet("分类统计") ws_summary.append(["商品类别", "总销售额"]) for category, total in category_sum.items(): ws_summary.append([category, total]) output_path = os.path.join(OUTPUT_DIR, "汇总统计.xlsx") wb_out.save(output_path) print(f"合并完成,共读取 {len(files)} 个文件,总行数 {len(all_rows)} 行") print(f"结果已保存到:{output_path}") if __name__ == "__main__": merge_sales()代码里用到了iter_rows(min_row=2, values_only=True),这里的values_only=True会直接返回每个单元格的值,而不返回单元格对象,遍历更高效。
读取时还有一个细节值得注意:data_only=True只适用于文件里的公式已经被 Excel 计算过并缓存了结果的情况。如果源文件是代码生成的,且单元格是直接写入的数值,那无论是否加data_only都能读到数值。
执行脚本:
cd scripts python merge_sales.py运行预期:
合并完成,共读取 5 个文件,总行数 50 行 结果已保存到:../output/汇总统计.xlsx打开生成的汇总文件,你会看到两个工作表:“合并明细”里是所有门店数据按顺序追加的完整表,“分类统计”里已经有按手机、电脑、家电、配件分组求和后的结果了。
3.4 Excel 自动化进阶提示
上面只是入门级汇总,实际工作中的 Excel 自动化还会涉及很多场景,常用的处理方向大概是下面这几个:
- 单元格格式设置:字体、颜色、对齐方式、边框,可以使用
openpyxl.styles.Font / Alignment / Border。 - 合并单元格与冻结窗格:
ws.merge_cells("A1:C1"),ws.freeze_panes = "A2"。 - 条件判断与公式写入:可以直接把 Excel 公式字符串赋给单元格,比如
ws["C2"] = "=A2+B2"。 - 图表插入:
openpyxl.chart.BarChart可以把分类汇总结果直接做成柱状图。 - 超大批量文件处理:如果文件非常多,建议用 pandas 批量读取并拼接,内存管理比手工循环更高效。
如果你连一个 Excel 都不需要保留格式,只做数据提取,pandas 一行读取就够:
import pandas as pd df = pd.read_excel("../data/sales/华东一店_销售明细.xlsx") print(df.head())然后所有分组聚合逻辑都可以基于 DataFrame 完成:
summary = df.groupby("商品类别")["销售额"].sum().reset_index() summary.to_excel("../output/pandas_summary.xlsx", index=False)具体选 openpyxl 还是 pandas,取决于你的目标:如果重点是保留原格式修改和样式设置,选 openpyxl;如果重点是数据整理和统计分析,pandas 更顺手。
4. Python 操作 Word:从模板占位符到批量生成合同
Word 自动化的思路和 Excel 很不一样。Excel 核心是数据表处理,Word 核心是段落与排版。python-docx 是一个操作 .docx 文档的库,它不能运行 Word VBA,也不能操作 .doc(老格式),但它能把文本写入段落、设置样式、插入表格和图片。
4.1 先理解 python-docx 文档模型
python-docx 的模型可以这样理解:
- Document:代表一个 Word 文档,对应 .docx 文件;
- Paragraph:段落对象,Word 中回车形成一段;
- Run:段内具有相同样式的一段连续文本,同一个段落可以由多个 Run 组成;
- Table:表格对象,类似 Excel 的工作表,通过行列访问单元格。
一个最小示例,创建一个文档并添加标题和段落:
from docx import Document doc = Document() doc.add_heading("部门会议通知", level=1) doc.add_paragraph("请各部门负责人准时参加。") doc.save("../output/通知示例.docx")4.2 Word 文档中替换文本时要注意 Run 问题
在实践中,最容易让新手困惑的地方在于:docx 库不能直接像字符串替换那样把你想要的关键词精确替换,因为 Word 的正文会按格式拆分成多个 Run,例如字体不同、加粗位置不同都可能导致文本被拆开。如果你直接遍历paragraph.text判断包含关系,再把整个段落文本重新赋值,可能造成样式丢失。
一种可靠的做法是:读取某个文件前,先把模板中需要替换的文本用相同的字符样式书写,并使用占位符,比如{公司名称}、{项目金额}、{生效日期}。然后遍历段落中的runs,把包含占位符的 Run 做局部替换。
下面是一个更稳定的替换方案:
def replace_placeholder_in_paragraph(paragraph, old_text, new_text): if old_text not in paragraph.text: return False for run in paragraph.runs: if old_text in run.text: run.text = run.text.replace(old_text, new_text) return True # 如果占位符被拆到多个 run 中,说明模板制作需要优化 return False这个方案能处理绝大多数情况,但前提是:模板制作用的是可以整体匹配的占位符,且没有把一个占位符拆散成多个 Run。如果遇到实在拆散的模板,更稳妥的办法是重构模板,把占位符所在的段落作为一个整体重新赋值。
4.3 需求描述:批量生成录用通知
假设你需要给 10 位新员工发送不同内容的录用通知书。每个人的姓名、岗位、薪资、入职日期不同,其余内容相同。
准备一个 Word 模板templates/offer_template.docx,内容如下:
录用通知书 尊敬的 {姓名} 先生/女士: 恭喜您通过面试,您已被我司录用。 具体信息如下: 岗位:{岗位} 试用期薪资:{薪资} 元/月 入职日期:{入职日期} 请您携带相关材料于入职当天上午 9:00 到公司办理手续。然后编写以下脚本:
# 文件路径:scripts/batch_offer.py import os from docx import Document TEMPLATE_PATH = "../templates/offer_template.docx" OUTPUT_DIR = "../output/offers" employees = [ {"姓名": "张伟", "岗位": "Python 开发工程师", "薪资": "15000", "入职日期": "2025-03-03"}, {"姓名": "李娜", "岗位": "测试工程师", "薪资": "12000", "入职日期": "2025-03-05"}, {"姓名": "王强", "岗位": "产品经理", "薪资": "18000", "入职日期": "2025-03-10"}, {"姓名": "赵敏", "岗位": "运维工程师", "薪资": "13500", "入职日期": "2025-03-12"}, {"姓名": "陈晨", "岗位": "前端开发工程师", "薪资": "14000", "入职日期": "2025-03-15"}, ] def replace_placeholder(paragraph, old_text, new_text): for run in paragraph.runs: if old_text in run.text: run.text = run.text.replace(old_text, new_text) def generate_offer(employee_info): os.makedirs(OUTPUT_DIR, exist_ok=True) doc = Document(TEMPLATE_PATH) for paragraph in doc.paragraphs: replacements = { "{姓名}": employee_info["姓名"], "{岗位}": employee_info["岗位"], "{薪资}": employee_info["薪资"], "{入职日期}": employee_info["入职日期"], } for key, value in replacements.items(): replace_placeholder(paragraph, key, value) output_path = os.path.join(OUTPUT_DIR, f"{employee_info['姓名']}_录用通知.docx") doc.save(output_path) print(f"已生成:{output_path}") if __name__ == "__main__": for emp in employees: generate_offer(emp)脚本流程很清楚:加载模板文档,遍历所有段落在每个段落内完成四组占位符替换,最后保存新文件。对于 10 个员工,只要循环 10 次即可。
运行:
python batch_offer.py到output/offers/目录可以看到已经生成 5 份录用通知。用 Word 打开查看,正文中的占位符都被替换成了员工的实际信息。
这里值得提醒:模板文件的命名、存储路径以及文本里的花括号都需要保持统一,否则脚本可能找不到需要替换的文本。处理前建议先备份原始模板文件。
4.4 Word 中操作表格
Office Word 实际工作中经常还要操作表格。在 python-docx 中,可以通过doc.tables访问文档中的所有表格:
from docx import Document doc = Document("../output/offers/张伟_录用通知.docx") for table in doc.tables: for row in table.rows: for cell in row.cells: print(cell.text) cell.text = cell.text.replace("旧值", "新值") doc.save("替换表格内容.docx")写新的表格同样也很方便:
doc = Document() table = doc.add_table(rows=2, cols=3) table.style = "Table Grid" # 加上表格线条 table.cell(0, 0).text = "姓名" table.cell(0, 1).text = "岗位" table.cell(0, 2).text = "入职日期" doc.save("../output/新表格.docx")5. Python 操作 PPT:从空白演示文稿到页面批量生成
PPT 自动化用到的工具是 python-pptx。它的编程模型与 Word 类似,但也有自己的词汇:Presentation 对应一个 .pptx 文件,Slide 对应一页幻灯片,Shape 是页面上的形状,Placeholder 是占位符,Layout 是母版提供的版式。
5.1 python-pptx 的基本读取与写入
打开已有 PPT 模板并读取每页文本信息:
from pptx import Presentation prs = Presentation("../templates/weekly_report_template.pptx") for slide in prs.slides: print("---- 当前页 ----") for shape in slide.shapes: if shape.has_text_frame: for paragraph in shape.text_frame.paragraphs: text = "".join(run.text for run in paragraph.runs) if text.strip(): print(text)创建一页完全空白的演示文稿,并写入标题与内容:
from pptx import Presentation from pptx.util import Inches, Pt from pptx.dml.color import RGBColor prs = Presentation() slide = prs.slides.add_slide(prs.slide_layouts[1]) # 标题和内容版式 slide.shapes.title.text = "Python 办公自动化实战" title_shape = slide.shapes.title body_shape = slide.placeholders[1] body_shape.text = "Excel / Word / PPT 三合一" prs.save("../output/pptx_demo.pptx")看上去是不是很简单?真正复杂的点在于排版位置、字号、颜色和对齐方式,这些都涉及坐标和样式的设置。
5.2 需求描述:自动生成周报 PPT
假设有个产品运营岗位,每周要按同样的逻辑生成一份周报 PPT,包含 3 页内容:
- 封面页:标题“XX 产品运营周报”,副标题为当前日期;
- 数据页:本周新增用户数、活跃用户数、转化率三个关键指标;
- 图表页:新增用户数近 7 日趋势柱状图。
python-pptx 自带的图表插入接口可以很好地满足第三点;图表本身会嵌入 PPT,编辑时和手动插入的图表行为一致。
5.3 批量生成周报完整脚本
先制作一个周报数据 JSON 或 Python 字典:
report_data = { "title": "知识星球产品运营周报", "report_date": "第 10 周(2025-03-03 至 2025-03-09)", "metrics": [ {"name": "新增用户", "value": 22130}, {"name": "活跃用户", "value": 45678}, {"name": "付费转化率", "value": "8.6%"}, ], "trend_dates": ["周一", "周二", "周三", "周四", "周五", "周六", "周日"], "trend_values": [2500, 3200, 2900, 4100, 3800, 4600, 5300], }完整脚本:
# 文件路径:scripts/build_ppt_report.py from pptx import Presentation from pptx.util import Inches, Pt from pptx.chart.data import CategoryChartData from pptx.enum.chart import XL_CHART_TYPE from pptx.dml.color import RGBColor report_data = { "title": "知识星球产品运营周报", "report_date": "第 10 周(2025-03-03 至 2025-03-09)", "metrics": [ {"name": "新增用户", "value": 22130}, {"name": "活跃用户", "value": 45678}, {"name": "付费转化率", "value": "8.6%"}, ], "trend_dates": ["周一", "周二", "周三", "周四", "周五", "周六", "周日"], "trend_values": [2500, 3200, 2900, 4100, 3800, 4600, 5300], } def add_report_cover(prs): slide = prs.slides.add_slide(prs.slide_layouts[0]) # 标题版式 slide.shapes.title.text = report_data["title"] slide.placeholders[1].text = report_data["report_date"] def add_metrics_slide(prs): slide = prs.slides.add_slide(prs.slide_layouts[1]) slide.shapes.title.text = "核心指标" body = slide.placeholders[1] text_frame = body.text_frame text_frame.clear() for idx, metric in enumerate(report_data["metrics"]): p = text_frame.paragraphs[0] if idx == 0 else text_frame.add_paragraph() p.text = f'{metric["name"]}:{metric["value"]}' p.font.size = Pt(28) p.font.color.rgb = RGBColor(0x2F, 0x54, 0x96) def add_trend_chart_slide(prs): slide = prs.slides.add_slide(prs.slide_layouts[5]) # 仅标题版式 slide.shapes.title.text = "近 7 日新增用户趋势" chart_data = CategoryChartData() chart_data.categories = report_data["trend_dates"] chart_data.add_series("新增用户", report_data["trend_values"]) graphic_frame = slide.shapes.add_chart( XL_CHART_TYPE.COLUMN_CLUSTERED, Inches(1), Inches(2), Inches(8), Inches(5), chart_data ) def main(): prs = Presentation() add_report_cover(prs) add_metrics_slide(prs) add_trend_chart_slide(prs) output_path = "../output/运营周报.pptx" prs.save(output_path) print(f"PPT 周报已生成:{output_path}") if __name__ == "__main__": main()运行后生成的 PPT 页面有三张。第二页的核心指标虽然能显示数据,但目前是普通文本,如果你想要更醒目的数字卡片效果,你可以使用文本框+形状填充来绘制卡片。
5.4 python-pptx 效果优化点
如果你不只是做一个“能带文字的 PPT”,而是想做得更像人肉手工做的,后面几个方向值得搞一搞:
- 使用现成模板,不新建空白 Presentation,而是
Presentation("../templates/公司模板.pptx"); - 设置字体、颜色、行距和对齐:
paragraph.alignment = PP_ALIGN.CENTER; - 不直接操作占位符 index,而是通过
slide_layout.placeholders确认 placeholder 名称; - 利用
add_picture()插入从 Excel 生成的图表或图片,比如把 pandas 生成的 matplotlib 统计图嵌入到 PPT 页; - 批量生成时先遍历模板页数,确认版式里 title 占位符存在,避免索引越界。
6. 综合实战:Excel 数据统计后导入 Word 报告并输出 PPT
有时候 Excel、Word、PPT 不能完全割裂开。工作中更常见的是一条链式的处理流程:数据在 Excel 里 → 整理成表格或图表 → 放进 Word 汇总报告 → 再提炼几页 PPT。
下面这个综合小项目,把 Excel 的统计结果写入一个 Word 报告文档,同时生成一页 PPT 概要页。这也是很多自动化场景的通用模板。
6.1 需求说明
从output/汇总统计.xlsx里读取“分类统计”工作表,把分类名称和总销售额按表格形式写到 Word 报告里;然后把销售额最高的分类名称和数值写到 PPT 封面页下面的正文里。
6.2 核心代码:跨文件自动化串联
# 文件路径:scripts/pipeline_report.py import os from openpyxl import load_workbook from docx import Document from pptx import Presentation from pptx.util import Pt DATA_FILE = "../output/汇总统计.xlsx" WORD_OUTPUT = "../output/销售分析报告.docx" PPT_OUTPUT = "../output/销售概要.pptx" def read_summary(): wb = load_workbook(DATA_FILE, data_only=True) ws = wb["分类统计"] rows = [] for row in ws.iter_rows(min_row=2, values_only=True): if row[0]: rows.append(row) wb.close() return rows def write_word_report(summary_rows): doc = Document() doc.add_heading("月度销售分析报告", level=1) table = doc.add_table(rows=1, cols=2) table.style = "Table Grid" hdr = table.rows[0].cells hdr[0].text = "商品类别" hdr[1].text = "总销售额" for category, total in summary_rows: row_cells = table.add_row().cells row_cells[0].text = str(category) row_cells[1].text = str(total) doc.add_paragraph("") doc.add_paragraph("说明:以上数据来自各门店上报的销售明细合并结果。") doc.save(WORD_OUTPUT) print(f"Word 报告已生成:{WORD_OUTPUT}") def write_ppt_summary(summary_rows): top_category, top_total = max(summary_rows, key=lambda x: x[1] or 0) prs = Presentation() slide = prs.slides.add_slide(prs.slide_layouts[0]) slide.shapes.title.text = "销售简报" sub = slide.placeholders[1] sub.text = f"本月销售额最高的类别:{top_category},总销售额 {top_total} 元" prs.save(PPT_OUTPUT) print(f"PPT 概要已生成:{PPT_OUTPUT}") if __name__ == "__main__": rows = read_summary() write_word_report(rows) write_ppt_summary(rows)执行脚本后,Excel → Word → PPT 的三步骤自动完成,中间不需要任何人工操作。
这个例子看起来简单,但它代表了一种非常实用的思维方式:先梳理业务流程,确定数据从哪里来、结果要到哪里去,再把每一步拆成一个函数,最后用主函数串联。真实的办公自动化项目基本都遵循这个套路。
7. 常见报错与问题排查
这部分是我在实际使用 Python 办公自动化过程中反复遇到的问题,整理成一个速查表,方便你在跑代码时快速定位。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
ModuleNotFoundError: No module named 'openpyxl' | 没有安装依赖库或装到了别的 Python 环境 | 执行pip install openpyxl,用python -m pip检查当前环境 |
| 读取 Excel 时发现读不到公式结果 | 文件从未用 Excel 打开过,公式没有缓存结果 | 使用data_only=True之前,先确认源文件确实有被 Excel 计算过一次;不可靠时改用公式计算逻辑 |
| 生成的 Word 文档占位符没有被替换 | 文字被拆在多个 Run 中 | 重新整理模板,修改段落的 runs 或直接逐 Run 替换 |
| 运行脚本后找不到输出文件 | 脚本当前工作目录与代码里的相对路径不一致 | 使用绝对路径,或先os.chdir()切换到项目根目录;也可以基于__file__拼接路径 |
| openpyxl 无法读取 .xls 老文件 | openpyxl 只支持 .xlsx | 先把 .xls 转换为 .xlsx,或用 pandas + xlrd(xlrd 仅支持 .xls 新版本) |
| python-docx 创建的文档打不开 | 保存路径不存在,或文件正在被 Word 占用 | 先确保目录已创建;关闭已打开的 Word 再重新运行 |
| pptx 出现 placeholder index 越界 | 模板版式没有对应的占位符位置 | 改用placeholder.idx遍历,或先检查版式占位符存在性 |
| 批量处理文件时内存占用过高 | 大量读取 Excel 后没有及时关闭工作簿 | 读取完及时执行wb.close(),或按文件分批处理 |
| 中文文件名乱码 | 脚本文件本身不是 UTF-8 编码 | 用支持 UTF-8 编码的编辑器保存脚本;路径中包含中文时避免硬编码 |
额外的排查建议:
- 修改代码时保留最小复现文件,日志里多打印
文件路径与当前工作表名称,这样可以快速定位是路径问题还是内容问题。 - 第一次处理正式数据前,先用一两份模拟数据跑通流程,再批量执行。涉及正式合同、财务报表时,尤其建议在测试目录验证。
8. 格式与样式设置:Python 办公自动化的“面子工程”
代码能写入文本和数值之后,很多朋友会遇到下一个需求:“我想要生成的文件看起来像人做的,而不是像纯文本倒进去的。”
这类格式设置,在三个库里分别对应不同的对象:
8.1 Excel 单元格格式美化
openpyxl 中,设置字体、背景色和对齐方式常用到 styles 子模块:
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side wb = Workbook() ws = wb.active # 标题行样式 font_title = Font(name="微软雅黑", size=12, bold=True, color="FFFFFF") fill_title = PatternFill(start_color="2F5496", end_color="2F5496", fill_type="solid") alignment_center = Alignment(horizontal="center", vertical="center") ws["A1"] = "商品类别" ws["A1"].font = font_title ws["A1"].fill = fill_title ws["A1"].alignment = alignment_center # 设置列宽 ws.column_dimensions["A"].width = 20 # 设置行高 ws.row_dimensions[1].height = 28 # 给边框 thin_border = Border( left=Side(style="thin"), right=Side(style="thin"), top=Side(style="thin"), bottom=Side(style="thin"), ) ws["A1"].border = thin_border8.2 Word 文本样式
python-docx 中可以使用doc.styles、paragraph.style或直接运行字体设置:
from docx.shared import Pt, RGBColor doc = Document() p = doc.add_paragraph("这是一段红色加粗的示例文字。") run = p.runs[0] run.font.bold = True run.font.size = Pt(16) run.font.color.rgb = RGBColor(0xFF, 0x00, 0x00) run.font.name = "微软雅黑"8.3 PPT 文本框样式
PPT 在生成幻灯片时,重点是掌握pt(磅)和Inches单位的换算使用。
from pptx.util import Inches, Pt from pptx.dml.color import RGBColor left = Inches(1) top = Inches(1.5) width = Inches(6) height = Inches(1) textbox = slide.shapes.add_textbox(left, top, width, height) tf = textbox.text_frame tf.text = "我是标题内容" p = tf.paragraphs[0] p.font.size = Pt(18) p.font.bold = True p.font.color.rgb = RGBColor(0x2F, 0x54, 0x96)格式处理如果需求比较复杂,比如需要批量处理多个带样式文件的模板,建议把模板先人工做成标准样式,再由脚本对需要变化的字段做局部替换,这样比完全用代码从零设置格式稳定很多。
9. 工程化与扩展:如何提升办公自动化脚本的稳定性
做完一个真实业务之后,就有必要跳出“跟代码”的思维,想让自动化这套东西运到更稳、跑得时间更久,要有几个工程层面的调整。
9.1 用配置文件代替硬编码
我最早写脚本时,文件路径、替换文字等参数都直接写在代码里。这种脚本今天能用,明天换了路径就要改代码,一旦上线给同事用,就会变成“只有我能运行的程序”。
建议把路径和参数放到配置文件里,比如使用一个config.yaml:
paths: data_dir: ./data/sales output_dir: ./output template_file: ./templates/offer_template.docx replace_fields: 公司名称: 示例科技有限公司 部门: 技术部然后在脚本中读取配置文件:
import yaml def load_config(path="config.yaml"): with open(path, "r", encoding="utf-8") as f: return yaml.safe_load(f)这样做的好处是:字段更新、目录变更都不需要修改代码逻辑。
9.2 日志输出与断点续跑
当文件数量达到几百上千时,脚本跑得再快也可能因为个别文件格式不合法而中断。这里有一个很实际的经验:
- 单个文件处理先用
try-except捕获异常,把失败文件名记录到日志; - 成功后把结果写到 “处理成功.txt”,失败写进 “失败清单.txt”;
- 脚本运行结束后查看失败清单,再修问题重跑失败文件。
这样就不会因为遇到一个损坏文件而所有数据都要重来。
import logging logging.basicConfig( filename="../logs/auto.log", level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s", ) def process_one(file_path): try: # 业务处理逻辑 pass except Exception as exc: logging.error(f"处理失败:{file_path},原因:{exc}")9.3 GUI 化或命令行化
如果脚本是给非技术人员使用的,可以考虑做一个简单的命令行交互或桌面小工具。用argparse可以在命令行接收参数:
import argparse parser = argparse.ArgumentParser(description="Excel 汇总工具") parser.add_argument("--data-dir", required=True, help="原始数据目录") parser.add_argument("--output", default="output/result.xlsx", help="输出文件路径") args = parser.parse_args() print(args.data_dir, args.output)也可以使用 tkinter 做一个极简文件选择器,让同事点选目录就能运行。但如果仅给自己用,其实保持 Python 脚本命令行运行是最轻量的。
9.4 文件备份与二次确认
办公自动化操作真实数据时,最怕的是覆盖重要文件。有几个习惯值得从一开始就养成:
- 正式执行前先备份原始文件目录;
- 脚本中尽量避免覆盖源文件,尽可能把结果输出到
output/目录; - 批量删除或写入前增加确认提示,比如输入
yes才继续; - 对 Excel 的修改操作,建议先
load_workbook后复制一份副本.xlsx再处理。
10. 总结与下一步学习建议
本文从一个相对完整的实践视角,带你走完了 Python 操作 Excel、Word、PPT 的核心链路。现在做个简单的梳理:
- 在 Excel 方面,掌握了 openpyxl 的加载工作簿、读取单元格、写入数据、保存文件的完整流程,并通过多 Excel 合并统计样例,理解遍历文件、合并数据和分组统计的组合实现方式。
- 在 Word 方面,掌握了 python-docx 的操作模型,学会了如何把模板 Word 文档中的占位符批量替换成不同人员的信息,也了解了处理表格文件的基础方法。
- 在 PPT 方面,掌握了 python-pptx 的创建、写入文本、插入简单柱状图的流程,并尝试把真实数据变成可演示的周报页面。
- 在工程层面,你能体会到脚本不应一次性写完就废弃,尽可能把路径抽成配置,加入日志、备份和异常处理,才能在真实工作中持续复用。
后面的学习建议,可以按几条路线往前走:
第一条,深入数据清洗与分析。如果你希望接手更复杂的 Excel 表格,建议多练 pandas 的 groupby、pivot_table、merge,这些函数解决复杂业务报表时非常高效。
第二条,深入 Word 与 PPT 模板制作。学习如何制作稳定、适配脚本替换的 Office 模板,合理设计段落样式、母版占位符,就能让最终产物有更好的视觉效果,也能减少脚本的临时处理逻辑。
第三条,学习定时调度。如果需要每天定时跑一次报表,可以先学习 Windows 任务计划程序或 Linux 上的 cron,把 Python 脚本配置为每日执行,实现零手工干预的自动化。
第四条,探索其他文件格式。CSV、JSON、PDF 都是办公数据流转的常见格式,遇到 PDF 抽取表格或批量合并场景时,可以补充了解 pdfplumber 等库。
动手建议也很简单:从你手头最重复、最无聊的那张 Excel 表开始,用 Python 写一个小脚本,尝试把第一版跑通。不用管代码写得是否优雅,只要运行成功一次,你后续的学习动力就会不一样。
如果本文中的示例代码对你的工作有帮助,可以对照实际文件结构适当修改直接使用。也建议你在本地准备一个练习文件夹,把代码亲手敲一遍、运行一遍,理解每一段代码为什么这么写。这样从“看得懂例子”到“自己写自动化工具”的过渡才真正完成。