Excelの値をPythonで取得する方法

久しぶりです。プログラマーJです。

ゲームデータをExcelで管理することもあると思います。その際、バイナリデータに変換することで、ビルドすることなくパラメータを変更することが可能です。

そこで今回はPythonでExcelのデータを取得する方法をご紹介します。

環境

  • Windows 10
  • Python 3.7.1
  • pywin32

pywin32とは

pywin32はCOMオブジェクトを介してExcelを操作できるモジュールです。

導入方法

コマンドプロンプトで以下を実行します。

pip install pywin32

使い方

使い方
Python
# -*- coding: utf-8 -*-

import os
import win32com.client as win32

# Excelファイルは以下の想定です
#         A               B
# ┌───────────────┬───────────────┐
# │      名前     │       値      │ # 1行目
# ├───────────────┼───────────────┤
# │   アイテム1    │        100    │ # 2行目
# ├───────────────┼───────────────┤
# │   アイテム2    │        200    │ # 3行目
# ├───────────────┼───────────────┤
# │   アイテム3    │        300    │ # 4行目
# ~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~
# │  アイテム999   │      99900    │ # 1000行目
# ├───────────────┼───────────────┤
# │  アイテム1000  │     100000    │ # 1001行目
# └───────────────────────────────┘


try:
	# COMを利用してExcelに接続
	app = win32.Dispatch("Excel.Application")

	# エクセルファイルを開く
	path = os.path.abspath("./test.xlsx")
	book = app.Workbooks.Open(path)

	# シートを取得
	# book.Worksheets("シート1") のように文字列でも取得可能.
	sheet = book.Worksheets(1) 

	# セルを取得
	wk = sheet.UsedRange 		# 使用範囲を取得
	columns = wk.Columns.Count	# 行数
	rows = wk.Rows.Count		# 列数

	for y in range(1,rows+1):
		for x in range(1,columns+1):
			# セルから値を取得
			print(sheet.Cells(y, x).Value)
	
finally:
	# ブックを閉じ、COMを終了させる
	book.Close(SaveChanges=False)
	app.Quit()
	del app

上記のコードを実行するとわかるのですが、非常に時間がかかります。

このままでは作業に支障をきたすぐらい遅いので高速化を行います。

高速化

for文で表示しているところを計測します。処理のばらつきを考慮し、3回行った平均にします。

# 3回の平均を計測
N = 3
times = []
for idx in range(N):
	start = time.perf_counter()
	for y in range(1,rows+1):
		for x in range(1,columns+1):
			print(sheet.Cells(y, x).Value)
	times.append(time.perf_counter() - start)

print("time {:.7f} sec".format(sum(times)/len(times))) # 秒表示

結果は 6.5105476秒 でした。
遅い原因はCells関数が現在のプロセスからExcelのプロセス(EXCEL.EXE)にアクセスし、大量のオーバーヘッドを発生をさせているためです。
なのでCells関数を使わない方法でアクセスします。

cells = wk.Value
for y in range(0,rows):
	for x in range(0,columns):
		print(cells[y][x])

wk.Valueはシートのデータを取得しているので、それをキャッシュすることで高速に値を取得できます。
こちらも同じように3回の平均を計測したところ、0.1483422秒 でした。
速度が97.7%向上し、高速化に成功しました。

最後に

お手軽にExcelの値を取得することができました。あとはstructモジュールを使用すれば、バイナリデータも作成できます。
また、.xlsxはバイナリデータなので中間ファイルに出力することでファイル管理も楽にしたいところですね。

Follow me!