45
64

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ルーチンワークはPythonにやらせよう Seleniumで勤怠処理を自動化する

Last updated at Posted at 2022-09-16

はじめに

本記事は勤怠管理システムにおける日々の勤怠入力を自動化し、ルーチンワークを自動化するための方法について記載しています。

勤怠入力などのルーチンワークを自動化することで、日々の勤怠入力にかかる時間を削減します。
また入力漏れや入力不備を防止し、入力不備によって発生する対応がなくなることで、余計なストレスを低減できます。

概要

本記事で紹介している勤怠処理の自動化を行うための環境は以下の通りです。

勤怠処理自動化.png

OSはmacOSですが、Windowsの場合はタスクスケジューラを使用することで、同様の仕組みが構築できます。

項目 バージョン等
OS macOS
Python 3.8
Selenium 4.4
ブラウザ Chrome

勤怠処理の自動化は、以下の仕組みによって実現しています。
在宅勤務と出社では勤怠処理が異なるため、基本的にフルリモート前提で在宅勤務の場合に処理を行うよう設定しています。

  1. cronによってシェルスクリプトを起動
  2. シェルスクリプトで在宅勤務の判定を行う
  3. 在宅勤務の場合、Pythonのプログラムを起動
  4. Seleniumで勤怠入力

実装

Pythonのプログラムは、仮想環境を作成して実行しています。

仮想環境の作成及びSeleniumの導入

Pythonの仮想環境はvenvを使用して作成します。

仮想環境を作成するためには、以下のコマンドを実行します。
<Dir>には任意のディレクトリ名を指定します。

$ python3 -m venv <Dir>
$ source <Dir>/bin/activate

仮想環境構築後、seleniumをインストールします。
仮想環境が有効な場合はプロンプトの表示が変わります。
例えば、kintaiディレクトリが有効の場合は以下のような出力になります。

(kintai) $ pip3 install selenium

pipのバージョンが古いことによって、以下のようなエラーが出力される場合は、pipのアップグレードを行います。

$ pip3 install --upgrade pip

  • エラーの出力例
Failed to build cryptography
ERROR: Could not build wheels for cryptography which use PEP 517 and cannot be installed directly
WARNING: You are using pip version 19.2.3, however version 22.2.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

ドライバのダウンロード

Seleniumをインストールしただけは使用することができません。
ブラウザに対応しているドライバをインストールする必要があります。

Chromeを起動し、chrome://settings/helpにアクセスしてバージョンを確認します。

スクリーンショット 2022-09-01 19.36.14.png

バージョンを確認後、Downloadsから同じバージョンのChromeDriverのダウンロードを行い、任意のディレクトリに配備します。

ブラウザのバージョンをあげた場合は、互換性を保つためにドライバのバージョンもあげる必要があります。

以下はブラウザのバージョンと、ドライバのバージョンの違いによって、発生したエラーの出力例です。

  • エラーの出力例
selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 103
Current browser version is 105.0.5195.52 with binary path /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

Selenium

以下はSeleniumを用いて、Webサイトにログインする処理のスニペットです。
URLや、ブラウザを操作するために取得する要素は利用する勤怠システムによって異なるため、一例です。

#! /usr/bin/env python3
import datetime
import time
import traceback

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.select import Select

USERID= os.environ['USERID']
PASS = os.environ['PASS']

driver = '/opt/chrome/chromedriver'
options = webdriver.chrome.options.Options()
browser = webdriver.Chrome(executable_path=driver, chrome_options=options)

base_url = 'https://<勤怠システムのURL>/'

# USERIDとPASSを入力して、ログインボタンを押す場合の例
try:
    browser.get(base_url + '<ログインページを指定>')

    e = browser.find_element(By.ID, '<IDの要素を指定>')
    e.clear()
    e.send_keys(USERID)

    e = browser.find_element(By.ID, '<パスワードの要素を指定>')
    e.clear()
    e.send_keys(PASS)

    e.find_element(By.XPATH, '<XPATHを指定>').click()
    time.sleep(3)

except Exception as e:
    traceback.print_exc()

