ほんじゃらねっと

ダイエット中プログラマのブログ

ボケてきたのかタイムカードの打刻を忘れてしまうので、打刻漏れ防止用チェックプログラムを作成した

f:id:piro_suke:20160620020919j:plain

毎朝出社時に社員カードで入室し、

入室したのと同じカードで出勤打刻をするのだが、

入って数歩のところにタイムレコーダーが置いてあるにも関わらず、

打刻が漏れることがある。

どうやら、

雨の日に途中で傘を置いたり(傘立てはドアとタイムレコーダーの間にある)

誰かと会って話しながら入室したりすると

ルーチンが壊れて打刻を忘れてしまうことがあるようだ。

どれだけ変化に弱いルーチンなんだ、という話だが、

ともあれ打刻が漏れると手続きが面倒なので、

自動チェックの仕組みを考えた。

会社のタイムレコーダーは社内用出勤管理Webサイトと連動しており、

そこで自分の打刻時間を確認することができるようになっている。

仕組みとして、

出勤してるであろう時間と始業開始時間の間にこのサイトをチェックして、

打刻がなければ通知する、というスクリプトを作れば解決できそうだ。

私の場合、だいたい始業30分前くらいに出社しているので、

始業15分前にチェックを走らせ、

打刻されていなければチャットワークにアラートを流すようにする。

もしアラートが届いたら急いで打刻すれば間に合う。

出勤後はチャットワークを開いておく習慣ができているので、

通知さえあれば気づけるはず。

スクリプトを作成する

色々触ったりHTMLソースを見たりしてみたところ、

うちの出勤管理Webサイトは

Javascript使いまくりで、ブラウザがIE限定の作りになっているようなので

ブラウザの動きをそのままブラウザに任せることができる

Seleniumを使ってアクセスするのが良さそうだ。

Selenium - Web Browser Automation

SeleniumはPython APIが提供されている。

下記のドキュメントを参照しながらスクリプトを書いていく。

Selenium with Python — Selenium Python Bindings 2 documentation

環境準備

ライブラリはpipでインストールできる。

pip install selenium

IEを操作するには、IE用のドライバが別途必要となる。

下記のページからダウンロードできる。

InternetExplorerDriver · SeleniumHQ/selenium Wiki · GitHub

ダウンロードしたexeをスクリプトと同じフォルダに置いておく。

スクリプトを書く

続いてスクリプトの内容。

処理としては、

  • ログイン画面を開く
  • ユーザー名とパスワードを入力してSubmitする
  • ログイン後画面にチームメンバーの出勤状況一覧が表示される
  • 自分の出勤時刻を取得する
  • 出勤時刻をチャットワークに通知する

という流れとする。

うちの社内システムにアクセスするスクリプトを公開してもしょうがないので、

代わりに使用したSeleniumのメソッドを紹介しておく。

Windows環境でPython3で動作確認済み。

まずSeleniumのwebdriverをimportする。

webdriver経由でブラウザにアクセスするイメージだ。

from selenium import webdriver

最初にwebdriverオブジェクトを作成してブラウザを起動する。

先にダウンロードしたIEドライバを使う。

# driver = webdriver.Ie("<ドライバファイルへのパス>")
driver = webdriver.Ie("IEDriverServer64.exe")

次にURLを指定してページを開く。

driver.get("http://...")

ページを開くと、以降そのページの内容をwebdriver経由で取得・操作できる。

ページ要素を取得する方法はいくつか用意されている。

4. Locating Elements — Selenium Python Bindings 2 documentation

それぞれ、その要素を操作可能なオブジェクトを返してくれる。

id属性で取得するなら、find_element_by_idメソッドを使う。

name_input = driver.find_element_by_id("login-name")

CSSクラス名で取得するなら、CSSセレクタで指定できる

find_element_by_css_selectorメソッドを使う。

汎用的で使いやすそう。

password_input = driver.find_element_by_css_selector(".password")

上記の取得メソッドは同じフレーム内の要素にしかアクセスできない。

別フレーム内の要素にアクセスする場合、

webdriverで操作対象のフレームにターゲットを切り替える必要がある。

switch_to.frameメソッドにフレームのname属性を渡すとフレームが切り替わる。

