- 为什么需要程序化操作 Word
在很多业务场景中,我们需要批量生成格式统一的 Word 报告、合同、标书或证书。手动复制粘贴不仅效率低下,还容易出错。使用 Python 可以:
-
从数据库/Excel 中读取数据,动态填入 Word 模板
-
批量替换文档中的占位符
-
自动生成结构化的表格和图表
-
将大量文本信息快速整理成标准排版
-
实现办公流程自动化,节省 90% 以上的重复操作时间
Python 操作 Word 的主流库是 python-docx,它可以在不使用 Microsoft Word 应用程序的情况下创建、修改 .docx 文件,跨平台且性能优越。
2. 环境准备与库安装
确保你的 Python 版本 ≥ 3.7。安装核心库:
bash
pip install python-docx
# 如果需要转 PDF(推荐两种方式之一)
pip install docx2pdf # 跨平台,但依赖系统 Word 或 LibreOffice(Windows/macOS 下常用)
pip install pywin32 # 仅 Windows,调用 MS Word 应用程序
验证安装:
bash
import docx
print(docx.__version__)
输出信息:
3. 入门:创建你的第一个 Word 文档
我们从零开始生成一个文档,并向其中添加内容。
bash
from docx import Document
# 创建一个文档对象
doc = Document()
# 添加标题 (默认样式为 'Title')
doc.add_heading('Python Word 操作入门', level=1)
# 添加段落
doc.add_paragraph('这是第一个用 Python 生成的 Word 文档。')
# 保存文档
doc.save('01_hello.docx')
print("文档已生成:01_hello.docx")
输出信息:
打开生成的文档,你会看到大标题和一行普通文字。add_paragraph 还可以传入第二个参数指定样式,例如:
bash
doc.add_paragraph('一段重要的提示', style='Intense Quote')
读取已有文档
bash
doc = Document('01_hello.docx')
for para in doc.paragraphs:
print(para.text)
输出信息:
bash
Python Word 操作入门
这是第一个用 Python 生成的 Word 文档。
关键点:
-
Document()创建一个新文档,传入路径则打开已有文件。 -
paragraphs属性返回文档中所有段落对象,text属性获取文本。 -
标题、列表项等本质上也是段落,只是应用了不同的样式。
4. 段落操作:增删改查与样式设置
段落是文档的基本单元。我们可以精细控制对齐方式、行间距、缩进等。
4.1 段落对齐与间距
bash
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Pt, Inches
doc = Document()
para1 = doc.add_paragraph('居中对齐的段落')
para1.alignment = WD_ALIGN_PARAGRAPH.CENTER
para2 = doc.add_paragraph('右对齐,行间距 1.5 倍,段前 12 磅, 段后 6 磅。')
para2.alignment = WD_ALIGN_PARAGRAPH.RIGHT
para_format = para2.paragraph_format
para_format.line_spacing = 1.5
para_format.space_before = Pt(12)
para_format.space_after = Pt(6)
para3 = doc.add_paragraph('首行缩进 0.5 英寸的段落。' * 5)
para3.paragraph_format.first_line_indent = Inches(0.5)
doc.save('02_paragraph_format.docx')
print("段落格式示例已生成:02_paragraph_format.docx")
输出信息:段落格式示例已生成:02_paragraph_format.docx
参数说明:
-
WD_ALIGN_PARAGRAPH.LEFT/RIGHT/CENTER/JUSTIFY控制水平对齐。 -
line_spacing可设置为浮点数(倍数)或具体Pt值(固定值)。 -
space_before/space_after段前段后间距,first_line_indent首行缩进。
4.2 添加换行与分页
bash
para = doc.add_paragraph('第一行')
para.add_run('\n第二行(在同一个段落中换行)')
doc.add_page_break() # 手动分页
doc.add_paragraph('新一页的内容')
5. Run 与字体:精细到文字的格式控制
一个段落由多个 Run 对象组成。Run 是相邻的、具有相同格式的文本块。通过它,我们可以为同一段落中的不同文字设置不同的字体、颜色、加粗等。
bash
from docx.shared import Pt, RGBColor
from docx import Document
doc = Document()
p = doc.add_paragraph()
# 添加多个 Run
run1 = p.add_run('正常文字 ')
run2 = p.add_run('加粗红色 ')
run2.bold = True
run2.font.color.rgb = RGBColor(0xFF, 0x00, 0x00)
run2.font.size = Pt(14)
run3 = p.add_run('斜体下划线')
run3.italic = True
run3.underline = True
run3.font.name = 'Arial'
doc.save('03_run_format.docx')
print("Run 格式示例已生成:03_run_format.docx")
输出信息:Run 格式示例已生成:03_run_format.docx
常用字体属性
bash
from docx.shared import Pt
from docx.enum.text import WD_UNDERLINE
run = p.add_run('示例文本')
run.font.name = '黑体'
run.font.size = Pt(12)
run.font.bold = True
run.font.italic = True
run.font.underline = WD_UNDERLINE.DOT_DASH # 点划线型下划线
run.font.color.rgb = RGBColor(0, 51, 153)
run.font.highlight_color = WD_COLOR_INDEX.YELLOW # 需导入 WD_COLOR_INDEX
打印 Run 内容:
bash
for para in doc.paragraphs:
for run in para.runs:
print(f"文本: {run.text} | 粗体: {run.bold} | 字体: {run.font.name}")
输出示例:
bash
文本: 正常文字 | 粗体: None | 字体: None
文本: 加粗红色 | 粗体: True | 字体: 黑体
文本: 斜体下划线 | 粗体: None | 字体: Arial
注意:未显式设置字体名称时,
run.font.name可能返回None,表示继承所在样式。
6. 表格实战:从创建到复杂排版
python-docx 提供了灵活的表格 API,支持创建、合并单元格、设置样式等。
6.1 创建表格并填充数据
bash
doc = Document()
doc.add_heading('员工信息表', level=2)
# 创建 4 行 3 列的表格
table = doc.add_table(rows=4, cols=3, style='Table Grid')
# 表头
headers = ['姓名', '部门', '工龄']
for i, header in enumerate(headers):
cell = table.cell(0, i)
cell.text = header
# 表头加粗
for paragraph in cell.paragraphs:
for run in paragraph.runs:
run.bold = True
# 数据
data = [
['张三', '研发部', '3'],
['李四', '市场部', '5'],
['王五', '财务部', '2']
]
for row_idx, row_data in enumerate(data, start=1):
for col_idx, cell_text in enumerate(row_data):
table.cell(row_idx, col_idx).text = cell_text
doc.save('04_table.docx')
print("表格已生成:04_table.docx")
6.2 合并单元格与调整列宽
bash
# 接上面代码,在已创建的表格上操作
# 合并第一行的前两列
a = table.cell(0, 0)
b = table.cell(0, 1)
a.merge(b)
a.text = '基本信息(合并单元格)'
# 设置列宽
from docx.shared import Cm
for cell in table.columns[0].cells:
cell.width = Cm(4)
for cell in table.columns[1].cells:
cell.width = Cm(4)
for cell in table.columns[2].cells:
cell.width = Cm(2)
doc.save('04_table_merged.docx')
print("合并单元格表格已生成")
6.3 逐行添加、删除行
bash
# 动态添加行
row = table.add_row()
row.cells[0].text = '赵六'
row.cells[1].text = '行政部'
row.cells[2].text = '1'
# 删除最后一行(如果不需要)
# table._tbl.remove(table.rows[-1]._tr) # 内部方法,谨慎使用
打印表格内容验证:
bash
for row in table.rows:
for cell in row.cells:
print(cell.text, end='\t')
print()
输出:
bash
基本信息(合并单元格) 部门 工龄
张三 研发部 3
李四 市场部 5
王五 财务部 2
赵六 行政部 1
7. 图片与超链接:让文档图文并茂
7.1 插入图片并控制尺寸
bash
from docx.shared import Inches
doc = Document()
doc.add_paragraph('下方是一张示例图片(请确保图片文件存在):')
# 插入内联图片
doc.add_picture('python_logo.png', width=Inches(2), height=Inches(1.2))
# 只设宽度时高度自动等比例缩放
doc.add_picture('chart.png', width=Inches(4))
doc.save('05_image.docx')
print("图片文档已生成")
add_picture 常用参数:
-
width/height:指定尺寸,若只指定一个,另一个按比例计算。 -
单位可用
Inches,Cm,Pt等。
7.2 添加超链接
python-docx 没有直接提供独立的超链接函数,但我们可以通过添加具有超链接样式的段落,并附加关系来实现。推荐方法:
bash
from docx.oxml.ns import qn
import docx
def add_hyperlink(paragraph, text, url):
"""为段落添加超链接"""
part = paragraph.part
r_id = part.relate_to(url, docx.opc.constants.RELATIONSHIP_TYPE.HYPERLINK, is_external=True)
hyperlink = docx.oxml.shared.OxmlElement('w:hyperlink')
hyperlink.set(qn('r:id'), r_id)
new_run = docx.oxml.shared.OxmlElement('w:r')
rPr = docx.oxml.shared.OxmlElement('w:rPr')
c = docx.oxml.shared.OxmlElement('w:rStyle')
c.set(qn('w:val'), 'Hyperlink')
rPr.append(c)
new_run.append(rPr)
new_run.text = text
hyperlink.append(new_run)
paragraph._p.append(hyperlink)
return hyperlink
doc = Document()
p = doc.add_paragraph('访问 ')
add_hyperlink(p, 'Python 官网', 'https://www.python.org')
doc.save('06_hyperlink.docx')
print("超链接文档已生成")
执行后,段落中的"Python 官网"就会显示为蓝色下划线超链接。
8. 页面控制:分节符、页眉页脚与页码
一个 Word 文档可以包含多个节(Section),每个节可以独立设置页面尺寸、方向、页眉页脚等。
8.1 分节与页面设置
bash
from docx import Document
from docx.shared import Inches, Cm
from docx.enum.section import WD_ORIENT
doc = Document()
# 第一节(默认存在)
section1 = doc.sections[0]
section1.page_width = Cm(21)
section1.page_height = Cm(29.7)
section1.orientation = WD_ORIENT.PORTRAIT # 纵向
section1.left_margin = Cm(2.5)
section1.right_margin = Cm(2.5)
doc.add_paragraph('第一节的内容。')
# 添加新节,并设置为横向
doc.add_section()
section2 = doc.sections[1]
section2.orientation = WD_ORIENT.LANDSCAPE
section2.page_width = Cm(29.7)
section2.page_height = Cm(21)
doc.add_paragraph('第二节为横向页面,适合放置宽表格。')
doc.save('07_sections.docx')
print("分节文档已生成")
8.2 页眉和页脚
bash
doc = Document()
section = doc.sections[0]
# 页眉
header = section.header
header_para = header.paragraphs[0]
header_para.text = "公司内部文件 - 机密"
header_para.alignment = 2 # 居中 (CENTER)
# 页脚添加页码
footer = section.footer
footer_para = footer.paragraphs[0]
# 加入自动页码字段(PAGE 域)
footer_para.text = "第 "
run = footer_para.add_run()
fldChar1 = run._r.makeelement(docx.oxml.ns.qn('w:fldChar'), {"w:fldCharType": "begin"})
instrText = run._r.makeelement(docx.oxml.ns.qn('w:instrText'), {})
instrText.text = " PAGE "
fldChar2 = run._r.makeelement(docx.oxml.ns.qn('w:fldChar'), {"w:fldCharType": "end"})
run._r.append(fldChar1)
run._r.append(instrText)
run._r.append(fldChar2)
footer_para.add_run(" 页")
doc.add_paragraph('正文内容...')
doc.save('08_header_footer.docx')
print("页眉页脚文档已生成")
打开文档后,页脚会显示"第 X 页"。不同节可以拥有独立的页眉页脚。
9. 样式与主题:打造专业文档模板
除了内建样式(如 Title, Heading 1, Normal 等),我们可以自定义样式,实现统一排版。
9.1 使用内建样式
bash
doc = Document()
doc.add_paragraph('标题自动应用 Heading 1', style='Heading 1')
doc.add_paragraph('此处为正常正文', style='Normal')
doc.add_paragraph('带编号的列表项 1', style='List Number')
doc.add_paragraph('带编号的列表项 2', style='List Number')
doc.save('09_builtin_styles.docx')
9.2 自定义段落样式
bash
from docx.enum.style import WD_STYLE_TYPE
style = doc.styles.add_style('MyCustomStyle', WD_STYLE_TYPE.PARAGRAPH)
style.font.name = '微软雅黑'
style.font.size = Pt(11)
style.font.color.rgb = RGBColor(0x33, 0x33, 0x33)
style.paragraph_format.space_after = Pt(8)
style.paragraph_format.line_spacing = 1.2
doc.add_paragraph('使用自定义样式的段落。', style='MyCustomStyle')
9.3 修改当前文档的默认样式
bash
doc = Document()
style = doc.styles['Normal']
style.font.name = 'Times New Roman'
style.font.size = Pt(12)
style.paragraph_format.space_after = Pt(6)
doc.add_paragraph('所有 Normal 都会继承此设置。')
10. 高级操作:文档合并、替换与邮件合并
10.1 合并多个 Word 文档
思路:将一个文档的所有元素(段落、表格等)逐一复制到另一个文档末尾。
bash
from docx import Document
def merge_docs(target_doc, source_path):
src = Document(source_path)
for element in src.element.body:
target_doc.element.body.append(element)
doc = Document()
doc.add_heading('合并文档示例', 0)
doc.add_paragraph('第一部分')
# 模拟两个独立文档
Document('part1.docx').save('part1.docx') # 自己创建,可替换为真实文件
Document('part2.docx').save('part2.docx')
merge_docs(doc, 'part1.docx')
merge_docs(doc, 'part2.docx')
doc.save('10_merged.docx')
print("合并完成:10_merged.docx")
注意:此方法会复制元素但不会自动处理样式/图片关系,复杂文档建议使用
python-docx模板方式或 COM 对象。
10.2 文本替换
bash
doc = Document('template.docx') # 包含占位符如 {{name}}
for para in doc.paragraphs:
if '{{name}}' in para.text:
para.text = para.text.replace('{{name}}', '张三')
# 注意:这种方式会清除原有 Run 级格式。更优雅的方法是遍历 Run 替换,保留格式:
for para in doc.paragraphs:
for run in para.runs:
if '{{' in run.text:
run.text = run.text.replace('{{name}}', '张三')
doc.save('10_replaced.docx')
10.3 邮件合并(类似 Mail Merge)
典型场景:用同一个模板,根据数据源生成多份信函。
bash
data = [
{'name': '张三', 'amount': 5000},
{'name': '李四', 'amount': 3000}
]
for i, record in enumerate(data):
doc = Document('template_letter.docx')
for para in doc.paragraphs:
for run in para.runs:
if '{{name}}' in run.text:
run.text = run.text.replace('{{name}}', record['name'])
if '{{amount}}' in run.text:
run.text = run.text.replace('{{amount}}', str(record['amount']))
doc.save(f'letter_{i+1}.docx')
print("批量信函已生成")
11. 格式转换:Word 转 PDF 等
11.1 使用 docx2pdf (Windows/macOS)
bash
from docx2pdf import convert
convert('report.docx', 'report.pdf')
print("转换完成:report.pdf")
批量转换:
bash
convert('input_folder/', 'output_folder/')
11.2 使用 win32com (仅 Windows, 功能更强大)
bash
import win32com.client
def docx_to_pdf(input_path, output_path):
word = win32com.client.Dispatch("Word.Application")
word.Visible = False
doc = word.Documents.Open(input_path)
doc.SaveAs(output_path, FileFormat=17) # 17 代表 PDF
doc.Close()
word.Quit()
print(f"PDF 已生成: {output_path}")
docx_to_pdf('report.docx', 'report.pdf')
FileFormat 常量参考:
-
16:docx
-
17:PDF
-
其他格式可查 MSDN。
12. 实战案例:自动化生成月度报表
场景:从 Excel 读取销售数据,生成图文并茂的 Word 报告,并导出 PDF。
数据准备 (sales_data.xlsx)
脚本实现
bash
import pandas as pd
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
import matplotlib.pyplot as plt
from docx2pdf import convert
import os
# 1. 读取数据
df = pd.read_excel('sales_data.xlsx')
print("读取数据预览:\n", df)
# 2. 生成图表
plt.figure()
plt.plot(df['月份'], df['销售额(万)'], marker='o', label='销售额')
plt.plot(df['月份'], df['利润(万)'], marker='s', label='利润')
plt.xlabel('月份')
plt.ylabel('金额(万元)')
plt.title('月度销售趋势')
plt.legend()
plt.tight_layout()
chart_file = 'sales_chart.png'
plt.savefig(chart_file)
plt.close()
# 3. 创建 Word 报告
doc = Document()
# 标题
title = doc.add_heading('月度销售报告', level=0)
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 摘要
summary = doc.add_paragraph()
summary.add_run('报告摘要:').bold = True
summary.add_run(f'本期共分析 {len(df)} 个月数据,平均销售额 {df["销售额(万)"].mean():.2f} 万元。')
# 表格
doc.add_heading('详细数据', level=2)
table = doc.add_table(rows=len(df)+1, cols=3, style='Light Shading Accent 1')
# 表头
for i, col in enumerate(df.columns):
table.cell(0, i).text = col
for run in table.cell(0, i).paragraphs[0].runs:
run.bold = True
# 数据行
for idx, row in df.iterrows():
for j, val in enumerate(row):
table.cell(idx+1, j).text = str(val)
# 插入图表
doc.add_heading('销售趋势图', level=2)
doc.add_picture(chart_file, width=Inches(5.5))
# 页脚
footer = doc.sections[0].footer
footer_para = footer.paragraphs[0]
footer_para.text = "自动生成报告 - 仅供内部使用"
report_path = 'monthly_report.docx'
doc.save(report_path)
print(f"Word 报告已生成:{report_path}")
# 4. 转换成 PDF
pdf_path = 'monthly_report.pdf'
try:
convert(report_path, pdf_path)
print(f"PDF 报告已生成:{pdf_path}")
except Exception as e:
print(f"PDF 转换失败(可能未安装 Word 或依赖缺失): {e}")
执行输出:
bash
读取数据预览:
月份 销售额(万) 利润(万)
0 1月 120 30
1 2月 150 40
2 3月 180 50
Word 报告已生成:monthly_report.docx
PDF 报告已生成:monthly_report.pdf
这个案例串联了数据读取、图表生成、文档排版、页眉页脚、格式转换等核心技术。
13. 总结与扩展资源
通过本文,你已经从零开始掌握了 Python 操作 Word 的核心技能:
-
文档创建、段落与格式
-
表格、图片、超链接
-
页眉页脚、分节布局
-
样式与模板化
-
文档合并与邮件合并
-
Word 转 PDF 实际部署
常见问题与注意事项
-
字体缺失 :服务器环境无中文字体时,生成的 docx 在其他电脑打开可能显示为方块。解决方案:安装所需字体,或通过
run.font.name设置通用字体(如宋体)。 -
图片路径:务必使用绝对路径或在运行目录下。
-
样式继承 :当 Run 的某个属性为
None时,表示继承最近的非 None 值,这可能造成格式混乱,建议显式设置。 -
大文档性能 :通过
python-docx处理超长表格或大量图片时,速度会下降。可考虑直接操作 XML 或使用流式生成。