実録!ものぐさプログラマーの日報自動化奮闘記
2017-06-01 システム関連(Perlなど)

こんにちわ。システム事業部の菊田です。
今日は前々から面倒に感じてて自動化したいなーと思ってた「日報」をテーマにしてみました。
自分が働きはじめた20年前は、まだ手書きの日報が主流だったので、電子データへの記載でOKな今時の日報は各段に楽にはなってるのは認めます。
でもやっぱり、入力方法が簡易的になったところで、菊田はどうも日報というものが面倒くさく、、、
仕事終わって、よしスッキリ帰るぞー!って時に、その日1日を1つ1つ思い出す作業が、とってもおっくうで。。。
かといって何かの作業とか依頼とか調査終える毎に日報書いてくようなマメさもありません。
うちの東京のスタッフのように
「サスケを使って業務をすればそれがそのまま日報になる」
くらいの利便性を実現する「ものづくり」に、今回は取り組んでみたいと思います!
今日は前々から面倒に感じてて自動化したいなーと思ってた「日報」をテーマにしてみました。
自分が働きはじめた20年前は、まだ手書きの日報が主流だったので、電子データへの記載でOKな今時の日報は各段に楽にはなってるのは認めます。
でもやっぱり、入力方法が簡易的になったところで、菊田はどうも日報というものが面倒くさく、、、
仕事終わって、よしスッキリ帰るぞー!って時に、その日1日を1つ1つ思い出す作業が、とってもおっくうで。。。
かといって何かの作業とか依頼とか調査終える毎に日報書いてくようなマメさもありません。
うちの東京のスタッフのように
「サスケを使って業務をすればそれがそのまま日報になる」
くらいの利便性を実現する「ものづくり」に、今回は取り組んでみたいと思います!
ちなみに以前
ラズパイを触ってみた勉強会の時にも、最後のほうで「日報自動化したい!」と言ってたようでした
仕様の検討
そんなわけで、さっそく仕様を検討したいと思います。
ちょっとまわりくどいですが、どのような思考で進めたのかがわかるかたちで、段階的に説明させてもらいます。
やりたいことは、ふわっと、「日報を自動生成する」ということですが、、、もう少し具体的に落とし込みます。
どういう形式でまとめるのがいいのか悩ましいのですが、、「5W2H」風にまとめみることにしました。
ちょっとまわりくどいですが、どのような思考で進めたのかがわかるかたちで、段階的に説明させてもらいます。
やりたいことは、ふわっと、「日報を自動生成する」ということですが、、、もう少し具体的に落とし込みます。
どういう形式でまとめるのがいいのか悩ましいのですが、、「5W2H」風にまとめみることにしました。
①いつ(When)
菊田が仕事を終えて「帰った」と判断できるタイミングで日報を「自動で」作成します
②どこから(Where)
菊田の業務の記録がいろいろ残っている、会社のPC上で動くものを作ってみます
③何の情報を(What)
業務の内容をどうやって取得するかというのは、、、職場の事情により様々だと思いますけど、うちの会社の場合は幸い、PマークとかISMSの兼ね合いで、Google Apps一択での業務となっているので、ここをトラッキングすれば概ね業務を網羅できる想定です!
(具体的な方法は後ほど説明します)
(具体的な方法は後ほど説明します)
④どういう理由で(Why)
これは、、、まぁ、上述の通り、「日報面倒くさい」ってゆう意識低い発想で、、、
⑤どれぐらいで(How Much/Many)
お金はかけません。頻度は、日報なんで毎日です。
⑥どうやるのか(How)
このあと詳細説明していきますね
要点が整理され、ちょこっとだけ見通しよくなりました。
要点が整理され、ちょこっとだけ見通しよくなりました。
いつ(When)の実現
さて、何をもって「仕事を終えた」と判別するか。
普通に考えると、勤怠管理のログ(うちの会社ではジョブカン使ってます)でもチェックして、「退勤」になってたら「帰った」と判断したいところですが、、、
客先やセミナーに行くなどして、外出してそのまま直帰ってパターンに対応できないので社内の勤怠ログは使えません。
その日のうちにちゃんと日報が作成されていればいいので、ここは「確実に仕事はしていないだろう状態」になったら、、、ということで考えます。
ということで
普通に考えると、勤怠管理のログ(うちの会社ではジョブカン使ってます)でもチェックして、「退勤」になってたら「帰った」と判断したいところですが、、、
客先やセミナーに行くなどして、外出してそのまま直帰ってパターンに対応できないので社内の勤怠ログは使えません。
その日のうちにちゃんと日報が作成されていればいいので、ここは「確実に仕事はしていないだろう状態」になったら、、、ということで考えます。
ということで
菊田の「位置情報」が、家の最寄り駅である地下鉄宮の沢駅付近に接近したら、、、
仕事が終わって日報を書くべき状態になっている可能性の高いので、ここをトリガーにしようと思います。
「家の位置情報」じゃなく「地下鉄の位置情報」にしたのは、家だと、休みの日は、ずっと通知が来ることになるんで、うるさいからです。
位置情報のトラッキング
菊田の位置情報をトラッキングする方法です。
ここはシンプルにIFTTT(イフト)を使うのが便利なので、これを使います
ここはシンプルにIFTTT(イフト)を使うのが便利なので、これを使います
mythings
https://mythings.yahoo.co.jp/が、UI的には一番わかりやすくて好きなんですが、ちょっと今回認証しようとしたら、リダイレクトが無限ループっぽくなって、各サービスとうまく連携できなかったので、今回は昔から使い慣れてるIFTTTにしました。
やり方は至極シンプルで、IF(もし)、This(これだったら) Then That(あれをやる)という頭文字通りのサービスで、いろいろなWEBサービスを組み合わせて、レシピを作れます。
やり方は至極シンプルで、IF(もし)、This(これだったら) Then That(あれをやる)という頭文字通りのサービスで、いろいろなWEBサービスを組み合わせて、レシピを作れます。

