はてだBlog(仮称)

私的なブログど真ん中のつもりでしたが、気づけばWebサイト系のアプリケーション開発周りで感じたこと寄りの自分メモなどをつれづれ述べています。2020年6月現在、Elasticsearch、pandas、CMSなどに関する話題が多めです。...ですが、だんだんとより私的なプログラムのスニペット置き場になりつつあります。ブログで述べている内容は所属組織で販売している製品などに関するものではなく、また所属する組織の見解を代表するものではありません。

openpyxl のさわりのサンプルコード(PythonでEXCELファイルを扱う一例)

はじめに

感染症の例を見ていると、可視化やそもそも現場でのデータ収集というのはなかなか難しいなと感じる次第です。

大半の混乱は一元化や入力の標準化などの情報化の定石で解決する部分もあるでしょうが、今回のような走りながら速記するというような状況では、他者が後出しで簡単に言うようにはいかないところもあるでしょう。

という壮大なテーマとどこまで関連するかは別として、感染症の件から少し連想して(また言葉足らずなのでかなり飛躍しますが)、罫線入りの既存EXCELファイル(様式のテンプレートファイルに該当)に、なんらかのデータを反映して出力するPythonのミニマムな例2020はどんなもんだろうと、確認してみたので、そのサンプルコードです。

openpyxl

ググった範囲では、openpyxlというものがメジャーなようです。

openpyxl.readthedocs.io

さっそく試してみる

これ(ss2.xlsx) を

f:id:azotar:20200608003527p:plain

これ(ss2.output.xlsx)

f:id:azotar:20200608005207p:plain

にして出力します。

A3セル(ただし、結合セルがどうなるか見てみたかったので、A3-B4までの結合セルにしてあります。)を「えーさん」から「えーさん に追記してみる」という文字に置き換えします。

Pythonサンプルコード(ちょっと本来は不要なトリッキーなことまぜこみあり(後述))

import openpyxl
import sys
import io

wb = openpyxl.load_workbook('ss2.xlsx')
st = wb['Sheet1']
st['A3'] = st['A3'].value + ' に追記してみる'
#wb.save('ss22.xlsx')
b = io.BytesIO()
wb.save(b)
b.seek(0)
with open("ss2.output.xlsx","wb") as f:
    f.write(b.read())

これを、foo.py などとして保存して、カレントディレクトリにss2.xlsxが配置されているディレクトリで、実行してください。

この類のプログラムを見慣れた方には解説不要かもしれません。

ワークブックのオブジェクトをロードして、シートを選択して、セルを指定して... というのが、dictライクな操作でできるようですね。

見てのとおり、例外処理などは行っていませんし、本格的に取り回すには、openpyxlの他メソッドはもちろん、Pythonプログラムとして他にもやるべきことがありそうですが、比較的とっつきやすいアーキテクチャシンタックスのような気がします。

なお、ここではコメントアウトしてありますが、ファイルを素直に別ファイル含めて保存する場合は、「save」メソッドを使えば良いようです。

本来やりたいことだけをシンプルに対応するのであれば、コメントアウトを外して、「b = io.BytesIO()」以降は不要です。

なんで、ややトリッキーな例を入れたかはここでは割愛しますが、何をやっているかだけ解説しておくと、saveの代わりに、一時的にバイナリのバイトストリームにデータ格納して、それを明示的にファイルオブジェクトに書き出ししています。

最近のEXCELファイル自体は、XMLファイル等が入ったフォルダをzip化したものだそうですが、ひとまず今回の例の範囲であればこのような方法でも行けました。

補足

ググった範囲だと、oepnpyxlでは罫線が消える場合が頻出するということを記載しているブログなどがいくつかみられました。

今回のシンプルな例だと特に罫線が消えるということは発生しませんでしたが、注意が必要かもしれません。 また、画像の貼り付けがされている場合に(画像の中身や配置に特に変更はしないとしても)、openpyxlでうまく取り扱えるのかは確認していません。