KonifarPod

退職日に福利厚生のマッサージを受けたくて予約システムを監視するバッチを作った話

   

Pocket

2月、退職するちょっと前の話。我ながらしょうもないことだと思うんですが、プログラムがちょっと書けてよかったと感じた、という話です。

退職日にどうしてもマッサージを受けたかったんです。結構大きい会社だったので福利厚生もしっかりしていて、月2回無料でマッサージが受けられる福利厚生があったんですよ。無料というだけでも素晴らしいんですが、マッサージ師の1人『Fさん』の技術が飛び抜けていて、僕は心酔してしまっていました。Fさんは体を軽く撫でただけで凝っているところがわかるだけでなく、僕がラグビーをやっていたことや朝から胃の調子が悪いことなどをズバっと当てた魔術師のような凄腕マッサージ師です。

 

【事の発端】

そんなFさんのマッサージを、退職日にどうしても受けておきたかった僕。しかし、あまりに人気のFさんの枠は予約開始5分で埋まってしまうのです。とはいえいつ更新されるかわからない予約システムを見張るのもめんどくさいなぁ、なんて考えながら当時隣の席にいた先輩Oさんと雑談していた時、突如僕の心に火がつきました。

Refeel2 「Oさん、僕もうすぐ退職じゃないですか」

Refeel1 「はい、そうですね」

Refeel2 「ぼく退職前に、どうしてもFさんのマッサージ受けたいんですよね」

Refeel1 「あ〜なるほど」

Refeel2 「できれば退職日に60分受けたいんですよね」

Refeel1 「それはハードルが高いですねえ」

Refeel2 「そうなんですよ。かと言って、朝からブラウザに張りついて監視するのも嫌じゃないですか」

Refeel1 「ふむふむ」

Refeel2 「なんかいい方法ないですかねえ・・・」

Refeel1 「Seleniumで監視すればいいんじゃないですか?」

 

「Seleniumで監視すればいいんじゃないですか?」 

この言葉を聞いた時、僕の心に火がつき実行することに決定しました。

Seleniumとは、ざっくり言うと画面の自動テストツールです。WebDriverというAPIが公開されていて、ブラウザを立ち上げたり入力欄に文字を打ったりボタンを押したりといったテストを自動的に行うことができます。予約システムはブラウザベースのものだったので、確かにやろうと思えばできそうな気はしました。Selenium をいじるのも初めてでしたが、2時間ほど費やす価値は十二分にあると判断。不敵に笑うOさんを横目に見ながら、Fさんのマッサージ予約公開情報監視バッチ『Fバッチ』を作成することに決めました。

とは言え、あまり時間はかけられません。退職直前ということもあって、本業の忙しさが半端じゃないからです。当然と言えば当然ですが。なので、2時間以内に作ることにしました。


【作成開始】

監視に必要な動きは4つでした。

① ログイン
② 次の週へボタンを押下(1週間前から予約可能なので)
③ 退職日の 2/1(金)のスケジュールにFさんがいることを確認
④ 自分のGmailに通知

 

④の部分はメール通知じゃなくて予約のところまで自動化しちゃえばいいんじゃないの?とも思ったのですが、毎回スケジュールが固定ではないのと、さすがにそこまで自動化するのはバグった時にちょっと怖かったのでやめました。メール通知でも十分ですしね。

クロールするバッチを作るなら PythonやRubyの方が簡単に書けるんですが、当時の僕はJavaで書くのが一番慣れていて速かった(むしろJavaくらいしかちゃんと書けなかった)ので、Javaバッチで実装することにしました。実際の処理はこんな感じです。(一部改変)

 

