マクロや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()というコードはないので、

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



ThunderbirdのQuickTextでテンプレートを使ってワンクリックでメールを作る

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

 

Pythonでの業務効率化と並行して、サンダーバードThunderbird)をフル活用する努力をしてます。

①テンプレート作成画面の本文入力欄で下記を入力

*****************************************

TO=displayname| 様\n

お世話になっております。
昨日はありがとうございました。
今後ともよろしくお願いいたします。

****************************************

 

スクリプト作成画面で下記を「SetSubject」という名前のスクリプトとして登録

******************************************************

let subject = this.mVariables[0];

if (this.mWindow.document.getElementById('msgSubject')) {
this.mWindow.document.getElementById('msgSubject').value = subject;
}

********************************************************

 

③テンプレート作成画面の件名欄に下記を入力

***************************************

SCRIPT=SetSubject| [[ATTSUBJECT]]

***************************************

すると件名に添付ファイル名が入力されます。

 

注文書Noや請求書Noを件名にいれて、発注管理などしている場合、役立ちます。

送ったか否か、件名検索を掛けられるようになるので、漏れ確認が確実にできます。

 

アドレス帳に表示名が「〇〇様」の”様”抜きで入っていれば、このままコピペすればうまくいきます。



エクセルデータをPythonで読み込んでGoogleカレンダーに入力:その2

サンプルコードを載せます。

ソースコードと同じ場所にtest.xlsを置きます。

A列に場所、B列に開始日時、C列に終了日時が入ってます。

実際、業務に使っているエクセルはここまで単純じゃない(つまり、入れたい予定の項目セルが

飛び散っていたりする)とは思います。

②下記コードを実行

なので、下記コードは飛び散った項目セルを

「sheet.cell(0,0).value」で個別に指定して、任意の回数=入力したい予定の数だけ

for文で回す仕様になっています。

#以下、googleカレンダーへの書き込みのために必要なコード
from __future__ import print_function
import datetime
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

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

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

#ソースファイルのあるフォルダに予定の読み取り先のエクセルを置き
#そのファイルパスを作成
conf_dir_path = os.getcwd()
conf_file_path = os.path.join(conf_dir_path, 'test.xls')
print(conf_file_path)

#エクセルを開く
wb=xlrd.open_workbook(conf_file_path)

#シートを選択
sheet = wb.sheet_by_name('任意のシート名')


# If modifying these scopes, delete the file token.pickle.
# ここのSCOPESはこのプログラムに与える権限によって変わる。
SCOPES = ['https://www.googleapis.com/auth/calendar']

def main():
    print("a")
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)
    service=build('calendar', 'v3', credentials=creds)

#ここからが変えるべきところ
#エクセルのセルを任意の回数読みとって、eventに書き込み
    for i in range(4):
        if i == 0:
         print("for文"+str(i)+"回目")
         summary=sheet.cell(0,0).value
         date1=sheet.cell(0,1).value
         date2=sheet.cell(0,2).value
         print(summary)
         print(date1)
         print(date2)
        elif i==1:
         print("for文"+str(i)+"回目")
         summary=sheet.cell(1,0).value
         date1=sheet.cell(1,1).value
         date2=sheet.cell(1,2).value
         print(summary)
         print(date1)
         print(date2)
        elif i==2:
         print("for文"+str(i)+"回目")
         summary=sheet.cell(2,0).value
         date1=sheet.cell(2,1).value
         date2=sheet.cell(2,2).value
         print(summary)
         print(date1)
         print(date2)
        elif i==3:
         print("for文"+str(i)+"回目")
         summary=sheet.cell(3,0).value
         date1=sheet.cell(3,1).value
         date2=sheet.cell(3,2).value
         print(summary)
         print(date1)
         print(date2)

        #インテンドが上のif文とずれるとeventが1回しか実行されないので注意
        event = {
          'summary': summary,
          'location': 'Shibuya Office',
          'description': 'サンプルの予定',
          'start': {
            'dateTime': date1,
            'timeZone': 'Japan',
          },
          'end': {
            'dateTime': date2,
            'timeZone': 'Japan',
          },
         }

        event = service.events().insert(calendarId='使用するGoogleカレンダーのID',
                                   body=event).execute()


        print (event['id'])

if __name__ == '__main__':

    main()
    print('実行されました')
    time.sleep(1)

for文はPythonらしくrangeを使わない方法もあるけれど、

そのためにはある程度、元のエクセルが整っている必要があるので、

rangeで泥臭く任意の回数、任意のセルを読み取る方式にしてます。

