實例7:用Python操作Word批量生成合同

我們在實例5中演示了如何用Python批量生成word版邀請函桥狡。我們是簡單粗暴地找到需要填寫受邀者信息所在位置(即run),然后將這個run直接替換成受邀者的公司名及姓名颅围。因為只有一處需要替換萌焰,所以這個方法行得通,但遇到合同谷浅,一般有十來處需要修改,如果也逐個去找其位置所在的run奶卓,那就反而會降低我們的工作效率一疯,背離辦公自動化的初衷了。實例5可以作為入門python-docx模塊的練手項目夺姑。

對于合同的批量處理墩邀,我們將使用更聰明的辦法。我們的思路是盏浙,先建立一個word模板眉睹,在合同里面需要變動信息的地方用“【....】”來代替,比如“【合同編號】”等废膘。然后再建一個Excel文檔竹海,將“【合同編號】”等信息作為標(biāo)題,將不同的合同信息放入這個Excel的每一行丐黄。然后用python-docx去讀取word模板中的所有內(nèi)容斋配,凡是遇到“【....】”的字符,就用Excel中的對應(yīng)標(biāo)題下的信息去進行替換灌闺。Excel中從第二行開始每一行代表一個合同內(nèi)需要填入的信息艰争。

我們建立的模板和合同信息如下圖所示:

image

這里有幾個注意事項:

  1. Excel文檔中數(shù)字需要改成文本格式桂对,不然像合同編號20190401在寫入到word時會變成20190401.0甩卓。至于怎么轉(zhuǎn)格式,請參考度娘:http://jingyan.baidu.com/artic
  2. Excel中的公式需要去除蕉斜,不然填到word中的信息是公式逾柿,而不是值。
  3. Word模板中的“【....】”和Excel中的標(biāo)題必須一一對應(yīng)蛛勉,且必須是全中文或全英文字符鹿寻,因為python-docx會將中英混合的內(nèi)容視為兩個及以上的格式(run),導(dǎo)致在替換的時候無法正確識別诽凌。
  4. Word模板做好后毡熏,要用python-docx讀取一下,看看“【....】”是不是一個獨立的run侣诵,若不是痢法,則需要從Excel標(biāo)題欄中重新復(fù)制狱窘,覆蓋word模板中的“【....】”信息,已保證這一串字符是一個run财搁。
import docx #導(dǎo)入docx庫
doc = Document("data/合同模板.docx") #打開word文件
for para in doc.paragraphs: #讀取word中的每個段落
    for run in para.runs: #讀取每個段落中的不同格式(run)
        print(run.text)
>>
合同編號:
【合同編號】

【貨物名稱】
采購
合同
甲方
:
【采購方】

乙方
-------省略----------

通過以上程序蘸炸,我們打印顯示了合同里面的所有的格式(其中每一行代表一個格式(run))對應(yīng)的文本(text),我們可以看到“【....】”都是在一行里面的尖奔,這樣就沒問題搭儒。由于word版合同里還有一些是在表格里面的,通過doc.paragraphs是無法抓取出來的提茁,此時需要用doc.tables淹禾,表格(tables)里面又包含行(rows),行還包含單元格(cell)茴扁,所以需要讀取所有的表格铃岔,然后讀取所有的行,再讀取單元格峭火,并打印顯示出來毁习。可見 “【....】” 也是在一行里面的卖丸,這樣可保證后續(xù)替換時可查找到纺且,不會導(dǎo)致遺漏。

for table in doc.tables:
        for row in table.rows:
            for cell in row.cells:
                print(cell.text)
>>
甲方(蓋章):【采購方】 

法人代表:
或委托代理人:

開戶行: 【開戶行】
賬  號:【賬號】
聯(lián)系人:【聯(lián)系人】
電  話:【電話】
住  所:【住所】

乙方(蓋章):ABC商貿(mào)有限公司

法人代表:
或委托代理人:

開戶行:中國建設(shè)銀行
賬  號:989898989898
聯(lián)系人:張三豐
電  話:999-99999
住  所: 桃花源

