TokyoRのATNDを監視してメールを送るツールを作ってみた

TokyoRのATNDを監視してメールを送るツールを作ってみた
## 動機

ほぼ毎月開催されている「R勉強会＠東京（#TokyoR）」は人気が高く、ATNDに参加募集があがってから2〜3日で定員を超えてしまうこともしばしばです。

twitterのタイムラインをチェックする、ハッシュタグ#TokyoRのツイートをチェックする、ATNDの検索ページをブックマークしておいてちょくちょく検索してみる、などをしていれば問題なく参加登録できますが、根が面倒くさがりなもので、「ATNDをチェックして、最新の開催情報を自分にメールする仕組み」が欲しくなりました。

「欲しいものは作れ」という声が聞こえた気がするので自分で作ってみます。

## 材料
- Rスクリプト（自作）
- mailgunアカウント（フリー）←自由に踏めるメールサーバーがある人は不要
- herokuアカウント（フリー）

## 手順
### ATNDからの情報取得方法を決める
ぱっと思いついたのはATNDのAPI(http://api.atnd.org) を使うことです。
キーワード「tokyor」を含むイベントのうち最新のものは以下のクエリで取得できます。
`http://api.atnd.org/events/?keyword=tokyor&count=1`
なお、デフォルトでは結果はxmlで戻ってきます。formatオプションでjsonも指定できます。
`http://api.atnd.org/events/?keyword=tokyor&count=1&format=json`

### Rスクリプト（前半）を書く
まずは手元のMacで動くRスクリプトを書いてみます。

`{curl}`と`{jsonlite}`を使います。

```
library(curl)
library(jsonlite)
con <- curl("http://api.atnd.org/events/?keyword=tokyor&count=1&format=json")
df <- fromJSON(readLines(con, warn = FALSE))$events$event
bodymessage <- paste(substr(df$started_at, 1, 10), df$title, df$event_url, sep = " ")

bodymessage
# 2015-10-10 第51回R勉強会＠東京（#TokyoR） http://atnd.org/events/70522
```

xmlでもやってみました。
R Advent Calendar 2014の７日目にdichika氏が投稿された「R Advent Calendar 2014に記事が追加されたらメールが届くようにした(http://d.hatena.ne.jp/dichika/20141207) 」を参考に書いていきます。
`html()`はdeprecatedだから`read_xml()`使えと言われたり`html_node()`も`xml_node()`もdeprecatedだ`{xml2}`を使えと言われたりして苦しみながらなんとか書き上げました。xmlから中身を取り出すのは初めてなので、もっとスマートなやり方があるのかもしれません。

```
#devtools::install_github("hadley/rvest")
library(rvest)
result <- read_xml("http://api.atnd.org/events/?keyword=tokyor&count=1") %>%
  xml_children() %>%
  xml_children() %>%
  xml_children() %>%
  xml_text()

bodymessage <- paste(substr(result[6], 1, 10), result[2], result[5], sep = " ")
```

今回私は`{curl}`と`{jsonlite}`を使う方でいきます。

### Rスクリプト（後半）を書く
後半のスクリプトはほぼ先ほどのdichika氏の記事から丸ぱくりです。
ただ、私の環境ではgmailをsmtpサーバーとして使おうとすると認証がうまくいきませんでした。
そこで、`send.mail()`のヘルプに出ている、認証を使わない方法

```
send.mail(from = "foo@gmail.com",
          to = "foo+test@gmail.com",
          subject = "最新TokyoR開催情報",
          body = message,
          smtp = list(host.name = "aspmx.l.google.com", port = 25),
          authenticate = FALSE,
          send = FALSE)
```

にしてみたところ、うまくはいきますが、gmailから「送信元偽装してるな。お前フィッシングだろ」と目をつけられます。このスクリプトを繰り返し実行していると、googleから迷惑メール送信アカウントとしてマークされてしまうかもしれません。

それはいやなので、アプリからのメール送信に使えるサービスを探したところ、mailgun (https://mailgun.com) というサービスがありました。フリーのアカウントで月間１万通まで無料でメールを送信できます。APIでの利用が推奨されていますが、smtpでの送信も可能です。登録も簡単です。mailgunやgmailに頼らなくても自由に使えるメールサーバーを持っているかたはどうぞそちらをお使いください。

```
#install.packages(mailR)
library(mailR) # Java6SE runtimeが無いと突然落ちるので注意
send.mail(from = "postmaster@sandboxxxxx.mailgun.org",
          to = "my@address.com",
          subject = "最新TokyoR開催情報",
          body = bodymessage,
          encoding = "utf-8",
          html = FALSE,
          smtp = list(host.name = "smtp.mailgun.org", 
                      port = 465, 
                      user.name = "postmaster@sandboxxxxx.mailgun.org",
                      passwd = "xxxxxx",　
                      ssl = TRUE),
          authenticate = TRUE,
          send = TRUE,
          debug = FALSE) # うまく動かないときはここをTRUEにする
```
dichika氏のソースには`library(mailR)`のコメントに「Java runtimeが無いと突然落ちるので注意」と書いてありました。私のMacにはJava8のruntimeが入っているので大丈夫だろうと思ってスクリプトを実行したら、いきなり落ちました。Java6SEが必要だそうです。ちょっとだけコメントを修正しました。

Macの場合はここ(https://support.apple.com/kb/DL1572) からDLします。

### herokuアプリとして登録する
heroku (https://www.heroku.com) は手軽に使えるPaaSのひとつです。rubyやpythonでの利用が普通ですが、サードパーティのbuildpackageを使うことでRでも使えます。

herokuでRを動かすためのbuildpackageはこちら(https://github.com/virtualstaticvoid/heroku-buildpack-r) です。readmeも丁寧ですしサンプルプログラムも豊富なので、使い方の説明は割愛します。
私がはまったのは１つだけ。パッケージをインストールするためのinit.rをinit.Rとしていて、それが原因で`git push heroku master`がうまくいかなかったのですが、ログからはそれが読み取れなくて悩みました。

init.r : パッケージインストール部分

```
install.packages("curl", repos = "http://cran.rstudio.com")
install.packages("jsonlite", repos = "http://cran.rstudio.com")
install.packages("mailR", repos = "http://cran.rstudio.com")
```

whenTokyoR.R：メイン

```
Sys.setlocale("LC_ALL", "ja_JP.UTF-8") # これを入れないと漢字が消える

library(curl)
library(jsonlite)
con <- curl("http://api.atnd.org/events/?keyword=tokyor&count=1&format=json")
df <- fromJSON(readLines(con, warn = FALSE))$events$event
bodymessage <- paste(substr(df$started_at, 1, 10), df$title, df$event_url, sep = " ")

library("mailR") # Java6SE runtimeが無いと突然落ちるので注意
send.mail(from = "postmaster@sandboxxxxxxx.mailgun.org",
          to = "my@address.com",
          subject = "latest TokyoR event",
          body = bodymessage,
          encoding = "utf-8",
          html = FALSE,
          smtp = list(host.name = "smtp.mailgun.org", 
                      port = 465, 
                      user.name = "postmaster@sandboxxxxxxx.mailgun.org",
                      passwd = "xxxxxxxxxxx",
                      ssl = TRUE),
          authenticate = TRUE,
          send = TRUE,
          debug = FALSE) # うまく動かないときはここをTRUEにする
```

スクリプトを入れたフォルダーで以下を実行します。

```
$ git init
$ git add . 
$ git commit -m 'init'
$ heroku create --stack cedar-14 --buildpack https://github.com/virtualstaticvoid/heroku-buildpack-r.git#cedar-14
$ git push heroku master
```

deployの際にinit.rで指定したパッケージがインストールされます。5分位待って、deployが完了したら、以下のコマンドでスクリプトを実行してみます。

```
$ heroku run R -f ./whenTokyoR.R --gui-none --no-save
```

指定したアドレス(上のサンプルではmy@address.com)あてにメールが届いたら成功です。

### 定期的にスクリプトを実行する
ここまででは、まだスクリプトは手動で実行する必要があり、うれしくありません。手動でスクリプトを流すんなら、ブラウザでブックマークを開いたほうが楽チンです。

幸い、herokuには定期的に処理を流すオプション（add-on）があります。
アプリの管理画面上でResourcesタブを選択し、Add-ons欄で Heroku Scheduler を追加します。

Heroku Schedulerの設定画面で `R -f ./whenTokyoR.R --gui-none --no-save`をセットし、Frequencyを`Daily`,`Hourly`,`Every 10 minutes`から選択して保存したら完了です。指定した間隔で処理が流れ、メールが飛んできます。

### 今後の課題
更新がないのに延々と同じ内容のメールが来るのもうざいので、前回の結果を覚えておき、更新があったときだけメールを飛ばすようにしたいです。



今日はここまで。
Enjoy!!