如何用 Python 和 Flask 建立部署一个 Facebook Messenger 机器人

这是我建立一个简单的 Facebook Messenger 机器人的记录。功能很简单,它是一个回显机器人,只是打印回用户写了什么。

回显服务器类似于服务器的“Hello World”例子。

这个项目的目的不是建立最好的 Messenger 机器人,而是让你了解如何建立一个小型机器人和每个事物是如何整合起来的。

技术栈

使用到的技术栈:

  • Heroku 做后端主机。免费级足够这个等级的教程。回显机器人不需要任何种类的数据持久,所以不需要数据库。
  • Python 是我们选择的语言。版本选择 2.7,虽然它移植到 Pyhton 3 很容易,只需要很少的改动。
  • Flask 作为网站开发框架。它是非常轻量的框架,用在小型工程或微服务是非常完美的。
  • 最后 Git 版本控制系统用来维护代码和部署到 Heroku。
  • 值得一提:Virtualenv。这个 python 工具是用来创建清洁的 python 库“环境”的,这样你可以只安装必要的需求和最小化应用的大小。

机器人架构

Messenger 机器人是由一个响应两种请求的服务器组成的:

  • GET 请求被用来认证。他们与你注册的 FaceBook 认证码一同被 Messenger 发出。
  • POST 请求被用来实际的通信。典型的工作流是,机器人将通过用户发送带有消息数据的 POST
    请求而建立通信,然后我们将处理这些数据,并发回我们的 POST 请求。如果这个请求完全成功(返回一个 200 OK 状态码),我们也将响应一个
    200 OK 状态码给初始的 Messenger请求。

这个教程应用将托管到 Heroku,它提供了一个优雅而简单的部署应用的接口。如前所述,免费级可以满足这个教程。

在应用已经部署并且运行后,我们将创建一个 Facebook 应用然后连接它到我们的应用,以便 Messenger 知道发送请求到哪,这就是我们的机器人。

机器人服务器

基本的服务器代码可以在 Github 用户 hult(Magnus Hult) 的 Chatbot 项目上获取,做了一些只回显消息的代码修改和修正了一些我遇到的错误。最终版本的服务器代码如下:


  1. from flask import Flask, request 
  2. import json 
  3. import requests 
  4. app = Flask(__name__) 
  5. ### 这需要填写被授予的页面通行令牌(PAT) 
  6. ### 它由将要创建的 Facebook 应用提供。 
  7. PAT = '' 
  8. @app.route('/', methods=['GET']) 
  9. def handle_verification(): 
  10.   print "Handling Verification." 
  11.   if request.args.get('hub.verify_token', '') == 'my_voice_is_my_password_verify_me': 
  12.     print "Verification successful!" 
  13.     return request.args.get('hub.challenge', '') 
  14.   else: 
  15.     print "Verification failed!" 
  16.     return 'Error, wrong validation token' 
  17. @app.route('/', methods=['POST']) 
  18. def handle_messages(): 
  19.   print "Handling Messages" 
  20.   payload = request.get_data() 
  21.   print payload 
  22.   for sender, message in messaging_events(payload): 
  23.     print "Incoming from %s: %s" % (sender, message) 
  24.     send_message(PAT, sender, message) 
  25.   return "ok" 
  26. def messaging_events(payload): 
  27.   """Generate tuples of (sender_id, message_text) from the 
  28.   provided payload. 
  29.   """ 
  30.   data = json.loads(payload) 
  31.   messaging_events = data["entry"][0]["messaging"] 
  32.   for event in messaging_events: 
  33.     if "message" in event and "text" in event["message"]: 
  34.       yield event["sender"]["id"], event["message"]["text"].encode('unicode_escape') 
  35.     else: 
  36.       yield event["sender"]["id"], "I can't echo this" 
  37. def send_message(token, recipient, text): 
  38.   """Send the message text to recipient with id recipient. 
  39.   """ 
  40.   r = requests.post("https://graph.facebook.com/v2.6/me/messages", 
  41.     params={"access_token": token}, 
  42.     data=json.dumps({ 
  43.       "recipient": {"id": recipient}, 
  44.       "message": {"text": text.decode('unicode_escape')} 
  45.     }), 
  46.     headers={'Content-type': 'application/json'}) 
  47.   if r.status_code != requests.codes.ok: 
  48.     print r.text 
  49. if __name__ == '__main__': 
  50.   app.run() 

