計算思維中識別日常生活中的模式,識別日常生活中的模式是一項具有普遍需求的技能,無論是復盤找規(guī)律總結(jié)方法論,信息化建設(shè)中總結(jié)標準流程,建設(shè)線上流程;發(fā)現(xiàn)生活中的重復性工作等.
需求
在word中有一項很強大的功能:郵件合并,可以方便的生成請柬,工資條,信封等,避免了簡單低效的重復操作,這個屬于word中比較實用的功能,計算機二級MS Office高級應用中也會用到.但是郵件合并只能從excel中抽取數(shù)據(jù),批量生成word,如果有一部分有規(guī)律的word,郵件合并就沒有辦法了.
我們可以用python讀取excel數(shù)據(jù),并批量生成word,下面我們就講解如何實現(xiàn).

會把excel中的成績數(shù)據(jù),根據(jù)上圖中間的模板,生成每個學生的成績單,而完成上述任務只需要不到20行代碼:

用字符串模擬批量生成
實際上,請柬,信封,作業(yè)本封面都是有一個固定的模板,然后填寫必要的信息.模板應用非常廣泛,office辦公軟件中就存在巨大的模板,我們平時也會下載各種模板,模板會為我們節(jié)約大量時間提高效率;在現(xiàn)在的web開發(fā)中,前端頁面大多是用模板生成的,比如flask框架的jinjia2模板.
單個同學的例子
比如,我們要發(fā)獎狀
student = '張三'
template = "恭喜{}同學成為三好學生"
print(template.format(student))
程序運行結(jié)果如下:
D:\寫作>C:/Users/xpro/AppData/Local/Programs/Python/Python37-32/python.exe d:/寫作/01email.py
恭喜張三同學成為三好學生
我們把template變量看做是獎狀,name變量代表的是獲獎的同學張三,最后輸出了獲獎信息,恭喜張三同學成為三好學生.
python中一切皆對象, 字符串也是對象, format是字符串對象的一個方法,作用是把參數(shù)填充到字符串中用大括號標記的地方,比如
"恭喜{}同學成為三好學生".format("張三"), 就是把用format方法把學生姓名張三填充到模板字符串"恭喜{}同學成為三好學生"中的大括號, 字符串"恭喜{}同學成為三好學生"以張三為參數(shù)調(diào)用format方法之后,就會變成了恭喜張三同學成為三號學生.
不熟悉format函數(shù)使用的話,可以識別下列二維碼:

這是一個非常簡單的例子,但是卻是python實現(xiàn)郵件合并的原型,當我們根據(jù)數(shù)據(jù)和模板批量生成文件的時候,需要的不外乎大量的姓名列表,一個模板,然后輸出,只不過細節(jié)可能會更多一些.假設(shè)我們有一個列表,列表里有很多姓名(可以來自excel或者數(shù)據(jù)庫或者csv文件),然后循環(huán)執(zhí)行生成模板的代碼就好了,距離如下:
students = ['張三', '李四', '王五', '趙六'] # 數(shù)據(jù)源
template = "恭喜{}同學成為三好學生" # 模板
for student in students: # 循環(huán)
print(template.format(student)) # 根據(jù)模板生成文件
運行結(jié)果如下:
D:\寫作>C:/Users/xpro/AppData/Local/Programs/Python/Python37-32/python.exe d:/寫作/01email.py
恭喜張三同學成為三好學生
恭喜李四同學成為三好學生
恭喜王五同學成為三好學生
恭喜趙六同學成為三好學生
在這個例子里,我們簡單地打印字符串,代替需要批量生成的文件,比如生成的word,ppt或者生成圖片,但是跟把大象放冰箱,總共分幾步一樣,一共分為,準備數(shù)據(jù)源,準備模板,根據(jù)數(shù)據(jù)和模板批量生成三個步驟:
- 準備數(shù)據(jù)源
- 準備模板
- 根據(jù)數(shù)據(jù)和模板批量生成
是不是很簡單.
虛擬數(shù)據(jù)
對于python不是很熟悉的老師,可以跳過虛擬數(shù)據(jù)這部分.
每次用列表生成示例數(shù)據(jù)是很麻煩的,我們結(jié)束一個庫來幫我們生成虛擬的姓名數(shù)據(jù),我們要用到一個叫做faker的python第三方庫,安裝方式是
pip install faker
用faker庫生成姓名
虛擬姓名
Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from faker import Faker
>>> fake = Faker('zh_CN') # 指定local所屬地區(qū)中國
>>> fake.name()
'蘇紅霞'
>>> fake.name()
'董雷'
>>>
在交互式命令行中,我們可以很容易的看到,faker庫會幫我們生成虛擬的姓名,但是符合我們中國人的姓名習慣的.
生成虛擬地址
>>> fake.address()
'江西省合山縣東麗劉街k座 806555'
>>> fake.address()
'重慶市柳縣沙灣吳街P座 708245'
>>>
改寫生成獎狀的程序如下
from faker import Faker
fake = Faker('zh_CN')
template = "恭喜{}同學成為三好學生" # 模板
for i in range(5):
student = fake.name()
print(template.format(student))
因為可以用faker庫生成姓名,所以不再需要姓名列表,你可以理解為我們的數(shù)據(jù)源從students列表變成了faker庫,運行結(jié)果如下
D:\寫作>python 01email.py
恭喜楊林同學成為三好學生
恭喜王成同學成為三好學生
恭喜劉瑞同學成為三好學生
恭喜王玉同學成為三好學生
恭喜郭欣同學成為三好學生
這里我用了python命令執(zhí)行了01email.py文件,這里需要注意的是faker庫每次調(diào)用生成的數(shù)據(jù)不通,我第二次運行結(jié)果如下:
D:\寫作>python 01email.py
恭喜林峰同學成為三好學生
恭喜鮑瑩同學成為三好學生
恭喜祁婷同學成為三好學生
恭喜惠雪梅同學成為三好學生
恭喜盧秀芳同學成為三好學生
讀取excel數(shù)據(jù)

