<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 7207字,需瀏覽 15分鐘

           ·

          2021-12-02 11:59

          點(diǎn)擊上方“Python爬蟲與數(shù)據(jù)挖掘”,進(jìn)行關(guān)注

          回復(fù)“書籍”即可獲贈Python從入門到進(jìn)階共10本電子書

          莫學(xué)武陵人,暫游桃源里。

          大家好,我是宿者朽命,微信名是【??(這是月亮的背面)】,今天給大家分享使用python的zipfile模塊巧解word批量生成問題,這里提供兩種方案給大家參考。

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

          • 方案二:zipfile巧解word文檔


          • 平臺:windows10
          • 解釋器:python3.7

          任務(wù)需求

          現(xiàn)有一包含目標(biāo)數(shù)據(jù)的excel文檔,需要將其中的每一行數(shù)據(jù)的對應(yīng)內(nèi)容替換到指定word中,并逐一保存。

          任務(wù)拆解

          首先查看word文檔格式,可以看到文件后綴為.doc,需要替換的是正文部分紅框中的英文部分。目標(biāo)數(shù)據(jù)excel文檔,將excel中的對應(yīng)列下的數(shù)據(jù)替換到word文檔中。excel數(shù)據(jù)比較規(guī)整無需二次處理,如果列名與word文檔中不對應(yīng)或者沒有,則需要調(diào)整或新增。如此一來只要考慮如何讀取doc文件并按一定邏輯進(jìn)行替換即可。

          任務(wù)方案

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

          在這次需求之前我并沒有用過python操作word文檔,感謝交流群內(nèi)各位大佬相助,從Python+Excel+Word一秒制作百份合同文章中雖然跟著步伐編寫代碼,而當(dāng)執(zhí)行時(shí)報(bào)錯了,目標(biāo)字符串沒有被替換上等等。

          • 問題一:模塊安裝錯誤,文章中import docx,我誤以為pip install docx就行了,而調(diào)用Document類時(shí),發(fā)現(xiàn)模塊下無該類,遂進(jìn)行百度,應(yīng)當(dāng)時(shí)pip install python-docx,import docx。
          • 問題二:python-docx模塊不能操作doc文檔,上述已提到,本次處理的word文檔為doc后綴,需要將其轉(zhuǎn)換docx后綴方可正常操作,其實(shí)一個文檔通過word軟件進(jìn)行另存為即可,但是在python編程中就顯得不太優(yōu)雅,主要是我太懶了,最多就將目標(biāo)文件路徑拷貝至代碼中,所以使用win32com模塊調(diào)用word程序轉(zhuǎn)換doc文檔為docx文檔。
          • 問題三:Python+Excel+Word一秒制作百份合同這篇文章中是定位到具體文本段在進(jìn)行替換,首次嘗試時(shí),發(fā)現(xiàn)并不能替換成功,將代碼逐步運(yùn)行定位問題所在??梢韵胂笙翫ocument是將整個word文檔分成多個paragraphs,一個paragraphs有很多行,每行有多個文本塊,由于每行中的文本塊的劃分不太明白,中英文輸入法不同方式輸入的中/英文會導(dǎo)致本是一個單詞被拆開,也有可能是該word文檔中含有一定格式造成,如下劃線,在無下劃線的情況下,單詞沒有被分開,嘗試用paragraphs.text進(jìn)行內(nèi)容的替換,文本可以替換成功,但下劃線的格式被丟棄,所以只能采取文本塊下的text方法進(jìn)行替換,在原word文件中用同一種輸入法輸入英文(與excel的列名相對應(yīng),應(yīng)保證該字符串不在word中其他地方出現(xiàn),即中文也是可以的,推薦寫法:#列名#)

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

          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轉(zhuǎn)存為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)??#?文件夾沒有時(shí)自動創(chuàng)建
          ????#?獲取excel數(shù)據(jù)
          ????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中一定有相應(yīng)的解決方案,但是我初次嘗試,對其中源碼部分猶如天書般的存在,在多次調(diào)用方法下發(fā)現(xiàn)其中的一個參數(shù)輸出,wordfile.part.blob:輸出內(nèi)容讓我想起了之前解密excel時(shí)看到的文件開頭,xml文件,然后首先嘗試替換其中文本,原以為會像run.text = run.text.replace(col_name, str(value))一樣即可,然而報(bào)錯了,禁止修改。

          方案二:zipfile巧解word文檔

          正當(dāng)我認(rèn)為別無他法時(shí),就此作罷時(shí),百度百科幫助了我:docx文檔本質(zhì)上就是xml文件,emmmm,很妙,之前為了提取xlsx中的圖片解壓縮過xlsx文件然后提取,果然可行,替換的主體文件就是word文件夾下的document.xml文件當(dāng)然在代碼編寫前首先嘗試能不能手動復(fù)原為docx,用7z默認(rèn)參數(shù)還原失敗,經(jīng)過多番尋找,用zip類型壓縮即可,軟件不限,手動解壓及替換字符壓縮均成功,開始敲代碼。除習(xí)慣性用pandas讀取excel文件外,也不用安裝其他包,在現(xiàn)用python3.7中均為內(nèi)置包。使用zipfile對壓縮類文件進(jìn)行解壓,文章學(xué)習(xí)來源:

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

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

          • 問題一:文章中的壓縮文件為 zipfile.ZIP_DEFLATED,對遍歷后的所有文件進(jìn)行壓縮至一個目錄下,這就出現(xiàn)了還原后的docx內(nèi)的文件層次不對應(yīng),docx讀取失敗。改用zipfile.zlib.DEFLATED方可成功按層次壓縮。
          • 問題二:zipfile壓縮文件保存時(shí),應(yīng)當(dāng)有文件名及其別名,且別名不能為絕對路徑,為了能正常還原也應(yīng)使用原有名稱,在代碼中為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轉(zhuǎn)存為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?"系統(tǒng)找不到指定的文件"
          ????????????
          #?替換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)??#?深復(fù)制xml內(nèi)容
          ????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)??#?文件夾沒有時(shí)自動創(chuàng)建

          ????#?獲取excel數(shù)據(jù)
          ????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)

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

          總結(jié)

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

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


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


          版權(quán)聲明:本文為CSDN博主「宿者朽命」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。

          原文鏈接:https://blog.csdn.net/weixin_46281427/article/details/121588786

          小伙伴們,快快用實(shí)踐一下吧!如果在學(xué)習(xí)過程中,有遇到任何問題,歡迎加我好友,我拉你進(jìn)Python學(xué)習(xí)交流群共同探討學(xué)習(xí)。

          -------------------?End?-------------------

          往期精彩文章推薦:

          歡迎大家點(diǎn)贊,留言,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持

          想加入Python學(xué)習(xí)群請?jiān)诤笈_回復(fù)【入群

          萬水千山總是情,點(diǎn)個【在看】行不行

          /今日留言主題/

          隨便說一兩句吧~~

          瀏覽 60
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本黄色电影免费 | 8x8x皇冠视频免费观看 | aⅴ亚洲高清 | 欧美视频一区二区 | 中国福利视频黄色一级片 |