让我们分解代码。第一部分是引入所需的依赖:


  1. from flask import Flask, request 
  2. import json 
  3. import requests 

接下来我们定义两个函数(使用 Flask 特定的 app.route 装饰器),用来处理到我们的机器人的 GET 和 POST 请求。


  1. @app.route('/', methods=['GET']) 
  2. def handle_verification(): 
  3.   print "Handling Verification." 
  4.   if request.args.get('hub.verify_token', '') == 'my_voice_is_my_password_verify_me': 
  5.     print "Verification successful!" 
  6.     return request.args.get('hub.challenge', '') 
  7.   else: 
  8.     print "Verification failed!" 
  9.     return 'Error, wrong validation token' 

当我们创建 Facebook 应用时,verify_token 对象将由我们声明的 Messenger 发送。我们必须自己来校验它。最后我们返回“hub.challenge”给 Messenger。

处理 POST 请求的函数更有意思一些:


  1. @app.route('/', methods=['POST']) 
  2. def handle_messages(): 
  3.   print "Handling Messages" 
  4.   payload = request.get_data() 
  5.   print payload 
  6.   for sender, message in messaging_events(payload): 
  7.     print "Incoming from %s: %s" % (sender, message) 
  8.     send_message(PAT, sender, message) 
  9.   return "ok" 

当被调用时,我们抓取消息载荷,使用函数 messaging_events 来拆解它,并且提取发件人身份和实际发送的消息,生成一个可以循环处理的 python 迭代器。请注意 Messenger 发送的每个请求有可能多于一个消息。


  1. def messaging_events(payload): 
  2.   """Generate tuples of (sender_id, message_text) from the 
  3.   provided payload. 
  4.   """ 
  5.   data = json.loads(payload) 
  6.   messaging_events = data["entry"][0]["messaging"] 
  7.   for event in messaging_events: 
  8.     if "message" in event and "text" in event["message"]: 
  9.       yield event["sender"]["id"], event["message"]["text"].encode('unicode_escape') 
  10.     else: 
  11.       yield event["sender"]["id"], "I can't echo this" 

对每个消息迭代时,我们会调用 send_message 函数,然后我们使用 Facebook Graph messages API 对
Messenger 发回 POST 请求。在这期间我们一直没有回应我们阻塞的原始 Messenger请求。这会导致超时和 5XX 错误。

上述情况是我在解决遇到错误时发现的,当用户发送表情时实际上是发送的 unicode 标识符,但是被 Python 错误的编码了,最终我们发回了一些乱码。

这个发回 Messenger 的 POST 请求将永远不会完成,这会导致给初始请求返回 5xx 状态码,显示服务不可用。

通过使用 encode('unicode_escape') 封装消息,然后在我们发送回消息前用 decode('unicode_escape') 解码消息就可以解决。


  1. def send_message(token, recipient, text): 
  2.   """Send the message text to recipient with id recipient. 
  3.   """ 
  4.   r = requests.post("https://graph.facebook.com/v2.6/me/messages", 
  5.     params={"access_token": token}, 
  6.     data=json.dumps({ 
  7.       "recipient": {"id": recipient}, 
  8.       "message": {"text": text.decode('unicode_escape')} 
  9.     }), 
  10.     headers={'Content-type': 'application/json'}) 
  11.   if r.status_code != requests.codes.ok: 
  12.     print r.text 

部署到 Heroku

一旦代码已经建立成我想要的样子时就可以进行下一步。部署应用。

那么,该怎么做?

我之前在 Heroku 上部署过应用(主要是 Rails),然而我总是遵循某种教程做的,所用的配置是创建好了的。而在本文的情况下,我就需要从头开始。

幸运的是有官方 Heroku 文档来帮忙。这篇文档很好地说明了运行应用程序所需的最低限度。

长话短说,我们需要的除了我们的代码还有两个文件。第一个文件是“requirements.txt”,它列出了运行应用所依赖的库。

需要的第二个文件是“Procfile”。这个文件通知 Heroku 如何运行我们的服务。此外这个文件只需要一点点内容:


  1. web: gunicorn echoserver:app  

Heroku 对它的解读是,我们的应用通过运行 echoserver.py 启动,并且应用将使用 gunicorn 作为 Web 服务器。我们使用一个额外的网站服务器是因为与性能相关,在上面的 Heroku 文档里对此解释了:

