找回密码
立即注册
搜索
发回帖 发新帖

6544

积分

0

好友

829

主题
发表于 9 小时前 | 查看: 3| 回复: 0

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 内容读写与格式设置。掌握样式继承、文本替换和页面布局的关系,并结合基础文档与结果验证,可完成规范的批量文档生成。




上一篇:智能体AI打破CPU与GPU平衡:算力配比从1:4走向1:1
下一篇:Linux 生产环境网络故障排查:从 DNS、路由到 TCP 连接
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-19 18:35 , Processed in 0.156605 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表