勤怠管理システムにログインするためのID及びパスワードのクレデンシャル情報は、ハードコーディングを避けるために、環境変数として取り込んでいます。環境変数の設定については後述します。

Seleniumのバージョン

2021年の10月13日にSelenium 4が発表されています。
本記事執筆時点では4.4.xが最新です。

Selenium 4に関する主な変更点はUpgrade to Selenium 4から確認できます。

例えば、ID属性を指定して要素を取得する場合、従来はfind_element_by_idメソッドを使用していました。
Selenium 4では、以下の書き方に変更されています。

# Selenium 3
find_element_by_id('<要素名>')
# Selenium 4
find_element(By.ID, '<要素名>')

古い書籍やブログなどでは、従来のSelenium 3などの書き方に関する情報が多いため、参考にする場合は注意が必要です。

Seleniumの使い方

Seleniumでブラウザを操作する際の基本的な使い方について、以下に記載しています。
ブラウザ操作の詳細は、DocumentationのBrowserから確認できます。

本記事では以下のブラウザ操作の組み合わせによって、自動化を実現しています。

  • ブラウザの起動
base_url = "<勤怠システムのURL>"
browser.get(base_url) 
  • ブラウザの起動(ヘッドレスモード1
options = webdriver.chrome.options.Options()
options.add_argument('--headless')

browser = webdriver.Chrome(executable_path="/opt/chrome/chromedriver", chrome_options=options)
  • 要素を取得して入力
e = browser.find_element(By.ID, 'USER_ID')
e.send_keys(USERID)
  • ボタンをクリック
browser.find_element(By.XPATH, '<XPATHを指定>').click()
  • クエリーパラメータの指定
import datetime

today_tmp = datetime.date.today()
YEAR = today_tmp.strftime('%Y') 
MONTH = today_tmp.strftime('%m') 
DAY = today_tmp.strftime('%d') 

# 今日の日付にアクセス
base_url = 'https://<勤怠システムのURL>'
e = browser.get(base_url + f'<特定のページ>.php?D_YEAR={YEAR}&D_MONTH={MONTH}&D_DAY={DAY}')
  • セレクトボックスを指定
e = browser.find_element(By.XPATH, '<XPATHを指定>')
select_object = Select(e)
select_object.select_by_index(3)

セレクトボックスから0から始まるため、例として4個目を取得したい場合、indexは3を選択します。

  • ブラウザの終了
browser.quit()

自動化

OSの機能を活用して自動化の仕組みを構築します。

シェルスクリプト

cronによって勤務終了後の時間になったら、シェルスクリプトが起動します。

勤怠管理システムにログインするためのID及びパスワードのクレデンシャル情報は、環境変数としてexportします。

勤怠システムのパスワードは、security find-generic-passwordコマンド(-aはアカウント名、-sはキーチェーンの項目名を指定)で、macのキーチェーンに登録したパスワードを取得しています。

在宅勤務の判定を行うために、networksetupコマンドを実行して接続しているWi-FiのSSIDを取得し、SSIDが自宅の場合はPythonのプログラムを実行します。
networksetupコマンドはシステム環境設定のネットワークを設定するためのコマンドです。

#!/bin/bash

export USERID=********
export PASS=$(security find-generic-password -a "${USERID}" -s kintai -w)

network=$(networksetup -getairportnetwork en0 | awk '{print $4}')
home_ssid=********

DIR=$(cd $(dirname $0) && pwd)

if [ "${network}" = "${home_ssid}" ] ; then
        echo "勤怠処理開始"
        source "${DIR}"/bin/activate
        python3 "${DIR}"/kintai.py
fi

スクリプト終了後にsayコマンドで音声を付けてみるのも良いと思います。
sayコマンドは色々なvoiceが設定できます。

$ say -v Samantha -r 50 "thank you for your hard work"

キーチェーンの登録

キーチェーンは事前に以下の手順で登録します。

キーチェーンアクセスを起動し、新規に項目を作成します。

スクリーンショット 2022-08-25 20.15.52.png

勤怠システムで使用するIDと、パスワードを入力して追加を押します。

スクリーンショット 2022-08-25 20.11.08.png

パスワードを入力して、「キーチェーンを変更」を押します。

スクリーンショット 2022-08-25 20.11.27.png

作成した項目を選択し、ダブルクリックまたは右クリックで「情報を見る」を押します。

スクリーンショット 2022-08-25 20.14.08.png

シェルスクリプトからアクセスを許可するために、アクセス制御の「この項目の使用をすべてのアプリケーションに許可」にチェックを入れて、「変更内容を保存」を押します。

スクリーンショット 2022-08-25 20.13.19.png

キーチェーンアクセスからパスワードを取得し、環境変数としてインポートすることで、パスワードをハードコーティングしないようにしています。パスワードを変更した際はキーチェーンアクセスの値を変更すれば良いので、コードを修正することもありません。

cron

cronの自動起動の設定と、アクセス許可の設定を行います。

crontab

基本は平日の月曜から金曜までしか仕事しないため、19時に勤怠を入力する場合はcrontabで以下のように設定します。
cron実行時のPATHは限られているため、最低限必要なPATHを追加しています。

PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
00 19 * * 1-5 /Users/workman/Documents/kintai/shell.sh

cronに対するアクセス許可の設定

またcronによって起動されたシェルスクリプトに対する、アクセス許可の設定が必要です。
アクセス許可がない場合は以下のようなエラーが出力されます。

/bin/bash: /Users/workman/Documents/kintai/hell.sh: Operation not permitted

「システム環境設定」を起動し、「セキュリティとプライバシー」の「プライバシー」の中の「フルディスクアクセス」を選択して、「+」を押します。

スクリーンショット 2022-08-30 19.49.43.png

cronを追加する場合はcommand+shift+Gでフォルダの場所選択ダイアログを開き、/usr/sbin/cronを入力して移動を押します。

スクリーンショット 2022-08-25 19.54.08.png

cronを選択して「開く」を押します。

スクリーンショット 2022-08-25 19.54.36.png

cronが選択されます。

スクリーンショット 2022-08-25 20.00.22.png

cronが実行される度に、コンソールで以下のように出力されます。

You have mail in /var/mail/<user name>

上記出力より、cronの結果は以下のファイルを参照して確認できます。

cat /var/mail/<user name>

  • cronの実行結果の例
勤怠処理開始
/Users/workman/Documents/kintai/kintai.py:19: DeprecationWarning: executable_path has been deprecated, please pass in a Service object
  browser = webdriver.Chrome(executable_path=driver, chrome_options=options)
/Users/workman/Documents/kintai/kintai.py:19: DeprecationWarning: use options instead of chrome_options
  browser = webdriver.Chrome(executable_path=driver, chrome_options=options)
勤怠処理終了

Pythonの場合はtry/exceptを設定して、エラーハンドリングを行うようにすることで、プログラムが異常終了した際の例外をキャッチできます。

おわりに

ルーチンワークの自動化によって、生み出される時間の恩恵は計り知れません。
自動化しているので勤怠入力という行為を行うことは無くなりました。
また勤怠入力漏れなどによる、煩わしい通知も来なくなったので一石二鳥です。

運用上の留意点としては、cronが動く前に仕事を終えた場合はリカバリーの仕組みがないため、オンデマンドで実行できる仕組みも別で用意しておくと良いと思います。

シェルを直接実行したり、aliasでコマンドを設定するなどでも実行できますが、Macの場合はAutomatorと組み合わせて、アプリケーションにしてポチッと押すだけの仕組みにするのが楽だと思います。

Automatorについては以前書いたMacでディスプレイの配置を簡単に変更するためのLifehackを参照。

追記

本記事執筆時点で、Seleniumに関する以下の課題がありました。

  • ドライバのバージョンアップ
  • executable_pathと、chrome_optionsの警告

これらの対応方法については、Seleniumで使用するドライバのバージョンアップを自動化するに記載しています。

参考

  1. ※ブラウザを非表示にして起動する

45
64
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
64

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?