zoukankan      html  css  js  c++  java
  • 最全总结 | 聊聊 Python 办公自动化之 Word(下)

    image

    1. 前言

    关于 Word 文档的读写,前面两篇文章分别进行了一次全面的总结

    最全总结 | 聊聊 Python 办公自动化之 Word(上)

    最全总结 | 聊聊 Python 办公自动化之 Word(中)

    本篇文章作为一个办公自动化 Word 篇的一个补充,写写几个比较实用的办公场景

    包含:

    • 页眉页脚处理

    • 合并多个文档

    • 新增数字索引

    • doc 批量转 docx

    • 对比文档差异性

    • 特别内容标注

    • 替换文字内容

    2. 页眉页脚

    每一个页面章节都包含:页眉页脚

    它可以单独设置,每个页面都不一样;也可以全部设置成与首页一样

    这个功能,由章节对象中的属性 different_first_page_header_footer 来控制

    • 当值为 True 时,代表页眉页脚不同于首页,每个页面章节的页眉、页脚都可以单独设置

    • 当值为 False 时,所有页面的页眉、页脚都一样

    # 1、获取待处理页眉、页脚的章节
    header = self.doc.sections[0].header
    footer = self.doc.sections[0].footer
    
    # True if this section displays a distinct first-page header and footer
    # True:页眉页脚不同于首页,每个页面章节的页眉页脚单独设置
    # False:每个页面的页眉页脚相同
    self.doc.sections[0].different_first_page_header_footer = True
    

    添加页眉页脚包含两种,分别是:普通页眉页脚、自定义样式的页眉页脚

    1 - 普通页眉页脚

    def add_norm_header_and_footer(header, footer, header_content, footer_content):
        """
        增加一个普通的页眉、页脚,并居中显示
        :param header_content:
        :param footer_content:
        :return:
        """
        # 新增/修改页眉、页脚
        # 注意:一般页眉、页脚里只有一个段落
        header.paragraphs[0].text = header_content
        footer.paragraphs[0].text = footer_content
    
        # 居中显示
        header.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
        footer.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    
    # 2、新增页眉
    # 2.1 普通的页眉、页脚
    add_norm_header_and_footer(header, footer, "我是一个页眉", "我是一个页脚")
    2 - 自带样式的页眉页脚
    

    2 - 自带样式的页眉页脚

    def add_custom_style_header_and_footer(header, footer, header_content, footer_content, style):
        """
        新增自定义的页眉、页脚
        :param header:
        :param footer:
        :param header_content:
        :param footer_content:
        :param style:
        :return:
        """
        # 注意:style_type=2,否则会报错
        header.paragraphs[0].add_run(header_content, style)
        footer.paragraphs[0].add_run(footer_content, style)
    
    # 2.2 自带样式的页眉、页脚
    # 创建一个样式
    style_paragraph = create_style(document=self.doc, style_name="style5", style_type=2, font_size=30,
                                   font_color=[0xff, 0x00, 0x00], align=WD_PARAGRAPH_ALIGNMENT.CENTER)
    add_custom_style_header_and_footer(header, footer, "我是页眉2", "我是页脚2", style_paragraph)
    

    如果想将文档中所有的页眉、页脚删除掉,只需要 2 个步骤:

    • 遍历文档中所有页面章节,将其 different_first_page_header_footer 属性值设置为 False

    • 设置章节对象页眉页脚的 is_linked_to_previous 属性值为 True

      PS:当 is_linked_to_previous 设置为 True 时,页眉页脚会被删除

    def remove_all_header_and_footer(doc):
        """
        删除文档中所有页眉和页脚
        :param doc:
        :return:
        """
        for section in doc.sections:
            section.different_first_page_header_footer = False
            # 当is_linked_to_previous设置为True时,页眉页脚会被删除
            section.header.is_linked_to_previous = True
            section.footer.is_linked_to_previous = True
    

    3. 合并多个文档

    日常工作中,经常会遇到将多个 Word 文档合并成一个文件的需求

    这里,可以使用另外一个 Python 依赖库:docxcompose

    # 合并多个文件的依赖库
    pip3 install docxcompose
    

    使用也非常简单,只需要下面 4 行代码,就能将多个文件进行合并,生成到一个新的文件中去

    from docxcompose.composer import Composer
    
    def compose_files(self, files, output_file_path):
        """
        合并多个word文件到一个文件中
        :param files:待合并文件的列表
        :param output_file_path 新的文件路径
        :return:
        """
        composer = Composer(Document())
        for file in files:
            composer.append(Document(file))
    
        # 保存到新的文件中
        composer.save(output_file_path)
    

    4. 新增数字索引

    我们经常需要在文档页脚处添加页面数字索引,可惜 python-docx 并没有提供现有方法

    但是,在 stackoverflow 上找到实现的方式

    https://stackoverflow.com/questions/56658872/add-page-number-using-python-docx?rq=1

    from docx.oxml.xmlchemy import BaseOxmlElement, ZeroOrOne, ZeroOrMore, OxmlElement
    from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
    from docx.oxml import ns
    
    def create_element(self, name):
        return OxmlElement(name)
    
    def create_attribute(self, element, name, value):
        element.set(ns.qn(name), value)
    
    def add_page_number(self, run):
        """
        添加页面索引
        :param run:
        :return:
        """
        fldChar1 = self.create_element('w:fldChar')
        self.create_attribute(fldChar1, 'w:fldCharType', 'begin')
    
        instrText = self.create_element('w:instrText')
        self.create_attribute(instrText, 'xml:space', 'preserve')
        instrText.text = "PAGE"
    
        fldChar2 = self.create_element('w:fldChar')
        self.create_attribute(fldChar2, 'w:fldCharType', 'end')
    
        # run._r:class 'docx.oxml.text.run.CT_R'>
        run._r.append(fldChar1)
        run._r.append(instrText)
        run._r.append(fldChar2)
    

    默认生成的数字索引在页脚左下角,并不美观!

    因此,这里我们可以使用 第一篇文章 的方法创建一个「文字块样式」,然后以文字块 Run 的形式,添加到页脚的第一个段落中去

    # 注意:要设置页眉页脚的对齐方式,必须设置到段落上(文字块不能添加对齐方式)
    doc.sections[0].footer.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    
    # 创建一个文字块样式,指定字体名称、大小、颜色
    style = create_style(document=doc, style_name="style", style_type=2, font_size=10,
                         font_color=[0x00, 0x00, 0x00], font_name="黑体")
    self.add_page_number(doc.sections[0].footer.paragraphs[0].add_run("", style))
    doc.save("./output.docx")
    print('添加页码索引成功!')
    
    

    需要注意的,如果需要设置页面数字索引的对齐方式,必须针对页脚的段落进行设置,修改其 alignment 属性值即可

    5. doc 转 docx

    python-docx 对 doc 格式的文档不太友好,要处理这类文档,我们需要先将它转换为 docx 格式

    对于 Windows 系统,完全可以使用 win32com 这个模块,用命令去调用 Word 应用,打开源文件后,保存了 docx 格式的文件即可

    from win32com import client
    
    def doc_to_docx_in_win(path_raw, path_output):
    ​    """
        doc转为docx(win)
        :param path_original:
        :param path_final:
        :return:
        """
        # 获取文件的格式后缀
        file_suffix = os.path.splitext(path_raw)[1]
        if file_suffix == ".doc":
            word = client.Dispatch('Word.Application')
            # 源文件
            doc = word.Documents.Open(path_raw)
            # 生成的新文件
            doc.SaveAs(path_output, 16)
            doc.Close()
            word.Quit()
        elif file_suffix == ".docx":
            shutil.copy(path_raw, path_output)
    

    而对于 Mac/Linux,推荐使用 LibreOffice 去转换文档格式

    # 转换格式
    ./soffice --headless --convert-to docx 源文件.doc --outdir /output/path/
    

    PS:LibreOffice 是一款由社区创造的自由免费办公套件,跨平台,内置的 soffice 可以用于文件转换

    以 Mac OS 为例,我们按下面步骤来操作

    • 官网下载 LibreOffice 软件并安装

    • 找到 LibreOffice 软件安装目录,将 soffice 命令所在目录配置到环境变量中

    • 重启 Pycharm

    • 使用 os 模块下的 walk() 函数遍历所有源文件,组成一条 soffice 转换命令

    • 执行转换命令

    import os
    
    source = "./doc/"
    dest = "./docx/"
    g = os.walk(source)
    
    # 遍历文件夹
    for root, dirs, files in g:
        for file in files:
            # 源文件完整路径
            file_path_raw = os.path.join(root, file)
            print(file_path_raw)
    
            os.system("soffice --headless --convert-to docx {} --outdir {}".format(file_path_raw, dest))
    

    6. 对比文档差异性

    两个 Word 文档的对比也是工作中比较常见的需求了

    首先,遍历文档中所有段落,过滤掉空行,获取所有文本内容

    # 分别获取段落内容
    content1 = ''
    content2 = ''
    for paragraph in file1.paragraphs:
    ​    if "" == paragraph.text.strip():
            continue
        content1 += paragraph.text + '
    '
    
    for paragraph in file2.paragraphs:
        if "" == paragraph.text.strip():
            continue
        content2 += paragraph.text + '
    '
    
    # 如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
    print("第二个文档数据如下:
    ", content1.splitlines(keepends=False))
    print("第一个文档数据如下:
    ", content1.splitlines(keepends=False))
    

    接着,使用 Python 中的标准依赖库 difflib 对比文字间的差异,最后生成 HTML 差异报告

    import codecs
    from difflib import HtmlDiff
    
    # 差异内容
    diff_html = HtmlDiff(wrapcolumn=100).make_file(content1.split("
    "), content2.split("
    "))
    
    # 写入到文件中
    with codecs.open('./diff_result.html', 'w', encoding='utf-8') as f:
         f.write(diff_html)
    

    7. 特别内容标注

    我们经常需要对文档中部分重要内容进行特别标注

    比如,我们需要对文档中包含「 微信 」的文字块或单元格,标为红色并加粗显示

    1 - 段落内容

    只需要遍历出段落中所有文字块 Run,直接修改文字块的 Font 属性即可

    doc = Document(file)
    
    # 关键字的文字块或单元格标红,并加粗
    # 1、修改段落中包含关键字的文件块的样式
    for paragraph in doc.paragraphs:
        for run in paragraph.runs:
            if keyword in run.text:
                # 修改颜色为红色,并加粗显示
                run.font.bold = True
                run.font.color.rgb = RGBColor(255, 0, 0)
    

    2 - 表格内容

    设置满足条件的单元格样式有点特别,需要经过下面 4 个步骤

    • 获取单元格对象,获取单元格文本内容,并临时保存

    • 清空单元格数据

    • 单元格对象追加一个段落和一个文字块 Run,返回一个文字块对象

    • 设置文字块对象样式,标红并加粗

    tables = [table for table in doc.tables]
    for table in tables:
        for row in table.rows:
            for cell in row.cells:
                if keyword in cell.text:
                    # 原内容
                    content_raw = cell.text
                    # 清空单元格数据
                    cell.text = ""
                    # 追加数据进去,并设置样式
                    run = cell.paragraphs[0].add_run(content_raw)
                    run.font.color.rgb = RGBColor(255, 0, 0)
                    run.font.bold = True 
    

    8. 替换文字内容

    有时候,我们需要将文档中某个关键字全部替换成一个新的内容

    这时候,我们可以遍历所有段落和表格,使用 replace() 函数对段落文本和单元格内容进行替换

    def replace_content(self, old_content, new_content):
    ​    """
        替换文档中所有内容
        :param old_content:旧的内容
        :param new_content:新的内容
        :return:
        """
        # 替换段落
        for paragraph in self.doc.paragraphs:
            if old_content in paragraph.text:
                # 替换内容后,重新设置进去
                paragraph.text = paragraph.text.replace(old_content, new_content)
    
        # 替换表格
        # document.tables[表格索引].rows[行索引].cells[单元格列索引].text = “新的数据”。
        tables = [table for table in self.doc.tables]
        for table in tables:
            for row in table.rows:
                for cell in row.cells:
                    if old_content in cell.text:
                        # 重新设置单元格内容
                        cell.text = cell.text.replace(old_content, new_content)
    
        # 保存到一个新的文件中
        self.doc.save('./new.docx')
    

    9. 最后

    到此,Python 自动化 Word 篇的内容全部结束了!

    如果实际工作中,有一些其他的业务场景文中没有覆盖到,可以在文末进行留言,后面办公自动化实战篇可能会提供对应的解决方案!

    要获取全部源码,关注公众号「 AirPython 」,后台回复「 word 」即可获得全部源码

    如果你觉得文章还不错,请大家 点赞、分享、留言下,因为这将是我持续输出更多优质文章的最强动力!

    推荐阅读
    最全总结 | 聊聊 Python 办公自动化之 Excel(上)

    最全总结 | 聊聊 Python 办公自动化之 Excel(中)

    最全总结 | 聊聊 Python 办公自动化之 Excel(下)

    最全总结 | 聊聊 Python 办公自动化之 Word(上)

    最全总结 | 聊聊 Python 办公自动化之 Word(中)

  • 相关阅读:
    处理跨浏览器的事件处理程序
    html5 canvas时钟
    拖拽事件的原理
    改变top使用轮播图
    程序开发之最大子数组
    第四周学习进度
    敏捷开发相关阅读
    构建之法读书笔记04
    四则运算终结版
    第三周学习进度
  • 原文地址:https://www.cnblogs.com/xingag/p/14038340.html
Copyright © 2011-2022 走看看