\ ポイント最大11倍! /

【ExcelとPythonの最強コラボ!】win32comを使ったExcel操作のすべて

Python の Excel 系ライブラリは openpyxl が有名です。

ところが、openpyxl はグラフや罫線などが消えてしまう不具合があり、クライアントワークなどで安全に自動化したい場合はちょっと怖い面も。

そこで便利なのが win32com というライブラリ。

win32com は Excel のマクロと同じくらいの安定性があるので安心です。

注意点としては、Excel (Office)のインストールが必須なことと、openpyxl に比べて速度は遅めな点。

また、macOS では動作しません。
macOS で安全に Excel 操作をしたい場合には xlwings というライブラリを使うことになります。

ちなみに win32com を使うと Outlook の自動化もできます。

» 参考:【Python】win32comを使ったOutlook操作のすべて

今回ご紹介する Excel 操作のコードは、Excel VBA のものとほぼ同じ。

VBA を学習してみたいという場合には『パーフェクト Excel VBA』という本はとてもわかりやすかったです。

必須ではありませんが、興味のある方にはおすすです。

著:高橋 宣成
¥3,536 (2024/10/01 11:22時点 | Amazon調べ)

win32comでExcel操作をする流れとサンプルコード

細かい実装方法の前に、win32com を使って Excel を自動化する際の全体像からお見せしたいと思います。

全体の流れは次の通りです。

  1. win32comライブラリのインストール
  2. インポート
  3. Excelアプリケーションの呼び出し
  4. ブックの呼び出し
  5. シートの呼び出し
  6. 自動化したい操作

まずはステップ①として、以下のコードをコマンドプロンプト上(または仮想環境上)で実行して、win32com ライブラリをインストールします。

pip install pywin32

あとは実装したい内容に即してコードを書いていくだけです。

まずは簡単な例として、A1 セルに「テスト」という文字列を入力して保存するコードをご紹介します。

import win32com.client
import getpass

user_name = getpass.getuser()
book_path = rf'C:¥Users¥{user_name}¥Documents¥book.xlsx'

# ExcelAppのインスタンス化
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = False  # 画面非表示 
excel.DisplayAlerts = False # 警告非表示

# ブック / シートの呼び出し
wb = excel.Workbooks.Open(book_path)
ws = wb.Worksheets(1)  # 一番左のシート

# A1セルにテストと入力
ws.Range('A1').Value = 'テスト'

ws.Save()
ws.Close()

# ExcelAppインスタンスの解放
excel.Quit()

では、詳細の説明に入っていきます。

事前準備

win32com を使う準備として、大きく3ステップがあります。

  • ライブラリのインストール(コンソール上)
  • インポート
  • Excel APPの呼び出し

お気づきの方もいらっしゃるかもですが、一般的なライブラリの使い方と同じです。

Python 環境は構築済みであることが前提です。

ライブラリのインストール

プロジェクトの最初に一度だけ、以下のコマンドを実行してください。

pip install pywin32

もしバージョン管理ツールのpoetryを使いたい場合にはpoetry add pywin32とします。

poetryを使ってみたい!という方は以下の記事も参考にしてみてください。僕は通常pipではなく、poetryを使っています。

ライブラリ名は win32com ではなく、pywin32 なのでお間違いなきよう!

インポート

続いてインポートです。
Excel 自動化の際にはwin32com.clientをインポートしておくと便利です。

import win32com.client

上記だけで動かない場合には、追加でpythoncomを呼び出すと動く場合があります。

import pythoncom
pythoncom.CoInitialize()

pythoncom は Python 上から COM オブジェクトを操作するのに必要な機能を提供するものです。その意味では呼び出し必須…とも思えるのですが、なぜか僕の環境では pythoncom なしで動きます。

win32com.client 単体で動かなければ pythoncom を呼び出す、くらいに考えておけば良いと思います。

Excel APP の呼び出し

続いてExcel アプリケーションを呼び出します。

# ExcelAppのインスタンス化
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = False  # 画面非表示 
excel.DisplayAlerts = False # 警告非表示

上記の例では Excel アプリケーション呼び出しと同時に、自動処理中の画面の非表示と警告の非表示(「保存しますか?」などと聞かれるダイアログを無効化)を加えています。

こちらは必要に応じて True、False を切り替えてお使いください。

コードの最後には Excel アプリケーションを終了するため、次のコマンドを書いておきます。

excel.Quit()

終了処理は意外と見落としがちですが、これがないと Excel アプリケーションがバックグラウンドで起動しっぱなしになり、色々不都合が出るので必須です。

途中でエラーが起こりそうなら、finally として Quit 文を追加しておくことも多いです。

try:
    # 処理内容を書く
except:
    # 例外処理
finally:
    excel.Quit

ブックの操作

ブック / シートの操作は次のような種類があります。

  • 開く
  • 新規作成
  • 保存
  • 削除
  • 閉じる

ブックを開く

基本の開き方は以下の通りです。

# ブックを開く
wb = excel.Workbooks.Open(book_path)

引数を設定することで「パスワード保護」「読み取り専用」「外部参照リンクの更新」などのオプションも細かく指定できます。

詳しくは公式ドキュメントをご参照ください。

公式ドキュメント

ブックを新規作成する

# ブックを新規作成
wb = Workbooks.Add()

# 名前をつけて保存
wb.SaveAs(book_path)

Addをしただけでは実際のファイルは作成されません。
そのため、xlsxファイルとして保存する際にはSaveAsを使います。

