Python

Pythonでエクセルを操作できるライブラリを解説

2021年8月14日

エクセルモジュール

Pythonでエクセルを操作するためのライブラリを解説します。

RPAでエクセルを操作するのにめんどくさいことが発生しており、カンタンにエクセルを操作できないか調べていました。

GolangやJavaとかでコンパイルしたプログラムを配るのもアリだと思ったのですが、メンテナンス性や言語的に初心者でもいけるPythonにすることにしました。

そのため、この記事で解説するライブラリは下記になります。

ライブラリ

  • OpenPyXL
  • XlsxWriter
  • xlwings

xlwingsはWindowsやMacでしかサポートしていない様で、XlsxWriterは名前の通り書き込み専用になっています。

そのため、ライブラリを選定していたりする場合は、無難にOpenPyXLが良いです。

ただ、OpenPyXLとXlsxWriterと連携させたりとかのやり方もアリだなと試してみて判断しました。

ちなみにxlwingsに関しては、Persmssionの問題で動きませんでした。

OpenPyXLについて

OpenPyXLについて

OpenPyXLは、Excel 2010をPythonで操作するためのライブラリです。

Excel 2010と思ったのですが、Microsoft365のエクセルで普通に動きました。

操作できるファイルは下記になります。

ファイル

  • xlsx
  • xlsm
  • xltx
  • xltm

OpenPyXLのインストール

pipコマンドでインストールします。

$  pip install openpyxl

画像とか操作する場合は、下記のpillowも一緒にインストールする必要があります。

$ pip install pillow

ブックの作成

エクセルのBookを作成を作成してみます。

from openpyxl import Workbook

file_name = 'sample.xlsx'
wb = Workbook()

wb.save(file_name)

Workbookをインポートします。

Workbookを呼び出して、saveの引数にファイル名を指定するだけでエクセルの作成が完了します。

カンタンですね。

シートの作成

Sheetの作成を行います。

エクセルのSheetの作成をするには、create_sheet関数を使います。

create_sheet(タイトル[, インデックス])

インデックスを指定することで、作成するシートの位置を変更することもできます。

from openpyxl import Workbook

file_name = 'sample.xlsx'
wb = Workbook()

ws = wb.create_sheet('サンプル')
ws1 = wb.create_sheet('sample', 0)
ws2 = wb.create_sheet('sample1', 1)
ws3 = wb.create_sheet('sample2', 2)

wb.save(file_name)

シートを作成するには、Workbookの中にあるので、wb.create_sheetとして使います。

作成したシートの結果が下記になります。

sample2とサンプルの間にあるSheetは、エクセルの最初からあるシートです。

サンプルは、インデックスを指定していないので、最後に作成されたということです。

エクセル Sheet作成

では、エクセルの最初からあるシートはどの様にアクセスするのか?

答えはactiveを利用することで、取得できます。

from openpyxl import Workbook

file_name = 'sample.xlsx'
wb = Workbook()

wd = wb.active
wd.title = 'デフォルト'

