1. 程式人生 > >python操作Excel檔案之openpyxl

python操作Excel檔案之openpyxl

安裝和配置

安裝openpyxl模組:

pip install openpyxl

若想使用插入圖片的功能:

pip install pillow

知識點講解

workbook 工作薄:一個Excel 檔案是一個工作薄 worksheet 工作表:一個工作薄中可以包含多個工作表,每個工作表都有自己的工作表名 cell 單元格:工作表中的小格子,一個工作表包含多個單元格,是儲存資料的最小物件

Tutorial

新建工作薄並操作

建立一個工作薄

無需單獨建立檔案再使用,只需引入Workbook類並直接使用:

from openpyxl import Workbook
wb = Workbook()

建立工作簿時至少包含一個工作表,可以通過openpyxl.workbook.Workbook.active()屬性來訪問這個工作表:

ws = wb.active

注意:這個函式使用_active_sheet_index屬性,預設為0,除非你更改這個值,否則在使用這個方法時總會得到第一個工作表。

通過openpyxl.workbook.Workbook.create_sheet()可以建立新的工作表:

ws1 = wb.create_sheet("Mysheet") 
# 在已有工作表列表尾插入該表
# or
ws2 = wb.create_sheet("Mysheet", 0) 
# 將該表插入至起始位置

建立工作表時自動為其命名,命名規則為按順序命名為Sheet, Sheet1, Sheet2, Sheet3……可以使用title屬性來更改工作表名:

ws.title = "New Title"

各個工作表的背景顏色預設為白色,可以通過向sheet_properties_tabColor屬性提供RRGGBB顏色編碼來更改背景顏色:

ws.sheet_properties_tabColor = '1072BA'

一旦為工作表命名,就可以通過工作表名得到該工作表:

ws3 = wb["New Title"]

可以通過openpyxl.workbook.Workbook.sheetnames()屬性得到所有的工作表名:

>>>print(wb.sheetnames)
['Sheet2', 'New Title', 'Sheet1']

或者迴圈輸出各個工作表的標題:

for sheet in wb:
    print(sheet.title)

通過openpyxl.workbook.Workbook.copy_sheet()方法在一個工作薄內複製工作表:

source = wb.active
target = wb.copy_worksheet(source)
# 複製wb工作薄中的第一個工作表並追加到現有工作表列表尾 
# ['Sheet2', 'New Title', 'Sheet1', 'Sheet2 Copy'] 

注意:只複製單元格(包括數值、風格、超連結和評註)和工作表特徵(包括維度、格式和屬性),不復制其他工作表或者工作薄特徵,例如:圖片和表格。 注意:不能在工作薄間複製工作表。可以複製只讀和只寫的工作薄的工作表。

操作資料

操作一個單元格

可以通過關鍵字來獲得單元格:

c = ws['A4']

返回A4單元格,或者建立A4單元格,如果本身不存在這個單元格的話。為單元格賦值:

ws['A4'] = 4

也可以通過openpyxl.worksheet.Worksheet.cell()方法來賦值:

d = ws.cell(row = 4, column = 2, value = 10)

注意:當建立一個工作表,不包含任何單元格。獲得單元格時,自動建立單元格。

for i in range(1, 101):
    for j in range(1, 101):
        ws.cell(row = i, culumn = j) 
# 獲得單元格
# 建立了一個無內容的100*100單元格 

操作多個單元格

使用分片獲得一定範圍的單元格:

cell_range = ws['A1':'C2']

獲得行、列範圍:

colC = ws['C']
col_range = ws['C':'D']
row10 = ws[10]
row_range = ws[5:10]

也可以使用openpyxl.worksheet.Worksheet.iter_rows()方法:

for row in ws.iter_rows(min_row = 1, max_col = 3, max_row = 2):
    for cell in row:
        print(cell)
<Cell Sheet1.A1>
<Cell Sheet1.B1>
<Cell Sheet1.C1>
<Cell Sheet1.A2>
<Cell Sheet1.B2>
<Cell Sheet1.C2>