Web 应用程序并发处理传入的 HTTP 请求比一次只处理一个请求的 Web 应用程序会更有效利地用测试机的资源。由于这个原因,我们建议使用支持并发请求的 Web 服务器来部署和运行产品级服务。

Django 和 Flask web 框架提供了一个方便的内建 Web 服务器,但是这些阻塞式服务器一个时刻只能处理一个请求。如果你部署这种服务到 Heroku 上,你的测试机就会资源利用率低下,应用会感觉反应迟钝。

Gunicorn 是一个纯 Python 的 HTTP 服务器,用于 WSGI 应用。允许你在单独一个测试机内通过运行多 Python
进程的方式来并发的运行各种 Python
应用。它在性能、灵活性和配置简易性方面取得了完美的平衡。回到我们之前提到过的“requirements.txt”文件,让我们看看它如何结合
Virtualenv 工具。

很多情况下,你的开发机器也许已经安装了很多 python 库。当部署应用时你不想全部加载那些库,但是辨认出你实际使用哪些库很困难。

Virtualenv 可以创建一个新的空白虚拟环境,以便你可以只安装你应用所需要的库。

你可以运行如下命令来检查当前安装了哪些库:


  1. kostis@KostisMBP ~ $ pip freeze 
  2. cycler==0.10.0 
  3. Flask==0.10.1 
  4. gunicorn==19.6.0 
  5. itsdangerous==0.24 
  6. Jinja2==2.8 
  7. MarkupSafe==0.23 
  8. matplotlib==1.5.1 
  9. numpy==1.10.4 
  10. pyparsing==2.1.0 
  11. python-dateutil==2.5.0 
  12. pytz==2015.7 
  13. requests==2.10.0 
  14. scipy==0.17.0 
  15. six==1.10.0 
  16. virtualenv==15.0.1 
  17. Werkzeug==0.11.10 

注意:pip 工具应该已经与 Python 一起安装在你的机器上。如果没有,查看官方网站如何安装它。

现在让我们使用 Virtualenv 来创建一个新的空白环境。首先我们给我们的项目创建一个新文件夹,然后进到目录下:


  1. kostis@KostisMBP projects $ mkdir echoserver 
  2. kostis@KostisMBP projects $ cd echoserver/ 
  3. kostis@KostisMBP echoserver $ 

现在来创建一个叫做 echobot 的新环境。运行下面的 source 命令激活它,然后使用 pip freeze 检查,我们能看到现在是空的。


  1. kostis@KostisMBP echoserver $ virtualenv echobot 
  2. kostis@KostisMBP echoserver $ source echobot/bin/activate 
  3. (echobot) kostis@KostisMBP echoserver $ pip freeze 
  4. (echobot) kostis@KostisMBP echoserver $ 

我们可以安装需要的库。我们需要是 flask、gunicorn 和 requests,它们被安装后我们就创建 requirements.txt 文件:


  1. (echobot) kostis@KostisMBP echoserver $ pip install flask 
  2. (echobot) kostis@KostisMBP echoserver $ pip install gunicorn 
  3. (echobot) kostis@KostisMBP echoserver $ pip install requests 
  4. (echobot) kostis@KostisMBP echoserver $ pip freeze 
  5. click==6.6 
  6. Flask==0.11 
  7. gunicorn==19.6.0 
  8. itsdangerous==0.24 
  9. Jinja2==2.8 
  10. MarkupSafe==0.23 
  11. requests==2.10.0 
  12. Werkzeug==0.11.10 
  13. (echobot) kostis@KostisMBP echoserver $ pip freeze > requirements.txt 

上述完成之后,我们用 python 代码创建 echoserver.py 文件,然后用之前提到的命令创建 Procfile,我们最终的文件/文件夹如下:


  1. (echobot) kostis@KostisMBP echoserver $ ls 
  2. Procfile     echobot     echoserver.py   requirements.txt 

我们现在准备上传到 Heroku。我们需要做两件事。第一是如果还没有安装 Heroku toolbet,就安装它(详见 Heroku)。第二是通过 Heroku 网页界面创建一个新的 Heroku 应用。

点击右上的大加号然后选择“Create new app”。

为你的应用选择一个名字,然后点击“Create App”。