Word模板做好后坯苹,“【....】”內(nèi)的信息就不可隨意變動了隆檀,即便我們將“【合同編號】”里面的“遍”字刪掉重新輸入,結(jié)果還是“【合同編號】”粹湃,但此時“【合同編號】”已經(jīng)不是一個格式了恐仑,會變成2個格式。如下示例顯示了這個結(jié)果,“【合同編號】”已經(jīng)不在同一行了为鳄。所以這個格式非常小氣裳仆,不可輕易得罪啊孤钦!此時需要重新去Excel標(biāo)題欄復(fù)制【合同編號】歧斟,再粘貼過去,保存偏形,即可恢復(fù)同一格式(也可以在word中復(fù)制“【合同編號】”静袖,覆蓋粘貼成文本)。

doc = Document("data\合同模板 - 需填入部分格式錯誤.docx") #打開word文件
for para in doc.paragraphs: #讀取word中的每個段落
    for run in para.runs: #讀取每個段落中的不同格式(run)
        print(run.text)
>>合同編號:
【合同編
號】

【貨物名稱】
采購
合同
甲方
:
【采購方】

此實例雖然是采購合同俊扭,其處理方法適用于所有合同的批量生成队橙,只需要準備好合同的模板,和需要填入合同的信息,剩下的就放心地交給Python吧捐康。合同信息和模板準備好之后仇矾,就可開始批量替換,生成合同了〗庾埽現(xiàn)在跟我出發(fā)贮匕。

import docx
def info_update(doc,old_info, new_info):
    '''此函數(shù)用于批量替換合同中需要替換的信息
    doc:合同模板
    old_info和new_info:原文字和需要替換的新文字
    '''
    #讀取段落中的所有run,找到需替換的信息進行替換
    for para in doc.paragraphs: #
        for run in para.runs:
            run.text = run.text.replace(old_info, new_info) #替換信息
    #讀取表格中的所有單元格花枫,找到需替換的信息進行替換
    for table in doc.tables:
        for row in table.rows:
            for cell in row.cells:
                cell.text = cell.text.replace(old_info, new_info) #替換信息

為方便后續(xù)重復(fù)調(diào)用刻盐,以上我們定義了一個函數(shù)info_update(),它包含三個參數(shù)doc,old_info, new_info劳翰,分別代表word模板隙疚,原文本,和新文本磕道。逐個讀取word模板中的所有信息,只要遇到原文本行冰,就替換成新文本溺蕉。然后再讀取word中的表格中的信息,也是遇到原文本悼做,就替換成新文本疯特。

from openpyxl import load_workbook #用于讀取Excel中的信息
wb = load_workbook('data/合同信息.xlsx')
ws = wb.active
doc = docx.Document("data/合同模板.docx")
for row in range(2, ws.max_row+1):
    for col in range(1, ws.max_column+1):
        #調(diào)用上面建立的函數(shù),替換信息
        info_update(doc,str(ws.cell(row=1,column=col).value), str(ws.cell(row=row,column=col).value))
    doc.save("data/{}合同.docx".format(str(ws.cell(row=row,column=3).value)))
    print("{}合同完成".format(str(ws.cell(row=row,column=3).value)))
>>
公司001合同完成
公司002合同完成
公司003合同完成
公司004合同完成
公司005合同完成
公司006合同完成
公司007合同完成
公司008合同完成
公司009合同完成
公司010合同完成

然后使用“openpyxl”庫的“l(fā)oad_workbook”模塊肛走,讀物Excel檔的合同信息漓雅,遍歷每一行,每一列朽色,調(diào)用替換信息的函數(shù)“info_update”完成合同信息替換邻吞,隨后保存。

我們以第一份合同為例葫男,逐個看這些步驟是如何完成的抱冷。因為Excel中第一行是標(biāo)題,合同信息是從第二行開始的梢褐,所以我們行是從2開始row in range(2, ws.max_row+1)旺遮,最大行加1結(jié)束(因為range函數(shù)是取不到最后一個數(shù)的,此例中最大行是11盈咳,如果不加1耿眉,則只能取到10,這樣最后一份合同就會被漏掉了)鱼响。列也類似鸣剪,不過是從第一列開始的col in range(1, ws.max_column+1)