wb.save(file_name

6行目のWorkBookでactiveを指定するだけで、デフォルトのシートを取得することができます。

7行目は、シートの名称を変更する処理を行なっています。

シートのコピー

シートのコピーもできますが、制約が結構あります。

ワークブック間でのシートのコピーはできないや、読み取り専用でもコピーができないなどがあります。

利用する関数は、下記になります。

copy_worksheet(コピー元のシート)

下記が試したソースコードになります。

from openpyxl import Workbook

file_name = 'sample.xlsx'
wb = Workbook()

ws = wb.active
ws.title = 'デフォルト'

ws_cp = wb.copy_worksheet(ws)
ws_cp.title = 'コピーしたシート'

wb.save(file_name)

6行目のシートを9行目でコピーして、シート名を変更したコードになっています。

結果は、シート名が「デフォルト」と「コピーしたシート」の2つのシートが出来上がります。

シートコピー結果

シートの削除

シートを削除するには、remove関数を利用します。

以前はremove_sheetだったのですが、非推奨になっています。

remove(削除したいシート)

コピーして作ったシートを削除してみます。

from openpyxl import Workbook

file_name = 'sample.xlsx'
wb = Workbook()

ws = wb.active
ws.title = 'デフォルト'

ws_cp = wb.copy_worksheet(ws)
ws_cp.title = 'コピーしたシート'

wb.remove(ws_cp)

wb.save(file_name)

シートを削除している部分は12行目になります。

結果は、「コピーしたシート」が無くなり、デフォルトだけが残ります。

シート削除

エクセルのロード

作成されたエクセルを読み込むためには、load_workbookを利用します。

エクセルを読み込む際は、load_workbookを利用する。Workbookで作成してsaveすると初期化されるので注意が必要。

load_workbookの引数は下記になります。

load_workbook(ファイル名)

試したコードは下記になります。

from openpyxl import Workbook, load_workbook

file_name = 'sample.xlsx'
# wb = Workbook()
wb = load_workbook(file_name)

ws = wb.active
ws.title = 'デフォルト'

wb.save(file_name)

4行目のWorkbookをコメントアウトして、5行目のload_workbookでファイルを読み込んでいます。

そのため、1行目にあるWorkbookは本当はインポートする必要はありません。

下記が結果になりますが、あらかじめエクセルに「初期化されない」と「テストです」を記載していました。

4行目と5行目のコメントアウトを反対に実行すると中身が消えるので、試したい方は試してみてください。

セルの操作

セルの操作は特に関数とかは必要ない感じです。

スライスの指定や配列といった指定方法で取得できる様です。

まずはデータを取得するために、エクセル側でカンタンなデータを作ります。

作成するデータは、AからCのセルの5行目までに列名と番号を振ったデータになります。

このデータを取得してみます。

スライスによる操作

スライスで取得してみます。

from openpyxl import load_workbook

file_name = 'sample.xlsx'
wb = load_workbook(file_name)

ws = wb.active

ab = ws['A1':'B5']

for data in ab:
    print(data[0].value, data[1].value)

8行目がスライスで取得している処理です。

その結果を、forを使ってループで回しています。

最初は下記のオブジェクトの状態で取得できていました。

<Cell 'デフォルト'.A1> <Cell 'デフォルト'.B1>
<Cell 'デフォルト'.A2> <Cell 'デフォルト'.B2>
<Cell 'デフォルト'.A3> <Cell 'デフォルト'.B3>
<Cell 'デフォルト'.A4> <Cell 'デフォルト'.B4>
<Cell 'デフォルト'.A5> <Cell 'デフォルト'.B5>

どうやって値を取得するのか分からなかったので調べると、単純にvalueで取得できました。

上の結果は、value無しの状態で、下記がvalueをつけた時の結果になります。

A1 B1
A2 B2
A3 B3
A4 B4
A5 B5

行と列による操作

まずは行の指定を行なって取得します。

指定方法はカンタンで、何行目から何行目までを指定するだけです。

from openpyxl import load_workbook

file_name = 'sample.xlsx'
wb = load_workbook(file_name)

ws = wb.active

ab = ws['3:5']

for data in ab:
    print(data[0].value, data[1].value, data[2].value)

今回はエクセルの3行目から5行目を取得する処理です。

結果は、下記になります。

A3 B3 C3
A4 B4 C4
A5 B5 C5

列もカンタンで、列のアルファベットを指定するだけです。

from openpyxl import load_workbook

file_name = 'sample.xlsx'
wb = load_workbook(file_name)

ws = wb.active

ab = ws['B']

for data in ab:
    print(data)

B列を取得しています。

結果は、下記になります。

<Cell 'デフォルト'.B1>
<Cell 'デフォルト'.B2>
<Cell 'デフォルト'.B3>
<Cell 'デフォルト'.B4>
<Cell 'デフォルト'.B5>

スライスを使わなくても下記の様にして取得することも可能です。

ws['A:B']

XlsxWriterについて

XlsxWriterについて

XlsxWriterは、Pythonを使ってエクセルのXLSXファイルを作成するライブラリです。

Excel 2007からサポートしている様です。

XlsxWriterのインストール

インストールするには、pipコマンドを利用してインストールします。

$ pip install XlsxWriter

ブックの作成

ブックの作成を行います。

作成するには、Workbookを使います。

OpenPyXLと作り方はほとんど同じですが、Workbookの引数でファイル名を指定します。

Workbook(ファイル名)

OpenPyXLと違うところは、saveをすることなくcloseを行います。

from xlsxwriter import Workbook

file_name = 'sample2.xlsx'
wb = Workbook(file_name)
wb.close()

使い方は他の言語のファイルを取り扱い方と同じなので、私はこちらの方が使いやすいです。

シートの作成

シートの作成を行いますが、先にデフォルトのシートを取得してシート名を変更してみます。

from xlsxwriter import Workbook

file_name = 'sample2.xlsx'
wb = Workbook(file_name)

ws = wb.add_worksheet()
ws.name = 'デフォルト'
wb.close()

6行目のadd_worksheetでシートを指定しています。

OpenPyXLと違って、インデックスを指定することができないので、add_worksheetを作った順で作成されていきます。

シート名を変更するにはnameを使わず、そのままadd_worksheetの引数を指定した方が良い気がします。

ws = wb.add_worksheet('デフォルト')

シートのコピー

XslxWriterでは、シートのコピーが無いです。

ドキュメント見てもないし、検索してもないのでいろいろ試してみました。

長くなったのですが、オブジェクトコピーするかないっぽいですね。

import copy

from xlsxwriter import Workbook

file_name = 'sample2.xlsx'
wb = Workbook(file_name)

ws = wb.add_worksheet('あいうえお')
ws.write('A1', 'aaaa')

obj = wb.worksheets_objs
cp = copy.copy(obj[0])
cp.name = 'test'
wb.worksheets().append(cp)

wb.close()

add_worksheetの中を確認すると、オブジェクトをworksheets_objsにappendしていました。

なのでworksheets()の戻り値が、worksheets_objsだったのでappendするとうまくいきました。

シートの削除

これもドキュメント確認したのですが、無いっぽいですね。

なので、worksheets_objsから削除するしかないです。

import copy

from xlsxwriter import Workbook

file_name = 'sample2.xlsx'
wb = Workbook(file_name)

ws = wb.add_worksheet('あいうえお')
ws.write('A1', 'aaaa')

obj = wb.worksheets_objs
cp = copy.copy(obj[0])
cp.name = 'test'
wb.worksheets().append(cp)

wb.worksheets().pop(0)

wb.close()

シートのコピーのソースコードを流用していますが、16行目のpopの処理で削除をしています。

popにインデックス番号を渡して削除しています。

インデックス管理だとめんどくさいので、ループで回してシート名とマッチしたインデックスを渡す関数作った方が楽ですね。

ダサいけど、下記のような感じですね。

import copy

from xlsxwriter import Workbook


def remove(wb, rm_name):
    for i, obj in enumerate(wb.worksheets_objs):
        if obj.name == rm_name:
            wb.worksheets().pop(i)
            break


file_name = 'sample2.xlsx'
wb = Workbook(file_name)

ws = wb.add_worksheet('あいうえお')
ws.write('A1', 'aaaa')

obj = wb.worksheets_objs
cp = copy.copy(obj[0])
cp.name = 'test'
wb.worksheets().append(cp)

remove(wb, 'あいうえお')

wb.close()

remove関数作って、ワークブックと削除したいシート名を入れて削除する様な感じで作成したけど、やっぱダサい。

あくまでも参考レベルですね。

エクセルのロード

XlsxWriterの名称の通り、書き込み専用のモジュールとなっています。

そのため、読み込んでどうにかしたい場合は、OpenPyXLなどの読み込みもできるモジュールを利用するしかないです。

セルの操作

セルに書き込んでみます。

書き込む関数は、writeとwrite_columnがあります。

from xlsxwriter import Workbook

file_name = 'sample2.xlsx'
wb = Workbook(file_name)

ws = wb.add_worksheet()

ws.write('A1', 'テスト')
ws.write_column(1, 1, 'XYでセット')
ws.write_column(1, 0, ['XYでセット'])

wb.close()

writeは、エクセルの列行を指定することで書き込むことができます。

write_columnについては、XとY軸の位置情報を指定した書き込みになります。

write_columnの書き込む引数は配列で渡す

配列じゃないと下記の様に、一つのセルに収まらない結果になります。

エクセルセル操作

xlwingsについて

xlwingsについて

xlwingsはエクセルがインストールされているのが前提です。

そのためWindowsかMacOSでしか動かないみたいです。

そうなると、LinuxのWebサーバーとかでは使えないようですね。

使う場面を考えると、Windowsサーバ構築して使うかRPA使ってWindows PCで使うとかですかね。

xlwingsでは何ができるのかというと、自動化を行うモジュールの様です。

xlwingsのインストール

インストールは、pipコマンドを使ってインストールします。

$ pip install xlwings

condaでもインストールできる様なので、condaの場合は下記になります。

$ conda install xlwings

ブックの作成

ブックを追加してみます。

import xlwings as xw

file_name = 'sample.3.xlsx'
wb = xw.Book()
wb.save(file_name)
wb.close()

実行してみたら、Permissionエラー出るんだけど。

appscript.reference.CommandError: Command failed:
		OSERROR: -1743
		MESSAGE: The user has declined permission.
		COMMAND: app('/System/Library/CoreServices/System Events.app').processes[its.unix_id == 3612].visible.get()

いろいろ調べているのですが、解決してもバージョンアップとかでぶっこわれる様です。

私の環境は、MacのBig surとWindows10で試してみました。

Macでは、通常のPythonとAnacondaをインストールしてもダメで、Windows10に関しては通常のPythonで試してみました。

ドキュメントに書かれているdotのバージョンなのかな?って思いましたが、動きませんでした。

動かない原因について、現在調査中です。

まとめ

Pythonでエクセルの操作をするモジュールについて、OpenPyXLとXlsxWriterについて解説しました。

xlwingsについては、バージョンの問題なのかうまく動かなかったので現在調査中です(解決次第、記事を更新します)。

基本的な操作に関しては、OpenPyXLで出来るので無難にOpenPyXLを使った方が良いでしょう。

OpenPyXLでできない部分に関して、XlsxWriterを使うなり他のライブラリを使うのがエクセル操作を行う上で無難な使い方になります。

1つのライブラリだけを使うのではなく、適材適所な形で使うことをオススメします。

-Python
-,