ジョブカンで自動打刻を設定し、プチストレスを解消してみた


# はじめに

ちゃんと定時には業務はしているもののWebの打刻を忘れがちになり、結局あとで、打刻してしまう今日このごろ。
打刻を忘れないように、定刻になったら、自動打刻するようなツールを作ってみました。
今回はWeb打刻にジョブカンを使用しておりますが、他のWeb打刻システムを利用している場合でも、ある程度応用はできますので、こちらを参考にしてみてください

# 使う技術

- Python: 今回使用する言語
- Selenium: Webブラウザを自動操作するためのライブラリ
- chrome webdriver: Webブラウザを自動操作するためのライブラリ
- jpholiday: 祝日を確認するためのライブラリ
- Windows Task Scheduler: 定期実行するためのアプリケーション

# Python環境構築

  環境が構築されていない場合は、以下のURLを参照し、環境を構築します。
  https://www.python.jp/install/install.html
  以下のコマンドが打てればセットアップできます。

  ```powershell
  # pythonのバージョン確認
  $ python -V
  ```

# ライブラリインストール

`requirements.txt`を用意する

```txt
attrs==23.2.0
botocore==1.34.51
certifi==2023.11.17
cffi==1.16.0
charset-normalizer==3.3.2
chromedriver-binary==123.0.6269.0.0
chromedriver-binary-auto==0.3.1
chromedriver-binary-sync==0.2.2
h11==0.14.0
idna==3.6
jmespath==1.0.1
jpholiday==0.1.8
outcome==1.3.0.post0
packaging==23.2
pycparser==2.21
PySocks==1.7.1
python-dateutil==2.8.2
python-dotenv==1.0.1
requests==2.31.0
selenium==4.17.2
six==1.16.0
sniffio==1.3.0
sortedcontainers==2.4.0
trio==0.24.0
trio-websocket==0.11.1
typing_extensions==4.9.0
urllib3==2.0.7
webdriver-manager==4.0.1
wsproto==1.2.0
```

```shell
# pipで必要なライブラリをインストール
pip install -r requirements.txt

# requirement.txtにライブラリがインストールされているか確認
pip freeze
```

上記に記載したライブラリは私が実際に使っているもので、古いため、もし最新版のライブラリをインストールしたい場合は以下のサイトを参照して確認してみてください。

https://pypi.org/


# スクリプトを用意する

以下に記載した内容を`jobcan.py`という名前でファイルを用意します。
myusernameとmypasswdの値をご自身がログインで使用しているユーザー名とパスワードにしてください。

Seleniumとchrome webdriverを使って、Webブラウザを自由に操作することができます。
jpholidayは祝日を確認するためのライブラリです。
祝日は会社が休みのケースがほとんどのため、実行されても、ジョブカン上では打刻されないように処理しています。
※ご自宅のネットワーク環境やPCのスペックによっては、処理が追いつかずに停止する場合があります。その場合は`time.sleep(1)`(１秒待機)の値を変更して、処理が止まらないように値を調整してください。

```
# 自動スクリプト
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.keys import Keys
import time
import jpholiday
import datetime

# 初期設定
myusername='xxxxxxx'
mypasswd = 'yyyyyyy'

# 祝日判定
date = datetime.date.today()
if jpholiday.is_holiday(date):
    print("祝日のため、打刻せずに、処理を終了します。")
else:
  # 自動処理
  driver = webdriver.Chrome()
  # driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
  driver.get("https://id.jobcan.jp/users/sign_in")
  time.sleep(1)

  e_username = driver.find_element(by="id", value="user_email")
  e_username.send_keys(myusername + Keys.RETURN)
  time.sleep(1)

  e_password = driver.find_element(by="id", value="user_password")
  e_password.send_keys(mypasswd + Keys.RETURN)
  time.sleep(1)

  new_screen = driver.get("https://ssl.jobcan.jp/jbcoauth/login")
  time.sleep(1)

  e_adit_btn = driver.find_element(by="id",value='adit-button-push')
  e_adit_btn.click()
  time.sleep(1)
  driver.close()
```

# テスト実行
以下のコマンドをターミナル上でで実行します。

