Contents
  1. 1. 使用Python以jinja2方式渲染docx文件: docxtpl
    1. 1.1. 起因:
    2. 1.2. 使用Python操作docx文件: python-docx和docxtpl包
    3. 1.3. 具体使用docxtpl来进行docx文档的编辑
    4. 1.4. Linux使用libreoffice在子线程上进行docx到PDF的转换

使用Python以jinja2方式渲染docx文件: docxtpl

起因:

在给LCY老师写国家语言委员会的申报平台时, 遇到了以下的需求:

  • 需要按照每个申报流程中的数据动态生成PDF文件进行下载
  • PDF可以按照申报书不同部分进行拼接

这个需求当初提出时, 我的第一思路是直接根据HTML生成PDF, 以HTML生成表格等等. 再将数据进行嵌入, 最后利用chrome的kernel来进行生成PDF.

这个思路源于当初给PHU老师写的一个爬虫程序, 当时是把Python官方的教程以PDF电子书的形式进行整合下载, 当时就是利用的chrome kernel进行PDF的生成. 因此我当时第一反应就是这样去做.

后来发现HTML的表格还挺难写的, (当时是CGH负责这方面的功能), 我意识到这个事情有难度, 直到后面这个功能落在我的头上的时候, 我开始重新思考解决方案.

能不能做一个docx模板呢, 我当时的想法是这样的, 后来发现还真的可以…

使用Python操作docx文件: python-docx和docxtpl包

使用Python操作docx文件在网上最多的答案是使用python-docx包, 而这个包的强大之处不是在于修改docx文件而是在于创建docx文件. python-docx中对于文档内容的修改是比较复杂和繁琐的.

docxtpl包(docx template)的目的就是为了将docx能够以模板的形式进行编辑, 它依赖于python-docx和jinja 2包.

关于docxtpl-CSDN

具体使用docxtpl来进行docx文档的编辑

docxtpl的使用非常的简单, 只需要准备好一个docx文件, 其中需要渲染数据的地方以jinja 2标签的方式进行填补就可以了.

如果是学过flask的同学一定对于jinja 2标签渲染不会陌生. 因为在flask狗书的开头就会使用flask+boostrap+jinja 2来进行一个前后端合并网站的搭建的.

这里截图举例一个非常简单的docx文档例子:

可以看出我们在需要替换模板数据的地方可以很好的使用jinja 2类标签进行填充.

然后我们可以使用以下代码进行替换(部分数据):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from docxtpl import DocxTemplate

# temp.docx是我们的模板docx文件
tpl = DocxTemplate("temp.docx")
# context是我们需要渲染的数据, 是dict类型
context = {
"data_1": "xxx",
"data_2": "yyy",
"data_3": [
{
"field_1": "111",
"field_2": "222",
"field_3": 333,
},
],
}
# 渲染
tpl.render(context)
# 保存为gen.docx
tpl.save("gen.docx")

可以看出使用docxtpl我们可以很轻松的完成对于docx模板内容的操控.

Linux使用libreoffice在子线程上进行docx到PDF的转换

有了渲染好的docx文件后, 就要进行从docx到PDF文件的转换了, 在网络上找到了很多的方法, 但是很多python的包都是针对于Windows进行转换的, Linux并没有直接用于docx到PDF转换的包, 这个是很令人沮丧的一件事情.

但是也不是完全没有办法, 我们可以利用在Linux上的强大软件Libreoffice: 开辟一个子线程, 然后使用Libreoffice的功能进行转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
import re
import subprocess

class LibreOfficeError(Exception):
def __init__(self, output):
self.output = output

def convert_to(folder, source, timeout=None):
args = ['libreoffice', '--headless', '--convert-to', 'pdf', '--outdir', folder, source]
process = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout)
filename = re.search('-> (.*?) using filter', process.stdout.decode())

if filename is None:
raise LibreOfficeError(process.stdout.decode())
else:
return filename.group(1)
Contents
  1. 1. 使用Python以jinja2方式渲染docx文件: docxtpl
    1. 1.1. 起因:
    2. 1.2. 使用Python操作docx文件: python-docx和docxtpl包
    3. 1.3. 具体使用docxtpl来进行docx文档的编辑
    4. 1.4. Linux使用libreoffice在子线程上进行docx到PDF的转换