Excelで自動化を考えるときに第一選択肢に出てくるのはVBAでしょう。
ただ、VBA私全くできません。。そして、全く学習する意欲が湧きません。。なんでしょう、なんか今からラダーやCやれって言われるよりなぜかやる気がおきませんw ディスってるわけでもないですし、実際に業務に利用されて活用されている方もよく知っているので、正直趣味の問題だとは思いますが。。
ということで、pythonを使ってエクセルを操作する方法を紹介していきます。利用するモジュールはOpenPyXLというエクセルを操作するためのモジュールです。
OpenPyXLとは何か?
OpenPyXLはエクセルの読み込み・書き出しなどの操作をpythonでするためのモジュールです。
実際にできることは以下のような操作です。
- エクセルファイルを作成する
- 既存のエクセルシートのデータを読み込む(セルの値を読み込む・書き込む)
- 計算式を設定する
- データのコピーをする
- グラフを作成する
- PandasやNumpyと連動させる
などなど、他にもフォーマット(style関係)やフィルターなんかも取り扱えます。あまり使わないですが、pivot-tableも読むことができます(作成はできません)
OpenPyXLで操作できるエクセルファイル
OpenPyXlは .xlsxフォーマットのエクセルファイルであれば対応可能です。フリーソフト系のlibra office とかでもxlsx形式で保存可能なので、要はファイルフォーマットが.xlsxになっていればいけます。
逆に、.xlsは対応できません。Excel2003以前の拡張子がExcelファイル(拡張子が.xls)を使いたいときはxlrdの利用を考えるべきですね。
というか、今時.xlsなんて残っているのかと言われますが、たまに私の手元に送られてくることもあり、まぁまだ生きてるんだろうなぁと思います。
早く消し去っ。。。(グサッ
OpenPyXLのインストール
pip( or pip3)でモジュール管理されている方は以下の形でインストしてください。
Anaconda(conda)の場合は、最初から入っていた気もします。(この頃使ってないので、記憶が定かではありませんが)
OpenPyXLでエクセルファイルを読み込む
何はともあれ何かファイルを読み込んでみましょう。
ファイルを読み込んでシート名一覧を取得する
from openpyxl import load_workbook
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
print(ss.sheetnames)
読み込みファイルの場所について
何個かサイトを調べていると、.xlsxファイルをPythonを動かしている環境と同じディレクトリに移動(コピー)する必要があると書いてあるサイトもありました。
そんなことはないかなと。絶対パスを通せば特段問題なく動作します。
ワークブックの取得
ワークブックの取得はload_workbookメソッドを利用します。引数にはpathやファイル名(同一フォルダに入れてある場合)です。
シート名の取得
ワークブックオブジェクト(load_workbookで取得したオブジェクトです)に対して、sheetnamesプロパティを取ればシート名の一覧が配列で返されます。
レスポンスはこんな感じ
['sheet1', 'sheet2', 'sheet3']
たまに、get_sheet_namesメソッドでシート名一覧を取得することを紹介している記事(多分古い記事です)がありますが、現在get_sheet_namesメソッドは非推奨になっていますので、sheetnamesプロパティを使うのが基本です。
シートの取得・追加・コピー・削除
基本的なシート系の操作についてです。
シートオブジェクトの取得
Workbookオブジェクトにシート名を指定して取得できます。
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
sheet1 = ss['sheet1']
シートの追加
シート追加はWorkbookオブジェクトのcreate_sheetメソッドで追加できます。一つ目の引数にシート名、二つ目の引数にシートを挿入する位置をインデックスで指定可能。引数の指定はどちらも任意です。
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
ss.create_sheet('Additional Sheet', 0)
シートのコピー
シートコピーはWorkbookオブジェクトのcopy_worksheetメソッドで可能。引数にコピー対象のWorksheetオブジェクトを指定します。
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
sheet1 = ss['sheet1']
sheet2 = ss.copy_worksheet(sheet1)
シートの削除
シート削除はWorkbookオブジェクトのremoveメソッドを利用します。引数は削除したいWorksheetオブジェクトを指定します。
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
sheet1 = ss['sheet1']
sheet2 = ss.remove(sheet1)
単一セル・複数セルの取得・編集
単一セルの取得と値の取得
単一セルを取得した場合は、セル名称(A1ノーテ)で取得してやれば可能です。セルの値を取得する場合は、cell obj.valueで取得可能
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
sheet1 = ss['sheet1']
b2_cell = sheet1['b2']
print(b2_cell.value)
単一セルの編集
単一セルが取得できれば、あとはvalueプロパティの置き換えで単一セルの編集は可能です。
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
sheet1 = ss['sheet1']
b2_cell = sheet1['b2']
b2_cell.value = "added from openpyxl"
print(be_cell.value)
シートオブジェクトからcellメソッドで編集する
セルを指定して値を取得する方法以外に、シートオブジェクトからcellメソッドを利用することで、直接行・列を指定して値を取得することも可能です。
valueはオプショナルです。値を入れ込みたくなくて、セルオブジェクトを取得したい場合は、valueを指定せずにいけばOKです。
キーワード引数で設定すると間違いが起きなくておすすめです。
複数セルの取得と値の取得
セルの範囲指定は①A1ノーテーションで指定する②行・列範囲で指定する、の2つの方法があります。
①A1ノーテーションで指定する方法
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
sheet1 = ss['sheet1']
B2toC5_cells = sheet1['b2':'c5']
for row in B2toC5_cells:
for cell in row:
print(cell.value)
②行・列範囲で指定する方法(値の取得は省略)
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
sheet1 = ss['sheet1']
#行単位で指定
cells1 = sheet1[10]
cells2 = sheet1[5:10]
#列単位で指定
cells3 = sheet1['A']
cells4 = sheet1['A':'C']
複数セルの編集
下記スクリプトだと、全部一括で同じ値にしてしまいますが、イメージは以下です。実際は条件分岐を与えて実行していきます。
path = "絶対Pathもしくは相対Pathを指定"
ss = load_workbook(path)
sheet1 = ss['sheet1']
B2toC5_cells = sheet1['b2':'c5']
for row in B2toC5_cells:
for cell in row:
cell.value = "modified from openpyxl"
Excelファイルの保存
Workbookオブジェクトのsaveメソッドに保存先パスを指定。新規作成の場合は新しいパス、上書き保存の場合は既存のパスを指定してください。基本は絶対Pathで指定してもらったほうがいいかと思います。
まとめ
GASとpythonを少しでも触ったことがある人であれば、非常にイメージしやすかったのではないでしょうか。
SpreadsheetAppと作りが似ているのがGASユーザにはありがたいですね。
スプレッドシート使えばいいという話もあるかもしれませんが、スクレイピングなどGASよりpythonの方が相性のいい物もありますので、openpyxlでローカルエクセル利用できるようになるといいですね。
sheetAPIを利用すればエクセルファイルのuploadやデータの書き込みも可能ですし。興味があれば以下の記事もお読みください。