技术背景与需求场景
- Word模板在办公自动化中的重要性
- Python处理Word文档的常见需求(批量生成报告、合同等)
- 传统手动替换的局限性及自动化解决方案的优势
核心工具库介绍
python-docx
:基础读写操作,但默认不支持模板变量替换docxtpl
:基于python-docx
的扩展,支持Jinja2模板语法mailmerge
:适用于简单邮件合并场景- 其他可选库(如
docx-mailmerge
)的简要对比
这里作者平常主要使用的是python-docx的方式,这里给大家提供一些常用word模板内容替换的方法及可能用到的函数
1.获取你的word模板内容
简单粗暴的方式,可以直接帮你看到你的模板每一个内容的数据及占位点(索引),其中当数据为字符串的内容,大多是直接展示,而当你看到某一个数据的为 " "字符串时,此时注意观察你模板中的上下文,该位置可能表示了你模板中的表格或者图形的占位(先记住,后面会用到!!)
def run():
text0 = doc.paragraphs[0].text
text1 = doc.paragraphs[1].text
text2 = doc.paragraphs[2].text
...
if __name__ == '__main__':
run()
2.正常文本内容的替换
当我们发现我们需要替换一段文字的时候,首先找到该段文字表示的位置,假如
text0 = doc.paragraphs[0].text 此时是一段文字
# 省略导包,根据代码缺失的去安装
new_file_path = 'xxx' # 文件路径
doc = Document(new_file_path)
paragraphs_1_text = '这是我要替换的文字'
# 通用替换文本方式
def replace_paragraph_text(paragraph, new_text):
"""可以在该方法下新增对特定段落的额外处理"""
# 遍历段落中的所有 runs
for run in paragraph.runs:
run.text = "" # 清空每个 run 的文本
# 将新文本插入到第一个 run 中,保留样式
paragraph.runs[0].text = new_text
if __name__ == '__main__':
text0 = "这是原来的文字" # 假设你的text0是这段文字
replace_paragraph_text(doc.paragraphs[0], paragraphs_1_text) # doc.paragraphs[0]为你段落的位置, paragraphs_1_text则是要替换的文本。
""" 使用该方式即可替换所有文字的段落 """
3.表格内容的替换
当发现我上面说的那种数据为空字符串的时候,而且你在模板中发现其为表格,就可以使用我下面的方式进行替换,一般表格的替换比较特殊,tables0 = doc.tables[xxx]来写表格的索引,可以不用去看段落的索引,而是根据你模板中的表格的数量索引来看,第一个表格索引就是0,以此类推。
tables0 = doc.tables[xxx] # 写你表格索引
def set_font_table(para, font_name="仿宋", font_size=12, char_spacing=None, bold=True):
"""
设置段落的字体为指定字体和大小,并可设置字间距,同时支持加粗
"""
for run in para.runs:
run.font.name = font_name
run.font.size = Pt(font_size)
run.font.bold = bold # 设置加粗
if char_spacing:
run.font.spacing = char_spacing
"""
可选部分,看是否删除表的数据
"""
#for row_index in range(len(tables0.rows)-1, 0, -1): # 从最后一行开始删除到第二行
# if row_index > 0: # 确保不删除表头行(假设表头是第一行)
# tables0._element.remove(tables8.rows[row_index]._element)
# 根据 table_data 重新添加行和填充数据
#for row_index, row_data in enumerate(table_data, start=1): # 从第二行开始
# # row = tables0.add_row() # 添加新的一行(根据上面是否删除表选择解注)
# for col_index in range(min(column_count, len(row_data))): # 保证不会超出列数范围
# cell = row.cells[col_index]
# cell.text = str(row_data[col_index])
# for para in cell.paragraphs:
# set_font_table(para, font_name="仿宋", font_size=12, bold=False)
# para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 常用部分
new_table_data = [[]] # 通常是这个格式,里面的每个[]存每一行表格数据
for row_index, row_data in enumerate(new_table_data, start=1): # 从第二行开始
for col_index, cell_data in enumerate(row_data, start=0): # 从第一列开始
# 获取每个单元格
cell = tables0.cell(row_index, col_index)
cell.text = str(cell_data)
for para in cell.paragraphs:
set_font_table(para, font_name="仿宋", font_size=12, bold=False)
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
一般通过上述方式可完成替换表格内容
4.图形内容的替换
首先需要用python的plt 方法进行生成图型(柱状图、折线图等),生成图形这部分代码省略,这里主要讲下如何进行段落替换,直接上代码:
chart_image_path = generate_bar_chart(数据内容, 地址) # 通过一个方法获取生成的柱状图地址
target_paragraph = doc.paragraphs[xxx] # 通过你的上下文段落来判断这里是否是一个图形,找出其对应的索引
old_inline = None
for element in target_paragraph._element.findall('.//wp:inline', namespaces={'wp': 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'}):
# for element in target_paragraph._element.iter():
if element.tag.endswith("inline"): # 检查是否是 <wp:inline> 元素
old_inline = element
break
from docx.shared import Inches
# 如果找到旧的 <wp:inline> 对象
if old_inline is not None:
# 插入新图片并获取其 <wp:inline> 对象
new_run = target_paragraph.add_run()
new_inline = new_run.add_picture(chart_image_path, width=Inches(5.5))._inline
# 替换旧的 <wp:inline> 对象
parent = old_inline.getparent()
parent.replace(old_inline, new_inline)
# 删除新插入的 run(因为我们已经替换了旧的 <wp:inline>)
target_paragraph._p.remove(new_run._element)
通常处理这样的word模板,是为了从某一数据源中,固定时间的获取某些数据来替换模板生成我们想要的报告文档之类的东西,为了实现自动化,该替换代码,通常在完成后,会与定时任务相关的东西相结合来使用。作者这里常用的是crontab来进行定时任务,大家可以借鉴或者是采取自己适合的方式进行处理。
希望对大家有所帮助!