python-docx 是用于创建、读取与编辑 Word 文档的第三方 Python 库,支持段落处理、文字格式设置、表格创建、图片插入及页面布局配置,常用于报告生成、信息提取与批量文档制作。
使用 python-docx 处理文档文件时,无需启动 Word。它的主要职责是管理文档内容与结构;页面渲染、自动分页和最终显示效果,则交给 Word 等文档处理软件完成。
一、安装与适用范围
1、安装与导入
在终端中执行:
python -m pip install python-docx
其中,python 应对应实际运行程序的 Python 环境。
安装后,使用以下方式导入:
from docx import Document
安装包名称为 python-docx,导入名称为 docx。安装时应使用完整包名,避免与名称相近的其他包混淆。
2、支持的文件格式
python-docx 主要用于处理 .docx 格式的 Word 文档,不直接支持旧版 .doc 文件。
处理 .doc 文件前,应先通过 Word 等软件转换为 .docx,不能仅修改文件扩展名。
创建文档时,可以使用内置的默认文档,也可以打开已有的 .docx 文件,在其基础上继续编辑。
3、主要应用
(1)文档创建与编辑:创建报告、通知、说明书等文档,添加标题、正文和列表。
(2)文本与表格读取:提取段落和表格中的内容,结合 Python 完成整理、统计或汇总。
(3)格式与布局设置:设置字体、字号、段落间距、缩进、页边距及纸张方向。
(4)图文报告生成:将文字、数据表格和图片组合为可继续编辑的 Word 文档。
(5)批量文档制作:以已有文档为基础,按不同记录生成通知、证明或个人信息表等文件。
二、核心对象与基本流程
1、文档
文档(Document)是操作 Word 文件的入口。
from docx import Document
# 创建新文档
doc = Document()
打开已有文档时,传入文件路径:
doc = Document("report.docx")
修改首先保存在内存中,调用 save() 后才会写入文件:
doc.save("report_updated.docx")
保存到已有路径会覆盖同名文件。需要保留原文件时,应使用新的文件名。
2、段落
段落(Paragraph)是组织文字内容的基本单位。正文、标题和列表项通常都以段落形式存在。
paragraph = doc.add_paragraph("本报告介绍本学期的学习情况。")
段落可设置对齐方式、缩进、行距、段前段后间距等。
段落与视觉上的一行文字并不等同:一个段落可以因页面宽度而自动排成多行。
3、文本片段
文本片段(Run)是段落内部用于承载文字及字符格式的对象。
paragraph = doc.add_paragraph()
paragraph.add_run("本次考核结果为:")
run = paragraph.add_run("优秀")
run.bold = True
该段落包含两个文本片段,其中"优秀"使用加粗格式。
同一段落可以包含多个文本片段。它们的边界由文档结构决定,不一定与词语、句子或可见的格式变化完全对应。
4、表格与单元格
表格(Table)由行、列和单元格(Cell)组成。
table = doc.add_table(rows=2, cols=2)
table.cell(0, 0).text = "姓名"
table.cell(0, 1).text = "成绩"
表格的行列索引从 0 开始,table.cell(0, 1) 表示第一行第二列。
单元格内部可以包含段落,也可以包含嵌套表格。
5、节
节对象 Section 用于管理页面尺寸、方向、页边距以及页眉页脚等设置。
section = doc.sections[0]
一个文档可以包含多个节,以便为不同部分设置不同的页面布局。
节不等同于页:一个节可以跨越多页,插入分页符也不会自动创建新节。
6、样式
样式(Style)用于集中管理重复使用的格式,例如标题、正文和列表格式。
doc.add_paragraph("学习情况", style="Heading 1")
与逐段设置格式相比,使用样式更便于保持全文一致,也有助于建立清晰的文档层级。
三、文档创建与内容读取
1、创建文档并写入内容
from docx import Document
doc = Document()
doc.add_heading("学生学习报告", level=0)
doc.add_heading("一、基本情况", level=1)
doc.add_paragraph("姓名:张三")
doc.add_paragraph("本学期完成了规定课程,学习情况良好。")
doc.add_heading("二、学习建议", level=1)
doc.add_paragraph("定期整理课堂笔记。", style="List Bullet")
doc.add_paragraph("结合实例巩固所学知识。", style="List Bullet")
doc.save("student_report.docx")
运行后生成 student_report.docx。
add_heading() 的 level 参数用于指定标题层级:
level=0:文档标题,对应 Title 样式
level=1:一级标题
level=2:二级标题
- 继续向下可使用至九级标题
标题层级不会自动为标题添加"一、""1、"等编号。示例中的编号由文本直接提供。
2、读取正文段落
from docx import Document
doc = Document("student_report.docx")
for paragraph in doc.paragraphs:
print(paragraph.text)
doc.paragraphs 返回正文中的顶层段落,不包含表格单元格中的段落,也不代表页眉、页脚等区域的全部内容。
读取单元格文字时,应通过表格对象访问。
3、读取表格内容
以下示例读取包含表格的 scores.docx。该文件可由第五章"创建并填充表格"的示例生成,也可替换为已有的 Word 文件路径。
from docx import Document
doc = Document("scores.docx")
for table_index, table in enumerate(doc.tables, start=1):
print(f"表格 {table_index}")
for row in table.rows:
values = [cell.text for cell in row.cells]
print(values)
doc.tables 返回正文中的顶层表格,不包含单元格内部的嵌套表格。
对于包含合并单元格的表格,行列访问结果可能重复指向同一个合并单元格,不能始终按规则矩阵直接理解。
4、按正文顺序读取段落与表格
分别遍历 doc.paragraphs 和 doc.tables,无法保留二者交错出现的顺序。
需要按正文顺序处理时,可使用 iter_inner_content():
from docx import Document
from docx.text.paragraph import Paragraph
from docx.table import Table
doc = Document("student_report.docx")
for block in doc.iter_inner_content():
if isinstance(block, Paragraph):
print("段落:", block.text)
elif isinstance(block, Table):
print("表格:")
for row in block.rows:
print([cell.text for cell in row.cells])
该方法依次产生正文中的顶层段落和表格。单元格内部、页眉页脚等区域仍需分别处理。
前文生成的 student_report.docx 仅包含段落,因此不会进入表格处理分支。若需观察段落与表格的交错读取效果,可在该文件中添加表格并保存后再次运行。
5、修改内容并另存
from docx import Document
doc = Document("student_report.docx")
for paragraph in doc.paragraphs:
if paragraph.text == "姓名:张三":
paragraph.text = "姓名:李四"
doc.save("student_report_updated.docx")
此例适合格式简单的完整段落替换。
对 paragraph.text 赋值,会将原有段落内容替换为一个新的文本片段。段落样式等段落级格式保留,但原有文本片段中的加粗、颜色等字符格式会被清除。
四、文字格式与样式设置
1、字符格式
from docx import Document
from docx.shared import Pt, RGBColor
doc = Document()
paragraph = doc.add_paragraph("考核结果:")
run = paragraph.add_run("优秀")
run.bold = True
run.font.size = Pt(14)
run.font.color.rgb = RGBColor(0, 112, 192)
doc.save("text_format.docx")
常用字符格式包括:
run.bold:加粗
run.italic:斜体
run.underline:下划线
run.font.name:字体名称
run.font.size:字号
run.font.color.rgb:字体颜色
加粗、斜体等属性通常有三种状态:
True:明确启用
False:明确关闭
None:未直接指定,由样式层级决定
因此,读取到 None 并不表示文字一定没有相应格式。
2、段落格式
from docx import Document
from docx.shared import Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH
doc = Document()
paragraph = doc.add_paragraph(
"本报告对本学期的学习情况进行整理,并提出后续学习建议。"
)
paragraph.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
fmt = paragraph.paragraph_format
fmt.first_line_indent = Pt(24)
fmt.space_before = Pt(0)
fmt.space_after = Pt(6)
fmt.line_spacing = 1.5
doc.save("paragraph_format.docx")
主要设置包括:
alignment:对齐方式
first_line_indent:首行缩进,负值表示悬挂缩进
left_indent、right_indent:左右缩进
space_before、space_after:段前和段后间距
line_spacing:行距
示例中的首行缩进是固定的 24 磅,不是与字号自动联动的"两字符缩进"。
line_spacing = 1.5 表示 1.5 倍行距;设置为 Pt(20) 则表示固定的 20 磅行距。固定行距过小时,可能影响较大文字或行内图片的显示。
3、统一设置文档样式
from docx import Document
from docx.shared import Pt
doc = Document()
normal = doc.styles["Normal"]
normal.font.size = Pt(12)
normal.paragraph_format.space_after = Pt(6)
normal.paragraph_format.line_spacing = 1.5
heading = doc.styles["Heading 1"]
heading.font.size = Pt(16)
heading.font.bold = True
heading.paragraph_format.space_before = Pt(12)
heading.paragraph_format.space_after = Pt(6)
doc.add_heading("学习情况", level=1)
doc.add_paragraph("本段使用正文样式。")
doc.add_paragraph("本段继承相同的正文格式。")
doc.save("styles.docx")
内置样式应使用英文名称访问,即使中文版 Word 显示为"正文""标题 1",代码中仍使用:
doc.styles["Normal"]
doc.styles["Heading 1"]
自定义样式则使用文档中实际定义的名称。
样式必须存在于当前文档中,才能按名称应用。使用已有文档作为基础时,应检查所需样式是否已定义。
4、中文字体设置
Word 可以为西文和东亚文字分别保存字体设置。仅设置 font.name,不一定能明确指定中文字体。
对于格式要求固定的中文文档,宜先在 Word 中建立好字体和样式,再由程序填充内容。
需要通过代码指定时,可补充东亚字体属性:
from docx import Document
from docx.shared import Pt
from docx.oxml.ns import qn
doc = Document()
normal = doc.styles["Normal"]
# 设置西文字体与字号
normal.font.name = "Times New Roman"
normal.font.size = Pt(12)
# 设置东亚文字字体
rpr = normal.element.get_or_add_rPr()
rfonts = rpr.get_or_add_rFonts()
rfonts.set(qn("w:eastAsia"), "宋体")
doc.add_paragraph("学习报告:Learning Report")
doc.save("chinese_font.docx")
其中,w:eastAsia 属于底层文档格式设置,使用时应保留命名空间处理。
字体名称不会将字体文件嵌入文档。打开文档的设备未安装相应字体时,软件可能使用替代字体,进而影响换行与分页。
五、表格与图片操作
1、创建并填充表格
from docx import Document
from docx.enum.table import WD_TABLE_ALIGNMENT
doc = Document()
doc.add_heading("学生成绩", level=1)
table = doc.add_table(rows=1, cols=3)
table.style = "Table Grid"
table.alignment = WD_TABLE_ALIGNMENT.CENTER
headers = ["姓名", "课程", "成绩"]
for cell, text in zip(table.rows[0].cells, headers):
cell.text = text
records = [
("张三", "Python", 90),
("李四", "Python", 85),
("王五", "Python", 88)
]
for record in records:
cells = table.add_row().cells
for cell, value in zip(cells, record):
cell.text = str(value)
# 设置表头加粗
for cell in table.rows[0].cells:
for paragraph in cell.paragraphs:
for run in paragraph.runs:
run.bold = True
doc.save("scores.docx")
表格文字通过字符串写入,因此示例使用 str(value) 将成绩转换为字符串。
table.alignment 设置表格在页面中的对齐方式,不控制单元格文字的对齐方式。单元格文字应通过其内部段落设置。
2、单元格格式与合并
以下代码接续上一节已创建的 doc 和 table 对象执行。完成对齐设置与合并操作后,需再次保存文档。
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_CELL_VERTICAL_ALIGNMENT
cell = table.cell(0, 0)
cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
for paragraph in cell.paragraphs:
paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
合并单元格时,可指定矩形区域的两个对角单元格:
merged_cell = table.cell(0, 0).merge(table.cell(0, 2))
merged_cell.text = "学生成绩汇总"
该示例合并第一行的三个单元格,随后将合并后的内容替换为标题。
对 cell.text 赋值,会重建单元格中的文本内容,不会保留原有的多个段落和局部字符格式。需要保留格式时,应操作单元格内部的段落和文本片段。
3、插入图片
以下示例要求当前工作目录中存在 chart.png:
from docx import Document
from docx.shared import Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH
doc = Document()
doc.add_heading("成绩分布", level=1)
paragraph = doc.add_paragraph()
paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = paragraph.add_run()
run.add_picture("chart.png", width=Cm(12))
caption = doc.add_paragraph("图 1:学生成绩分布")
caption.alignment = WD_ALIGN_PARAGRAPH.CENTER
doc.save("picture_report.docx")
仅指定宽度或高度时,另一维度按原始比例调整;同时指定宽度和高度时,应自行保证比例合理。
python-docx 的常规图片接口用于插入嵌入型图片。图片作为段落中的内容参与排版,不能直接等同于 Word 中可自由拖动、设置文字环绕的浮动图片。
示例中的图题是普通段落,不包含自动题注编号。
六、页面布局与页眉页脚
1、纸张尺寸与页边距
from docx import Document
from docx.shared import Cm
doc = Document()
section = doc.sections[0]
# A4 纵向页面
section.page_width = Cm(21)
section.page_height = Cm(29.7)
section.top_margin = Cm(2.5)
section.bottom_margin = Cm(2.5)
section.left_margin = Cm(2.5)
section.right_margin = Cm(2.5)
doc.add_paragraph("本文件采用 A4 纵向页面。")
doc.save("page_layout.docx")
页面布局由节控制。需要统一整个文档时,应逐节设置,而不是只修改第一节。
插入图片或设置表格宽度时,应考虑页面宽度扣除左右页边距后的可用空间。
2、分页与段落分页控制
插入显式分页符:
doc.add_page_break()
doc.add_heading("附录", level=1)
也可以通过段落属性控制分页:
heading = doc.add_heading("第二部分", level=1)
heading.paragraph_format.page_break_before = True
heading.paragraph_format.keep_with_next = True
常用属性包括:
page_break_before:段前分页
keep_with_next:与下一段保持在同一页
keep_together:尽量保持本段各行不跨页
这些设置由文档处理软件在排版时执行。应避免使用大量空白段落模拟分页或段间距。
3、创建不同布局的节
from docx import Document
from docx.shared import Cm
from docx.enum.section import WD_SECTION_START, WD_ORIENT
doc = Document()
first_section = doc.sections[0]
first_section.page_width = Cm(21)
first_section.page_height = Cm(29.7)
doc.add_heading("正文", level=1)
doc.add_paragraph("本部分采用纵向页面。")
# 新建从下一页开始的节
landscape = doc.add_section(WD_SECTION_START.NEW_PAGE)
landscape.orientation = WD_ORIENT.LANDSCAPE
landscape.page_width = Cm(29.7)
landscape.page_height = Cm(21)
doc.add_heading("宽表附录", level=1)
doc.add_paragraph("本部分采用横向页面。")
doc.save("sections.docx")
设置横向页面时,应同时确认纸张宽度与高度。分页符用于换页,分节符用于划分可独立配置页面布局的区域。
4、设置页眉与页脚
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
doc = Document()
section = doc.sections[0]
header = section.header.paragraphs[0]
header.text = "学生学习报告"
header.alignment = WD_ALIGN_PARAGRAPH.RIGHT
footer = section.footer.paragraphs[0]
footer.text = "教学资料"
footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
doc.add_paragraph("正文内容。")
doc.save("header_footer.docx")
多节文档的页眉页脚可能继承前一节的定义。需要为某一节设置独立内容时,应先解除相应链接:
section.header.is_linked_to_previous = False
section.footer.is_linked_to_previous = False
页眉与页脚分别控制链接关系;首页不同、奇偶页不同还涉及各自的页眉页脚对象。
上述页脚为固定文字,不是自动页码。
七、基于已有文档的批量生成
1、准备基础文档
可先在 Word 中制作 notice_template.docx,设置好纸张、页眉页脚、样式与正文,并插入占位符:
{{姓名}}同学:
你参加的{{课程}}课程考核成绩为{{成绩}}分。
此处的基础文档是普通 .docx 文件。"模板"表示用途,不要求使用 Word 的专用模板格式。
为便于后续替换,占位符宜采用统一格式,并避免在占位符内部设置不同的字符格式。
2、按记录生成文档
以下示例适用于占位符完整位于同一个文本片段中的简单文档:
from pathlib import Path
from docx import Document
records = [
{"姓名": "张三", "课程": "Python", "成绩": 90},
{"姓名": "李四", "课程": "Python", "成绩": 85}
]
output_dir = Path("notices")
output_dir.mkdir(parents=True, exist_ok=True)
def replace_in_paragraph(paragraph, mapping):
for run in paragraph.runs:
text = run.text
for key, value in mapping.items():
text = text.replace("{{" + key + "}}", str(value))
if text != run.text:
run.text = text
for index, record in enumerate(records, start=1):
# 每条记录重新加载基础文档
doc = Document("notice_template.docx")
for paragraph in doc.paragraphs:
replace_in_paragraph(paragraph, record)
# 处理顶层表格单元格中的段落
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
replace_in_paragraph(paragraph, record)
doc.save(output_dir / f"notice_{index:03d}.docx")
逐个文本片段修改文字,可保留该片段的字符格式。但如果占位符跨越多个文本片段,此方法无法完整匹配。
示例不处理页眉页脚、嵌套表格和文本框等区域。实际任务应根据基础文档的结构扩展遍历范围。
3、替换范围与格式保留
文本替换应同时考虑两个问题:
- 目标文字位于哪些文档区域。
- 替换后需要保留哪些格式与对象。
整段替换较为直接,但会重建段落内部内容;逐文本片段替换有利于保留字符格式,但需要处理跨片段匹配。
对于结构复杂或格式严格的文档,应先检查占位符在文档中的实际分布,再确定替换方式。
八、常用接口速览
以下采用常用调用形式,部分参数已简化。doc、paragraph、run 和 table 分别表示文档、段落、文本片段和表格对象。
1、文档创建与保存
Document():基于默认文档创建新文档。
Document(filename):加载已有 .docx 文件。
doc.save(filename):将文档保存到指定路径。
2、内容添加与读取
doc.add_heading(text, level=1):添加标题,返回段落对象。
doc.add_paragraph(text="", style=None):添加段落。
paragraph.add_run(text=None, style=None):在段落末尾添加文本片段。
paragraph.insert_paragraph_before(text=None, style=None):在当前段落之前插入段落。
doc.paragraphs:获取正文顶层段落。
doc.tables:获取正文顶层表格。
doc.iter_inner_content():按正文顺序迭代顶层段落与表格。
3、文字与格式
paragraph.text:读取或替换段落文字。
paragraph.runs:获取段落中的直接文本片段。
run.text:读取或替换文本片段内容。
run.font:访问字号、字体和颜色等字符格式。
paragraph.paragraph_format:访问缩进、间距和分页控制等段落格式。
doc.styles:访问文档样式集合。
4、表格与图片
doc.add_table(rows, cols, style=None):创建表格。
table.cell(row_idx, col_idx):按从 0 开始的行列索引访问单元格。
table.add_row():在表格末尾追加一行。
cell.merge(other_cell):合并由两个对角单元格确定的矩形区域。
doc.add_picture(path, width=None, height=None):在新段落中添加图片。
run.add_picture(path, width=None, height=None):在指定文本片段中添加图片。
5、页面与节
doc.add_page_break():添加分页符。
doc.add_section(start_type):添加节,并指定节的起始方式。
doc.sections:获取文档的节。
section.header、section.footer:访问相应节的默认页眉与页脚。
九、使用注意事项
1、文本读取范围
仅遍历 doc.paragraphs 无法提取文档中的全部文字。表格、页眉页脚等区域需要分别访问,文本框和修订内容等也不应假定已包含在常规段落遍历结果中。
paragraph.text 包含段落内超链接的显示文字,但不提供链接地址。
需要读取地址或单独处理超链接时,可使用 paragraph.hyperlinks;需要按顺序访问段落中的直接文本片段与超链接时,可使用 paragraph.iter_inner_content()。
paragraph.runs 不包含超链接内部的文本片段,因此第七章的替换示例也不处理超链接中的占位符。
对于信息提取任务,应先确认原文档使用了哪些结构,再制定读取规则。
2、格式继承与直接格式
最终显示格式可能同时受到文档默认设置、样式及直接格式影响。
修改正文样式后,已经设置直接格式的文字不一定随之改变。需要统一格式时,应检查局部设置是否覆盖了样式。
3、自动编号与域更新
列表编号、页码、目录等通常依赖编号定义或域。
写入普通文字"第 1 页"不会产生自动页码,手动输入"图 1"也不会建立自动题注。python-docx 不负责重新计算目录页码或更新所有域结果。
对于包含目录和自动编号的文档,宜使用已配置好的基础文档,并在 Word 等软件中完成必要的更新与检查。
4、分页与格式转换
python-docx 不包含完整的页面排版引擎,不能仅根据段落数量可靠计算文档页数,也不直接提供 PDF 导出功能。
最终分页受字体、纸张、页边距、表格尺寸及文档处理软件影响。需要 PDF 时,应通过 Word、LibreOffice 等软件完成转换,并检查输出结果。
5、文档验证
批量生成后,应核对:
- 必填字段是否完整,占位符是否仍有残留。
- 段落和表格顺序是否正确。
- 标题层级与样式是否统一。
- 中文字体、图片比例和表格宽度是否合适。
- 分页、页眉页脚及自动编号是否符合要求。
结构检查与版面检查应分别进行。程序能够成功保存文件,并不代表最终排版已经符合使用要求。
📘 小结
python-docx 以文档、段落、文本片段、表格和节为核心,支持 Word 内容读写与格式设置。掌握样式继承、文本替换和页面布局的关系,并结合基础文档与结果验证,可完成规范的批量文档生成。