你将会重定向到你的应用的控制面板,在那里你可以找到如何部署你的应用到 Heroku 的细节说明。


  1. (echobot) kostis@KostisMBP echoserver $ heroku login 
  2. (echobot) kostis@KostisMBP echoserver $ git init 
  3. (echobot) kostis@KostisMBP echoserver $ heroku git:remote -a <myappname> 
  4. (echobot) kostis@KostisMBP echoserver $ git add . 
  5. (echobot) kostis@KostisMBP echoserver $ git commit -m "Initial commit" 
  6. (echobot) kostis@KostisMBP echoserver (master) $ git push heroku master 
  7. ... 
  8. remote:        https://<myappname>.herokuapp.com/ deployed to Heroku 
  9. ... 
  10. (echobot) kostis@KostisMBP echoserver (master) $ heroku config:set WEB_CONCURRENCY=3 

如上,当你推送你的修改到 Heroku 之后,你会得到一个用于公开访问你新创建的应用的 URL。保存该 URL,下一步需要它。

创建这个 Facebook 应用

让我们的机器人可以工作的最后一步是创建这个我们将连接到其上的 Facebook 应用。Facebook 通常要求每个应用都有一个相关页面,所以我们来创建一个。

接下来我们去 Facebook 开发者专页,点击右上角的“My Apps”按钮并选择“Add a New App”。不要选择建议的那个,而是点击“basic setup”。填入需要的信息并点击“Create App Id”,然后你会重定向到新的应用页面。

 

在 “Products” 菜单之下,点击“+ Add Product” ,然后在“Messenger”下点击“Get
Started”。跟随这些步骤设置 Messenger,当完成后你就可以设置你的 webhooks 了。Webhooks
简单的来说是你的服务所用的 URL 的名称。点击 “Setup Webhooks” 按钮,并添加该 Heroku 应用的 URL
(你之前保存的那个)。在校验元组中写入
‘myvoiceismypasswordverifyme’。你可以写入任何你要的内容,但是不管你在这里写入的是什么内容,要确保同时修改代码中
handle_verification 函数。然后勾选 “messages” 选项。

点击“Verify and Save” 就完成了。Facebook 将访问该 Heroku 应用并校验它。如果不工作,可以试试运行:


  1. (echobot) kostis@KostisMBP heroku logs -t 

然后看看日志中是否有错误。如果发现错误, Google 搜索一下可能是最快的解决方法。

最后一步是取得页面访问元组(PAT),它可以将该 Facebook 应用于你创建好的页面连接起来。

从下拉列表中选择你创建好的页面。这会在“Page Access Token”(PAT)下面生成一个字符串。点击复制它,然后编辑 echoserver.py 文件,将其贴入 PAT 变量中。然后在 Git 中添加、提交并推送该修改。


  1. (echobot) kostis@KostisMBP echoserver (master) $ git add . 
  2. (echobot) kostis@KostisMBP echoserver (master) $ git commit -m "Initial commit" 
  3. (echobot) kostis@KostisMBP echoserver (master) $ git push heroku master 

最后,在 Webhooks 菜单下再次选择你的页面并点击“Subscribe”。

现在去访问你的页面并建立会话:

成功了,机器人回显了!

注意:除非你要将这个机器人用在 Messenger 上测试,否则你就是机器人唯一响应的那个人。如果你想让其他人也试试它,到Facebook 开发者专页中,选择你的应用、角色,然后添加你要添加的测试者。

总结

这对于我来说是一个非常有用的项目,希望它可以指引你找到开始的正确方向。官方的 Facebook 指南有更多的资料可以帮你学到更多。

你可以在 Github 上找到该项目的代码。

如果你有任何评论、勘误和建议,请随时联系我。

作者:Konstantinos Tsaprailis

来源:51CTO

时间: 2024-09-23 16:11:43

如何用 Python 和 Flask 建立部署一个 Facebook Messenger 机器人的相关文章

如何用 Python 和 Flask 建立部署一个 Facebook

这是我建立一个简单的 Facebook Messenger 机器人的记录.功能很简单,它是一个回显机器人,只是打印回用户写了什么. 回显服务器类似于服务器的"Hello World"例子. 这个项目的目的不是建立最好的 Messenger 机器人,而是让你了解如何建立一个小型机器人和每个事物是如何整合起来的. 技术栈 使用到的技术栈: Heroku 做后端主机.免费级足够这个等级的教程.回显机器人不需要任何种类的数据持久,所以不需要数据库. Python 是我们选择的语言.版本选择 2

