PythonからExcelを操作するpyExceleratorとxlrd/xlwt/xlutils

はじめまして。gumiのtamuraです!( ゚∀゚)o彡°PythonPython

Python使ってますか? Excel使ってますか?
両方使っているそんな貴方のために、今回はPythonExcelを操作するライブラリpyExceleratorxlrd/xlwt/xlutilsを紹介します。

pyExceleratorは長らく使われてきたExcelを読み書きするライブラリで実績があり、
実用上困ることはあまりありませんがメンテナンスがほぼされなくなっており、
(2005-10-26に0.6.3a、2009-04-12に最新の0.6.4.1がでたきり)
Python3の事を考えれば今後はxlrd/xlwt/xlutilsを用いる方が良いでしょう。
xlrd/xlwt/xlutilsはその役割によって、三つのライブラリに分かれており、
xlrdは.xlsファイルを読み込むため、xlwtは.xlsファイルを書き込むため、xlutilsはxlrdとxlwtに共通するユーティリティ関数などを提供します。
 
まず、PythonExcelにアクセスする利点とはなんでしょうか?

Excelにアクセスする手段として思いつくのはOLEという人も多いのではないでしょうか。
確かにOLEを使うと幾つかの言語においてCOMの標準インターフェイスを用いてExcelにアクセスする手段が提供されます。
しかし、

  • Windows上でしか動作しない
  • OLEを扱うため、裏でExcelが立ち上がり遅い

という欠点があります。
 
pyExceleratorやxlrd/xlwt/xlutilsならバイナリ操作をするので、

  • Windows/OSX/Linuxなど各種プラットフォームで動く
  • バイナリ直読み&書き換えなので速い

という利点があります。

pip環境であれば、pip install pyExceleratorやpip install xlrdでインストールできるのも便利なところです。
Windows上にはインストーラなども提供されていますので、非常に気軽に使い始めることができます。

また、Excelがインストールされている必要はなく、OpenOfiice.orgのCalcで保存した.xlsファイルも普通に扱うことができます。


では、なぜそもそもExcelを操作するライブラリを使う必要があるのでしょうか?
これは未だにExcelがデータ記述用のフォーマットとして扱われる事が多いからに他なりません。
仕様やデータなどが記述されたExcelやテキストがある場合、これらを実アプリ上で運用できるデータに変更するには、いずれかにマスタデータを持たなければなりません。

コンシューマゲーム制作などにおいては何らかのファイルですし、WebアプリであればDBやDBのデータを何らかの方法で記録したファイルとなるでしょう。

たとえば、PythonにおけるWebフレームワークの雄であるDjangoでDBにデータを反映するための仕組み、フィクスチャ(fixture)を扱う場合などは、データが記述されるフォーマットはjsonyamlxmlでなければなりません。
では、これらの場合データをどうつくるでしょうか?

  • DBにロードされるためのjsonyamlxmlに直に書いていく
    • いかに構造化されたテキストとはいえ、様々な計算を行ったりするのには不向きです。Excelが持つような数式の仕組みを使うことができないのですから。

  • Excelを見ながらjsonyamlxmlを手打ちしてそれをloaddata(DBにロードする)する。
    • これは変更があった場合に非常に面倒です。また打ち間違いもあり、決して効率的ではありません。yamlならまだしも、xmljsonを手打ちするのは多くの場合辛い気持ちになるでしょう。
  • Excelを見ながらDjangoの管理画面を使いデータを打ち込んだあと、dumpdataでjsonとして保持しておく。
    • Djangoの管理画面は便利ではありますがマスターとして扱うには心許ないですし、これも変更があった場合に非常に面倒です。たとえば、調整でDjangoの管理画面のデータをいじり、それをマスターデータに書き戻し忘れる、といった事も起きえるでしょう。
  • Excelをマスターデータとし、Excelを操作するライブラリで読み込みPyYAMLなどを用いてフィクスチャをはき出し、それをloaddataする。
    • Excelは常にマスターデータとして活用することができます。また、Excelの差分をチェックするツールなどを使えば、Excelの変化も追従することができます。


ただし、Excelをマスターデータにした場合はDjangoの管理画面と違い、Excelではリレーションなどを適切に扱ってくれる訳ではないことに留意してください。
けれど、多くの場合は変化しないデータを初期データとして用いるのでこれらの問題は起きづらいと考えられますし、これらをリレーション可能なデータとして扱う方法もpk/idなどを機械的に振れば可能でしょう。

この方法が絶対というわけではないですが、Excelをマスターデータとすることで、保存しスクリプトを走らせ実DBや実データに対して反映させることが容易になります。

ソースコードは以下のような感じでExcelのデータをとってくることができます。

# -*- coding: utf-8 -*-
import pyExcelerator
sheets = pyExcelerator.parse_xls('Sample.xls')
for sheet_name, values in sheets:
    print u'Name:%s' % sheet_name
    for row_index, col_index, in sorted(values.keys()):
        v = values[(row_index, col_index)]
        print '(%d,%d):%s' % (row_index, col_index, v)

ただし、pyExceleratorのparse_xlsで得られる辞書(キーと値)は疎な配列(スパース配列)であるため、必要ならば事前に楽な形式に変換しておくと便利です。
pyExceleratorにはサンプルも含まれており、非常に参考になります。(pyExceleratorのexampleディレクトリを参考にしてください)

# -*- coding: utf-8 -*-
from xlrd import open_workbook
wb = open_workbook('Sample.xls')
for s in wb.sheets():
    print 'Sheet:', s.name
    for row in range(s.nrows):
        for col in range(s.ncols):
            print s.cell(row, col).value,
        print ''

xlrdを使った場合はこうです。
内部構造はどうあれ、データのアクセスに関してはs.cell(row,col)といったようにアクセスできるxlrdの方が楽であると言えるでしょう。

もしExcelファイルからいちいちcsvに保存しなおしてファイルをパースしているが手間、といったケースやOLEを用いたアクセスでExcelを扱うのが凄く遅いので困っている、という場合はこれらのライブラリを使ってみてください。
少しでも役に立てば幸いです。