```shell
python jobcan.py
```

実行されると、以下の画像のようにChromeのWebブラウザが起動します。
※実行すると打刻されてしまいますので、途中で処理をやめるために、`Ctrl+C`を押して処理を終了してください。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306043/c7a068ac-5c62-ab0f-4387-7bced64fed90.png)

# 定期実行するための設定

上記で実行したスクリプトを定期実行するためにMacであれば、`crontab`、Windowsであれば`タスクスケジューラー`を使います。

今回実行環境が、Windowsのため、タスクスケジューラーで定期実行するための設定を行います。

「スタート」＞「Windows管理ツール」＞「タスクスケジューラ」の順に選択する

## タスクスケジューラーが開いたら、右のペインから「タスクの作成」をクリックします

![image-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306043/7320ca7c-e42f-cd56-5888-400d1c58480e.png)

- 任意の名前でタスクをクリックします

- タスクを実行するタイミングを指定します

  例：以下の画像は、月～金の午前9時に実行する例です。

![image-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306043/82752f3a-7e94-cafc-0af3-892ed6bc026a.png)

## 実行ファイルを選択
  - Program/script: pythonコマンドの場所を指定します。一般的には以下の場所に`python.exe`ファイルがあるかと思います。
      Pathの例: `C:\Users\[ユーザー名]\AppData\Local\Programs\Python\Python[バージョン]\python.exe`
  - Add arguments: 実行するファイル名（jobcan.py）
  - Start in: 実行ファイル（jobcan.py）が保管されているフォルダパスを指定します。

![image-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306043/92f39074-c794-e0c0-bbd6-b42ae9300fda.png)  

- 問題なければ、作成し、タスクスケジューラーからテスト実行してみて、問題なさそうであれば、`Ctrl+C`を押して終了してください。

お疲れ様でした。設定完了です。

# まとめ

ツールを導入してから定期実行することで、忘れることがなくなり、業務に集中できるようになりました。
たまに不具合が出る場合もありますが、手動の実行よりミスが少なく、プチストレスがなくなったのが何より大きいです。

# 余談

Slackで自動打刻している方もいると思いましたので、以下も作ってみました。
こちらも仕組み的にはほぼ同じです。
myusername,mypasswd,slackurl,urlの値や出社するメッセージ等を変更して、実行してみてください。

```python
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome import service as fs
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.alert import Alert
import time
import jpholiday
import datetime

# 初期設定
myusername = 'xxxxxx'
mypasswd  = 'yyyyyy'
slackurl    = 'https://[SlackのURL]' # ご自身の所属しているSlackのURLを入力してください
url = 'https://app.slack.com/client/XXXXX/YYYYY' # 目的地となる Slack チャンネル のURLを入力

# 祝日判定
date = datetime.date.today()
if jpholiday.is_holiday(date):
    print("祝日です")
else:
    # 自動処理
    driver = webdriver.Chrome()
    driver.get(slackurl)
    driver.implicitly_wait(1)  # 待機 (オプション)

    e_username = driver.find_element(by="id", value="email")
    e_username.send_keys(myusername)
    e_password = driver.find_element(by="id", value="password")
    e_password.send_keys(mypasswd + Keys.RETURN)

    driver.implicitly_wait(1)  # 待機 (オプション)
    driver.switch_to.new_window(driver.window_handles[0])
    driver.get(url)

    driver.implicitly_wait(1)  # 待機 (オプション)
    time.sleep(10)
    post_element = driver.find_element(By.CSS_SELECTOR, '[class="ql-editor ql-blank"]')
    post_element.click()
    driver.implicitly_wait(1)  # 待機 (オプション)
    post_element.send_keys("出社します")  # メッセージ入力
    post_element.send_keys(Keys.ENTER)
    driver.implicitly_wait(1)  # 待機 (オプション)
    send_message = driver.find_element(By.CSS_SELECTOR, '[class="c-button-unstyled c-icon_button c-icon_button--size_small c-wysiwyg_container__button c-wysiwyg_container__button--send c-icon_button--default"]')
    send_message.click()
    driver.implicitly_wait(1)  # 待機 (オプション)
    time.sleep(5)

    driver.quit()
```