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

皆さんは[TechCrunchさんのこの記事](http://jp.techcrunch.com/2016/04/13/20160412agents-on-messenger/)を読みましたか？読んでない？なら[こっち](http://blog.feedmatic.net/entry/2016/04/13/135236)は？あとは[ここ](http://www.itmedia.co.jp/news/articles/1604/13/news059.html)とか[ここ](http://japanese.engadget.com/2016/04/13/facebook-messenger-ai/)とか[ここ](http://itpro.nikkeibp.co.jp/atcl/column/15/061500148/041400053/)とか[ここ](http://qiita.com/naoyashiga/items/6c663f6e773490934312)とか。
記事急増中。これ全部4/13からの記事。読んでない人は是非読んでください。そして知らなかった人は感動してくださって結構です。
**Facebook MessengerをBotに出来るようになりました。**
Facebook APIを少しいじればあっという間にできます。

![スクリーンショット 2016-04-22 14.01.49.png](https://qiita-image-store.s3.amazonaws.com/0/102613/32ef15d5-daf5-1145-860a-c0a894bfce0f.png)


###どうやるの?
[ここ](https://developers.facebook.com/docs/messenger-platform/quickstart)を読めば何もかも書いてあるのですが、英語を読むと蕁麻疹が出る人たちのために適当に解説します。と言ってもやることはほとんどありません。だから俺も理解できました。
ちなみに今回は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](https://qiita-image-store.s3.amazonaws.com/0/102613/b1490eea-636e-c583-2a2f-cca34ce5ce87.png)
下から二つ目。Messenger-> スタート
![スクリーンショット 2016-04-22 17.04.35.png](https://qiita-image-store.s3.amazonaws.com/0/102613/0711b73a-d3df-94f3-c416-b277ab77fe88.png)

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

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

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

とりあえず認証の処理をするプログラムを先に書きました。pythonでTornadoを使用します。portはどうやら５０００が多いらしいので５０００で。
[FBの公式](https://developers.facebook.com/docs/messenger-platform/quickstart)にはjs用の処理があったのでpythonに直してみました。

```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](http://localhost:5000/webhook), トークンは認証用なのでなんでもいいんですが、pythonの変数で用いてる\<VERIFY_TOKEN>と同じ値にしてください。
今回は"test_fb"とかにしときました。
フォロー入力欄は好きなのチェックして保存・・・
![スクリーンショット 2016-04-22 17.12.42.png](https://qiita-image-store.s3.amazonaws.com/0/102613/f88d1795-ecb0-d0d8-0866-a48dc7466c3c.png)
・・・できません。httpsのやつにしてって言われます。

#####さぁどうするか
さあどうしよう。ちょっと使ってみたいだけなのにわざわざサーバーにあげるのはだるい。[https://localhost:5000](https://localhost:5000)は動かない(動かなかった)。
#####結論
[ngrok](https://ngrok.com/)という超便利なアプリケーションがこの世の中にはあるのです。
自分のlocalhostの一つのポートを一時的に外部でに公開できるという優れもの。しかもhttpsのURLも発行してくれる。すげぇ。
Macの人は brew install ngrok とかで入ります。入りますが、自分はうまくいかなかったので素直に[ngrokの公式](https://ngrok.com/)から落としてきました。
使い方は→[こっち](https://dashboard.ngrok.com/get-started)に従うのが確実です。公式最強。
`./ngrok http 5000`
って叩いて
![スクリーンショット 2016-04-22 17.15.08.png](https://qiita-image-store.s3.amazonaws.com/0/102613/1cecff60-aac8-5414-7598-f032a600f12a.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の公式](https://developers.facebook.com/docs/messenger-platform/quickstart)にはjsのサンプルコードがあります。見ればわかると思いますが、メッセージが来た時はwebhookのURLにpostが飛んできます。一方、メッセージを送る時は[https://graph.facebook.com/v2.6/me/messages](https://graph.facebook.com/v2.6/me/messages)にpostします。
もうここまできたら後はコード書くだけなので。一応自分が書いたコードを載せておきます。
\<VERIFY_TOKEN>はwebhook認証用URL。今回は"test_fb".
\<PAGE_ACCESS_TOKEN>は上記と同様、facebook pageに対するアクセストークンです。

```python: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をお送りください。