Python
Facebook
tornado
bot
FacebookMessengerBot

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

More than 1 year has 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をお送りください。