第一份合同對應(yīng)的row值為2,col值為1西傀。原信息是Excel中的標(biāo)題斤寇,對應(yīng)也就是word中的“【....】”部分。次數(shù)原信息先取ws.cell(row=1,column=1).value拥褂,即如下所示娘锁,為'【合同編號】'。因為Excel表中有一些數(shù)字饺鹃,加上str()是為了轉(zhuǎn)換為字符串莫秆。

image

新信息為ws.cell(row=2,column=2).value,如下所示悔详。然后就將word中'【合同編號】'替換為'手機'镊屎,再替換第二列,第三列.....直到替換完所有的列茄螃,于是第一份合同生成完成缝驳,我們使用doc.save保存。我們給保存的文件名加上公司名稱归苍,以便于區(qū)分用狱,公司名是Excel中第三列的值ws.cell(row=row,column=3).value

image

第一份合同完成后拼弃,回到for循環(huán)夏伊,開始第二份合同的替換和保存,直到搞定所有合同吻氧。最終成果如下:

image

所有源代碼和說明都在Jupyter notebook上完成溺忧,所用到的Excel 資料已上傳GitHub, 歡迎Fork或下載到本地隨意玩。盯孙。鲁森。轉(zhuǎn)載請注明出處,謝謝振惰。
GitHub鏈接:https://github.com/weidylan/Office_Automation_by_Using_Python
微信公眾號:Python操作Office軟件高效工作

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刀森,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子报账,更是在濱河造成了極大的恐慌研底,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件透罢,死亡現(xiàn)場離奇詭異榜晦,居然都是意外死亡,警方通過查閱死者的電腦和手機羽圃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門乾胶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事识窿≌独桑” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵喻频,是天一觀的道長缩宜。 經(jīng)常有香客問我,道長甥温,這世上最難降的妖魔是什么锻煌? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮姻蚓,結(jié)果婚禮上宋梧,老公的妹妹穿的比我還像新娘。我一直安慰自己狰挡,他們只是感情好捂龄,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著加叁,像睡著了一般跺讯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上殉农,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音局荚,去河邊找鬼超凳。 笑死,一個胖子當(dāng)著我的面吹牛耀态,可吹牛的內(nèi)容都是我干的轮傍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼首装,長吁一口氣:“原來是場噩夢啊……” “哼创夜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起仙逻,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤驰吓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后系奉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體檬贰,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年缺亮,在試婚紗的時候發(fā)現(xiàn)自己被綠了翁涤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖葵礼,靈堂內(nèi)的尸體忽然破棺而出号阿,到底是詐尸還是另有隱情,我是刑警寧澤鸳粉,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布扔涧,位于F島的核電站,受9級特大地震影響赁严,放射性物質(zhì)發(fā)生泄漏扰柠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一疼约、第九天 我趴在偏房一處隱蔽的房頂上張望卤档。 院中可真熱鬧,春花似錦程剥、人聲如沸劝枣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舔腾。三九已至,卻和暖如春搂擦,著一層夾襖步出監(jiān)牢的瞬間稳诚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工瀑踢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扳还,地道東北人。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓橱夭,卻偏偏與公主長得像氨距,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子棘劣,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 家族的姐妹中俏让,晶兒是大家公認的好,待人和善茬暇,認親首昔,熱情明事理,無論長輩晚輩糙俗,都很喜歡她沙廉。 晶兒真的是一個優(yōu)雅的女子...
    似曾相識a閱讀 215評論 4 3
  • 行走日記【21】 清晨,還是旅店前的街道臼节,可景觀已今非昔比撬陵。 長長地高架橋下已空無一人珊皿,往日里在橋下野宿的人被清理...
    樹偉閱讀 703評論 27 42
  • 不認識多好 你談天我可以禮貌 刻在嘴角的謎會很有腔調(diào) 不是小小姑娘 低頭會笑 這些年好與不好 誰想知道 過渡段要怎...
    不當(dāng)詩人閱讀 719評論 7 13