在Docker上部署Python的Flask框架的教程_python

本文中,我将尝试展示用Docker开发python应用(主要是Web应用)的可行方法.虽然我本人专注于Python的Flask微框架,但本文目的是演示如何通过Docker更好地开发和共享应用程序,(由任何语言和框架开发的应用程序).Docker通过封装依赖项,大大减少了开发环境和正式产品的差距. 大多数Python开发人员在开发中使用virtualenv.它提供了一种易用的机制让应用程序使用自己专用的依赖项,这些依赖项可能与在其它应用程序或操作系统存在冲突(尤其是不同的Pyhton版本,还有不同

如何运用Python建立你的第一个Slack聊天机器人?

聊天机器人(Bot) 是一种像 Slack 一样的实用的互动聊天服务方式.如果你之前从来没有建立过聊天机器人,那么这篇文章提供了一个简单的入门指南,告诉你如何用 Python 结合 Slack API 建立你第一个聊天机器人. 我们通过搭建你的开发环境, 获得一个 Slack API 的聊天机器人令牌,并用 Pyhon 开发一个简单聊天机器人. 我们所需的工具 我们的聊天机器人我们将它称作为"StarterBot",它需要 Python 和 Slack API.要运行我们的 Pytho

利用Python的Flask框架来构建一个简单的数字商品支付解决方案_python

作为一个程序员,我有时候忘了自己所具有的能力.当事情没有按照你想要的方式发展时,却很容易忘记你有能力去改变它.昨天,我意识到,我已经对我所出售的书的付款处理方式感到忍无可忍了.我的书完成后,我使用了三个不同的数字商品支付处理器,在对它们三个都感到不满后,我用Python和Flask,两个小时的时间写出了我自己的解决方案.没错!两个小时!现在,这个系统支撑着我的书籍付费流程,整个过程难以置信的简单,你可以在20秒内购买书籍并开始阅读. 往下看,看我是如何在一夜之间完成我自己的数字商品支付解决方案的

python新手求助-如何用Python设计一个光路反射系统?

问题描述 如何用Python设计一个光路反射系统? 菜鸟求教..设置一道光线之后加平面镜显示反射之后的光路..基本思路是什么.. 解决方案 理想情况下,就是光路遇到障碍物沿着法线对称,出射角等于入射角,所以就是几何问题. 解决方案二: 用python设计的一个小游戏一个python的网络日志系统

如何用python保持一个16bit的png格式图片?

问题描述 如何用python保持一个16bit的png格式图片? 我现在有一个二进制的数据,想要保存成16bit的灰度图像,help... 解决方案 是不是可以直接把二进制转换成16bit.存入文件

如何用python把一个txt文件中所有逗号——,替换成空格?

问题描述 如何用python把一个txt文件中所有逗号--,替换成空格? 如何用python把一个txt文件中所有逗号--,替换成空格? 就是a,b之间就是去掉逗号,但保持点距离 解决方案 读取open文件.然后read读取内容.用replace替换内容.write写回文件

在Linux上安装Python的Flask框架和创建第一个app实例的教程_python

无论你在linux上娱乐还是工作,这对你而言都是一个使用python来编程的很好的机会.回到大学我希望他们教我的是Python而不是Java,这学起来很有趣且在实际的应用如yum包管理器中很有用. 本篇教程中我会带你使用python和一个称为flask的微型框架来构建一个简单的应用,来显示诸如每个进程的内存使用,CPU百分比之类有用的信息.前置需求 Python基础.列表.类.函数.模块.HTML/CSS (基础). 学习这篇教程你不必是一个python高级开发者,但是首先我建议你阅读https

30分钟搭建Python的Flask框架并在上面编写第一个应用_python

Flask 是一种很赞的Python web框架.它极小,简单,最棒的是它很容易学.今天我来带你搭建你的第一个Flask web应用!和官方教程 一样,你将搭建你自己的微博客系统:Flaskr.和官方Flask教程不同的是--我们通过使用Stormpath来创建并管理用户账户和数据,你的工作效率会更高.开发进程会显著地加快! 我们这就开始吧. 注意:这篇教程面向Flask开发新人,帮助他们理解如何使用Flask和Stormpath建立一个简单的网站.本文是Flask官方教程的改版.目标 Flas