今話題のFacebook Messenger Botをpythonで実装してみた話

  • 62
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

皆さんはTechCrunchさんのこの記事を読みましたか?読んでない?ならこっちは?あとはこことかこことかこことかこことか。
記事急増中。これ全部4/13からの記事。読んでない人は是非読んでください。そして知らなかった人は感動してくださって結構です。
Facebook MessengerをBotに出来るようになりました。
Facebook APIを少しいじればあっという間にできます。

スクリーンショット 2016-04-22 14.01.49.png

どうやるの?

ここを読めば何もかも書いてあるのですが、英語を読むと蕁麻疹が出る人たちのために適当に解説します。と言ってもやることはほとんどありません。だから俺も理解できました。
ちなみに今回はpython×Tornadoで実装してます。

  1. 適当にFacebook Appと Facebook pageを作る。
  2. webhookで使うURLを認証する
  3. メッセージの受信と送信のプログラムを書く

では順番に見ていきましょう

1. 適当にFacebook Appと Facebook pageを作る。

本当に適当に作りました。今回はbotのお試しなので。Appのカテゴリ?はWWWとかでいいんだと思います。作ったらアプリの設定画面?に行ってください。
スクリーンショット 2016-04-22 16.27.17.png
下から二つ目。Messenger-> スタート
スクリーンショット 2016-04-22 17.04.35.png

Facebookページを選択するところがあるので、さっき適当に作ったページをセット。ページに対するアクセストークンが出てきます。

2. webhookで使うURLを認証する

webhookとは?
自分も知りませんでしたか、どうやら何かしらの変化があった時に任意のURLを叩いてもらうことができる機能らしいです(http://blog.manaten.net/entry/573)
botと化したメッセンジャーにメッセージが来た時、設定したURLにPostしてくれるみたいです。で、まずはそのURLを認証しなければならない。

とりあえず認証の処理をするプログラムを先に書きました。pythonでTornadoを使用します。portはどうやら5000が多いらしいので5000で。
FBの公式にはjs用の処理があったのでpythonに直してみました。

server.py
# -*- coding: utf-8 -*-
import tornado.ioloop
import tornado.web
import json

verify_token = <VERIFY_TOKEN>

class WebHookHandler(tornado.web.RequestHandler):
    def get(self):
        if self.get_argument("hub.verify_token", "") == verify_token:
            self.write(self.get_argument("hub.challenge", ""));
        else:
            self.write('Error, wrong validation token');


application = tornado.web.Application([
    (r"/webhook", WebHookHandler)
])


if __name__ == "__main__":
    application.listen(5000)
    tornado.ioloop.IOLoop.instance().start()

ここまで書き、ポート5000で立ち上がることを確認。
webhook用のURLを設定しましょ。

URLにhttp://localhost:5000/webhook, トークンは認証用なのでなんでもいいんですが、pythonの変数で用いてる<VERIFY_TOKEN>と同じ値にしてください。
今回は"test_fb"とかにしときました。
フォロー入力欄は好きなのチェックして保存・・・
スクリーンショット 2016-04-22 17.12.42.png
・・・できません。httpsのやつにしてって言われます。

さぁどうするか

さあどうしよう。ちょっと使ってみたいだけなのにわざわざサーバーにあげるのはだるい。https://localhost:5000は動かない(動かなかった)。

結論

ngrokという超便利なアプリケーションがこの世の中にはあるのです。
自分のlocalhostの一つのポートを一時的に外部でに公開できるという優れもの。しかもhttpsのURLも発行してくれる。すげぇ。
Macの人は brew install ngrok とかで入ります。入りますが、自分はうまくいかなかったので素直にngrokの公式から落としてきました。
使い方は→こっちに従うのが確実です。公式最強。
./ngrok http 5000
って叩いて
スクリーンショット 2016-04-22 17.15.08.png
こんなんが出てきたら勝利。 Forwardingされるアドレス(ca27a10aの部分)は毎回違うのが割り振られますが、とりあえず試すだけなら特に問題ないはず。
先ほどのwebhookのURLに割り振られたhttpsのアドレスをセット。今度は保存できるはず。

3. メッセージの受信と送信のプログラムを書く

送受信する前に認証が必要みたいです.
curl -ik -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=<PAGE_ACCESS_TOKEN>
って叩いてください. <PAGE_ACCESS_TOKEN>はfacebook pageに対するアクセストークンです。
{"success":true}
こんなのが出てきます。出てきたら準備ok

FBの公式にはjsのサンプルコードがあります。見ればわかると思いますが、メッセージが来た時はwebhookのURLにpostが飛んできます。一方、メッセージを送る時はhttps://graph.facebook.com/v2.6/me/messagesにpostします。
もうここまできたら後はコード書くだけなので。一応自分が書いたコードを載せておきます。
<VERIFY_TOKEN>はwebhook認証用URL。今回は"test_fb".
<PAGE_ACCESS_TOKEN>は上記と同様、facebook pageに対するアクセストークンです。

server.py
#!/bin/env python
# -*- coding: utf-8 -*-
import tornado.ioloop
import tornado.web
import json
import requests

verify_token = <VERIFY_TOKEN>
token = <PAGE_ACCESS_TOKEN>

def sendTextMessage(sender, text):
  if len(text) <= 0:
      return
  url = 'https://graph.facebook.com/v2.6/me/messages'
  headers = {'content-type': 'application/json'}
  data = {
        "recipient": {
            "id":sender
        },
        "message":  {
          "text":"echo: " + text
        }
  }
  params = {"access_token":token}

  r = requests.post(url, params=params, data=json.dumps(data), headers=headers)
  #print r.text

class WebHookHandler(tornado.web.RequestHandler):
    def get(self):
        if self.get_argument("hub.verify_token", "") == verify_token:
            self.write(self.get_argument("hub.challenge", ""));
        else:
            self.write('Error, wrong validation token');
    def post(self):
        print "receive!"
        data = json.loads(self.request.body)
        print data
        messaging_events = data["entry"][0]["messaging"]
        text = ""
        for event in messaging_events:
            sender = event["sender"]["id"];
            if ("message" in event and "text" in event["message"]):
                text = event["message"]["text"];
                sendTextMessage(sender, text)


application = tornado.web.Application([
    (r"/webhook", WebHookHandler)
])

if __name__ == "__main__":
    application.listen(5000)
    tornado.ioloop.IOLoop.instance().start()

プログラムの中身は極めて単純。メッセージが飛んできたらそれに "echo:"をつけて返す。それだけ。これだけで(一応)Botができます。自分が打ってきたのが返ってくるだけ。だけどちょー楽しい。

以上です。お疲れ様でした。皆様も楽しいBotLifeをお送りください。