Node.js(Express) と Heroku で Twitter ボットを作る


これは [Heroku Advent Calendar 2014](http://qiita.com/advent-calendar/2014/heroku) の１９日目(12/19)の投稿です。それほど Heroku に精通していないと思いつつ、Heroku を便利に使わせてもらっているので、この機に記事を書いてみます。

今回は、Node.js ＆ Express フレームワークで定期的にツイートするだけの Twitter ボットを作り、Heroku にデプロイする方法について書きます。
（今回の例は単純な例ですが、応用してもっと複雑なこともできるでしょう。）

Heroku へのデプロイについては、手順も楽だしハマることが無いので、逆にそれほど書くことが無いのですが^^;

> 今回の投稿の前提となる、私の周辺環境は下記と同じです。
> ⇒ [Node.js(express) 事始め ＆ Heroku へデプロイまでのメモ](http://qiita.com/hkusu/items/e46de8c446840c50aefe)
> Heroku を利用する準備は、既に済んでいるものとします。

なお、成果物としてのソースはこちらに置いたので、何かあれば参照、ご利用ください。
⇒ https://github.com/hkusu/time-signal-twitter-bot

## 手順

> Node.js に Express を導入するまでの手順は、上記の「事始め」の投稿の手順を確認ください。

### 必要なライブラリの導入

まず、ジョブの定期実行に必要な [node-cron](https://github.com/ncb000gt/node-cron) を導入します。

```shell:
$ npm install cron --save
```

他には Titter 連携ライブラリの [twit](https://github.com/ttezel/twit) 、ほかには 時間まわりのライブラリ [Moment.js](http://momentjs.com) を導入します。

```shell:
$ npm install twit --save
$ npm install moment --save
```

> 世界標準時でむりくり頑張ってますが、本当は Heroku でのタイムゾーン指定や node-time の導入、node-cron でのタイムゾーン指定をした方が良いかも。

結果、`package.json` は次のようになります。

```json:package.json
〜

  "dependencies": {
    "express": "^4.10.4",
    "twit": "^1.1.18",
    "cron": "^1.0.5",
    "moment": "^2.8.4"
  }

〜
```

### Twitter 側でアプリケーションを作成しキーを控える

ボット用の Twitter アカウントを用意するか、自分が普段つかっている Twitter アカウントでツイートさせたかったら自分の Twitter アカウントで。

https://apps.twitter.com で行います。詳しい説明は省きますが、以前に似たようなものを書いたので、よろしければ参照ください。
⇒ [Hubot を Twitter の公開タイムラインに住まわせる](http://qiita.com/hkusu/items/36ce56f3df4e7a0937cb)

※ Permissions で `Read and Write` にしておく必要があります。`Write` 権限がないとツイートできない為。

### スクリプトを書く

こちらに置いてあるのですが、
⇒ https://github.com/hkusu/time-signal-twitter-bot

書いたのは下記の２ファイルのみです。

#### app.js

Express まわりの基本的なロジックです。特殊なことをしてるとすれば、環境変数から Twitter に関するキーを読み込んでるところくらい。（キーはコミットしたくない為。）

本体ロジックからこのファイルをロードする為に、最後に `module.exports` しています。

```javascript:app.js
var express = require('express');
var app = express();

// 環境変数から Titter アプリケーションのキー等を取得
var options = {
  key: process.env.TWIBOT_TWITTER_KEY,
  secret: process.env.TWIBOT_TWITTER_SECRET,
  token: process.env.TWIBOT_TWITTER_TOKEN,
  token_secret: process.env.TWIBOT_TWITTER_TOKEN_SECRET
};
app.set('options', options);

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));

app.get('/', function(request, response) {
  response.send('This is Twitter-bot application.')
});

app.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'))
});

module.exports = app;
```

#### bin/index.js

Twitter ボットの本体です。今回はツイートするだけなので割りとシンプル。

- `Twit` クラスをインスタンス化する際に、環境変数から得たキー情報をセットしています。
- `CronJob` クラスをインスタンス化する際に、ジョブのタイムスケジュールをセットしています。
	- インスタンス化した時点でジョブが始まります。後から自分で起動したい場合は `start: false` とします。
	- 世界標準時間で設定しているので、日本時間 -９ 時間で考えてください。
	- この例だと、日本時間で朝９時から夜２３時の間、毎時０分０秒にツイートします。
- ツイートするメッセージは日本時間にしたいので、`moment().utc().add(9, 'h')` として、現在日本時間を算出しています。

```javascript:bin/index.js
var app = require('../app');
var Twit = require('twit');
var CronJob = require("cron").CronJob;
var moment = require('moment');
//var http = require('http');

var T = new Twit({
  consumer_key: app.get('options').key,
  consumer_secret: app.get('options').secret,
  access_token: app.get('options').token,
  access_token_secret: app.get('options').token_secret
});

var cronTime = '0 0 0-14 * * *';

new CronJob({
  cronTime: cronTime,
  onTick: function () {
    tweet();
  },
  start: true
});

function tweet(){
  var message = moment().utc().add(9, 'h').format("ただいま MM月DD日 HH時mm分です。");
  console.log(message);

  T.post('statuses/update', { status: message }, function(err, data, response) {
    //console.log('Tweet!');
  });
}
```

### スクリプト起動用の設定

`npm start` の内容を、`package.json` に記載します。

```json:package.json
〜

  "scripts": {
    "start": "node bin/index"
  },

〜
```

デバッグ用途でローカルで起動する場合は、環境変数を設定してから `$ npm start` とすればよいのですが、次のような起動用のシェルを組んでおくと便利です。

```sh:local_run.sh
#!/bin/sh

export TWIBOT_TWITTER_KEY=控えていた情報
export TWIBOT_TWITTER_SECRET=控えていた情報
export TWIBOT_TWITTER_TOKEN=控えていた情報
export TWIBOT_TWITTER_TOKEN_SECRET=控えていた情報

npm start
```

> このファイルは Git にコミットしないように注意。

スクリプトを修正したら `$ ./local_run.sh` で実行、を繰り返してデバック、開発を進めていけばよいです。

### Heroku へデプロイ

Heroku 用の `Procfile` を修正します。

```:Procfile
web: npm start
```

Git でコミットします。`.gitignore` は必要に応じて記載ください。

```shell:
$ git init
$ git add .
$ git commit -m "適当なコメント"
```

Heroku アプリケーションを作成しプッシュします。

```shell:
$ heroku create
$ git push heroku master
```

Heroku へ次のように環境変数を追加し `$ heroku open` してみます。

```shell:
$ heroku config:add TWIBOT_TWITTER_KEY=控えていた情報
$ heroku config:add TWIBOT_TWITTER_SECRET=控えていた情報
$ heroku config:add TWIBOT_TWITTER_TOKEN=控えていた情報
$ heroku config:add TWIBOT_TWITTER_TOKEN_SECRET=控えていた情報
```

エラーがなければ次のように表示されます。

![スクリーンショット_2014-12-17_17_29_35.png](https://qiita-image-store.s3.amazonaws.com/0/35733/9fc4f0f2-6f9b-8db4-5396-ef89da65580d.png "スクリーンショット_2014-12-17_17_29_35.png")

> Heroku へセットした環境変数の内容は `$ heroku config` で、Heroku 上のエラー内容は `$ heroku logs [--tail]` で確認できます。デバック用にスクリプト内で `console.log()` した内容もこのログに記載されます。

あとは Twitter アプリケーション用のアカウントで定期的にツイートされるはずです^^

![スクリーンショット_2014-12-17_17_32_51.png](https://qiita-image-store.s3.amazonaws.com/0/35733/a6ace537-430d-f1ec-b81e-b1471128e4ca.png "スクリーンショット_2014-12-17_17_32_51.png")

## ほか

Heroku の無料枠だと、アクセスが一定時間ない場合、眠ってしまいます^^; 私の場合は死活監視サービス（[Uptime Robot](https://uptimerobot.com)）を使ってるので、起きてますが..

## おわりに

Heroku はツール系のサービスを立ち上げるのにすごい楽ですね。私は Rails と Node.js 系の言語のものをデプロイしているのですが、他の言語のも使ってみようと思います。

明日は [etmnk](http://qiita.com/etmnk) さんによる記事です！