switch後にfind_element_by系メソッドを使うことで、そのフレームの要素にアクセスできる。

driver.switch_to.frame("フレームのname")
elem1 = driver.find_element_by_css_selector("フレーム内の要素")

iframe等name属性がついていないフレームにアクセスしたい場合は、

一旦そのフレームを親HTMLの要素として取得してからswitch_toする。

iframe = driver.find_element_by_id("example_iframe")
driver.switch_to.frame(iframe)

取得した要素内のテキストを取得したい時は、textプロパティを参照する。

sample_text = driver.find_element_by_id("text-div").text

Windowsで日本語を含むテキストをプロンプト上に表示するには、

下記のエンコードとデコードを組み合わせる方法でうまくいった。

なぜうまくいくかはよくわかっていないので説明できない。

sample_text = driver.find_element_by_id("text-div").text
print(sample_text.encode("cp932", "ignore").decode("cp932"))

続いてフォームへの入力方法。

要素を取得し、その要素のsend_keysメソッドにテキストを渡すことで、

その要素にテキストを入力することができる。

例えばログイン名用テキストフィールドに「testuser」と入力するなら

下記のような処理を書く。

name_input = driver.find_element_by_id("login-name")
name_input.send_keys("testuser")

send_keysメソッドにはテキスト以外にも特殊キーを渡すことができる。

特殊キーを使用する場合は、下記のパッケージもimportしておく。

from selenium.webdriver.common.keys import Keys

使える特殊キー変数は下記参照:

7. WebDriver API — Selenium Python Bindings 2 documentation

例えばReturnキーを入力したい場合は、send_keysにKeys.RETURNを渡す。

password_input.send_keys(Keys.RETURN)

他にも色々メソッドは用意されているようだが、

ここまでのメソッドを組み合わせることで、大抵のブラウザ操作は再現できると思う。

最後にブラウザを閉じるには、closeメソッドを使用する。

driver.close()

チャットワークに通知する

取得した出勤時刻をチャットワークにメッセージとして書き込む。

通知系はチャットワークに集めたいので、

下記のような関数を作って色々なスクリプトから使いまわしている。

import urllib.request
from urllib.parse import urlencode

def post_chatwork(message, room_id, api_key):
    endpoint = "https://api.chatwork.com/v1/rooms/" + room_id + "/messages"
    params = urlencode({
        "body": message
    }).encode("ascii")
    req = urllib.request.Request(endpoint, params, {
        "X-ChatWorkToken": api_key
    })  
    res = urllib.request.urlopen(req)
    return res.read()

使う時は、

post_chatwork(<通知内容>, <ルームID>, <APIキー>)

で指定ルームに通知できる。

自動化する

こうして作成したスクリプトをタスクスケジューラ(またはcron)に

登録しておけば毎朝決まった時刻にIEが勝手に起動してログインして

チャットワークに通知してくれる。

試してみた

ここ数日間、実際に自動化して動かしてみた。

実際に使ってみると、

ブラウザが急に起動して驚くし、結構ウザい。

やっていた作業を中断させられ、

ゆっくりユーザー名とパスワードが入力されるのを眺め、

ログイン後の画面で出勤時刻が表示されるのを見て、

ブラウザが閉じるのを見る。

その後チャットワークに通知が届く。

もう出勤時刻を見てしまってるので、チャットワークに通知が届く意味がほぼない。

とりあえず目的は果たせたが、

そのうちヘッドレス化して非表示にする方法を調査したい。

おわり

Seleniumは思ったより苦労せずに使えた感がある。

ログインとか検索とか登録とか、

画面のパターン別でメソッドを用意しておけば

Webアプリの動作テストスクリプトもさくさく書けそうだ。

Selenium実践入門 ―― 自動化による継続的なブラウザテスト (WEB+DB PRESS plus)

Selenium実践入門 ―― 自動化による継続的なブラウザテスト (WEB+DB PRESS plus)

  • 作者: 伊藤望,戸田広,沖田邦夫,宮田淳平,長谷川淳,清水直樹,Vishal Banthia
  • 出版社/メーカー: 技術評論社
  • 発売日: 2016/02/02
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログ (4件) を見る

セイコープレシジョン タイムレコーダー QR-330

セイコープレシジョン タイムレコーダー QR-330