新四季網

python生成word目錄(手把手教你使用python的zipfile模塊巧解word批量生成問題)

2023-09-21 13:50:50

今天給大家分享使用python的Zipfile模塊巧解word批量生成問題,這裡提供兩種方案給大家參考。

方案一:使用python-docx.Document讀取word文檔

方案二:zipfile巧解word文檔

平臺:windows10

解釋器:python3.7

任務需求

現有一包含目標數據的excel文檔,需要將其中的每一行數據的對應內容替換到指定word中,並逐一保存。

任務拆解

首先查看word文檔格式,可以看到文件後綴為.doc,需要替換的是正文部分紅框中的英文部分。

目標數據excel文檔,將excel中的對應列下的數據替換到word文檔中。

excel數據比較規整無需二次處理,如果列名與word文檔中不對應或者沒有,則需要調整或新增。如此一來只要考慮如何讀取doc文件並按一定邏輯進行替換即可。

任務方案

方案一:使用python-docx.Document讀取word文檔

在這次需求之前我並沒有用過python操作word文檔,感謝交流群內各位大佬相助,從Python Excel 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文檔。

問題三:Python Excel Word一秒製作百份合同這篇文章中是定位到具體文本段在進行替換,首次嘗試時,發現並不能替換成功,將代碼逐步運行定位問題所在。可以想像下Document是將整個word文檔分成多個paragraphs,一個paragraphs有很多行,每行有多個文本塊,由於每行中的文本塊的劃分不太明白,中英文輸入法不同方式輸入的中/英文會導致本是一個單詞被拆開,也有可能是該word文檔中含有一定格式造成,如下劃線,在無下劃線的情況下,單詞沒有被分開,嘗試用paragraphs.text進行內容的替換,文本可以替換成功,但下劃線的格式被丟棄,所以只能採取文本塊下的text方法進行替換,在原word文件中用同一種輸入法輸入英文(與excel的列名相對應,應保證該字符串不在word中其他地方出現,即中文也是可以的,推薦寫法:#列名#)

將上述問題逐一解決後,輸入目標文件路徑及輸入路徑就大功告成了。源碼:

from copy import deepcopyfrom pathlib import Pathfrom win32com import client as wc # pip install pypiwin32from docx import Document # pip install python-docximport 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為16doc.Closeword.Quitreturn 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)

在我以為大功告成之際,問題來了,原文檔中的方框沒了(漏!!!) 效果圖:

解決了格式卻解決不了特殊字符問題,禿了啊……,我想python-docx中一定有相應的解決方案,但是我初次嘗試,對其中源碼部分猶如天書般的存在,在多次調用方法下發現其中的一個參數輸出,wordfile.part.blob:

輸出內容讓我想起了之前解密excel時看到的文件開頭,xml文件,然後首先嘗試替換其中文本,原以為會像run.text = run.text.replace(col_name, str(value))一樣即可,然而報錯了,禁止修改。

方案二:zipfile巧解word文檔

正當我認為別無他法時,就此作罷時,百度百科幫助了我:

docx文檔本質上就是xml文件,emmmm,很妙,之前為了提取xlsx中的圖片解壓縮過xlsx文件然後提取,果然可行,替換的主體文件就是word文件夾下的document.xml文件

當然在代碼編寫前首先嘗試能不能手動復原為docx,用7z默認參數還原失敗,經過多番尋找,用zip類型壓縮即可,軟體不限,手動解壓及替換字符壓縮均成功,開始敲代碼。除習慣性用pandas讀取excel文件外,也不用安裝其他包,在現用python3.7中均為內置包。使用zipfile對壓縮類文件進行解壓,文章學習來源:

python中如何壓縮和解壓縮文件https://www.cnblogs.com/rongge95500/p/11271764.html

文章中寫得很詳細,我僅把os.path改寫成pathlib。但在對目錄下文件進行壓縮還原至docx文檔時出現了問題:

問題一:文章中的壓縮文件為 zipfile.ZIP_DEFLATED,對遍歷後的所有文件進行壓縮至一個目錄下,這就出現了還原後的docx內的文件層次不對應,docx讀取失敗。改用zipfile.zlib.DEFLATED方可成功按層次壓縮。

問題二:zipfile壓縮文件保存時,應當有文件名及其別名,且別名不能為絕對路徑,為了能正常還原也應使用原有名稱,在代碼中為f.write(文件路徑, 文件路徑別名)

源碼:

from shutil import rmtreeimport zipfilefrom copy import deepcopyfrom pathlib import Pathfrom win32com import client as wc # pip install pypiwin32import 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為16doc.Closeword.Quitreturn Path(docx_path)# docx文檔解壓def docx_unzip(docx_path):docx_path = Path(docx_path) if isinstance(docx_path, str) else docx_pathupzip_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.readreturn 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_pathwith 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 pathif 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_pathxml_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)

打開生成的文件,方框沒有消失,下劃線也在。

總結

經過幾番嘗試後,也是我的學識不深,在跌跌撞撞中找到一種既能替換docx中的字符串也不會改變原有格式的方案,相信一定會有更好的方案,只是此時我沒有找到,時間是不停地向前的,我也不應落下,以求共同富貴。如對此有疑問歡迎評論區留言。

PS: 如果電腦安裝的是WPS,可以嘗試手動轉換doc格式為docx格式,再進行批量操作。

於二零二一年十一月二十八日作

版權聲明:本文為CSDN博主「宿者朽命」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本聲明。

原文連結:https://blog.csdn.net/weixin_46281427/article/details/121588786

,
同类文章
葬禮的夢想

葬禮的夢想

夢見葬禮,我得到了這個夢想,五個要素的五個要素,水火只好,主要名字在外面,職業生涯良好,一切都應該對待他人治療誠意,由於小,吉利的冬天夢想,秋天的夢是不吉利的
找到手機是什麼意思?

找到手機是什麼意思?

找到手機是什麼意思?五次選舉的五個要素是兩名士兵的跡象。與他溝通很好。這是非常財富,它擅長運作,職業是仙人的標誌。單身男人有這個夢想,主要生活可以有人幫忙
我不怎麼想?

我不怎麼想?

我做了什麼意味著看到米飯烹飪?我得到了這個夢想,五線的主要土壤,但是Tu Ke水是錢的跡象,職業生涯更加真誠。他真誠地誠實。這是豐富的,這是夏瑞的巨星
夢想你的意思是什麼?

夢想你的意思是什麼?

你是什​​麼意思夢想的夢想?夢想,主要木材的五個要素,水的跡象,主營業務,主營業務,案子應該抓住魅力,不能疏忽,春天夢想的吉利夢想夏天的夢想不幸。詢問學者夢想
拯救夢想

拯救夢想

拯救夢想什麼意思?你夢想著拯救人嗎?拯救人們的夢想有一個現實,也有夢想的主觀想像力,請參閱週宮官方網站拯救人民夢想的詳細解釋。夢想著敵人被拯救出來
2022愛方向和生日是在[質量個性]中

2022愛方向和生日是在[質量個性]中

[救生員]有人說,在出生88天之前,胎兒已經知道哪天的出生,如何有優質的個性,將走在什麼樣的愛情之旅,將與生活生活有什么生活。今天
夢想切割剪裁

夢想切割剪裁

夢想切割剪裁什麼意思?你夢想切你的手是好的嗎?夢想切割手工切割手有一個真正的影響和反應,也有夢想的主觀想像力。請參閱官方網站夢想的細節,以削減手
夢想著親人死了

夢想著親人死了

夢想著親人死了什麼意思?你夢想夢想你的親人死嗎?夢想有一個現實的影響和反應,還有夢想的主觀想像力,請參閱夢想世界夢想死亡的親屬的詳細解釋
夢想搶劫

夢想搶劫

夢想搶劫什麼意思?你夢想搶劫嗎?夢想著搶劫有一個現實的影響和反應,也有夢想的主觀想像力,請參閱週恭吉夢官方網站的詳細解釋。夢想搶劫
夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂什麼意思?你夢想缺乏異常藥物嗎?夢想缺乏現實世界的影響和現實,還有夢想的主觀想像,請看官方網站的夢想組織缺乏異常藥物。我覺得有些東西缺失了