Pythonのwin32comライブラリーでExcel操作する方法をまとめた記事です。
前半は基本的なコードの書き方、後半は実践的なサンプルコードを紹介します。
なお、win32comはWindows環境かつExcelインストール済み環境でのみ動作します。
【基本編】コードの書き方
win32comでExcel操作をするための基本的なコードを紹介します。
なお、win32comでは大文字・小文字を区別するのでご注意ください。
win32comライブラリのインストール
一般的なライブラリ同様、win32comもpip installでインストールできます。
pip install pywin32
コマンドプロンプト上で上記のコードを実行することで、Outlook操作に必要なwin32comライブラリのインストールができます。
なお、冒頭でもご説明の通りwin32comはWindowsのみ対応です。MacOS等をお使いの場合はxlwingsやopenpyxlなどを使います。
import/Excel Appのインスタンス化
import win32com.client
# ExcelAppのインスタンス化
excel = win32com.client.Dispatch("Excel.Application")
# バックグラウンド
excel.Visible = False
# 警告非表示
excel.DisplayAlerts = False
VisibleはFalseにするとExcelの画面を表示されなくなるため、誤作動を防ぎたい場合に有効です。逆に挙動を確認したい場合はTrueにします。
また、「ブックを保存しますか?」などの警告を出したくない場合はDisplayAlertsをFalseにします。
ブックを開く
# ブックを開く
wb = excel.Workbooks.Open(book_path)
既存のブックを操作する場合には、まずブックを開きます。
ここで作成した変数wbは、シートをセットする際に使います。
シートをセット
# シートをセット
ws = wb.Worksheets(sheet_name)
sheet_nameには操作したいシート名を文字列で渡せばOKです。
セル番地で値を取得・入力
# 値を入力
ws.Range("A1").Value = "A1に入力"
# 値を取得
var = ws.Range("A1").Value
セル番地を指定して値を出し入れする場合はRangeメソッドを使います。
行・列番号で値を取得・入力
# 値を入力
ws.Cells(1, 1).Value = "A1に入力"
# 値を取得: A2セル
var = ws.Cells(2, 1).Value
変数で操作するセルを可変的にしたい場合はCellsの方が扱いやすいです。
関数の入力
# 関数を入力
ws.Range("A1").Formula = "=SUM(A2:A10)"
Valueを使ってしまうと文字列が入ってしまうのでFormulaを使います。
最終行の取得
# 最終行を取得(1列目)
endRow = ws.Cells(ws.Rows.Count, 1).End(-4162).Row
Cellsの第二引数(列番号)を1としているので、1列目の最終行を取得します。
なお-4162は何かというと、Ctrlを押したまま↑キーを押す挙動を表します。(VBAでいうところのxlUp)
今回は最終行の取得なので↑キーにしましたが、他の番号が知りたい方はWindowsの公式ドキュメントを参照してみてください。
セル範囲をリストに格納
# 空のリストを用意
array = []
# A1からB4セルをリストとして取得
array = ws.Range("A1:B4").Value
# リスト化
array = [list(map(int, row)) for row in array]
リストの中身はタプルになるので、純粋なリストに直す場合はリスト内包表記などで対応します。
最終行の取得と組み合わせるのも有効です。
すべてのセルをリストに格納
# すべてのセルをリストに格納
array = ws.UsedRange.Value
セル範囲を指定せずにすべてのセルを取得する場合は、UseRangeが使えます。
とはいえこの方法はごっそりと取得してきてしまって使いづらいので、Pandasのread_excelの方が扱いやすいです。
すべてのシートをA1セル選択状態にする
### すべてのシートをA1セル選択状態にする
# シート数を取得
sheet_num = wb.Worksheets.Count
# 後ろのシートから順に開く
for i in range(sheet_num, 0, -1):
ws = wb.Worksheets(i)
# シートをアクティブにする
ws.Activate
# A1セルをアクティブにする
ws.Cells(1, 1).Activate
列幅を自動調整
# 列幅を自動調整
ws.Columns("A:G").AutoFit()
列を隠す
# 列を隠す
ws.Columns("A:G").EntireColumn.Hidden = False
シートを追加
# 新しいシートを追加する
wb.Sheets.Add()
指定したシートの前にシートを追加
# wsの前に新規シートを追加
excel.Sheets.Add(Before=ws)
指定したシートの後にシートを追加
# wsの後に新規シートを追加
excel.Sheets.Add(Before=None, After=ws)
余談ですが、excel.Sheets.Add(After=ws)のようにBeforeを省略すると動作しません。
このようにwin32comでは名前つき引数が正常に動作しないことがあります。
シートの削除
# wsを削除
ws.Delete()
シート名の変更
# wsのシート名を変更
ws.Name = "new_name"
ブックを上書き保存する
# 上書き保存
wb.Save()
ブックを名前をつけて保存
# 名前をつけて保存
wb.SaveAs(output_path)
ブックを閉じる
# ブックを閉じる
wb.Close()
シートをPDF化する
# wsをPDF化する
ws.ExportAsFixedFormat(0, output_path)
複数シートをPDF化する
# sheet1,sheet2を選択する
wb.Worksheets(["sheet1", "sheet2"]).Select()
# 選択したシートをPDF化する
wb.ActiveSheet.ExportAsFixedFormat(0, output_path)
PDF化したいシートを選択した状態でExportAsFixedFormatを使います。
全シートをPDF化する
# 空のリストを準備
array = []
# 全シートをsheet_listに格納
for sheet_name in wb.Sheets:
array.append(sheet_name)
# 全シートを選択
wb.Worksheets(array).Select()
# 選択されたシートをPDF化
wb.ActiveSheet.ExportAsFixedFormat(0, output_path)
すべてのシートをPDF化する場合も考え方は同じです。
全シートを個別にPDFにする
# Sheetの数を取得
sheet_count = wb.Workbook.Count
# 左のシートから順次PDF化
for i in range(sheet_count):
# i+1番目のシートを選択(iはゼロ始まりのため、+1する)
wb.Worksheets(i+1).Select()
# 選択されたシートをPDF化
wb.ActiveSheet.ExportAsFixedFormat(0, output_path)
ご質問いただき加筆いたしました!
シート番号は1から始まるので、イテレーターのiに+1するのを忘れないでください。
【実践編】サンプルコード
【基本編】で紹介したコードを使ったサンプルコードを公開します。
ブック内の全シートをPDF化する
import getpass
import win32com.client
import os
user_name = getpass.getuser()
base_path = rf"C:\Users\{user_name}\Desktop"
book_path = os.path.join(base_path, "excel.xlsx")
sheet_name = r"sheet1"
output_path = os.path.join(base_path, "output.pdf")
# ExcelAppのインスタンス化
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = False
excel.DisplayAlerts = False
# ブック、シートのセット
wb = excel.Workbooks.Open(book_path)
ws = wb.Worksheets(sheet_name)
# 空のリストを準備
array = []
# 全シートをsheet_listに格納
for sheet_name in wb.Sheets:
array.append(sheet_name.Name)
# 全シートを選択
wb.Sheets(array).Select()
# 選択されたシートをPDF化
wb.ActiveSheet.ExportAsFixedFormat(0, output_path)
# ブックを閉じる
wb.Close()
# Excel Appを終了
excel.Quit()
まとめ
Windows以外のOSでは使えないというデメリットはあるものの、動作の安定性としてはwin32comが一番だと思います。
より高速な動作を求めるならopenpyxlを、Macで安定した動作を求めるならxlwingsの導入も検討してみてください。
コメント
コメント一覧 (6件)
ブック内の全シートを個別にPDFにしたい場合にはどうすればいいのでしょうか。
佐藤様、初めまして!ご質問ありがとうございます。
1シートに対して1つのPDFを出力するということでよろしいでしょうか?
手順としては次の流れになります。
・ブック内にあるシート数を取得
・シート番号をループする
・Select→PDF出力を繰り返す
本記事の【全シートを個別にPDFにする】という見出しをつけてサンプルコードを掲載させていただきましたので、よろしければ参考にしてみてください!
ご対応いただき、ありがとうございます。
早速試してみます
ぜひ試してみてください^^
もしうまく動かないようでしたらまたメッセージいただければと思います!
ブック内の全シートをPDF化するの
user_name = getpass.getuser()
book_path = rf”/Users/{user_name}/Desktop/excel.xlsx”
sheet_name = r”sheet1″
コードは何を意味しますでしょうか。
raise AttributeError(“%s.%s” % (self._username_, attr))というエラーが出ており対処に困っております。
お時間ございますときに、ご教授いただけましたら幸いです。
佐藤様
ご質問ありがとうございます!
すみません、コードにおかしな点がありましたので修正させていただきました。一度新しいコードで実行いただけますと幸いです!
なお、user_nameの部分ではパソコンのユーザー名を取得しています。
通常Windows PCは”C:\Users\ユーザー名\Desktop”という風に表されるので、getpass.getuser()を使ってプログラム上からユーザー名を取得すれば、動作させるPCが変わってもパスを修正せずに動作させることができます。