1. 根据模板批量生成文档

想要运用python来编辑word是有些难度的,主要是因为文档涉及到的因素比较多,仅仅是字体就有颜色、大小、加粗等等属性,这也就造成了使用python“无中生有”一个文档的困难性。

这里推荐一个使用模板批量生成文档的包:mailmerge

1.1 制定模板文件docx

我个人使用的是WPS,office的Word操作大同小异。

首先点击插入

Python wps模块 python wps文档_Python wps模块

之后点击文档部件,并选择,之后在弹出的对话框中选择邮件合并

Python wps模块 python wps文档_Python wps模块_02

在域代码那一栏后面写上变量名,

Python wps模块 python wps文档_python3_03

点击确定后得到:

Python wps模块 python wps文档_docx_04

重复操作得到如下所示结果:

 

Python wps模块 python wps文档_数组_05

上面的操作可以简单地理解为创建了几个“变量”,“变量”的格式就是之后生成的真实文档的格式,这样也就简化了多属性操作,之后我们就可以在python中通过docx-mailmerge库用实际的值来替换模板中的“变量”而得到真实文档。

(注:文件的扩展名必须是经由WPS/Office生成的.docx)。 

1.2 安装包

安装则比较简单:

pip3 install docx-mailmerge

1.3 生成单文档

from mailmerge import MailMerge


def write2docx(datum, template_name, output):
    doc = MailMerge(template_name)
    doc.merge(**datum)

    doc.write(output)

if __name__ == '__main__':
    datum = {'teacher_name': '路人甲', 'day': '365', 'name': '路人乙', 'date': '2019-01-01'}
    write2docx(datum, 'template.docx', '请假单.docx')

代码比较简单,需要注意的是变量的值必须是字符串,如果是其他的类型的话则可能会报错。上面的代码是根据模板生成的单文档, 如果要生成多个文档的话可以重复调用上面的函数。

1.4 生成一个多文档

mailmerge还可以根据模板生成一个多文档,这里所说的多文档就相当于若干个相同模板生成的单文档的合并,代码也比较简洁:

def write2one_docx(data, template, output, separator='page_break'):
    """
    根据data数组生成一个len(data)个的一个总文档
    :param data: 数组,键值对用来替换模板
    :param template: 模板完整名称
    :param output: 输出文件名称
    :param separator: 分隔符 默认为换页符
    :return:
    """
    doc = MailMerge(template)
    doc.merge_templates(data, separator=separator)

    doc.write(output)

if __name__ == '__main__':
    data = [
        {'teacher_name': 'sky', 'day': '3', 'name': 'moon', 'date': '2019/11/26'},
        {'teacher_name': '周志华', 'day': '3', 'name': 'moon', 'date': '2019/11/26'},
    ]
    write2one_docx(data, 'template.docx', 'two.docx', separator='textWrapping_break')

'page_break'是换页符,'textWrapping_break'是换行符。

导出的文档内容结果如下:

Python wps模块 python wps文档_python3_06

 2. 合并多个文档

把多个文件合并成为一个文件的解决办法是:打开一个文件,读取该文件的内容并添加到新文件的末尾。文档的合并也与此类似。

2.1 安装

pip install python-docx

2.2 代码的编写

def combine_word_documents(files, output):
    from docx import Document
    """
    合并多个文档为一个文档 目前会造成部分格式问题 需要保证输出文件所在的路径存在
    :param files: 数组,保存着要合并的文件路径
    :param output: 合并文件名称
    :return:
    """
    merged_document = Document()

    for index, file in enumerate(files):
        sub_doc = Document(file)

        # 在文档和文档之间添加一个换页
        if index < len(files) - 1:
            sub_doc.add_page_break()
        # 添加到总文件里
        for element in sub_doc.element.body:
            merged_document.element.body.append(element)

    merged_document.save(output)

实现起来并不算困难,不过我在合并文档的时候发现某些文字的格式会发生改变。

3. 读取一个xlsx文件

 openpyxl可以对xlsx文件进行操作。

3.1 安装

pip install openpyxl

3.2 读取xlsx并生成字典数组

def read_xlsx2dict(filename, sheet=None, callback=None):
    """
    读取excel文件,并得到[{}] 以第一行为键,其他行为指
    :param filename: 扩展名为xlsx的文件
    :param sheet: 要读取的sheet名称
    :param callback: callback(key, value)返回值用以代替原来的value
    :return: 数组
    """
    workbook = load_workbook(filename=filename)
    # 获取sheet
    sheet_names = workbook.sheetnames
    sheet = sheet_names[0] if not sheet else sheet
    table = workbook[sheet]
    # 把第一行作为键
    keys, index = None, 0
    # 按照行进行遍历
    for row in table.rows:
        line = []
        is_none = True
        # 获取每一个列
        for col in row:
            line.append(col.value)
            is_none = is_none and col.value is None
        # 第一列作为键
        if index == 0:
            keys = [key for key in line if key is not None]
        elif not is_none:
            datum = {}
            for i in range(len(keys)):
                if not callback:
                    datum[keys[i]] = callback(keys[i], line[i])
                else:
                    datum[keys[i]] = line[i]
            yield datum
        index += 1

默认读取第一个sheet。因为要生成键值对,所以该函数把第一行当作键,其他行则作为值,据此生成一个字典数组。

 

相关代码:https://github.com/sky94520/tools

word.py和src/template.docx