このほうが、どんなエクセルにも汎用的に対応可能です。

 

for文の中のif文とeventのインテンドがずれると、1回分しか予定が入力されません!!
ここがいちばん躓きました。

Pythonでエクセルの内容を読み取ってGoogleカレンダーへ予定を入力

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

 

この記事では、とりあえず、Googleカレンダーへのアクセスができるようになるところまでを書きます。

結構手間なので、同僚に作ったプログラムを実行してもらうまでには、なかなかハードルが高いけど、

それに見合う時短効果があるものを作る予定です!!

 

①グーグルアカウントにログインして下記にアクセスし、APIを取得

https://developers.google.com/calendar/quickstart/python?hl=ja

credentials.jsonというファイルをPythonのプログラムファイルを置いているフォルダと同じフォルダにダウンロードして保管しておく。

 

Google Client Libraryのインストール

下記のコマンドを実行する。

py -m pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

※「py -m」をつけるのを忘れずに。

ほかのサイトではこのことを書いてなくて、ハマりました。

③もし pipが古いバージョンと言われたら

「py -m pip install --upgrade pip」を実行してアップグレード

 

④次に、エクセルデータを扱うためのライブラリーをインストール

「py -m pip install xlrd」

⑤sampleファイルを準備して実行

公式サイトに記載の通り、上記のフォルダと同じフォルダにquickstart.pyファイルを作成し、以下のサイトを参考に実行。

https://non-dimension.com/python-googlecalendarapi/#toc1

すると、token.pickleというファイルができるので、以後、このファイルをPythonのプログラムファイルと同じフォルダにおいておけば、googleカレンダーへの認証が通ります。

次の記事で、具体的なエクセルからGoogleカレンダーへの予定入力のサンプルコードを公開します。

Pythonがnot foundだと?

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

 

Pythonのインストールでつまずいたので、書きます。

インストール後、Atomを入れてatom_runnnerをインストールし、実行したのに

Python was not found but can be installed from the Microsoft Store: https://go.microsoft.com/fwlink?linkID=2082640」というメッセージが出ました。

 

【原因】

・インストール時に「Add Python 3.6 to PATH」というチェックボックスがあったのに、チェックを入れなかった。

【解決方法】

・アンインストールして、再インストールで解決。

 

以下、ことの成り行きです。

Pythonソースコードを編集するための便利なソフトのことをIDE(総合開発環境)といいます。

ですが、テキストエディターでもPythonは書けるし、実行できます。その代表格がAtomです。

①下記のサイトでダウンロードします。

https://atom.io/

②インストールできました。

Pythonを実行するためのパッケージをインストールします。

④適当な場所に「python_test」というフォルダを作って、

File>Add Project Flolderでそのフォルダを追加します

⑤追加されたフォルダを右クリックしてNew Fileで「hellow.py」というファイルを作り、

「print("hellow")」

と入力します。

※かならず .py をつけないと、Pythonのプログラムと認識されないので注意。

⑥そして、atom runnner というパッケージをインストールして alt+Rをクリックすると

 「hellow」と出るはずが、出てきません。

Python was not found but can be installed from the Microsoft Store: https://go.microsoft.com/fwlink?linkID=2082640

Pythonがありませんよ。というエラーメッセージが出てます。

こうなったら、上記のようにチェックボックスにチェックをいれてPythonを再インストールしてください。

Pythonの開発環境を整えよう

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

 

①まず下記URLからPythonをダウンロードします。

https://www.python.org/downloads/release/python-390/

②ダウンロードしたexeファイルを実行してインストールします。

③すると、パスの長さ制限についてのメッセージがでるので、クリックしてOKします。

これで、パスの長さ制限によるバグがなくなります。

④インストールされたか、コマンドプロンプトで確認しましょう。

Windowsの検索ボタンに「cmd」といれてEnter入力し、コマンドプロンプトを起動

⑤py --list-paths

 を実行すると、Pythonがインストールされたフォルダパスが表示されます。

次の記事では、Pythonソースコードを編集するための環境について説明します!

【ワイン】メルシャン ワールドセレクション 赤

ウエルシアで購入 483円税抜

・品名 ワールドセレクション 赤
・産地 チリ
・製造者 メルシャン
・品種 カベルネ・ソーヴィニヨン
・香り 程よい果実感
・色  ミディアムボディのワインの色

・味  程よいタンニン。飲みやすい

・感想 瓶が透明なので、おそらく取れて一年以内のぶどうを使った若ワインと思われる。二日目もそれほど渋く酸味強くならずに美味しく飲めた。

・その他