最近引越したのですが、電子マネーが便利すぎて財布を持たずにその辺の店に入ったら現金のみの不意打ちを食らって恥ずかしくなることがあります。それを回避するために「このお店で電子マネー使える?」をすぐ教えてくれるLINE Botがあったら便利だなあと思い、プロトタイプを作ってみました。
できたもの(結果)
今回はWAONが使えるかを調べるものにしてみました。
店舗名をBotに送ると、 https://www.waon.net/shop/ のHTMLを取得してスクレイピングして店舗名を配列で取得し、その配列の中に「ユーザーが送った店舗名」が存在するかしないか、で判断しています。
使ったもの
サービス
Node-RED上で追加インストールしたノード
パレットを管理
からインストールできます。
1. Heroku一発ボタンでNode-REDが使えるサーバーを5分で作る
joeartsea/node-red-heroku - Buttons - Heroku Elements
クリックするだけでお手軽に完了です。
Node-REDのユーザー名とパスワードは初期値のままは避けてしっかり設定しましょう。
2. フロー構成
先頭(左端)はhttp in
ノード、末尾(右端)は、インストールした ReplyMessage
ノードです。
1つめ:http in
LINEサーバーからのWebhookを受け付けるノードです。
2つめ:function
スクレイピングを行う次以降のノードでmsg.payload
に入っているLINEメッセージが失われてしまうので、一時的にmsg.line
に退避させています。ここはchange
ノードでも同等のことができます。
3つめ:http request
WAON公式の「使えるお店を探す」ページをただただ取得しているだけです。このノードからは取得されたHTMLがそのままmsg.payload
に入って流れてゆきます。
4つめ:html
- p.useShopInner_boxText をセレクタとして
- 得られた要素の内側のテキストだけを
- 得られた数だけ配列にして1つのメッセージにして
-
msg.payload
に入れて送出
ということをやっています。
実際に店舗名が入っているのがこの箇所だったので、この該当セレクタを全て抜き出して配列化しています。
このあたりは以下の記事を参考にしました。
5つめ:function
debug
は省略します。
みんな大好きfunction
ノードです。
LINEから来たメッセージはmsg.line
に入っており、メッセージ本文が格納されているのはmsg.line.events[0].message.text
と、なんともややこしいところに入っています。ここに入っている文字列は「調べたい店舗名」を想定しているため、この文字列が先ほどの店舗配列が入っているmsg.payload
の中に存在するかを確認します。
そのあと、存在する・しないを表現する「返信メッセージ」を作り、msg.payload.events[0].message.text
にそのメッセージを入れて送り出します。
6つめ:ReplyMessage
LINE DevelopersでMessaging APIチャネルを作成し、「チャネルアクセストークン」と「チャネルシークレット」をそれぞれ取得してきてここに入れます。
3. LINE DevelopersでWebhook URLを設定
HerokuのURLに/webhook
というパスを追加したものがエンドポイントとなります。
LINEとの連携において必要な情報はこのWebhook URLのほかにはシークレットとアクセストークンであり、あとはLINE公式アカウントマネージャーで、「応答設定」が以下のようになっているか確認するだけです。
4. インポート用のフロー
この記事で作ったNode-REDのフローを試していただけるJSONを以下に貼っておきましたのでご利用ください。
LINE関係のノードはあらかじめインストールしておいてね!
[{"id":"e8b02747.23f5d8","type":"tab","label":"Flow 3","disabled":false,"info":""},{"id":"154b2525.fec9db","type":"http in","z":"e8b02747.23f5d8","name":"LINEサーバーからアクセス","url":"/webhook","method":"post","upload":false,"swaggerDoc":"","x":130,"y":40,"wires":[["bba70408.46ab88"]]},{"id":"bba70408.46ab88","type":"function","z":"e8b02747.23f5d8","name":"検索ワードを保持","func":"// LINEサーバーからの情報を「msg.line」に移動させる\nmsg.line = msg.payload;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":40,"wires":[["a8a136b3.2572f8"]]},{"id":"a8a136b3.2572f8","type":"http request","z":"e8b02747.23f5d8","name":"www.waon.net/shop/ へアクセス","method":"GET","ret":"txt","paytoqs":"ignore","url":"https://www.waon.net/shop/","tls":"","persist":false,"proxy":"","authType":"","x":640,"y":40,"wires":[["94932a54.7ab588"]]},{"id":"11d8c7c5.9be6d8","type":"debug","z":"e8b02747.23f5d8","name":"返信メッセージの中身をdebug表示","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.events[0].message.text","targetType":"msg","statusVal":"","statusType":"auto","x":520,"y":300,"wires":[]},{"id":"94932a54.7ab588","type":"html","z":"e8b02747.23f5d8","name":"店舗名だけ抜き出して配列化","property":"payload","outproperty":"payload","tag":"p.useShopInner_boxText","ret":"text","as":"single","x":940,"y":40,"wires":[["379230a2.79ac6","4d01bc93.b27434"]]},{"id":"379230a2.79ac6","type":"function","z":"e8b02747.23f5d8","name":"検索ワードが店舗一覧の中にあるか?","func":"const searchShop = msg.line.events[0].message.text;\nconst result = msg.payload.findIndex((shopName) => shopName == searchShop);\nmsg.payload = msg.line;\nmsg.payload.events[0].message.text = '電子マネーWAONは「'+searchShop+'」で'+((result == -1)?'のご利用はできません。':'ご利用いただけます。');\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":210,"y":160,"wires":[["567abac0.ee3784","11d8c7c5.9be6d8"]]},{"id":"4d01bc93.b27434","type":"debug","z":"e8b02747.23f5d8","name":"店舗配列をdebug表示","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1220,"y":40,"wires":[]},{"id":"567abac0.ee3784","type":"ReplyMessage","z":"e8b02747.23f5d8","name":"LINEで返信","replyMessage":"","x":590,"y":160,"wires":[]}]