マクロやPythonやiDeCoや積立NISAなどについてのブログ

自分が調べたことを備忘的に書きます。インデックス投資で豊かな老後を目指します。

Pythonで複数のエクセルシートを自動印刷!

 ※この記事は、すでに閉じた私の別ブログ「ブラック企業の文系サラリーマンがPythonを駆使して定時退社」に以前掲載していたものを転載したものです。

 

マクロなら簡単だけど、Pythonだと「Python、エクセル、印刷」と検索してもいまいち、ずばり!な答えが見つからなかったので、サンプルコードを載せます。
これさえできれば、今後の事務仕事でどんなタイプの仕事をすることになっても、役立つはずです。

 

ポイントは

・ws.active=シート番号

・ws.sheet_view.tabSelected = False

アクティブなシートを明示して、タブを選択する。

これさえできればOK。

 

【以下、サンプルコード】

# OSの機能を使うためのライブラリ
import os.path
import time
import win32api
import win32print

# エクセルを扱うためのライブラリをインポート
import openpyxl

# exeファイルに引数を設定する
import argparse  # 1. argparseをインポート

#職場のほかの人にexe化したものを渡すときは、別途バッチファイルを作って渡すと
#便利かと思うので書いています。 
#バッチファイルの実行時に、引数を渡すため、オブジェクトを作る
parser = argparse.ArgumentParser(description='このプログラムの説明(なくてもOK)')  # 2. パーサを作る
# parser.add_argumentで受け取る引数を追加していく
# 必須の引数を追加(バッチ実行するフォルダのパスを渡す引数) 
parser.add_argument('current_dir', help='この引数の説明(バッチファイルを実行したフォルダを渡す)')

# 引数を解析 以後、args.current_dirで入力した引数を引用できる
args = parser.parse_args()

# 実行したファイルがあるフォルダに読み込みたいエクセルを置き
# そのファイルパスを作成
conf_dir_path = os.getcwd()
conf_file_path = os.path.join(args.current_dir, 'test.xlsx')


# 印刷する関数 win32api.ShellExecuteを使用して
# 通常使うプリンターから出力する
def PrintOut():
    win32api.ShellExecute(
        0,
        "print",
        conf_file_path,
        "/c:""%s" % win32print.GetDefaultPrinter(),
        ".",
        0
    )


# エクセルを開く
wb = openpyxl.load_workbook(conf_file_path)

# 一度、すべてのシートをtablesectedをFalseにして
# アクティブなシートは0番目であると、明示する
# そうしないと、前回保存した際のシートが選択されたままになってしまい
# 意図しないシートが印刷されてしまいます

# すべてのシート名を取得
wsall = wb.sheetnames

# for文ですべてのシートtablesectedプロパティをFalseにして
# どのシートも選択してない状態をつくる
for s in wsall:
    #各シートをfor文で渡して
    ws = wb[s]
    #それらについて、すべてtablesectedプロパティをFalseにする
    ws.sheet_view.tabSelected = False
# ここで一旦保存し、閉じて、どのシートも選択してない状態が完成
wb.save(conf_file_path)
wb.close()

# そして再び開く
wb = openpyxl.load_workbook(conf_file_path)

#これで、0番目=一番左のシートが選択された状態で開く。

# for文やif文で印刷したいワークーを指定する
# ベタ打ちでもなんでもOK
# 以下は、3番目と4番目シートを印刷する場合のfor文
for i in range(2,4):
    #ワークシートを番号で指定(一番左が0)
    ws = wb.worksheets[i]
    #今のシートがアクティブであると明示する。これ重要
    wb.active = i
    #tabselrectedプロパティをTrueにして、選択状態を維持する
    ws.sheet_view.tabSelected = True

#選択した状態で一度保存する。
#保存しないと、保存前の選択状態で印刷されてしまうので注意
wb.save(conf_file_path)
#上で定義したプリントアウト関数を実行
PrintOut()
#ワークブックを閉じる
wb.close()
print('実行されました')
time.sleep(1)

 

【使うライブラリ】

・openpyxl

注意点:一番左のシートインデックス番号はゼロとなるので注意

ちなみにxlrdの場合は一番左のシートが1になります。

 

【初心者がはまるポイント】

エクセルを自分で操作するときに複数シートを選択する際は

シートのタブをctrlを押しながら複数クリックすると思います。

その動作をopenpyxlで実現するにはどうするか、という視点が大事で、

その手動での感覚と、pythonのコード感覚にズレがあるので、うまくいかない。

 

・ws.sheet_view.tabSelected = False

をいったんすべてのシートで実行して

なにもシートが選択されていない状態を作る。

 

通常、エクセルを開いた時にはすでに何かしらのシートが選択されています。

その状態からスタートすると、プログラマーの意図しないシートが最初から選択されているので、

「意図しないシートが勝手に印刷されるよー>< ぴえん」

という状態になってしまいます。

ですので、このワンステップが重要。

 

・ws.active=シート番号

でいまアクティブにしているシートを明示する

マウスをつかって、何かしらのシートを選択した状態がこれです。

シートを選択しただけで、まだ何もしてません。

 

・ws.sheet_view.tabSelected = True

任意のタブを選択する

CTRLを押しながら、シートのタブをクリックした状態がこれです。

これを印刷したいシートすべてに実行した状態が

「複数シートをctrlを押しつつクリックして選択した状態」

というわけです。

 

・win32api.ShellExecute(0,"print",conf_file_path,"/c:""%s" %win32print.GetDefaultPrinter(),".",0)

のwin32apiを使って、印刷します。

残念ながら、openpyxlにはws.print()というコードはないので、

こうするしかありません。