レガシーなマクロ付きExcel ファイルを API 化する話

Toshiaki Takahashi
The Finatext Tech Blog
9 min readDec 18, 2023

--

こんにちは、Finatextの @toshipon です。この記事はFinatextグループ10周年記念アドベントカレンダーの18日目の記事です。昨日は河本さんが「メガベンチャーから来たエンジニアおじさんが振り返る、スタートアップ選びのポイント」という記事を公開しています。

この記事の概要

多くの企業では、既存の業務プロセスにおいて Excel マクロや関数を活用した複雑な計算処理をオフラインで実施しているケースが存在します。最近、これらの計算処理をオンラインサービスに転換するニーズをチラホラとお見受けします。本記事では、既存のExcelファイルを用いて、APIを介して処理結果をオンラインで取得する方法について解説します。

免責事項

本記事では、Microsoftの製品を使用する上でのライセンスに関連する情報を記載しています。ライセンス体系は常にアップデートされているため同様のユースケースにて Microsoft 製品を利用する際には、必ず Microsoftのサポートに問い合わせ、適切な検討をおこなっていただければと思います。

また、今回紹介する Excel をサーバーサイド環境で実行するといった構成は、GUIアプリケーションをプログラム上から操作するため、一定の不安定さに課題がある背景から Microsoft ではサーバー上での Microsoft Office アプリケーションの自動化は推奨しておらず、サポートもされていません。
Excel を用いたサーバーサイドオートメーションの検討をする際には、スクラッチでシステムを作り変える等、別の代替手段も合わせて検討する必要があります。

前提条件

既存のExcelファイルの活用

本記事の対象は、現在 Excelマクロや関数を用いた処理を行っている業務です。これらの既存のExcelファイルをAPI経由での処理に適応させる方法を紹介します。

Microsoft 365 のライセンスについて

サーバーサイドでMicrosoft 365製品を利用するには、専用のライセンスが必要です。「Microsoft 365 E3 Unattended」というライセンスをVMサーバー単位で購入することで、サーバーサイドオートメーションを実現できます。2023年12月時点で、このライセンスはAzure上のVMサーバーでのみ利用可能で、AWSが提供する Windows Server 2022 on EC2 では使用できない点に注意が必要です。

サーバーサイドオートメーションの定義と制約

サーバーサイドオートメーションは、人の操作介入なしにExcelを操作する処理を指します。サーバーサイドオートメーションで Microsoft 365製品を利用する際には、特定の定められた制約に従う必要があります。具体的なライセンス利用のシナリオは、主に以下の2つが挙げられます。

  1. Microsoft 365 ライセンスを保有するクライアントによってトリガーされ、サーバーサイドオートメーションを実行し Excel操作が行われる
  2. 定期バッチやメール受信など人の介入がないイベントをトリガーにサーバーサイドオートメーションを実行し Excel 操作が行われる

これらのシナリオに応じたAPIサーバーのアーキテクチャ設計が必要です。

Excelを使ったAPIサーバーの実現手段

既述の2つのシナリオを踏まえて、以下の方法でExcelを活用したAPIサーバーを実現します。

1. Microsoft 365 ライセンスを保有するクライアントがAPIを呼び出す場合

このケースでは、クライアントがAPIを呼び出し、サーバー側でExcelの処理を実行します。

上記図のように、Microsoft 365 ライセンスを保有しているクライアントは、ライセンス規約上、Excel 操作を行うサーバーサイドオートメーションのプロセスを直接トリガーすることができるため、Web ページを通してAPI経由で Excel の計算結果を受け取ることが可能になります。

例えば、Azure Application Gateway からロードバランシングされた複数のVMサーバーで構成された環境で Excel の処理を行い、APIの結果として返却することも可能です。Microsoft 365 E3 ライセンスは VM サーバーの台数分購入が必要になります。

2. クライアントがMicrosoft 365 ライセンスを持っていない場合