今回は、菊田の位置情報を検知するのに「location」と、そのタイミングで通知メールを送る「Gmail」の組み合わせでレシピ作成しました。
菊田の現在地が地下鉄宮の沢駅だったら、「通勤メール」という件名のメールを送信します。
こんな手軽に菊田が地下鉄駅を利用したことを捕捉できるなんて、、、とっても手軽ですよねぇ。。
菊田の現在地が地下鉄宮の沢駅だったら、「通勤メール」という件名のメールを送信します。
こんな手軽に菊田が地下鉄駅を利用したことを捕捉できるなんて、、、とっても手軽ですよねぇ。。
メールのトラッキング
次に、菊田の会社のPCから、決まった時刻に、件名が「通勤メール」というものを探す簡易プログラムを作成し動かします。
簡易的なプログラムでお見せするレベルのものではないですが、、、
// メールボックス接続
$mailbox="{xxxxxxxxxxxxxx:110/pop3/notls}INBOX";
$user="xxxxxxxxxxxxxx";
$pass="xxxxxxxxxxxxxx";
$mbox = imap_open( $mailbox, $user ,$pass) or die("接続エラー\n");
// メールボックスのメッセージ数を取得
$cnt=imap_num_recent($mbox);
$count = imap_num_msg($mbox);
for($idx=0;$idx<$count;$idx++){
$head = imap_header($mbox, $count - $idx);
// 受信日時
$check_date =strtotime($head->date);
// 対象日時(定時の17:30以降の時間帯に地下鉄駅を利用したログを監視)
$min = mktime(17,30,0,$month,$day,$year);
$max = mktime(23,59,59,$month,$day,$year);
if ( $min <= $check_date AND $max >= $check_date) {
// IFTTTから送信されてきた件名「通勤メール」の有無をチェック
if (preg_match("/通勤メール/",$subject)){
// 帰宅した!日報生成
こんな感じでIFTTTから送られてくる「通勤メール」という件名のメールをチェックするだけのシンプルなものです。
作成したプログラムはGistにアップしたので、後ほど全体晒します
これで日報を書くべきタイミングが確定しました。
ちなみに会社のPCはWindowsでバッチ処理とか書きづらかったのでWindows Subsystem for Linuxを有効にしてbashを使えるようにしてます。
作成したプログラムはGistにアップしたので、後ほど全体晒します
これで日報を書くべきタイミングが確定しました。
ちなみに会社のPCはWindowsでバッチ処理とか書きづらかったのでWindows Subsystem for Linuxを有効にしてbashを使えるようにしてます。
余談ですが、、、
セキュリティの兼ね合いで今回はあえてまわりくどいことをしておりますが、自己責任追える方なら、IFTTTから一発で、ローカルのPCのプログラムを叩く方法を取ることも可能です。

IFTTTのレシピで、「Maker Webhooks」を使えば、任意のURLへリクエストを発生させることができるので、ここに、「ngrok」で外部からのURLリクエストを可能な状態にしておけば、位置情報の検知と同時に、ローカルのプログラムを即座に実行することが可能になります。
ngrokは自分のローカルの開発環境にスマホとか実機でアクセスしたいんだよなーって人が活用するものですが、こんな応用も可能なので、ご興味ある方はお試しくださいませ
ngrokは自分のローカルの開発環境にスマホとか実機でアクセスしたいんだよなーって人が活用するものですが、こんな応用も可能なので、ご興味ある方はお試しくださいませ
何の情報を(What)
次に業務の内容を取得します。
・・・ちょっと、書き始めはいろいろGoogleのAPIと連携して、検索していろいろ取得しようと構想してたんですが、、、すみません、ちょっとこのくだりは、シンプルな方法にさせていただきます!
・・・ちょっと、書き始めはいろいろGoogleのAPIと連携して、検索していろいろ取得しようと構想してたんですが、、、すみません、ちょっとこのくだりは、シンプルな方法にさせていただきます!

「ブラウザの閲覧履歴を自動取得する」
方法です。
いや、言い訳するわけではないんですが、いろいろと突き詰めて考えていくと、、、
案外、業務のほとんどは、「ブラウザ」でやるものばかりなんですよねぇ。
サーバの制御もクラウドだからブラウザの操作だし、
開発チケットなんて全部Backlogだし
メール打つのもGmailだし、
ハングアウトでチャットするのもブラウザだし。
つまるところ、、、ブラウザの履歴は、そのままその日の自分の業務そのものなんだなぁと。
・・・だんだんこじつけじみた話しになってきて恐縮ですが、今回はひとまず、この前提で進めさせていただきたいと思います!
いや、言い訳するわけではないんですが、いろいろと突き詰めて考えていくと、、、
案外、業務のほとんどは、「ブラウザ」でやるものばかりなんですよねぇ。
サーバの制御もクラウドだからブラウザの操作だし、
開発チケットなんて全部Backlogだし
メール打つのもGmailだし、
ハングアウトでチャットするのもブラウザだし。
つまるところ、、、ブラウザの履歴は、そのままその日の自分の業務そのものなんだなぁと。
・・・だんだんこじつけじみた話しになってきて恐縮ですが、今回はひとまず、この前提で進めさせていただきたいと思います!
ブラウザの履歴の取得方法
ブラウザの仕組みはあまりよく把握できてないんですが、ブラウザの履歴データはPC内にsqlite3のデータベースファイルとして保存されてて、gifアニメーションにある通り、
Windowsだと「c/Users/ユーザ名/AppData/Local/Google/Chrome/User\ Data/Default/History」
Macだと「/Users/ユーザ名/Library/Application Support/Google/Chrome/Default/History」
あたりに保存されてるようでした。
相手がSQLということなら、Webシステム担当してる技術者なら会話可能ですよね
Windowsだと「c/Users/ユーザ名/AppData/Local/Google/Chrome/User\ Data/Default/History」
Macだと「/Users/ユーザ名/Library/Application Support/Google/Chrome/Default/History」
あたりに保存されてるようでした。
相手がSQLということなら、Webシステム担当してる技術者なら会話可能ですよね
あ、ブラウザ立ち上げたままでこのファイルにアクセスしよいうとすると、ロックかかってるよって怒られるんで、やる時にはブラウザ閉じてからお試しください。
.tablesと打つとテーブル一覧が確認できますし、テーブル定義知りたいなら.schemaで確認できます。
.tablesと打つとテーブル一覧が確認できますし、テーブル定義知りたいなら.schemaで確認できます。
SELECT
datetime(last_visit_time / 1000000 + (strftime('%s', '1601-01-01') + (60*60*9)), 'unixepoch') as date,
title,
url
FROM urls
WHERE date(last_visit_time / 1000000 + (strftime('%s', '1601-01-01') + (60*60*9)),'unixepoch') = '2017-06-01';
ちょっと日付が1601年からの経過秒数のようで、現在時刻の変換の仕方がわからなかったので、強引ですが、日付変換した後の文字列で当日のデータを絞り込むようにしました。
Hands-on!
さて、前置きが長くなりましたが、いよいよ動かしていきます。
まず起点となるには、IFTTTからの通知となります。
まず起点となるには、IFTTTからの通知となります。

ちゃんと菊田の帰宅に反応してリクエストが発生してくれました。
なんか、、、思ってたよりも、素朴ですね笑
なんか、、、思ってたよりも、素朴ですね笑
gist.github.com
https://gist.github.com/kzyplus/bba248f6edce3908549d4ca1f0195b63そしてメールチェックのプログラムのほうは最終的にはこんな形になりました。
ちょっと即席すぎて公開できるレベルのものではないのですが、、、、、
とてもシンプルな作りです。メールをチェックして、日報の作成タイミングなら、さきほどのブラウザ履歴のファイルへアクセスしてごにょごにょする感じです。
最終的には、その日の日付のテキストファイルに日報の内容を書き出し、保存する形にとどめました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
error_reporting(E_ERROR | E_WARNING | E_PARSE); | |
// -------------------------------------------- | |
// 対象日時チェック(コマンドライン引数かURLパラメータか) | |
$target_date = $_REQUEST['$target_date'] ? $_REQUEST['$target_date'] : ($argv[1] ? $argv[1] : date('Ymd')); | |
$year = substr($target_date,0,4); | |
$month = substr($target_date,4,2); | |
$day = substr($target_date,6,2); | |
if (false === checkdate($month,$day,$year)){ | |
echo "Incorrect date and time\n"; | |
exit; | |
} | |
// -------------------------------------------- | |
// 履歴データファイル(環境毎に適宜変更を) | |
$dbfile = dirname(dirname(dirname(dirname(dirname(__FILE__)))))."/AppData/Local/Google/Chrome/user_data/Default/History"; | |
// -------------------------------------------- | |
// 既に日報生成済みならやらない | |
if ( file_exists(dirname(__FILE__).'/report_'.$year.$month.$day.'.txt') ){ | |
# echo "report exists...Done\n"; | |
# exit; | |
} | |
// -------------------------------------------- | |
// メールボックス接続 | |
$mailbox="{xxxxxxxxxx}INBOX"; | |
$user="xxxxxxxxxx"; | |
$pass="xxxxxxxxxx"; | |
$mbox = imap_open( $mailbox, $user ,$pass) or die("接続エラー\n"); | |
// -------------------------------------------- | |
// メールボックスのメッセージ数を取得 | |
$cnt=imap_num_recent($mbox); | |
$count = imap_num_msg($mbox); | |
// とりあえず100件 | |
for($idx=0;$idx<100;$idx++){ | |
$head = imap_header($mbox, $count - $idx); | |
// 受信日時 | |
$check_date =strtotime($head->date); | |
// 対象日時(定時の17:30以降の時間帯に地下鉄駅を利用したログを監視) | |
$min = mktime(17,30,0,$month,$day,$year); | |
$max = mktime(23,59,59,$month,$day,$year); | |
if ( $min <= $check_date AND $max >= $check_date) { | |
// IFTTTから送信されてきた件名「通勤メール」の有無をチェック | |
$subject = mb_decode_mimeheader($head->subject); | |
if (preg_match("/通勤メール/",$subject)){ | |
// 帰宅した!日報生成 | |
// SqliteでChromeの履歴データにアクセス | |
$db = new SQLite3($dbfile); | |
$sql= <<<__SQL__ | |
SELECT | |
datetime(last_visit_time / 1000000 + (strftime('%s', '1601-01-01') + (60*60*9)), 'unixepoch') as date, | |
title, | |
url | |
FROM urls | |
WHERE date(last_visit_time / 1000000 + (strftime('%s', '1601-01-01') + (60*60*9)),'unixepoch') = '$year-$month-$day'; | |
__SQL__; | |
$results = $db->query($sql); | |
while ($row = $results->fetchArray()) { | |
list($protocol,$dummy,$domain) = explode('/',$row['url']); | |
// ドメイン毎に集計 | |
$group[$domain][$row['date']]=$row['title']; | |
} | |
foreach($group as $domain => $value){ | |
$report .= "・".$domain.PHP_EOL; | |
foreach($value as $date => $title){ | |
$report .= " ".$date.' '.$title.PHP_EOL; | |
} | |
} | |
$db->close(); | |
$report = <<<__TEXT__ | |
--- 業務内容 --- | |
$report | |
--- 感想 / 今日の一言 | |
お疲れ様でした!!! | |
__TEXT__; | |
file_put_contents(dirname(__FILE__).'/report_'.$year.$month.$day.'.txt',$report); | |
break; | |
} | |
} | |
} | |
imap_close($mbox); |
ちょっと即席すぎて公開できるレベルのものではないのですが、、、、、
とてもシンプルな作りです。メールをチェックして、日報の作成タイミングなら、さきほどのブラウザ履歴のファイルへアクセスしてごにょごにょする感じです。
最終的には、その日の日付のテキストファイルに日報の内容を書き出し、保存する形にとどめました。
そしてついに、日報が自動生成される!?

実際に家に帰っている最中の動作をキャプチャできないので、コマンドラインで日時を指定して、そのままサスケの日報にまで反映される部分をキャプチャしました。
無事、ブラウザの履歴をベースに、その日の業務内容が自動反映されてくれました。。。
が、、、、単なる履歴の羅列の日報って、、ちょっと微妙ですね、、、笑
まぁ、確実に菊田の一日をよく表してるとは思いますが、報告書の観点でいくと、問題ありでした。
※サスケに自動ログイン部分は、ソースコードには含まれておりません。
無事、ブラウザの履歴をベースに、その日の業務内容が自動反映されてくれました。。。
が、、、、単なる履歴の羅列の日報って、、ちょっと微妙ですね、、、笑
まぁ、確実に菊田の一日をよく表してるとは思いますが、報告書の観点でいくと、問題ありでした。
※サスケに自動ログイン部分は、ソースコードには含まれておりません。
結論
そんなこんなで、やはり日報というのは単なる出来事の羅列ではなくて、「報告書」であることを考えると、、、いまひとつの結果となりました。
機械学習で良い表現方法など学んでいけたら、もっといい感じにできそうでしょうかね。
まだ当分は、人の手で情報の精査は必要そうです。。
ただ、その日の出来事は、詳細に出力されるようになりましたので、「思い出す」労力はかからなくなりました!
また、今回はあえて「自動」をテーマにしましたが、よくよく考えると、仕事終わり書く日報が閲覧される可能性があるのは、翌日の営業時間内だと思うので、常時PCをつけっぱなしにしてまで自動化にこだわらず、普通にPCの起動プログラムにでも入れておいて、翌朝会社にきてPCを起動したら、前日の日報が作成される、、、ってゆうほうが、現実的な気がしてきました。
機械学習で良い表現方法など学んでいけたら、もっといい感じにできそうでしょうかね。
まだ当分は、人の手で情報の精査は必要そうです。。
ただ、その日の出来事は、詳細に出力されるようになりましたので、「思い出す」労力はかからなくなりました!
また、今回はあえて「自動」をテーマにしましたが、よくよく考えると、仕事終わり書く日報が閲覧される可能性があるのは、翌日の営業時間内だと思うので、常時PCをつけっぱなしにしてまで自動化にこだわらず、普通にPCの起動プログラムにでも入れておいて、翌朝会社にきてPCを起動したら、前日の日報が作成される、、、ってゆうほうが、現実的な気がしてきました。
もうひとつ問題が、、、
すみません、「誰かのためのものづくり」が勉強会のテーマなので、今回の方法は、他の誰かが使えるようなものにはなってないので、勉強会のテーマを実現できておりません。
もっと誰かのためになるようなものにしなければ、、、
もっと誰かのためになるようなものにしなければ、、、
というわけで、もう一つ別のものを作ってみました!!!

「自動」ではないのですが、今回と同じ出力結果を入手できるものを、「chromeの拡張機能」で作ってみました。
これならこの操作するブラウザに存在する履歴データにアクセスすることができるので、誰でも、どこでも、利用することができるようになります。
chromeのウェブストアに公開するには、5ドルの上納金をGoogleに収める必要がありますが、お金払えば、20個までは自由に拡張機能をストアに公開できるので、ご興味のある方は、chromeの拡張機能お試しください。(Googleの審査あります)
HTMLとjsの簡単な知識あれば誰でも作れますんで、ちょっとした便利ツール作るなら一番いいんじゃないですかね。
これならこの操作するブラウザに存在する履歴データにアクセスすることができるので、誰でも、どこでも、利用することができるようになります。
chromeのウェブストアに公開するには、5ドルの上納金をGoogleに収める必要がありますが、お金払えば、20個までは自由に拡張機能をストアに公開できるので、ご興味のある方は、chromeの拡張機能お試しください。(Googleの審査あります)
HTMLとjsの簡単な知識あれば誰でも作れますんで、ちょっとした便利ツール作るなら一番いいんじゃないですかね。

審査通らなかったので、一般公開はできませんでしたが・・・笑
ユーザの機密情報にアクセスする内容のものは、いろいろ手続きが必要なようで、勉強会当日までに審査通ることができませんでした。
もうちょっといい感じのものになったら、一般公開するかもしれません。
うぅ、、せっかくお金払ったのに。。
もうちょっといい感じのものになったら、一般公開するかもしれません。
うぅ、、せっかくお金払ったのに。。
Github
https://github.com/kzyplus/chrome_extensions仕方ないので、またも稚拙なソースコードを晒します。。
信用できる人はこちら一式ダウンロードいただき、以下にアクセス
chrome://extensions/
①デベロッパーモードへチェック
②「パッケージ化されていない拡張機能を読み込む」に、ダウンロードした一式をアップ
信用できる人はこちら一式ダウンロードいただき、以下にアクセス
chrome://extensions/
①デベロッパーモードへチェック
②「パッケージ化されていない拡張機能を読み込む」に、ダウンロードした一式をアップ
おわりに
すみません、なんか、いろいろ試したいことが溜まってて、実はここに挙げたもの以外にも、いろいろ試したことがあったのですが、だんだん終わりが見えなくなってきてしまったので、今日はここまでにしたいと思います。
業務効率化する際に、よく使われる(?)スタンダードな方法ばかりですので、ご参考いただけたらと思います。
次回はもっと一つのテーマに絞って掘り下げた内容にしたいと反省してますので許してください。
最後までおつきあいいただきありがとうございました。
業務効率化する際に、よく使われる(?)スタンダードな方法ばかりですので、ご参考いただけたらと思います。
次回はもっと一つのテーマに絞って掘り下げた内容にしたいと反省してますので許してください。
最後までおつきあいいただきありがとうございました。