工作需要制作每周一次的汇总报表,除了正文以外,还需要把上周的各种报表以附件的方式打包到报表里,有word文档,有excel表格,手工操作是这样的:插入-对象-由文件创建-勾选显示为图标-选择文件-确认,如图:

python向word插入图片 python在word表格里插图片_Word


插入后效果,双击图标可以打开:

python向word插入图片 python在word表格里插图片_python_02


看似简单的工作,但是一共有12个文件,目录不全相同,每次选择要选一次目录,费时费力还容易搞错。想用python来解决问题,发现python-docx只能插入图片,不能插入文件对象,在网上泡了几天没能找到方法。

没办法只好自己动手,我们知道docx实际上是一个压缩文件,解压缩后分析,在word\embeddings找到了这些插入的文件(注意文件名):

python向word插入图片 python在word表格里插图片_Word_03


那么是否可以替换掉这些文件然后再打包来达到我的目的,经过手工测试后发现行得通,下一步就是写代码了。

过程就不说了,绕了很多弯,碰了不少壁,现在分享一下心得和代码:

1.需要先制作word模版文件,要包含插入的文件对象,插入的文件对象可以是空文件,但是对象的文件名不能更改;

2.根据模版文件写入新word文件;

3.解压word文件;

4.替换掉word\embeddings的附件,注意顺序和文件名;

5.重新压缩还原word文件,这一步需要注意的是压缩格式,python zipfile包默认的格式office不认,要指定格定为DEFLATED。

下面是3-5步的代码:

#filename为相关文件列表,filename[0]就是需要处理的主word文件,filename[1]-[12]是12个需要插入的附件
import os,zipfile,shutil       #需要用到的包
azip = zipfile.ZipFile(filename[[0])          #以压缩格式打开word文件
tempdir=''
while True:
    tempdir= ''.join(random.sample(string.ascii_letters + string.digits, 8))   #生行8位临时文件夹名
    if not os.path.exists(tempdir):
        break
os.mkdir(tempdir)                  #创建临时目录
os.chdir(tempdir)                   #转到临时目录
azip.extractall()                     #解压word文件到临时文件夹
azip.close()                           #关闭word文档,否则后面重新压缩会报错
#把正确文件拷贝覆盖模版文件的空附件
try:
    shutil.copy(filename[1],'word\\embeddings\\Microsoft_Excel____.xlsx')
    shutil.copy(filename[2],'word\\embeddings\\Microsoft_Excel____1.xlsx')
    shutil.copy(filename[3],'word\\embeddings\\Microsoft_Excel____2.xlsx')
    shutil.copy(filename[4],'word\\embeddings\\Microsoft_Excel____3.xlsx')
    shutil.copy(filename[5],'word\\embeddings\\Microsoft_Excel____4.xlsx')
    shutil.copy(filename[6],'word\\embeddings\\Microsoft_Word___.docx')
    shutil.copy(filename[7],'word\\embeddings\\Microsoft_Word___5.docx')
    shutil.copy(filename[8],'word\\embeddings\\Microsoft_Word___6.docx')
    shutil.copy(filename[9],'word\\embeddings\\Microsoft_Word___7.docx')
    shutil.copy(filename[10],'word\\embeddings\\Microsoft_Word___8.docx')
    shutil.copy(filename[11],'word\\embeddings\\Microsoft_Word___9.docx')
    shutil.copy(filename[12],'word\\embeddings\\Microsoft_Word___10.docx')
    azip = zipfile.ZipFile(filename[0], 'w')    #以压缩格式新建word文档
    for i in os.walk('.'):                             #使用os.walk遍历整个目录及子目录,保证原有的目录结构不变
        for j in i[2]:
            azip.write(os.path.join(i[0],j), compress_type=zipfile.ZIP_DEFLATED)     #将文件逐个打包到word文档中,压缩格式指定为ZIP_DEFLATED
    azip.close()                                       #关闭文件
    os.chdir('..')
    shutil.rmtree(tempdir,ignore_errors=True)    #删除临时文件夹
except:
    pass

PS:除了word文件,其他的office文档插入的文件对象也可以照这个思路处理。