Posted at

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

More than 1 year has passed since last update.

この記事はSlack その2 Advent Calendar 2016の24日目の記事です。

image

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

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


スクレイピング

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

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

$ mkdir gourmet_bot; cd $_

$ npm init
$ npm i -S @slack/client cheerio

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


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は環境変数で設定しておきます。

$ export WEBHOOK_URL=https://hooks.slack.com/services/***

$ node
> require('./bot')()

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


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

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


index.js

const bot = require('./bot')

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


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

$ zip -r gourmet_bot.zip .


Lambda の設定

Functionの新規作成ページでBlank Functionを選びます。

image

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

次のページでFunctionの詳細設定を行います。

Nameを適当に入力し、RuntimeNode.jsを選択します。

Code entry typeUpload 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とは微妙に異なるので詳しくは公式リファレンスをみてください。

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


以上です。GUIが辛いので今後はCLIでやりたい。

これで#randomチャンネルが盛り上がるかどうかは謎。

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