openpyxl.worksheet.Worksheet.iter_cols()方法同理:

for col in ws.iter_cols(min_col = 1, max_row = 3, max_col = 3):
    for cell in col:
        print(cell)
<Cell Sheet1.A1>
<Cell Sheet1.A2>
<Cell Sheet1.B1>
<Cell Sheet1.B2>
<Cell Sheet1.C1>
<Cell Sheet1.C2>

通過openpyxl.worksheet.Worksheet.rows()屬性獲得一個工作表的全部單元格:

>>>ws = wb.active
>>>ws['C9'] = 'hello world'
>>>turple(ws.rows)
((<Cell Sheet.A1>, <Cell Sheet.B1>, <Cell Sheet.C1>),
(<Cell Sheet.A2>, <Cell Sheet.B2>, <Cell Sheet.C2>),
(<Cell Sheet.A3>, <Cell Sheet.B3>, <Cell Sheet.C3>),
(<Cell Sheet.A4>, <Cell Sheet.B4>, <Cell Sheet.C4>),
(<Cell Sheet.A5>, <Cell Sheet.B5>, <Cell Sheet.C5>),
(<Cell Sheet.A6>, <Cell Sheet.B6>, <Cell Sheet.C6>),
(<Cell Sheet.A7>, <Cell Sheet.B7>, <Cell Sheet.C7>),
(<Cell Sheet.A8>, <Cell Sheet.B8>, <Cell Sheet.C8>),
(<Cell Sheet.A9>, <Cell Sheet.B9>, <Cell Sheet.C9>))

或者openpyxl.worksheet.Worksheet.columns()屬性

>>>turple(ws.columns)
((<Cell Sheet.A1>,
<Cell Sheet.A2>,
<Cell Sheet.A3>,
<Cell Sheet.A4>,
<Cell Sheet.A5>,
<Cell Sheet.A6>,
...
<Cell Sheet.B7>,
<Cell Sheet.B8>,
<Cell Sheet.B9>),
(<Cell Sheet.C1>,
<Cell Sheet.C2>,
<Cell Sheet.C3>,
<Cell Sheet.C4>,
<Cell Sheet.C5>,
<Cell Sheet.C6>,
<Cell Sheet.C7>,
<Cell Sheet.C8>,
<Cell Sheet.C9>))

資料儲存

一旦建立了openpyxl.cell.Cell, 就可以為其賦值:

c.value = 'hello world'
print(c.value) # hello world
d.value = 4
print(d.value)  # 4

也可以使用其他格式和介面為其賦值:

wb = Workbook(guess_types = True)
c.value = '12%'
print(c.value)  # 0.12
d.value = 12.30
print(d.value)  # 12.3
import datetime
d.value = datetime.datetime.now()
print(d.value)  # datetime.datetime(2010, 9, 10, 22, 25, 18)

儲存為檔案

使用openpyxl.workbook.Workbook.save()方法來儲存一個工作薄:

wb = Workbook()
wb.save('balance.xlsx')

注意:自動覆蓋已有同名檔案。

儲存為流

當你想將檔案儲存為流,例如,當使用 Pyramid, Flask 和 Django等web程式時,你可以提供NamedTemporaryFile:

from tempfile import NamedTemporaryFile
from openpyxl import Workbook
wb = Workbook()
with NamedTemporaryFile() as tmp:
        wb.save(tmp.name)
        tmp.seek(0)
        stream = tmp.read()

你可以設定屬性template = True,來將一個工作薄存為模版:

wb = load_workbook('document.xlsx')
wb.template = True
wb.save('document_template.xlsx')

或設定為False來存為檔案:

wb = load_workbook('document_template.xltx')
wb.template = False
wb.save('document.xlsx', as_template=False)

注意: 儲存檔案時,你應該控制資料屬性和副檔名,否則MS等辦公文具打不開這些檔案。

