pythonのopenpyxlモジュールを使ってエクセル操作【8時間目:膨大な価格情報の中からある値だけを更新する】

pythonで巨大なエクセルファイルを更新する

今回は取り扱う内容はもしかすと業務に役立てることができるかもしれません。「退屈なことをpython」にやらせようのプログラムを解説していきます。事前知識として下記サイトをみていただくと内容がわかりやすいかもしれません。

まずはここから膨大な価格情報が書かれているエクセルファイルをダウンロードしてください。
automatestuff-ja/produceSales.xlsx at master · oreilly-japan/automatestuff-ja · GitHub

このエクセルファイルには品物の名前と値段と重さと総価格が書かれています。

openpyxl python

もしこんなふうに品物とその価格情報をひとつの膨大なエクセルファイルとして管理していた場合、ある項目を更新するのは非常に時間がかかってしまう作業になるかもしれません。もしかすると、エクセルの機能で検索したりするなどで、良い方法はあるかもしれません。ただ、

今回はpythonのコードで価格更新をします。これは、ひょっとすると役に立つ人には奴に立つかもしれないです。それではコードを見ていきましょう。

import openpyxl
wb = openpyxl.load_workbook('produceSales.xlsx')
sheet = wb.get_sheet_by_name('Sheet')

#農産物の種類と、更新する価格
PRICE_UPDATE = {'Garlic':3.87,
 'Celery':1.19,
 'Lemon':1.27}

#行をループして価格を更新する。
for row_num in range(2, sheet.max_row):#先頭の行を飛ばして全ての行をループ
 produce_name = sheet.cell(row=row_num, column=1).value#produce_nameにはセルの値が
 if produce_name in PRICE_UPDATE:#セルの値がキーとして存在したら
 sheet.cell(row=row_num, column=2).value = PRICE_UPDATE[produce_name]#キーが存在したときはprice_updateの値を代入
 
wb.save('updatedProduceSales.xlsx')

今回はわりとシンプルなコードになっています。品物の列をforループで全ての行を検索します。問題は13行目です。これは「セルの値がキーとして存在したら」という意味になります。その条件のときだけ14行目を実行します。

14行目は少し難しいかもしれません。PRICE_UPDATE[キー名]とすることで→その値(Garlicだったら3.87)がシートのセルに書き換わることになります。
どうでしょう?これは結構すごい?ような気がします。

forループは実際にどんなふうに回っているかイメージしにくいかもしれません。produce_name変数がありますが、これは一気に代入されているというわけではなく、シートの1行1行順番に値が代入されていると考えれば少し理解しやすいかもしれません。

実際にspyderのデバッグ機能のstep実行を使って1行ずつプログラムをすすめてみればわかります。

余談:プログラム実行中にブルースクリーンがでてしまった

あまりないとは思いますが、pythonプログラムを実行中にエクセルファイルをいじると、バグが発生してWindowsだとブルースクリーンになってしまう可能性があります。僕自身は最近1度経験しましたが、プログラムの世界ではわりとバグはおきてしまうものみたいです。

あまり関連はないですが、最後の16行目で違う名前でエクセルファイルを保存しているのがわかりますでしょうか?.save()メソッドに元のファイルと違う名前を渡すと、上書きせずに新しくファイルが作られます。上書きしたほうがスマートですが、バグのリスクを考えると、新しくファイルを保存したほうがよいケースもありそうです。