添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Python把图片文件和Excel表格数据批量自动地写到Word文档中

需求

在集体资产清查测绘相关的工作,外业调查的结果都写在Excel表格中,另外还有房屋测绘图、外业的照片文件;集体资产清查测绘汇交的报告需要把Excel表格中的数据和相关图片按照一定的规则写到Word文档报告中。

这种工作如果都是人手动去编辑Word文档报告,一方面工作量大,另外Word文档的质量也很难把控;更重要的是Excel中的一个信息改了也要手动同步Word文档。本文基于Python提供的相关类库,实现批量把Excel表格数据和照片文件写到Word文档,以提高形成Word文档报告的效率和质量。

实现逻辑

第一步:Excel表格数据读取

第一步是读取Excel表格中数据并进行标准化,为了方便后续脚本读取,这里使用字典数据类型存储表格的数据。Python操作Excel表格的类库很多,具体可以参考前面的文章: Python3操作Excel常用库整理(xlrd/xlwt,openpyxl,xlwings和xlsxwriter)

本文选用 xlwings库,因为 xlwings库支持xls和xlsx格式的Excel文件,同时支持使用单元格号进行定位,定位读取到单元格的值非常方便,例如通过下面的语句就可以获取到G2单元格的值。

import xlwings as xw
app = xw.App(visible=False, add_book=False)
app.display_alerts = False
app.screen_updating = False  # 是否实时刷新excel程序的显示内容
wb = app.books.open(excelpath) #根据文件路径读取Excel表格
sheet=wb.sheets[0]              #获取到第一个表格
value=sheet.range('G2').value    #通过G2单元格号获取单元格值

第二步:表格数据和图片写入word文档

本文操作word文档使用的Python库为docx,通过docx库可以实现表格数据和图片写入到word文档中。因为这次的word文档报告比较有规律,如一个楼栋的信息保存到word文档的一张表中(一楼一张表保存到word文档的一页),楼层的每层信息保存到word文件的一张表中(一层一张表保存到word文档的一页中)……,所以把word文档以内容进行划分为多个word文档模板,Python脚本就可以读取对应的模板批量生成对应的报告。word文档模板文件列表如下图

模板文件

Python脚本把数据写入word文件 需要解决两个难点:一个是数据定位,就是Excel数据写到Word文档的哪个位置;另一个是Word文档的格式控制 ,本文为了偷懒,把一个完整的报告切分为多个模板文件,格式尽可能在模板文件中定义好。

参考了网上的很多文章, 在Python脚本中Word文档数据定位的逻辑其实跟我们在office软件中进行关键词的替换类似 ;首先我们也是在Word文档中定义了很多关键词,然后通过Python脚本用Excel中的数据去替换这些关键词;所以这里就要与第一步获取的Excel数据字典对应起来。如楼层表的数据和图片的定位如下图所示。

楼层表变量设置

这个逻辑梳理清晰后,更多的工作量就是把Excel数据字典的值与Word文档模板中的变量对应起来;Python脚本中批量地进行变量替换和插入图片的核心函数代码如下:

def replaceText2(docment, dic):
    替换word文档中的变量
    :param docment:word文档对象
    :param dic: 替换值的字典
    :return:
    for para in docment.paragraphs:
        runs = para.runs
        for i, run in enumerate(runs):
            if str(run.text).startswith('#'): 
                count = i  # 记录启动子位置
                tmp = run.text # '#'  # tmp写入启动子
                while tmp not in list(dic.keys()):  # tmp继续写入启动子后的run,直到tmp和dic中的键匹配
                    count += 1
                    tmp += runs[count].text
                    runs[count].clear()
                runs[i].text = runs[i].text.replace(runs[i].text, dic[tmp])
    for table in docment.tables:
        for row in table.rows:
            for cell in row.cells:
                #遍历表格段落内容,回到上个步骤,将cell当作paragraph处理
                for paragraph in cell.paragraphs:
                    runs = paragraph.runs
                    for i, run in enumerate(runs):
                        #替换功能
                        if str(run.text).startswith('#'):
                            num = i  # 记录启动子位置
                            tmp = run.text #'#'  # tmp写入启动子
                            while tmp not in list(dic.keys()):  # tmp继续写入启动子后的run,直到tmp和dic中的键匹配
                                num += 1
                                tmp += runs[num].text
                                runs[num].clear()
                            runs[i].text = runs[i].text.replace(runs[i].text, str(dic[tmp]))
def addPicToWord(picPath,docment):
    图片插入到word文档中
    :param picPath: 图片的路径
    :param docment: word文档对象
    :return: 
    for table in docment.tables:
        for row in table.rows:
            for cell in row.cells:
                for paragraph in cell.paragraphs:
                    # 根据文档中的占位符定位图片插入的位置
                    if '<<pic>>' in paragraph.text:
                        # 把占位符去掉
                        paragraph.text = paragraph.text.replace('<<pic>>', '')
                        run = paragraph.add_run('')
                        if picPath!=None:
                            # 添加图片并根据表格的高度进行缩放
                            picture=run.add_picture(picPath)
                            source_height=picture.height
                            afterheight=row.height-10000
                            picture.height = afterheight
                            picture.width = int(picture.width * (afterheight / source_height))   

word文档模板中的表格行数是固定的,遇到楼栋数量较多时,需要在楼栋总表word文档模板的表格中根据数据的情况,在表格指定位置(不是表格最后)自动添加行;例如需要在表格的第i行插入新的一行;脚本中指定位置插入一行的逻辑有点像我们在office中手动操作word文档,插入复制行的逻辑,添加行用到的代码如下:

from copy import deepcopy
new_table_row = deepcopy(table.rows[i-1]) #把第i-1行 进行深复制
table.rows[i]._tr.addprevious(new_table_row._element) #在第i行插入复制的行

以多个word文档模板的方式可以解决绝大部分的格式问题,但是在实际的操作中一些格式还是无法自动地进行设置;例如单元格的样式设置函数代码如下:通过代码可以精细化设置单元格的字体样式,字号大小,对齐方式等。

def setCellStyle(cell,docment):
    设置word文档表格单元格的样式
    :param cell: 单元格对象
    :param docment: word文档对象
    :return: 
    # 设置字体
    cell.paragraphs[0].style = docment.styles["Normal"]
    for paragraph in cell.paragraphs:
        for run in paragraph.runs:
            font = run.font