Pythonによるオフィスワークの自動化では、エクセルファイルを操作できるOpenPyXLは欠かせないライブラリです。インストールは以下のようにpip
を用いて簡単にできます。
C:¥Users¥ichiro> py -m pip install openpyxl
# その他の例(環境によりコマンドは様々です)
mac:~ ichiro$ python3 -m pip install openpyxl
OpenPyXLを用いて既存のエクセルファイルを読み込むには、以下のようにload_workbook()
を用います。
>>> import openpyxl
>>> wb = openpyxl.load_workbook("./Files/tokyo_branch_201808.xlsx")
>>> ws = wb["Sheet1"]
>>> ws["A1"].value
'東京本社月次決算'
ここで以前は、表示形式が「ユーザー定義」のセルを含んでいるとエラー(KeyError)が表示されましたが、バージョン2.6.1からそのセルは「標準(General)形式」として読み込まれるようになりました。
例えば、以下のように年月を「ユーザー定義」でyyyy"年"m"月"
としていたのに、OpenPyXLでは「標準」で読み込まれるので、日付で入力していた値はシリアル値で取得されます。
# ユーザー定義のはずが「標準(General)」で読み込まれる
>>> ws["B1"].number_format
'General'
# 値はシリアル値で取得される
>>> ws["B1"].value
43313
つまり、想定と違う表示形式で読み込まれることになるので注意が必要です。
load_workbook()
は真っ先によく用いるメソッドですので、最初でつまずかないよう少し詳しく解説してみました。参考にしていただけたら嬉しいです。
以前の動作確認
以前(バージョン2.6.0まで)は、以下のように読み込むエクセルファイル内に認識できない形式のセルがあるとエラー(KeyError
)が表示されていました。
>>> wb = openpyxl.load_workbook("./Files/tokyo_branch_201808.xlsx")
Traceback (most recent call last): File "
", line 1, in wb = openpyxl.load_workbook("./Files/tokyo_branch_201808.xlsx") File "C:\Users\ichiro\AppData\Local\Programs\Python\Python37-32\lib\site-packages\openpyxl\reader\excel.py", line 312, in load_workbook reader.read() File "C:\Users\ichiro\AppData\Local\Programs\Python\Python37-32\lib\site-packages\openpyxl\reader\excel.py", line 273, in read apply_stylesheet(self.archive, self.wb) File "C:\Users\ichiro\AppData\Local\Programs\Python\Python37-32\lib\site-packages\openpyxl\styles\stylesheet.py", line 189, in apply_stylesheet stylesheet = Stylesheet.from_tree(node) File "C:\Users\ichiro\AppData\Local\Programs\Python\Python37-32\lib\site-packages\openpyxl\styles\stylesheet.py", line 103, in from_tree return super(Stylesheet, cls).from_tree(node) File "C:\Users\ichiro\AppData\Local\Programs\Python\Python37-32\lib\site-packages\openpyxl\descriptors\serialisable.py", line 104, in from_tree return cls(**attrib) File "C:\Users\ichiro\AppData\Local\Programs\Python\Python37-32\lib\site-packages\openpyxl\styles\stylesheet.py", line 93, in __init__ self._normalise_numbers() File "C:\Users\ichiro\AppData\Local\Programs\Python\Python37-32\lib\site-packages\openpyxl\styles\stylesheet.py", line 166, in _normalise_numbers fmt = BUILTIN_FORMATS[style.numFmtId] KeyError: 55
上記のエラーは、以下のopenpyxl.styles.numbers
モジュールのソースコードを見ると分かりますが、BUILTIN_FORMATS
の辞書には55
というキーがないことを表しています。
openpyxl.styles.numbersモジュールのソースコード
このように、以前は認識できない表示形式のセルがあると例外として教えてくれましたが、バージョン2.6.1で以下のIssue(課題)の投稿に対処し、認識できない形式は「標準(General)」として読み込むようになりました。
Issue#1182 ‘I cannot load my excel file though openpyxl’
シートのコピーは問題ありません
なお、copy_worksheet()
では、ユーザー定義の書式形式はそのままコピーされます。
新しいバージョンでユーザー定義のセルを読み込む対処例
上記の例では、セルの値が日付のはずがシリアル値として読み込まれてしまうので何か対策が必要です。該当するファイルが少なければ、手動でファイルを修正するのが簡単ですが、数量が多くなる場合はコードで実装しておく必要があります。
対処法1:手動でエクセルファイルを修正する
以下のようにセルの書式設定で「表示形式」を組み込みの日付に変更します。
コードからこの修正したファイルを読み込むと、以下のように日時(datetime.datetime)で認識されているのが確認できます。表示形式もエクセルで設定した通りになっています。
>>> ws["B1"].value
datetime.datetime(2018, 8, 1, 0, 0)
>>> ws["B1"].number_format
'yyyy"年"m"月";@'
対処法2:コードで値を変換する
コードで日付のシリアル値をdatetime.datetime型に変換するには、openpyxl.utils.datetimeモジュール
のfrom_excel()関数
を用います。
>>> dt = ws["B1"].value
>>> dt
43313
>>> from openpyxl import utils
>>> dt = utils.datetime.from_excel(dt)
>>> dt
datetime.datetime(2018, 8, 1, 0, 0)
openpyxl.utilsパッケージ
には、結構便利なツールがありますので、一度のぞいて見ることをオススメします。