讀取并處理excel數(shù)據(jù),最好用的就是numpy庫了,不過numpy不如xlrd庫直觀,我們先用xlrd來寫示例程序.這次的數(shù)據(jù)源是excel,是一個有姓名,語數(shù)英成績的excel表,當前目錄下的data.xlsx文件,數(shù)據(jù)在excel文件的Sheet1工作表中.
import xlrd
# 用xlrd模塊的open_workbook方法打開excel文件
# 類似于我們在wps,office的打開操作
# 參數(shù)是文件的路徑,字符串前面的r表示路徑
xls = xlrd.open_workbook(r'data.xlsx')
# 通過工作表的名字Sheet1獲取工作表1
sheet1 = xls.sheet_by_name('Sheet1')
# 第一行第一列是姓名表頭
# 但是python中是從0開始計數(shù)
# student的值是姓名
student = sheet1.cell_value(0, 0)
print(student)
# 運行結(jié)果是: 姓名
運行結(jié)果如下
D:\寫作>python 01email.py
姓名


第一個學生張三是第2行第1列的數(shù)據(jù),讀取方法如下
import xlrd
# 用xlrd模塊的open_workbook方法打開excel文件
# 類似于我們在wps,office的打開操作
# 參數(shù)是文件的路徑,字符串前面的r表示路徑
xls = xlrd.open_workbook(r'data.xlsx')
# 通過工作表的名字Sheet1獲取工作表1
sheet1 = xls.sheet_by_name('Sheet1')
# 第一行第一列是姓名表頭
# 但是python中是從0開始計數(shù)
# student的值是姓名
# cell_value方法獲取單元格的值
# 第一個參數(shù)代表行序號,第二個參數(shù)代表列序號
student = sheet1.cell_value(1, 0)
print(student)
# 運行結(jié)果是: 姓名
運行結(jié)果
D:\寫作>python 01email.py
張三
當我們知道了如何讀取姓名,也就知道了如何讀取語數(shù)英的成績分別是
chinese = sheet1.cell_value(1, 1)
math = sheet1.cell_value(1, 2)
english = sheet1.cell_value(1, 3)
接下來我們輸出張三同學的成績單:
import xlrd
# 讀取數(shù)據(jù)源
xls = xlrd.open_workbook(r'data.xlsx')
sheet1 = xls.sheet_by_name('Sheet1')
# 模板
template = "{}同學的成績?nèi)缦?語文{},數(shù)學{},英語{}"
student = sheet1.cell_value(1, 0)
chinese = sheet1.cell_value(1, 1)
math = sheet1.cell_value(1, 2)
english = sheet1.cell_value(1, 3)
# 根據(jù)模板輸出信息
print(template.format(student, chinese, math, english))
運行結(jié)果如下:
D:\寫作>python 01email.py
張三同學的成績?nèi)缦?語文89.0,數(shù)學100.0,英語100.0
接下來我們只需要用循環(huán)讀取數(shù)據(jù)就可以了,有個問題,excel中有多少行數(shù)據(jù)呢?可以用工作表的nrows獲取行數(shù),需要注意的是excel的第一行不是數(shù)據(jù)而是表頭,循環(huán)的時候需要跳過.
import xlrd
# 讀取數(shù)據(jù)源
xls = xlrd.open_workbook(r'data.xlsx')
sheet1 = xls.sheet_by_name('Sheet1')
# 模板
template = "{}同學的成績?nèi)缦?語文{},數(shù)學{},英語{}"
rows = sheet1.nrows # 表格行數(shù)
for i in range(1, rows): # 跳過表頭一行
student = sheet1.cell_value(i, 0) # 第i行代表第i行數(shù)據(jù)
chinese = sheet1.cell_value(i, 1)
math = sheet1.cell_value(i, 2)
english = sheet1.cell_value(i, 3)
# 根據(jù)模板輸出信息
print(template.format(student, chinese, math, english))
運行結(jié)果如下:
D:\寫作>python 01email.py
張三同學的成績?nèi)缦?語文89.0,數(shù)學100.0,英語100.0
李四同學的成績?nèi)缦?語文92.0,數(shù)學99.0,英語98100.0
王五同學的成績?nèi)缦?語文95.0,數(shù)學97.0,英語88.0
趙六同學的成績?nèi)缦?語文98.0,數(shù)學98.0,英語78.0
word模板