wb = load_workbook('document.xlsx')  
# 需要儲存為*.xlsx
wb.save('new_document.xlsm') 
# MS Excel 打不開該檔案
# or
# 需要指明 keep_vba=True
wb = load_workbook('document.xlsm')
wb.save('new_document.xlsm')
# MS Excel打不開
# or
wb = load_workbook('document.xltm', keep_vba=True)
# 保持副檔名為 *.xltm.
wb.save('new_document.xlsm')
# MS Excel 打不開

載入已有檔案

通過載入openpyxl.load_workbook() 來開啟已有工作薄:

from openpyxl import load_workbook
wb2 =load_workbook('balance.xlsx')
print

Cookbook

簡單應用

寫一個工作薄

from openpyxl import Workbook
from openpyxl.compat import range
from openpyxl.utils import get_column_letter

wb = Workbook()

dest_filename = 'empty_book.xlsx'

ws1 = wb.active
ws1.title = "range names"

for row in range(1, 40):
     ws1.append(range(600))
# ws1工作表中存在40*600單元格,每行的內容相同,為從0到599

ws2 = wb.create_sheet(title="Pi")

ws2['F5'] = 3.14

ws3 = wb.create_sheet(title="Data")
for row in range(10, 20):
     for col in range(27, 54):
         _ = ws3.cell(column=col, row=row, value="{0}".format(get_column_letter(col)))
# 為單元格賦值該列的字母內容 

print(ws3['AA10'].value) # AA

wb.save(filename = dest_filename)

讀取已有工作薄

from openpyxl import load_workbook
wb = load_workbook(filename = 'empty_book.xlsx')
sheet_ranges = wb['range names']
print(sheet_ranges['D18'].value) # 3

注意: load_workbook()方法的幾個屬性: guess_types:讀取單元格時使型別介面有效或者無效(預設為無效); data_only:控制帶有公式表示的單元格是顯示為公式(預設)或者為上一次使用Excel開啟表格時的資料; keep_vba:控制是否保護Visual Basic元素(預設不保護),如果保護,則不能被編輯。

注意 使用openpyxl讀取Excel檔案,無法讀取到圖片和表格,所以使用相同名字儲存工作薄時,會失去圖片和表格。

使用數字格式

import datetime
from openpyxl import Workbook

wb = Workbook()
ws = wb.active
# 使用python datetime賦值
ws['A1'] = datetime.datetime(2010, 7, 21)

ws['A1'].number_format
# yyyy-mm-dd h:mm:ss

wb.guess_types = True
# 數字加 % 表示百分數
ws['B1'] = '3.14%'
wb.guess_types = False
ws['B1'].value
# 0.031400000000000004

ws['B1'].number_format
# 0%

使用公式

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 一個簡單的公式
ws['A1'] = '=SUM(1,1)'
wb.save("formula.xlsx")

openpyxl不會計算公式,但是可以判斷是否存在這麼一個公式:

>>> from openpyxl.utils import FORMULAE
>>> "HEX2DEC" in FORMULAE
True

合併/拆開單元格

合併單元格時,保留左上角的單元格,其他全部刪除:

from openpyxl.workbook import Workbook

wb = Workbook()
ws = wb.active

ws.merge_cells('A2:D2')
ws.unmerge_cells('A2:D2')

# 或者
ws.merge_cells(start_row=2, start_column=1, end_row=4, end_column=4)
ws.unmerge_cells(start_row=2, start_column=1, end_row=4, end_column=4)

插入圖片

from openpyxl import Workbook
from openpyxl.drawing.image import  Image

wb = Workbook()
ws = wb.active
ws['A1'] = 'you should see one logo below'

img = Image('logo.png')

ws.add_image(img, 'A1')
wb.save('logo.xlsx')

摺疊(隱藏)

import openpyxl

wb = openpyxl.Workbook()
ws = wb.create_sheet()
ws.column_dimensions.group('A', 'D', hidden = True) 
# A-D列被隱藏
ws.row_dimensions.group(1, 10, hidden = True)
# 1-10行被隱藏

wb.save('group.xlsx')

參考