Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

皆さんは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をお送りください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away