#randomがイマイチ盛り上がらないのでサーバレスなグルメBot作った

この記事は[Slack その2 Advent Calendar 2016](http://qiita.com/advent-calendar/2016/slack2)の24日目の記事です。

![image](https://qiita-image-store.s3.amazonaws.com/0/97243/02ecb3bf-4fd8-c96e-2fcb-80e5109613de.png)

今年の4月頃から会社でSlackを導入し、案件毎のチャンネルを作ったりしてそれなりに活用しているけれど、#randomチャンネルにほとんど投稿が無くて寂しい！少しでも活性化出来ればと思ってオリジナルのBotを導入してみました。

とりあえずは定期的にオススメのお店情報を投稿するだけのシンプルなBotを作ってみます。hubotは大袈裟だしサーバーを用意して常駐させるのも面倒だったので、AWS Lambdaを使ったサーバレス的な実装をしてみました。

## スクレイピング

現時点(2016.12.29)で、食べログやRettyにはAPIが無いようなので、自力でスクレイピングする必要があります。

とりあえずNode.jsプロジェクトを初期化し、必要なモジュールをインストールしておきます。

```bash
$ mkdir gourmet_bot; cd $_
$ npm init
$ npm i -S @slack/client cheerio
```

食べログをスクレイピングしてSlackに投稿する一連のスクリプトを作成します。

```js:bot.js
const request = require('request')
const cheerio = require('cheerio')
const IncomingWebhook = require('@slack/client').IncomingWebhook

module.exports = () => {
  const url = 'https://tabelog.com/tokyo/rstLst/?Srt=D&SrtT=rt&sort_mode=1&ChkNewOpen=1'
  const webhook_url = process.env.WEBHOOK_URL

  request(url, (err, res, body) => {
    const $ = cheerio.load(body)
    const topics = $('li.list-rst').map((i, el) => {
      const a = $('a.list-rst__comment-text.cpy-comment-text', el).first()
      return {
        url: a.attr('href'),
        restaurant: $('a.list-rst__rst-name-target.cpy-rst-name', el).text().trim(),
        title: a.text().trim(),
        star: $('span.tb-rating__val.tb-rating__val--strong.list-rst__rating-val', el).first().text().trim(),
        meta: $('span.list-rst__area-genre.cpy-area-genre', el).first().text().trim(),
        price: $('li.tb-rating.tb-rating--sm.list-rst__budget-item', el).map((i, el) => $(el).text().trim() ).get().join(' ')
      }
    }).get()
    console.log(topics)

    const text = "*週間食べログ人気ランキング*\n\n" + topics.map((topic, i) => {
      return `[${i+1}] ${topic.restaurant} ${topic.meta} :star: ${topic.star} :moneybag: ${topic.price}\n<${topic.url}|${topic.title}>`
    }).join("\n\n")

    const webhook = new IncomingWebhook(webhook_url)
    webhook.send(text)
  })
}
```

### 動作確認

SlackのWebhook URLは環境変数で設定しておきます。

```bash
$ export WEBHOOK_URL=https://hooks.slack.com/services/***
$ node
> require('./bot')()
```

Slackに投稿できていることを確認します。

## AWS Lambda のデプロイパッケージ作成

まずエンドポイントとなるスクリプトを作成します。

```js:index.js
const bot = require('./bot')

exports.handler = (event, context, callback) => {
  bot()
}
```

プロジェクト全体をzipで圧縮します。

```bash
$ zip -r gourmet_bot.zip .
```

## Lambda の設定

Functionの新規作成ページでBlank Functionを選びます。
![image](https://qiita-image-store.s3.amazonaws.com/0/97243/1dafdd62-0022-a0f7-b0ee-bc8aee5b3d9f.png)

Functionのトリガーを設定するよう促されるけど、とりあえずスルーしてNextボタンで次に進みます。

次のページでFunctionの詳細設定を行います。
**Name**を適当に入力し、**Runtime**は``Node.js``を選択します。
**Code entry type**は``Upload a .ZIP file``を選ぶとアップロードボタンが表示されるので、先程作成したzipを選択します。
**Environment variables**にはローカルで設定したSlackのWebhook URLを入力しておきます。
**Timeout**は少し長めに30秒としておきます。
その後は指示に従って保存します。

**Test**ボタンを押すとテスト用に送信されるJSONを設定するダイアログが開きますが、今回は一切不要なのでデフォルトのHello Worldか{}を入力して保存し、テストを実行してみます。これでSlackに投稿されていればLambdaの設定は完了です。

## CloudWatch (スケジューリング) の設定

Add triggerのタブから``CloudWatch Events - Schedule``を選択し、適当な**Rule name**を入力して**Schedule expression**を設定すると定期的に実行されるようになります。cronっぽいけどLinuxのcrontabとは微妙に異なるので詳しくは[公式リファレンス](http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html)をみてください。

毎週月曜日9:30に実行されるスケジュール設定は``cron(30 0 ? * MON *)``のようになります。JSTで設定できれば楽なのですが、おそらくGMT限定っぽいので逆算しています。

---

以上です。GUIが辛いので今後はCLIでやりたい。
これで#randomチャンネルが盛り上がるかどうかは謎。

使用したソースコード : https://github.com/d-mato/gourmet_bot