手把手教你使用python的zipfile模块巧解word批量生成问题
马哥Linux运维
共 6540字,需浏览 14分钟
·
2022-01-18 18:17
今天给大家分享使用python的zipfile模块巧解word批量生成问题,这里提供两种方案给大家参考。
方案一:使用python-docx.Document读取word文档
方案二:zipfile巧解word文档
平台:windows10
解释器:python3.7
任务需求
任务拆解
任务方案
方案一:使用python-docx.Document读取word文档
问题一:模块安装错误,文章中import docx,我误以为pip install docx就行了,而调用Document类时,发现模块下无该类,遂进行百度,应当时pip install python-docx,import docx。 问题二:python-docx模块不能操作doc文档,上述已提到,本次处理的word文档为doc后缀,需要将其转换docx后缀方可正常操作,其实一个文档通过word软件进行另存为即可,但是在python编程中就显得不太优雅,主要是我太懒了,最多就将目标文件路径拷贝至代码中,所以使用win32com模块调用word程序转换doc文档为docx文档。 问题三:文章中是定位到具体文本段在进行替换,首次尝试时,发现并不能替换成功,将代码逐步运行定位问题所在。可以想象下Document是将整个word文档分成多个paragraphs,一个paragraphs有很多行,每行有多个文本块,由于每行中的文本块的划分不太明白,中英文输入法不同方式输入的中/英文会导致本是一个单词被拆开,也有可能是该word文档中含有一定格式造成,如下划线,在无下划线的情况下,单词没有被分开,尝试用paragraphs.text进行内容的替换,文本可以替换成功,但下划线的格式被丢弃,所以只能采取文本块下的text方法进行替换,在原word文件中用同一种输入法输入英文(与excel的列名相对应,应保证该字符串不在word中其他地方出现,即中文也是可以的,推荐写法:#列名#)
from copy import deepcopy
from pathlib import Path
from win32com import client as wc # pip install pypiwin32
from docx import Document # pip install python-docx
import pandas as pd
# python-docx不能处理doc文档,使用win32com转存为docx文档
def doctransform2docx(doc_path):
docx_path = doc_path + 'x'
suffix = doc_path.split('.')[1]
assert 'doc' in suffix, '传入的不是word文档,请重新输入!'
if suffix == 'docx':
return Document(doc_path)
word = wc.Dispatch('Word.Application')
doc = word.Documents.Open(doc_path)
doc.SaveAs2(docx_path, 16) # docx为16
doc.Close()
word.Quit()
return Document(docx_path)
# 替换docx中的特定字符,由于run方法在有格式的docx文件中展示效果很差,故将docx中的文本的需要填充出英文字符占位
def replace_docx(name, values, wordfile, path_name='Company'):
wordfile_copy = deepcopy(wordfile) # 防止原文件被篡改,deepcopy为副本
for col_name, value in zip(name, values):
if col_name == 'Company':
path_name = str(value)
for paragraphs in wordfile_copy.paragraphs:
for run in paragraphs.runs:
run.text = run.text.replace(col_name, str(value))
# docx文档替换完毕,另存为,一定要用绝对路径
wordfile_copy.save(f'{save_folder}/{path_name}.docx')
if __name__ == '__main__':
# 定义需处理的文件路径
doc_path = r"D:\solve_path\单位.doc"
excel_path = r"D:\solve_path\信息.xls"
save_folder = Path('D:/docx_save')
save_folder.mkdir(parents=True, exist_ok=True) # 文件夹没有时自动创建
# 获取excel数据
data = pd.read_excel(excel_path)
wordfile = doctransform2docx(doc_path)
data_save = data.apply(lambda x: replace_docx(x.index, x.values, wordfile), axis=1)
方案二:zipfile巧解word文档
问题一:文章中的压缩文件为zipfile.ZIP_DEFLATED,对遍历后的所有文件进行压缩至一个目录下,这就出现了还原后的docx内的文件层次不对应,docx读取失败。改用zipfile.zlib.DEFLATED方可成功按层次压缩。 问题二:zipfile压缩文件保存时,应当有文件名及其别名,且别名不能为绝对路径,为了能正常还原也应使用原有名称,在代码中为f.write(文件路径, 文件路径别名)
from shutil import rmtree
import zipfile
from copy import deepcopy
from pathlib import Path
from win32com import client as wc # pip install pypiwin32
import pandas as pd
# doc文档不包含所需xml文件,使用win32com转存为docx文档
def doctransform2docx(doc_path):
docx_path = doc_path + 'x'
suffix = doc_path.split('.')[1]
assert 'doc' in suffix, '传入的不是word文档,请重新输入!'
if suffix == 'docx':
return Path(doc_path)
word = wc.Dispatch('Word.Application')
doc = word.Documents.Open(doc_path)
doc.SaveAs2(docx_path, 16) # docx为16
doc.Close()
word.Quit()
return Path(docx_path)
# docx文档解压
def docx_unzip(docx_path):
docx_path = Path(docx_path) if isinstance(docx_path, str) else docx_path
upzip_path = docx_path.with_name(docx_path.stem)
with zipfile.ZipFile(docx_path, 'r') as f:
for file in f.namelist():
f.extract(file, path=upzip_path)
xml_path = upzip_path.joinpath('word/document.xml')
with xml_path.open(encoding='utf-8') as f:
xml_file = f.read()
return upzip_path, xml_path, xml_file
# 讲文件夹中的所有文件压缩成docx文档
def docx_zipped(docx_path, zipped_path):
docx_path = Path(docx_path) if isinstance(docx_path, str) else docx_path
with zipfile.ZipFile(zipped_path, 'w', zipfile.zlib.DEFLATED) as f:
for file in docx_path.glob('**/*.*'):
f.write(file, file.as_posix().replace(docx_path.as_posix() + '/', ''))
# 删除生成的解压文件夹
def remove_folder(path):
path = Path(path) if isinstance(path, str) else path
if path.exists():
rmtree(path)
else:
raise "系统找不到指定的文件"
# 替换docx中的特定字符,重新保存document.xml至需要压缩的目录下
def replace_docx(name, values, xml_file, xml_path, unzip_path, path_name='Company'):
xml_path = Path(xml_path) if isinstance(xml_path, str) else xml_path
xml_file_copy = deepcopy(xml_file) # 深复制xml内容
for col_name, value in zip(name, values):
if col_name == 'Company':
path_name = str(value)
xml_file_copy = xml_file_copy.replace(col_name, str(value))
with xml_path.open(mode='w', encoding='utf-8') as f:
f.write(xml_file_copy)
# xml文档替换完毕,通过zipfile重新压缩另存为docx文档
docx_zipped(unzip_path, f'{save_folder}/{path_name}.docx')
if __name__ == '__main__':
# 定义需处理的文件路径
doc_path = r"D:\solve_path\单位.doc"
excel_path = r"D:\solve_path\信息.xls"
save_folder = Path('D:/docx_save')
save_folder.mkdir(parents=True, exist_ok=True) # 文件夹没有时自动创建
# 获取excel数据
data = pd.read_excel(excel_path)
docx_path = doctransform2docx(doc_path)
unzip_path, xml_path, xml_file = docx_unzip(docx_path)
data_save = data.apply(lambda x: replace_docx(x.index, x.values, xml_file, xml_path, unzip_path), axis=1)
remove_folder(unzip_path)
总结
原文链接:https://blog.csdn.net/weixin_46281427/article/details/121588786
文章转载:Python编程学习圈
(版权归原作者所有,侵删)
评论