広告

面倒な打刻はPythonで自動化しよう!【Part2】PySimpleGUIで自動打刻GUIアプリを作る

2022年4月18日

前回の記事で、Pythonプログラムを実行しておくだけで自動で打刻ができるようになりました。しかし、依存モジュールを事前にインストールしておく必要があったり、プログラミングに詳しくない人には扱いづらい問題がありました。

PythonプログラムをGUIアプリにして、実行ファイル形式にすれば、上述の問題は解決できます。さらには、異なるパソコンでアプリを実行できたり、同僚に配布することも可能になり、利便性が高まります。

この記事では、前回作成したプログラムをもとにしたGUIアプリの作成と、実行ファイルの作成方法をご紹介します。

この記事でできるようになること

  • GUIアプリを実行させておけば自動で打刻できる
  • GUIアプリのボタンを押すことでも打刻できる
  • 打刻GUIアプリを実行ファイル(.app/.exe)にできる

GUIアプリと実行ファイルの作成に必要なPythonライブラリ

PySimpleGUI

PySimpleGUIは、その名の通りシンプルに扱えるGUIフレームワークです。

Python向けのGUIフレームワークは、有名なものではtkinterやQtなどが存在しますが、それらをベースに簡潔に短いコードでGUIアプリを作れるのがPySimpleGUIです。公式によると、「他のGUIフレームワークに比べると1/2から1/10のコード量で済むかもしれない」と公言しており、手っ取り早くGUIアプリを開発したい時は非常におすすめです。

ただし、LGPLライセンスのため、一般向けに配布する際はライブラリのソースコードの開示、ライセンスと著作権の表示などが必要になることに注意です。

PyInstaller

PyInstallerは、Pythonアプリケーションと依存関係をパッケージ化します。

Pythonプログラムを実行する際は、依存ライブラリなどをインストールしておく必要があります。しかし、パッケージ化することで、依存モジュールをインストールせずにアプリケーションを実行できるようになります。

PyInstaller自体はPySimpleGUIより要件の厳しいGPLライセンスですが、作成したアプリケーションはライセンスを気にすることなく利用可能です。

PySimpleGUIの使い方

PySimpleGUI

最初にPySimpleGUIをインストールします。

 pip install pysimplegui

PySimpleGUIの使い方は非常にカンタンで、やるべきことは以下の3つだけです。

  • テキストやボタンなどでレイアウト定義
  • ウィンドウ生成
  • イベントループ内でイベント処理

目で見るよりも実際にアプリを動かしてみたほうが理解しやすいと思うので、下記にサンプルアプリを用意しました。

import PySimpleGUI as sg

# レイアウト定義
# PySimpleGUIの要素はhttps://pysimplegui.readthedocs.io/en/latest/call%20reference/を参照
layout = [[sg.Text('文字を入力してください'), sg.InputText()],[sg.Text('', key='-input-')],
          [sg.Button('OK'), sg.Button('Cancel')]]

# ウィンドウ生成
window = sg.Window('Test Window', layout)
# イベントループ
while True:
    # eventでイベントの種類、valueで値の参照
    event, values = window.read()
    # アプリを終了するか、キャンセルボタンを押したとき
    if event == sg.WIN_CLOSED or event == 'Cancel':
        break
    # OKボタンを押したらウィンドウを更新
    elif event == 'OK':
        window['-input-'].update(values[0])

window.close()

レイアウトは二次元配列で定義します。要素にkeyを設定することで、イベントループ内でkeyから要素を参照できます。

PySimpleGUIの要素一覧はこちらのページで確認できます。

layout = [[sg.Text('文字を入力してください'), sg.InputText()],[sg.Text('', key='-input-')],
          [sg.Button('OK'), sg.Button('Cancel')]]

イベントの処理はループ内で処理します。window.read() でイベントの種類と値を取得します。window['-input-'] で要素を参照して画面の更新などが可能です。value はインデックスかkeyで値を参照できます。

while True:
    # eventでイベントの種類、valueで値の参照
    event, values = window.read()
    # アプリを終了するか、キャンセルボタンを押したとき
    if event == sg.WIN_CLOSED or event == 'Cancel':
        break
    # OKボタンを押したらウィンドウを更新
    elif event == 'OK':
        window['-input-'].update(values[0])

下記コマンドを実行すると、アプリケーションが立ち上がります。

python sample.py

自動打刻GUIアプリの実装

PySimpleGUIの使い方もわかったところで、前回のPart1で作成したプログラムをもとにGUIアプリとして生まれ変わらせてあげます。

今回作成するのはこちらのGUIアプリです。

現在時刻と打刻ボタン、自動打刻用のチェックボックスだけのシンプルなGUIアプリです。

ボタンで打刻もできますが、チェックボックスを入れておくと自動で打刻できる仕様にしました。