private static void execute(final String url, final String user_id, final String password) {
    // 開く
    WebDriver driver = new FirefoxDriver();
    driver.get(url);
    System.out.println("Page Open !");
    
    // ログイン
    WebElement elUserId = driver.findElement(By.name("j_username"));
    elUserId.sendKeys(new String[] {user_id});
    WebElement elPassword = driver.findElement(By.name("j_password"));
    elPassword.sendKeys(new String[] {password});
    elPassword.submit();
    System.out.println("Login Succeed !");

    // 次の期間に移動
    WebElement nextPage = driver.findElement(By.partialLinkText(">"));
    nextPage.click(); System.out.println("Next Page moved!");
    // 対象日付(1週間後)を計算
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.DATE, 7);
    int y = cal.get(cal.YEAR);
    int m = cal.get(cal.MONTH) + 1;
    int d = cal.get(cal.DATE);
    int dw = cal.get(Calendar.DAY_OF_WEEK);
    SimpleDateFormat weeks = new SimpleDateFormat ("EEE",Locale.JAPANESE);
    String w = weeks.format(cal.getTime());
    System.out.println("Target Date is " + y + "/" + m + "/" + d + "(" + w + ")");

    // 探索
    WebElement targetTd = driver.findElement(By.xpath("//table//table//table/tbody/tr[2]/td[" + dw + "]"));
    String schedule = targetTd.getText();
    int index = schedule.indexOf("虎ノ門");
    String scheduleToranomon = schedule.substring(index + 1);
    
    if (index == -1) {
        System.out.println("Not yet schedule open !");
    } else if (scheduleToranomon.indexOf("Fさん") == -1) {
        sendMail("今すぐアクセス!http://bsi/refeel/cfb/");
        System.out.println("F is nothing !");
    } else {
        sendMail("Fさんあり!今すぐアクセス!http://bsi/refeel/cfb/");
        System.out.println("F is here !");
    }

    // 終わり
    driver.quit();

 

ところどころキモいコードがいっぱいあると思います。URLのページを開いてユーザーIDとパスワードでログインし、次の期間に移動、ターゲット日を探すところまではいいのですが、問題はその後。虎ノ門のFさんの予定があるかどうかを判定するところです。

システムのHtmlがイケてなくて、tableの中にtableが入ってたんですね。。。そのせいで実装がちょっとめんどくさかったんですが、頑張って書きました。他は特につまるところもなくやれました。Selenium楽ちん。

 

【そして当日・・・】

当日10時についた僕。一応テストではちゃんと通知されることを確認したのですが、本番では何が起こるかわからないのがシステムの常です。どうなることかドキドキしながら通知を待ちました。

30分が過ぎました。いつもはだいたい10時半くらいに更新されるのですが、どうやら手動でアップデートしてるらしくいつ更新されるかわかりません。

40分を過ぎても通知が来ず、若干の不安を感じ始めました。普通に予約ページ確認すればいいじゃん、というのはもっともな意見なのですが、なんだか負けた感があるのでできませんでした。

バッチをまわすこと50分。。。もはや仕事が手につかなくなってきた頃。。。

ついに来ました!僕のGmailに『Fさんあり!今すぐアクセス!』メールが来ました!

速攻ログインして60分コースを予約。正直震えました。その日は朝からやり遂げた感いっぱいで、とても気持ちよく仕事ができました。

ちなみに僕が速攻予約した時、すでに他に予約してる人がいたんですよね。更新〜ログインまでのタイムラグは1分以内だったはずなので、もしかしたら他にも同じようなことをやっている人がいたのかもしれません。

 

【当時を振り返ると・・・】

退職当日は最後にとても気持ちよくマッサージを受けることができました。プログラムが書けるようになってよかったなと心から思いました。

普段の仕事以外で、ちょっとした不便を少しずつ改善していくのはメリットも大きく勉強になりますね。今やるならChromeプラグインかrubyバッチで実装すると想いますが、当時もSeleniumをいじるきっかけになりましたしとても勉強になりました。これからも本業をしっかりやりつつ、自分のやりたいことをちょくちょく実現していきたいと思います。

ちなみに当時作ったソースはさすがにGithubにはあげられないのでこっそり後輩に引き渡しました。

Pocket

 - Develop, 小ネタ