如何用 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

相关文章
|
15天前
|
Python
python3之flask快速入门教程Demo
python3之flask快速入门教程Demo
37 6
|
16天前
|
开发框架 数据库 开发者
Web开发新境界:用Python玩转Django和Flask!
【6月更文挑战第12天】Python的Web开发框架Django和Flask各有千秋。Django是全能型框架,适合快速开发大型应用,提供ORM、模板引擎、URL路由和后台管理等全面功能。Flask则轻量级且灵活,适用于小型到中型应用,以其简单易用、高度可扩展和灵活路由著称。两者结合使用,能应对各种Web开发需求。
|
17天前
|
Java Serverless 应用服务中间件
Serverless 应用引擎操作报错合集之部署python项目时,构建过程报错,怎么解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
10天前
|
关系型数据库 MySQL 数据库
如何使用Python的Flask框架来构建一个简单的Web应用
如何使用Python的Flask框架来构建一个简单的Web应用
21 0
|
1月前
|
应用服务中间件 nginx Docker
使用 Python Flask 创建简易文件上传服务
在平时工作中,文件上传是一项常见的需求,例如将应用异常时通过脚本生成的dump文件收集起来进行分析,但实现起来却可能相当复杂。幸运的是,Flask框架提供了一种简单而高效的方式来处理文件上传,代码不到100行。在本文中,我们将探讨如何使用Flask实现文件上传功能,编写Dockerfile将应用程序通过docker部署。
|
11天前
|
分布式计算 DataWorks 调度
阿里云DataWorks-部署自定义python项目问题
阿里云DataWorks-多种方式部署自定义python项目并进行调度
|
11天前
|
存储 数据挖掘 索引
Python streamlit框架开发数据分析网站并免费部署
使用Python的Streamlit框架,开发了一个在线数据分析工具,替代Excel查看设备温度CSV数据。通过pandas读取数据,matplotlib绘制图表。程序处理CSV,提取所需列,计算最大最小平均值,用户可多选查看特定数据。[GitHub](https://github.com/yigedaigua/MGHB)上有完整代码,应用已部署至Streamlit Cloud。
|
13天前
|
存储 Linux Docker
python项目 以docker形式打包部署全流程
在很久很久以前,我已经听过Docker的大名,当时服务着急上线虽然考虑过用Docker来部署我的服务,但是因为赶期的原因放弃了。 这两天因为华为云服务器到期,而且阿里云服务器优惠力度特别大的原因,我要把华为云服务器里的工程迁移到阿里云。 迁移的过程中,大量的时间精力浪费在了重装python,加载依赖,迁移项目,配置端口等环境配置的工作上。 我在想,如果当时用了Docker部署,我至于受这气?
|
19天前
|
DataWorks 算法 安全
DataWorks产品使用合集之如何部署自己写的Python算法
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
18 5
|
1月前
|
应用服务中间件 API nginx
使用Python和Flask构建RESTful Web API
使用Python和Flask构建RESTful Web API
37 0

热门文章

最新文章