このケースでは、サーバーサイドでクライアントがトリガーするのではなく、独立してExcelの処理を実行し、その結果をAPI経由で提供します。

Microsoft 365 ライセンスを保有していないクライアントは、ライセンス規約上、Excel 操作を行うプロセスを直接トリガーすることができないため、定期バッチや非クライアントがトリガーする処理を通して Excel の計算処理を実行します。

定期バッチ処理等で実行した Excel の処理結果をキャッシュサーバーに保持し、クライアントは Azure Functions を通してキャッシュのデータをAPIの結果として返却して受け取ります。直接的に Excel の結果を受け取るとはできないですが、間接的にAPIのレスポンスとしてExcel の処理結果の取得をします。

Excelをプログラムから操作する

今回、Excelをプログラムから実行する方法として、Pythonの「pywin32」ライブラリを使用するケースを紹介します。このライブラリは、Excelのマクロや関数、オブジェクト操作に対応しており、他のライブラリに比べて比較的 Excel の操作可能範囲が広いです。以下に Python の Flask サーバー経由で Excel の計算結果を API のレスポンスとして返却するサンプルコードを記載します。

python
from flask import Flask
import win32com.client
import pythoncom
from contextlib import contextmanager

app = Flask(__name__)

@contextmanager
def co_initialize():
pythoncom.CoInitialize() # Excelを操作する場合は必須
try:
yield
finally:
pythoncom.CoUninitialize()

def set_value(name, ws, val):
obj = None
for shape in ws.Shapes:
if shape.Name == name:
obj = shape

if obj is not None and hasattr(obj, 'ControlFormat') and hasattr(obj, 'FormControlType'):
ctl = obj.ControlFormat
if obj.FormControlType == 2: # dropdown
ctl.ListIndex = val
elif obj.FormControlType == 1: # checkbox
ctl.Value = val

@app.route('/calc')
def calc():
with co_initialize():
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = False # ExcelをGUI上表示しない
excel.DisplayAlerts = False # ポップアップアラートが出ると止まってしまうので抑制

wb = excel.Workbooks.Open(r"C:\PathToFile\hoge.xlsm", ReadOnly=True)
ws = wb.Worksheets("シート1")

set_value("DRP_ドロップダウン1", ws, 1)
set_value("CHK_チェックボックス2", ws, 1)

result = {"data": ws.Range("A1").Value}

return result

if __name__ == '__main__':
app.run(debug=True)

このように、Python から Excel のセルやオブジェクトを操作して、最終的にマクロや Excel 関数によって計算された結果を セルの値を読み取ることで取得ができるようになります。

技術的な課題

Excelプログラムの実行における不安定さと処理速度

サーバーサイドで Excel のプログラムを実行する際の不安定な動作や処理速度の問題があります。これらに対処するため、以下のような方法も検討する必要があります。

  • VMサーバーにヘルスチェックを設置し、応答がない場合は自動的にサーバーをシャットダウンするために、VMサーバーのオートスケーリングを組んでそれを利用して新しいVMサーバーに切り替えます
  • 大量のリクエストが押し寄せる場合を想定して、リクエストは一時的にキューに保存し、非同期で処理するようにし急激なサーバー負荷を抑制します
  • Excelの実行結果はキャッシュサーバーに保持し、同じ計算の再実行を避けることで処理効率を向上させます

最後に

今回は、既存のExcelファイルを活用したシステム構成に関する内容を紹介いたしました。この例に限らず弊社では既存の業務を SaaS プロダクトに置き換えてアジリティを持ってお客様に商品展開や顧客体験の提供の手助けをするためのチャレンジが沢山あります。ご興味のある方は是非ご連絡いただけると、より具体的なお話をさせていただきたいと思います。

https://hd.finatext.com/recruit/

明日は瀬能さんによる「Streamlit Bootcamp #1」についての記事です。お楽しみに!

関連記事

--

--