PythonでExcelファイル(xlsx)を読み書きするopenpyxlの使い方
Pythonのライブラリopenpyxlを使うとExcelファイル(.xlsx
)を読み書き(入出力)できる。使い方を説明する。
BitBucketのレポジトリと公式ドキュメントは以下のリンクから。
- openpyxl / openpyxl — Bitbucket
- openpyxl - A Python library to read/write Excel 2010 xlsx/xlsm files — openpyxl 2.5.3 documentation
PythonでExcelファイルを扱うライブラリの違いや使い分けなどは以下の記事を参照。
openpyxlは既存のExcelファイルの書式を保ったまま編集・追記(セルの値の変更、新たなセルの追加など)したい場合に便利。書式などは気にせず数値や文字列のデータを読み込んで分析するのであればpandasがおすすめ。
ここでは以下の内容について説明する。
- openpyxlのインストール
- Excelファイルの読み込み
- 基本的な使い方(ワークブック、シート、セルの取得)
- 任意の範囲のセルの値を2次元配列として取得
- セルの編集・追記
- 単独のセルに上書き・追加
- 複数のセルに2次元配列を書き込み
- ワークシートの追加・コピー・削除
- Excelファイルの書き込み(新規作成・上書き保存)
openpyxlのインストール
pip
でインストールできる(環境によってはpip3
)。
$ pip install openpyxl
Excelファイルの読み込み
基本的な使い方(ワークブック、シート、セルの取得)
openpyxlでは以下のクラスが定義されている。
Workbook
クラス: ワークブック全体Worksheet
クラス: 一つのシートCell
クラス: 一つのセル
ここでは以下のxlsx
ファイルを例にセルの値を取得する方法を説明する。
sheet1
とsheet2
の二つのワークシートを持つ。sheet1
の中身は以下の通り。
A B C
one 11 12 13
two 21 22 23
three 31 32 33
openpyxlをインポート。結果を見やすくするためにpprintモジュールもインポートしている。
import openpyxl
import pprint
openpyxl.load_workbook()
にExcelファイルのパスを指定してWorkbook
オブジェクトを取得。sheetnames()
属性でシート名一覧のリストを取得できる。
wb = openpyxl.load_workbook('data/src/sample.xlsx')
print(type(wb))
# <class 'openpyxl.workbook.workbook.Workbook'>
print(wb.sheetnames)
# ['sheet1', 'sheet2']
Workbook
オブジェクトから[シート名]
でWorksheet
オブジェクトを取得。
sheet = wb['sheet1']
print(type(sheet))
# <class 'openpyxl.worksheet.worksheet.Worksheet'>
Worksheet
オブジェクトから['A2']
のようなエクセルのセル指定文字列でCell
オブジェクトを取得。Cell
オブジェクトの属性value
でそのセルの値を取得できる。
cell = sheet['A2']
print(type(cell))
# <class 'openpyxl.cell.cell.Cell'>
print(cell.value)
# one
Worksheet
オブジェクトのcell()
メソッドで行番号、列番号を指定してCell
オブジェクトを取得することも可能。xlrdやxlwtと違い、1始まりなので注意。
cell = sheet.cell(row=2, column=1)
print(type(cell))
# <class 'openpyxl.cell.cell.Cell'>
print(cell.value)
# one
任意の範囲のセルの値を2次元配列として取得
Worksheet
オブジェクトから['A2:C4']
のように範囲を指定すると、Cell
オブジェクトを要素とする2次元のタプル(タプルのタプル)を取得できる。
pprint.pprint(sheet['A2:C4'])
# ((<Cell 'sheet1'.A2>, <Cell 'sheet1'.B2>, <Cell 'sheet1'.C2>),
# (<Cell 'sheet1'.A3>, <Cell 'sheet1'.B3>, <Cell 'sheet1'.C3>),
# (<Cell 'sheet1'.A4>, <Cell 'sheet1'.B4>, <Cell 'sheet1'.C4>))
['A2:C4']
のようなエクセルのセル指定文字列ではなく、iter_rows()
メソッドで行番号、列番号の範囲を指定してジェネレータとして取得することも可能。ジェネレータはlist()
でリスト化できる。
g = sheet.iter_rows(min_row=2, max_row=4, min_col=1, max_col=3)
print(type(g))
# <class 'generator'>
pprint.pprint(list(g))
# [(<Cell 'sheet1'.A2>, <Cell 'sheet1'.B2>, <Cell 'sheet1'.C2>),
# (<Cell 'sheet1'.A3>, <Cell 'sheet1'.B3>, <Cell 'sheet1'.C3>),
# (<Cell 'sheet1'.A4>, <Cell 'sheet1'.B4>, <Cell 'sheet1'.C4>)]
以下のようなリスト内包表記を利用した関数を定義すると2次元タプルの各要素(Cell
オブジェクト)から値を取得して2次元配列とすることができる。
- 関連記事: Pythonリスト内包表記の使い方
def get_value_list(t_2d):
return([[cell.value for cell in row] for row in t_2d])
l_2d = get_value_list(sheet['A2:C4'])
pprint.pprint(l_2d, width=40)
# [['one', 11.0, 12.0],
# ['two', 21.0, 22.0],
# ['three', 31.0, 32.0]]
iter_rows()
と組み合わせると、1始まりの行番号・列番号で範囲を指定して2次元配列(リストのリスト)として取得する関数を定義できる。
def get_list_2d(sheet, start_row, end_row, start_col, end_col):
return get_value_list(sheet.iter_rows(min_row=start_row,
max_row=end_row,
min_col=start_col,
max_col=end_col))
l_2d = get_list_2d(sheet, 2, 4, 1, 3)
pprint.pprint(l_2d, width=40)
# [['one', 11.0, 12.0],
# ['two', 21.0, 22.0],
# ['three', 31.0, 32.0]]
Worksheet
オブジェクトのvalues
属性でシートのすべての要素のジェネレータを取得できる。
g_all = sheet.values
print(type(g_all))
# <class 'generator'>
pprint.pprint(list(g_all), width=40)
# [(None, 'A', 'B', 'C'),
# ('one', 11.0, 12.0, 13.0),
# ('two', 21.0, 22.0, 23.0),
# ('three', 31.0, 32.0, 33.0)]
values
属性の場合、元のExcelファイルによっては空白None
の列や行が生じる場合もあるので注意。
セルの編集・追記
単独のセルに上書き・追加
エクセルのセル指定文字列で指定したCell
オブジェクトには新しい値を代入できる。
sheet['C1'] = 'XXX'
sheet['E1'] = 'new'
pprint.pprint(list(sheet.values), width=40)
# [(None, 'A', 'XXX', 'C', 'new'),
# ('one', 11.0, 12.0, 13.0, None),
# ('two', 21.0, 22.0, 23.0, None),
# ('three', 31.0, 32.0, 33.0, None)]
cell()
メソッドの場合は引数value
に新たな値を渡すとその値がセルに書き込まれる。
sheet.cell(row=2, column=5, value=14)
pprint.pprint(list(sheet.values), width=40)
# [(None, 'A', 'XXX', 'C', 'new'),
# ('one', 11.0, 12.0, 13.0, 14),
# ('two', 21.0, 22.0, 23.0, None),
# ('three', 31.0, 32.0, 33.0, None)]
いずれの場合も、既にデータがあるセルに対しては上書き、データがないセルに対しては新たなセルの追加になる。
複数のセルに2次元配列を書き込み
以下のような関数を定義すると、2次元配列(リストのリスト)を書き込むことができる。引数start_row
, start_col
に2次元配列が書き込まれる行番号と列番号を1始まりで指定する。
def write_list_2d(sheet, l_2d, start_row, start_col):
for y, row in enumerate(l_2d):
for x, cell in enumerate(row):
sheet.cell(row=start_row + y,
column=start_col + x,
value=l_2d[y][x])
l_2d = [['four', 41, 42, 43], ['five', 51, 52, 53]]
write_list_2d(sheet, l_2d, 5, 1)
pprint.pprint(list(sheet.values), width=40)
# [(None, 'A', 'XXX', 'C', 'new'),
# ('one', 11.0, 12.0, 13.0, 14),
# ('two', 21.0, 22.0, 23.0, None),
# ('three', 31.0, 32.0, 33.0, None),
# ('four', 41, 42, 43, None),
# ('five', 51, 52, 53, None)]
ワークシートの追加・コピー・削除
Workbook
オブジェクトのcreate_sheet()
メソッドで新たなワークシートを追加できる。引数に新たなシート名を指定する。
sheet_new = wb.create_sheet('sheet_new')
print(wb.worksheets)
# [<Worksheet "sheet1">, <Worksheet "sheet2">, <Worksheet "sheet_new">]
sheet_new['A1'] = 'new sheet!'
print(list(sheet_new.values))
# [('new sheet!',)]
ワークシートのコピーはcopy_worksheet()
メソッド。引数に指定するのはシート名ではなくWorksheet
オブジェクト。同一ワークブック内でのみコピー可能。
sheet_copy = wb.copy_worksheet(wb['sheet1'])
print(wb.worksheets)
# [<Worksheet "sheet1">, <Worksheet "sheet2">, <Worksheet "sheet_new">, <Worksheet "sheet1 Copy">]
pprint.pprint(list(sheet_copy.values))
# [(None, 'A', 'XXX', 'C', 'new'),
# ('one', 11.0, 12.0, 13.0, 14),
# ('two', 21.0, 22.0, 23.0, None),
# ('three', 31.0, 32.0, 33.0, None),
# ('four', 41, 42, 43, None),
# ('five', 51, 52, 53, None)]
ワークシートの削除はremove()
メソッド(古いバージョンではremove_sheet()
)。引数に指定するのはシート名ではなくWorksheet
オブジェクト。
wb.remove(wb['sheet1 Copy'])
print(wb.worksheets)
# [<Worksheet "sheet1">, <Worksheet "sheet2">, <Worksheet "sheet_new">]
Excelファイルの書き込み(新規作成・上書き保存)
Workbook
オブジェクトのsave()
メソッドにパスを指定するとファイルとして保存される。
新たなパスの場合は新規作成、既存のファイルのパスを指定すると上書き保存となる。上書きの場合、元のファイルのデータは削除されるので注意。
wb.save('data/dst/openpyxl_sample.xlsx')
既存のファイルに追記したい場合は、対象のファイルを読み込んで編集後、同じファイルパスに書き込み(保存)する。編集したデータで上書きされる。