ブックを保存する

保存には「上書き保存」と「名前をつけて保存」の2パターンがあります。

# 上書き保存
wb.Save()

# 名前をつけて保存
wb.SaveAs(book_path)

SaveAsの場合は保存先のパスを引数に渡します。

ブックを削除する

ブックごと削除する場合はosライブラリのremoveを使います。

import os

# ブックを削除する
os.remove(book_path)

ブックを閉じる

開いたファイルは、最終的に閉じましょう。

wb.Close()

Save等で保存した後にも忘れずに閉じるようにします。

シートの操作

シート操作には次のようなものがあります。

    • 開く
    • 追加
    • シート名変更
    • 削除
    • 全シートを取得

シートを開く

シート名、またはシート番号から操作したいシートを選択します。

# 名前からシートを開く
ws = wb.Worksheets("Sheet1")
# 番号からシートを開く
ws = wb.Worksheets(1)

シート番号から指定する場合、一番左のシートは1です。(Pythonのように0始まりではないので注意)

シートを追加する

シートを追加する場合、新しいシートの追加位置を指定します。

# 一番左のシートを取得
ws = excel.Sheets(1)

# 一番左にシートを追加する
excel.Sheets.Add(Before=ws)

あるシートの右側に新しいシートを追加したい場合には、次のように書きます。

# 一番左のシートを取得
ws = excel.Sheets(1)

# 2番目にシートを追加する
excel.Sheets.Add(Before=None, After=ws)

ここでBefore=Noneを書かないとうまく動作しないので注意が必要です。

通常は名前付き引数としてAfterとしているので動作するはずですが、win32comでは名前付き引数がうまく機能しないので上記のような配慮が必要になります。

シート名を変更する

シートを追加すると同時にシート名を変更することが多いです。

# シート名を変更する
ws.Name = '新しいシート名'

シートを削除

# シートを削除する
ws.Delete()

ブック内の全シートを取得

全シートを取得するには、Worksheetsを使います。

# 全シート名をprintする
for ws in wb.Worksheets:
    print(ws.Name)

もう少しスッキリ書くならリスト内包表記を使いましょう。

# 全シート名をprintする
[print(ws.Name) for ws in wb.Worksheets]

もちろん、if文を組み合わせて条件に応じて操作方法を分けるといった方法も有効です。

セルの操作方法

Excelのセル操作とは、例えば次のようなものです。

  • 値を入力 / 取得する
  • セルの書式設定をする
  • 背景色や文字色などを変更する

コードの書き方としてはそこまで難しいものではないので、一つずつ丁寧に解説していきます。

セルに値を入力する

まずはA1セルに「テスト」という文字列を入力する例を見ていきます。

直感的にわかりやすいのはRangeメソッドを使った方法です。

# A2セルに値を入力する
ws.Range('A2').Value = 'テスト'

上記の他に、win32com(VBA)ではCellsメソッドも用意されており、次のように書くとA1セルに「テスト」という文字列を入力できます。

# A2セルに値を入力する
ws.Cells(2, 1).Value = 'テスト'

Cellsの第一引数に行番号を、第二引数に列番号を渡します。

直感的にはRangeの方がわかりやすいものの、次のような変数を使って入力先のセルを動的に変化させたい時にはCellsメソッドの方が便利です。

# 値を入力する行列番号を変数に格納
row_num = 10
col_num = 5

# 値をセルに入力する
ws.Cells(row_num, col_num).Value = 'テスト'

複数セルに値を入力する

特定の範囲内のセルに「同じ値」を入力したい場合は以下のようにします。

# A1セルからB5セルまで値を入力する
ws.Range('A1:B5').Value = 'テスト'

各セルに違う値を入力したい場合には、次のような感じでリスト型として渡せばOKです。

# 代入する値をリストで用意
cells_list = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]

# A1からB5セルまで値を入力する
ws.Range('A1:B5').Value = cells_list

また、セル範囲の指定に変数を使いたい場合は以下のようにRangeとCellsを組み合わせて使うと簡単です。

# セル番号をセット
start_row = 1
start_col = 2
end_row = 5
end_col = 5

# 文字列を入力する
ws.Range(ws.Cells(start_row, start_col), ws.Cells(end_row, end_col)).Value = 'テスト'

関数を入力する

関数を入力する場合は、Valueの代わりにFormulaにします。

# A2からA10セルの合計値をA1セルに表示する
ws.Range('A1').Formula = "=SUM('A2:A10')"

セルの書式設定

表示形式を変えたり罫線や色を変更する方法を紹介します。

フォントの設定

# フォントサイズ
ws.Range('A1').Font.Size = 12

# 太字
ws.Range('A1').Font.Bold = True
# イタリック
ws.Range('A1').Font.Italic = True
# 下線
ws.Range('A1').Font.Underline = True
# 取消線
ws.Range('A1').Font.Strikethrough = True

# 文字色
vbRed = 0xFF
ws.Range('A1').Font.Color = vbRed

まとめ

冒頭でも説明した通り、openpyxlでは罫線やグラフが消えてしまうので、win32comを使うのがおすすめです。

この記事が気に入ったら
フォローしてね!

シェア・記事の保存はこちら!

この記事を書いた人

karo@プログラマのアバター karo@プログラマ プログラマ

「書くことで人の役にたつ」をモットーに活動中。
本職はプログラマで、Pythonが得意。
基本情報技術者試験合格。

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)