Pythonファイル(main.py)を新規作成して、GUIを実装していきます。

import PySimpleGUI as sg
import datetime
import desknets

WORK_START = "08:45"
REST_START = "12:00"
REST_END = "12:50"
WORK_END = "18:00"

# 打刻フラグ
START_PRESSED = False
REST_START_PRESSED = False
REST_END_PRESSED = False
END_PRESSED = False

def get_current_time():
    return datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')

sg.theme('DarkBlue3')
layout = [
    [sg.Text(get_current_time(), font=('Meiryo', 30),
             justification='center', key='-now-')],
    [sg.Button('出勤', key='-start-'), sg.Button('昼休み開始', key='-rest_start-'),
     sg.Button('昼休み終わり', key='-rest_end-'), sg.Button('退勤', key='-end-'), sg.Checkbox('自動', key='-auto-')],
]
window = sg.Window('Auto stamping app.', layout)
calendar_update_counter = 0
while True:
    now = datetime.datetime.now().strftime('%H:%M')
    # 時刻更新用に1秒毎に-timeout-イベント発生
    event, values = window.read(timeout=1000, timeout_key='-timeout-')
    calendar_update_counter += 1

    # 自動打刻
    if now == WORK_START:
        if START_PRESSED == False and values['-auto-']:
            START_PRESSED=True
            desknets.stamp('-start-')
    elif now == REST_START:
        if REST_START_PRESSED == False and values['-auto-']:
            REST_START_PRESSED=True
            desknets.stamp('-rest_start-')
    elif now == REST_END:
        if REST_END_PRESSED == False and values['-auto-']:
            REST_END_PRESSED=True
            desknets.stamp('-rest_end-')
    elif now == WORK_END:
        if END_PRESSED == False and values['-auto-']:
            END_PRESSED=True
            desknets.stamp('-end-')

    if event == sg.WIN_CLOSED:
        break
    elif event in '-timeout-':
        window['-now-'].update(get_current_time())
    # ボタンを押したときのイベント処理
    elif event == '-start-' or event == '-rest_end-' or event == '-rest_start-' or event == '-end-':
        desknets.stamp(event)

window.close()

打刻用のプログラムは、前回実装したプログラムから、scheduleを使った定期実行部分を削除し、引数のイベント名に応じて出勤、昼休み開始終了、退勤の打刻をさせます。

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import time

url = 'https://*****'
id = '*****'
password = '******'

# ヘッドレスモードの場合コメントイン
# options = webdriver.ChromeOptions()
# options.add_argument('--headless')

def stamp(event):
    driver = webdriver.Chrome(ChromeDriverManager().install())
    #  ヘッドレスモードの場合
    # driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
    driver.get(url)
    driver.find_element_by_name('UserID').send_keys(id)
    driver.find_element_by_name('_word').send_keys(password)
    driver.find_element_by_id("login-btn").click()
    time.sleep(1)
    driver.find_element_by_xpath("//li[@title='タイムカード']").click()
    time.sleep(1)
    if event == '-start-':
        driver.find_element_by_class_name('jtcard-btn-stime').click()
    elif event == '-rest_start-':
        driver.find_element_by_class_name('jtcard-btn-outtime').click()
    elif event == '-rest_end-':
        driver.findelement_by_class_name('jtcard-btn-intime').click()
    elif event == '-end-':
        driver.find_element_by_class_name('jtcard-btn-etime').click()
    time.sleep(1)
    driver.quit()

ターミナルで下記コマンドを実行してGUIが立ち上がり、打刻できれば完成です。

python main.py

実行ファイルの作成

ここからは、作成したGUIアプリを実行ファイルにします。

最初にPyInstallerをインストールします。

pip install pyinstaller

インストールを終えたら、下記コマンドで実行ファイルを作成します。

pyinstaller main.py --noconsole --onefile

–noconsole:コンソール画面を表示させません

–onefile:複数のファイルを1つの実行ファイルにさせます

実行ファイルの作成が完了すると、distフォルダ下に実行ファイル(main.app)が作成されます。

注意ポイント

実行ファイルは、使用しているパソコンのOS(Windows/Mac)にのみ対応しています。

Mac OSの場合、使用しているMacのアーキテクチャにのみ対応した実行ファイルが生成されます。Intel版とM1版の両方に対応させたい場合は、–target-arch universal2を付け加える必要があります。

pyinstaller main.py --onefile --noconsole --target-arch universal2                                                                                            

まとめ

この記事では、前回作成したPythonプログラムを、PySimpleGUIを使ってGUIアプリにして、PyInstallerで実行ファイルにできました。

実行ファイル形式のGUIアプリであれば、友人や同僚などにも気軽に配布して使ってもらえるようになります。Pythonで作成したプログラムをGUIアプリにして配布したい場合は、今回紹介した方法が役立ちますので、是非参考にしてみてください。