pip install docxtpl
解決了數(shù)據(jù)源的問題,我們來研究如何生成word,實際上我們在郵件合并的時候,就是要有一個word模板,然后根據(jù)word模板插入相關(guān)的域,就是可以用郵件合并生成數(shù)據(jù)了,實際上這里也許要一個word模板,word模板如下
要生成word模板,需要用到一個第三方庫,python強大的原因之一,就是有各種第三方庫可以滿足我們的需求.

import xlrd
from docxtpl import DocxTemplate
# 讀取數(shù)據(jù)源,打開word
xls = xlrd.open_workbook(r'data.xlsx')
sheet1 = xls.sheet_by_name('Sheet1')
rows = sheet1.nrows # 表格行數(shù)
# 讀取數(shù)據(jù)并生成文件
for i in range(1, rows): # 跳過表頭一行
student = sheet1.cell_value(i, 0) # 第i行代表第i行數(shù)據(jù)
chinese = sheet1.cell_value(i, 1)
math = sheet1.cell_value(i, 2)
english = sheet1.cell_value(i, 3)
# 根據(jù)模板輸出信息
# 打開一個模板
doc = DocxTemplate(r"score.docx")
data = {} # 構(gòu)造填充模板需要的數(shù)據(jù)
data['student'] = student
data['chinese'] = chinese
data['math'] = math
data['english'] = english
doc.render(data) # 填充數(shù)據(jù)data到模板
doc.save("{}.docx".format(student)) # 根據(jù)模板為每個學生生成成績單
程序運行后,會在當前目錄下生成以學生名字命名的word文件,如下圖:


可以看到跟之前字符串的例子是類似的,數(shù)據(jù)自動的填充到了word模板之中.
字典
注意之前我們渲染字符串的時候,通過向字符串的format方法,傳遞變量,就可以完成字符串的填充.而渲染模板則要復雜的多,首先我們用python中的字典保存了需要填充到模板中的變量,

這個跟JavaScript中的json數(shù)據(jù)格式有些類似的.python中字典的鍵值可以字符串,然后冒號后面是對應的鍵的值,比如student鍵的值是趙六,然后這些值會通過doc對象的render方法填充到word模板:

word模板的寫法是,用兩個大括號包裹變量,習慣上變量兩邊有個空格,如
{{ student }},data字典中student鍵值對應的值會被doc對象的render方法填充到{{ student }},也就是word模板中,更加詳細的關(guān)系如下圖
包括注釋和空行在內(nèi)不到30行代碼,就可以很輕松的生成成績單了.當然代碼是可以更加精簡的,但是會更難以理解.

docx-mailmerge庫
python有豐富的第三方庫,實際上早已經(jīng)有人想到用python模擬郵件合并,并專門寫了一個庫docx-mailmerge,但是這個庫需要用戶熟悉郵件合并,并有插入域的操作,不如直接在word里用jinja2的語法生成模板來的方便.所以不予采用.但是這個方法不需要理解字典這種數(shù)據(jù)結(jié)構(gòu).
小結(jié)
通過不到30行代碼,哪怕是成千上萬條數(shù)據(jù),也可以方便的用python生成成績報告了.
擴展
其實python讀取word/excel/ppt和生成word/excel/ppt都是很容易的,而且根據(jù)成績生成圖表也是很容的,所以往成績單插入折線圖/雷達圖也是很容易的,也可以讀取別的word中的內(nèi)容插入到成績單,或者讀取excel的數(shù)據(jù),批量插入到ppt中.