現代生活中,我們很難不與excel表打交道,excel表有著易學易用的優點,只是當表中資料量很大,我們又需要從其他表冊中複製貼上一些資料(比如身份證號)的時候,我們會越來越倦怠,畢竟我們不是機器,沒法長時間做某種重複性的枯燥操作。想象這樣一個場景,我們有個幾千行的表要填,需要根據姓名輸入其對應的身份證號,但之前我們已經做過一個類似的表,同樣的一些人的姓名跟身份證號是完整的,那麼我們就需要通過一個個查詢姓名,然後把身份證號碼複製到我們當前要做的表裡去。
當我日復一日重複著這些操作的時候,我都很想有一個自動化工具來完成這種操作,把做為人的我從這種非人的折磨裡解脫出來,最後還是想到了python,因為這樣我能很少的關注語言內部的一些細節,從而專注於解決這個問題。
python有很多專門處理excel的第三方庫,我選擇了openpyxl,因為支援微軟最新excel的格式xlsx,其官網地址為openpyxl.readthedocs.io/en/latest/i…,官網上的教程很全面,有其他需求的可以好好研究一番。
其安裝命令為 pip install openpyxl
(線上安裝)或者 easy_install openpyxl
。
openpyxl的操作可以分四步,第一步載入現有workbook或者建立workbook到記憶體,分別使用
from openpyxl import load_workbook
from openpyxl import Workbook
#載入現有workbook中
wb1=load_workbook('lalala.xlsx')
"""
在源表資料量很大的時候,這裡我們可以使用openpyxl的read_only模式
載入源表,這樣做的好處是不用把整個表都載入記憶體
"""
wb1=load_workbook(filename='lalala.xlsx',read_only=True)
#建立workbook
wb2 = Workbook()
複製程式碼
第二步就是操作excel表中的sheet了,通過Workbook()建立的workbook預設活動的sheet名稱為Sheet,可以通過python互動命令列進行驗證。
#獲取活動的sheet
ws = wb.active
#設定sheet的標題
ws.title = "range names"
#建立以Pi為標題的sheet
ws = wb.create_sheet(title="Pi")
#獲取標題為Sheet1的sheet
ws=wb['Sheet1']
複製程式碼
第三步就是操作sheet中的cell了。需要注意的是,一個cell的位置由它所在的列跟行共同決定,比如一個cell,它在A列,並在第三行,就可以通過ws['A3']
來訪問。cell還具有row跟column屬性,cell.row跟cell.column的資料型別如下圖所示。
特別注意當用read_only模式載入workbook時,cell.row跟cell.column都是int物件。cell.column記錄的是cell所在列離第一列的偏移數,並非workbook中真正代表列數的大寫字母,比如“A”。
#獲取第一行,資料型別為tuple
row=ws[1]
#獲取A列,資料型別為tuple
column=ws['A']
#設定F5的值
ws['F5']='sfs'
#設定cell的值
ws['F5'].value='hello'
#獲得cell的行數
m=ws['F5'].row
#獲得cell的列數
n=ws['F5'].column
#獲得特定區域的值,比如從F5到F30,資料型別為tuple
k=ws['F5':'F30']
#獲得特定區域的值,比如從F5到G30,資料型別為tuple
j=ws['F5':'G30']
#獲取sheet的最大行數
row_count=ws.max_row
#獲取sheet的最大列數
column_count=ws.max_column
複製程式碼
最後一步把更改儲存,這裡要注意,當要儲存的表在別的軟體(microsoft office或者wps)中開啟時,儲存操作會報錯。
wb1.save('empty_book.xlsx')
wb2.save(filename='other_book.xlsx')
複製程式碼
實現需求
新建一個get_info_from_excel.py檔案,用你習慣的編輯器來編輯,首先需要引入openpyxl庫中的load_workbook模組。可以使用load_workbook載入已經存在的excel表。
from openpyxl import load_workbook
複製程式碼
我們的目的是從源excel表中提取資訊並批量複製到目標excel表中,所以我們首先定義一些變數。
#源表名稱
source_file_name='lalala.xlsx'
#目標表名稱
target_file_name='lelele.xlsx'
#源表中要提取資訊的sheet
source_sheet_name='Sheet2'
#目標表中要批量複製資訊的sheet
target_sheet_name='Sheet2'
#源表中的標題行在哪一行
source_header_row=3
#目標表中的標題行在哪一行
target_header_row=2
#源表中要根據哪一列資料提取資訊,根據源表標題行
source_cell_condition='姓名'
#目標表中要根據哪一列資料複製資訊,根據目標表標題行
target_cell_condition='姓名'
#源表中要提取資訊的列
source_cell_filled='身份證號'
#目標表中要複製資訊的列
target_cell_filling='身份證號'
複製程式碼
將源表跟目標表載入記憶體,方便下一步操作這兩個表。
#在源表資料量很大的時候,這裡我們可以使用openpyxl的read_only模式載入源表,這樣做的好處是不用把整個表都載入記憶體
#wb_w=load_workbook(source_file_name)
wb_r=load_workbook(filename=source_file_name,read_only=True)
wb_w=load_workbook(target_file_name)
複製程式碼
從前面已經定義的sheet名稱跟標題行數獲取源表跟目標表的標題行:
ws_r=wb_r[source_sheet_name]
ws_w=wb_w[target_sheet_name]
header_row_r=ws_r[source_header_row]
header_row_w=ws_w[target_header_row]
複製程式碼
操作源表標題行,獲取我們想要的資訊:
"""
openpyxl用read_only模式載入workbook時,獲取到的cell不是一般的cell,
經過測試cell.column變成偏移了幾列的整數,所以這裡我們定義一個函式來處理,
把整數轉換成excel真正的列數,比如“A”、“BB”等。
"""
def readOnly_offsetColunmNumber_toRealColumn(number):
column=''
if number<=26:
column=chr(number+ord('A')-1)
else:
number1=number//26
column1=chr(number1+ord('A')-1)
number2=number%26
column2=chr(number2+ord('A')-1)
column=column1+column2
return column
#初始化兩個變數,分別是源表的條件列,要複製的列
source_condition_column=''
source_filled_column=''
"""
迴圈源表的標題列,得到條件列的位置以及要複製列的位置,
再通過內嵌的迴圈得到條件列的最大行數
"""
for cell in header_row_r:
if cell.value==source_cell_condition:
source_condition_column=readOnly_offsetColunmNumber_toRealColumn(cell.column)
elif cell.value==source_cell_filled:
source_filled_column=readOnly_offsetColunmNumber_toRealColumn(cell.column)
複製程式碼
操作目標表標題行,獲取我們想要的資訊:
#初始化兩個變數,分別是目標表的條件列,要貼上的列
target_condition_column=''
target_filling_column=''
"""
迴圈目標表的標題列,得到條件列的位置以及要貼上列的位置,
再通過內嵌的迴圈得到條件列的最大行數
"""
for cell_j in header_row_w:
if cell_j.value==target_cell_condition:
target_condition_column=cell_j.column
elif cell_j.value==target_cell_filling:
target_filling_column=cell_j.column
複製程式碼
現在我們已經得到所有需要的資訊,該到實際貼上資料的時候了。
"""
迴圈目標表的條件列,內部巢狀迴圈源表的條件列,一旦目標表條件列的某個cell
與源表條件列某個cell的值相同,我們就把源表要複製列的同一行的cell的值
賦予目標表要貼上列的同一行的cell。
"""
for cell_m in ws_w[target_condition_column+str(target_header_row+1):target_condition_column+str(ws_w.max_row)]:
for cell_n in ws_r[source_condition_column+str(source_header_row+1):source_condition_column+str(ws_r.max_row)]:
if cell_m[0].value==cell_n[0].value:
ws_w[target_filling_column+str(cell_m[0].row)].value=ws_r[source_filled_column+str(cell_n[0].row)].value
複製程式碼
最後儲存目標workbook就可以了。
wb_w.save(target_file_name)
複製程式碼
注意:如果excel中標題行有合併居中的話,指令碼會報錯,一種辦法就是去掉合併居中;另一種就是在原標題行下再插入一行新的行再把原標題行的內容貼上進去,用插入的這一行作為標題行。