MoneyForwardクラウド勤怠の打刻を自動化【面倒なことはPythonにやらせよう】


免責事項

当記事に掲載された内容によって生じた損害等の一切の責任を負いません。この記事は個人の趣味として執筆したもので、私の所属している企業とは関係ありません。また、企業の規則等を破ることを推奨するものではありません。

MoneyForwardクラウド勤怠の利用規約について

利用規約を確認しましたが、コンピューターからの自動操作を禁止している記載は発見できませんでした。(お前見落としてるぞというところに気づいた方がいらっしゃれば、教えてください。すぐにやめます)

(6) 本サービス並びに本サービスを通じてアクセスするコンテンツサイト及び情報提供元のネットワーク又はシステム等に過度な負荷をかける行為

(13) 当社による本サービスの運営を妨害するおそれのある行為

過度なアクセスをする処理は含まれていないので問題ないと判断しました。

(16) その他、当社が不適切と判断する行為

お願いMoneyForwardさん、不適切と判断しないで

自動化しようと思った経緯

毎朝同じ時刻に出勤打刻を行い、同じ時刻に退勤打刻を行う。これはもう、完全にwhile文なわけですよ。人がやる作業じゃないでしょ。ということで自動化します。(打刻の意味ねーじゃんというツッコミをお待ちしております)

使ったコード

Githubでコードを公開しています。
記事内では全てのコードを載せているわけではないので、もっと知りたい方は直接コードをご覧ください。もっとエレガントな方法があると思うので、気軽にIssueやPR投げてください。お願いします。
https://github.com/Haruka0522/AutoMFKintai

全体の構成

Seleniumを使ってPythonから打刻のウェブページにアクセス

datetimeとjpholidayを使って休日/平日の判断

事前に設定した出勤/退勤時刻になったらボタンをクリック

シンプルですね!

ログイン画面の突破

ソースコード(抜粋)

id_box = self.driver.find_element_by_name("employee_session_form[office_account_name]")
id_box.send_keys(self.company_id)

mail_box = self.driver.find_element_by_name("employee_session_form[account_name_or_email]")
mail_box.send_keys(self.mail)

password_box = self.driver.find_element_by_name("employee_session_form[password]")
password_box.send_keys(self.password)

login_button = self.driver.find_element_by_name("commit")
login_button.click()

ログイン画面にアクセス後、要素の名前で入力ボックスを特定し、そこにログイン情報を入力する処理を行います。この要素の名前というのはchromeでアクセスしてF12キーを押すことで開発者モードを使って確認することができます。
困難が予想されたログイン画面の突破ですが、簡単に突破することが可能でした。

注意

ソースコード上にパスワード等をハードコーディングして間違ってGithubにアップしてしまうと大変なので、pass.txtというテキストファイルにパスワード等を書き込んでこれを読み込むような方法を取りましょう。.gitignoreでpass.txtをgitの管理から除いておけば間違ってpushしてしまう心配がありません。

打刻ボタンのクリック

ソースコード(抜粋)

actions = ActionChains(self.driver)
actions.move_by_offset(480, 250)
actions.click()
actions.perform()

地味に苦戦したのがここです。打刻ボタンの要素を指定してクリックを試みるもうまくいかず、onclick()が書かれていたので直接Javascriptを実行することを試みるも何故かうまくいきませんでした。そこであまりいい方法ではないですが、画面の座標を指定してクリックするという手法を取りました。最初の設定でChromeのウィンドウサイズを固定しているので、おそらく環境が変わっても動くとは思いますが正直エレガントではないので今後改善したいところです。

土日祝、平日の判断

土日に間違って打刻してしまうことは避けたいです。私の場合は基本的に平日は働いているので、平日だけ打刻するように設定しました。

ソースコード

def is_holiday(date):
    return date.weekday() >= 5 or jpholiday.is_holiday(date)

datetimeライブラリとjpholidayライブラリを使用し、平日を判断させました。
datetimeの方は単純な土曜日曜を判断させるために、jpholidayは祝日を判断させるために使用しました。

参考記事

メインループ

while True:
    dt_now = datetime.datetime.now()
    if is_holiday(datetime.date.today()):  # 平日判断
        continue
    if dt_now.hour == start_time.hour and dt_now.minute == start_time.minute:
        operator.syukkin()
    elif dt_now.hour == end_time.hour and dt_now.minute == end_time.minute:
        operator.taikin()
    else:
        time.sleep(wait_time)

最後に

これを24時間動いてるコンピューター(ラズパイが省電力で良さそう)で走らせることで自動で打刻してくれるようになります。Googleカレンダーなどと連携して独自の休日などにも対応できればいいなー、そもそもこんなスクリプトを書かなくてもいいような制度になればいいなーなどと思っております。各方面から怒られそうな予感がしてますが、大丈夫かな…?