● ● ●
自动化处理Excel文件Pandas可是当之无愧的利器,那么有没有能自动化处理Word的神器呢?答案是有,本文将介绍如何使用python-docx库来处理Word文档,但是个人感觉它不能算上处理Word的神器,反而是一种不得已的选择,这可能也跟Word文档的数据结构化程度比Excel要复杂得多的缘故。
如果完全使用python-docx来生成完整的Word文档,要实现一些复杂样式会相当复杂,今天我就通过一个具体的示例来讲解一种折中的方案,那就是通过事先编写好的模板文件,仅通过更新模板文件中的定义好的占位符来生成Word文档。这样的方式可以最大限度地利用模板文件的样式,只需要学习几个python-docx简单的API就可以做到自动化生成漂亮报告,对于需要经常处理Word文档的工作者而言,可以让你从繁琐的键盘敲击中解放出来。使用python-docx前需要先进行安装。
pip install python-docx
为了方便演示,创建一个如下图所示的简单模板示例,我们的目标是编写python程序自动替换模板中的由{}包裹的内容,并生成样式和模板一致的Word报告。标题中的{report_date}将替换为报告的日期;正文段落的{num_xxx}表示将替换为数字,并设置为标红加粗的样式;{image_demo}表示这里将插入图片;最后表格部分仅保留表头,示例将第一列表头的内容作为识别要更新表格的标识,这里为NO.。
以上只是本次约定的规则,实际应用中你可以创建专业的模板并自行定义占位符的规则。
接着简单介绍python-docx的基本概念,让我们对它有个基本的理解,后面就直接通过具体的示例代码展示如何使用它们,这里完全不会用到其复杂的内容。
1. Document对象,对应的就是Word文档,打开或新建文档都使用Document方法。
2. 我们知道Word文档是由标题、段落、节、表格等元素组成,python-docx也都有对应的概念,它们是可迭代对象,在程序中可以遍历文档对象的段落、表格进行相应的处理操作。
3. Run对象,比如示例模板中的数字可以单独标红加粗,设置不同的样式,它们就是一个Run对象,简单理解,就是一个段落中的小分块,每个分块可以单独设置样式。
4. save方法将更新的Document保存为Word文档。
下面就直接给出代码,大部分代码都进行了注释,示例代码将模板文件命名为template.docx,另外还需要事先准备一个名为demo.png的图片放到和代码同一目录下。
import re
import time
from docx import Document
from docx.shared import Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
def format_number_red_bold(paragraph):
"""
将段落中的数字标红加粗
整体的思路是把段落重新拆分为文本和数字,然后重新创建新的Run对象,针对数字的样式进行修改
"""
# 正则表达式匹配数字
pattern = re.compile(r'\d ')
# 记录拆分的段落文本和数字Run对象
new_runs = []
# 当前处理的文本起始位置
start = 0
# 找到所有数字的位置
for match in pattern.finditer(paragraph.text):
number_start, number_end = match.span()
# 如果数字前面有文本,添加一个新的Run对象保存数字前的文本
if number_start > start:
text = paragraph.text[start:number_start]
new_runs.append((text, "text"))
# 创建包含数字的Run对象,并设置样式
text = paragraph.text[number_start:number_end]
new_runs.append((text, "digit"))
# 更新当前处理的文本起始位置
start = number_end
# 段落末尾的文本
new_runs.append((paragraph.text[start:], "text"))
# 清空段落
paragraph.text = ""
# 重新组装段落并将数字的样式改为标红加粗
for text, style in new_runs:
run = paragraph.add_run(text)
if style == "digit":
run.font.color.rgb = RGBColor(255, 0, 0) # 红色
run.font.bold = True # 加粗
def generate_report_from_template(template_path, output_path, report_data):
"""
根据提供的数据更新Word模板并生成报告文件
:param template_path: 模板文件
:param output_path: 输出报告文件
:param report_data: 包含要更新的数据字典,
"""
# 打开模板文档
doc = Document(template_path)
# 遍历模板文档中的段落
for para in doc.paragraphs:
# 遍历检查段落中是否有需要替换的占位符
for placeholder, new_text in report_data.items():
# 排除图片占位符
if not placeholder.startswith('image_'):
# 如果当前段落文本包含占位符,则替换为占位符对应的文本
if f'{{{placeholder}}}' in para.text:
para.text = para.text.replace(f'{{{placeholder}}}', new_text)
# 段落被占位符替换后样式会丢失,遍历段落设置数字的样式为标红加粗
for para in doc.paragraphs:
# 判断是否是需要对数字标红加粗的段落
if para.text.startswith("这是一段包含数字的段落示例"):
# 重新将需要标红加粗的数字进行样式修改
format_number_red_bold(para)
# 更新报告表格数据
for table in doc.tables:
# 获取表格第一行第一列标题,作为判定表格的依据
th0 = table.rows[0].cells[0].text
# 遍历报告数据中的数据
for thead, tdata in report_data.items():
# 如果第一列标题和报告数据中的key相同,则表明该表格需要更新
if th0 == thead:
# 记录新增表格的行
new_added_rows = []
for _ in tdata:
new_added_rows.append(table.add_row())
# 遍历新增的行
for index, new_row in enumerate(new_added_rows):
# 遍历每一行的单元格
for cell_idx, cell in enumerate(new_row.cells):
# 取表格对应的数据项设置为单元格的文本
cell.text = tdata[index][cell_idx]
# 设置单元格样式为居中
for p in cell.paragraphs:
p.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 更新报告图片
for para in doc.paragraphs:
# 遍历数据字典
for placeholder, image_path in report_data.items():
# 判断是否是图片占位符
if placeholder.startswith("image_"):
if f'{{{placeholder}}}' in para.text:
# 占位符所在的段落清除并添加图片
para.clear()
run = para.add_run()
# Inches(5)用于调整图片的大小比例
run.add_picture(image_path, width=Inches(5))
# 设置图片居中
para.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 保存更新后的文档
doc.save(output_path)
if __name__ == "__main__":
# 模板文件路径
template_path = "./template.docx"
# 指定生成word报告路径
output_path = "report.docx"
# 模拟报告数据
report_data = {
"report_date": time.strftime("%Y/%m/%d"),
"num_001": f"{123}",
"num_002": f"{456}",
"num_003": f"{789}",
"image_demo": "demo.png",
"NO.": [
("001", "key01", "val01"),
("002", "key02", "val02"),
("003", "key03", "val03"),
]
}
# 根据模板生成word报告
generate_report_from_template(template_path, output_path, report_data)
运行代码将会在相同目录下生成名为report.docx的Word文档,打开内容将如下图所示。
参考文献:
[1].https://python-docx.readthedocs.io/en/latest/index.html#api-documentation
,