如何在Google Cloud Platform上使用Webhooks部署Python Telegram机器人
而不是前言

-写一个电报机器人。 现在,即使是小学生也可以写作。
“然后为什么不呢?”我当时想(“好吧,”我现在要说)。
我们坐在Bean上,边喝咖啡边讨论了在不那么紧密的朋友圈中使用人工智能模型测试想法的可能性。 我的前同事莉娜(Lena)在各个方面都不是刚刚从地方法院毕业的金发女郎,他的理由如下。 通过创建机器人,您可以通过专注于机器学习的核心来节省接口的时间和精力。 您必须承认,在那个美丽的星期天早晨,无法抵制“女运动员,Komsomol成员和简单漂亮”这样的逻辑。 解决了。 电报机器人是指电报机器人。
首先,我爬入了Google,并找到了大量链接“如何在30分钟内制造机器人”。 它给了我很大的启发,以至于我没有超出名称范围,而是开始创建内核。 首先,我必须编写一个使用NLP(自然语言处理)的搜索查询处理系统。 编写内核花费了一些相当合理的时间(尽管如此,可口可乐的经验不能浪费)。 几天后,我准备在几个小时内将内核的第一个测试版本包装到其他几个发送-接收命令中,并在Telegram中运行所有这些操作,以使我的朋友们受益。 但事实确实如此。
突然出现了很多问题。 花了几天时间在互联网上搜索并与商店的同事交谈后,我意识到显而易见的东西并不明显,并且另一条“说明”也不会造成伤害。 所以这篇文章出现了。
而不是进入。 图书馆
有多个用于电报机器人的Python库。 电报本身指的是其中三个: python-telegram-bot , pyTelegramBotAPI , AIOGram 。 可以在Telegram网站上找到这些库和其他语言的示例的链接。 当然,仍然存在Telegram API本身 。 在实验过程中,我尝试了Telegram API和pyTelegramBotAPI的两个变体。 而停在第二。
通常,这些库的印象如下。 都非常相似,这不足为奇。 在我看来,Python-telegram-bot具有最好的文档,尽管有关它的工作已经停止(我希望我弄错了)。 可以看出,在pyTelegramBotAPI上的工作继续进行,出现了新功能。 AIOGram似乎越来越年轻。 在后者中,我不喜欢Webhooks上的文档,而是链接到Telegram网站。 但是,一切都会流动,一切都会改变。 最后的选择还有待做出。
在本文中,我们不会再讨论库的问题。
正如我已经提到的,关于机器人本身的代码,Internet上有许多手册专门用于创建简单和更复杂的程序。 就本文而言,这是无原则的。 为了确定起见,让我们从官方pyTelegramBotAPI github中获取两个示例:
- 使用轮询的电报机器人 ;
- 使用webhook的电报机器人 。
电报漫游器最有争议的主题是ssl证书,webhooks和diploing。 围绕这一点,集中我们的注意力。 下面,我将为您提供分步说明,使您可以在最短的时间内(至少在第一年内)以最简单,最可靠的方式将电报机器人放置在世界上最好的云服务之一上。 ssl证书的创建,在电报中的注册以及其他相关问题也将重点介绍。 如有必要,我将解释为什么我们使用这些团队。
轮询vs Webhook

如果不是因为轮询与Webhook之间的冲突以及Webhook的某些困难(部分是人为的),那么就不需要本文了。 由于这是至关重要的,因此让我们更详细地看一下。
什么是机器人,它如何与Telegram通信? 显然,机器人程序是在您的计算机或服务器上运行的程序。 通过发送和接收消息与电报进行通信。 如果发送消息一切都清楚了,那么一种选择就是发送(我们知道的“哪里”地址)。 有两种从Telegram接收机器人消息的选项。
第一个是Telegram服务器对机器人的消息的轮询(单词polling的字面翻译)。 第二个是带有IP地址(Webhook可以转换为Web陷阱)的“邮箱”,来自Telegram服务器的消息到达该邮箱。
与真实邮件最简单的比喻。 让mail(邮局)作为Telegram服务器,您就是您的机器人。 然后,在第一种情况下(轮询),您必须去邮局进行通信。 而且,如果您希望不延迟地接收消息,则不必走,而实际上来回奔波而无需喘息。 据我们了解,禁止在邮件中等待消息! 在第二种情况下,您告诉邮局您的家庭住址,然后在家里冷静地等待信件,喝茶或抽烟。
当然,对于一个人来说,第一选择似乎是最严厉的。 但是,在我们之间进行交谈时,如果我们在收到消息后发出带有代码的烙铁,那么我们就不在乎。 即使不是一个问题,也是如此。 邮件(电报服务器)有时会不时关闭午餐,然后移动。 在您的第一个选择(轮询)中,发生了一场悲剧,在机器人的真实世界中,悲剧以其徘徊和失败而告终。
在第二种情况下,带有地址(webhook)的“邮箱”不会发生。 因为您和您的机器人都不会走到任何地方,而只是等待。 而且,您不必在意邮局已移至何处,因为邮递员会将邮件带给您。
因此,就代码量而言(请参见上面的链接),第一种选择似乎更简单。 第二个更合乎逻辑,但更难。 对于其实现,您需要获取一个地址,确认其真实性并提升Web服务器,Telegram的消息将到达该Web服务器。
当然,对于第一种选择,可以在代码中添加异常处理。 例如,如果邮件已关闭,请等待。 但是互联网声称所有具有轮询功能的机器人都只是在玩。
起初,我不认为这个问题如此严重。 并且他选择了投票,建议我有一天将在网络钩子上重写它。 但这没有用。 在装有macOS的我的家用计算机上,该机器人可以正常工作一个小时和两个小时(当然,使用VPN),并且没有崩溃。 但是,一旦我将其转移到Linux上的云服务器上,它就无法工作20分钟。 我试图以不同的方式和设置解决此问题,但只收到了不同的错误代码。 塞拉维,这是电报。 失去了一天,我不得不毫不拖延地忙着上网。 最后,我想现在而不是一年内在服务器上启动该机器人。
在Webhook上重写代码
Webhook并不像绘制的那样可怕。
如果您已经具有带有轮询功能的漫游器代码,那么将其复制到webhook并不困难。 比较pyTelegramBotAPI库示例中的代码。 您会发现代码交集。 第一示例的线13-25与第二示例的线56-67相同。 这是一个逻辑单元,负责处理命令,消息和响应。 在这种情况下,示例太简单了,但它反映了主要的本质。
因此,僵尸程序的逻辑块必须保持不变,其余部分应使用第二个示例中逻辑块外部的普通复制粘贴代码进行更改(即复制行1至55和复制行70-87)。 如果您查看要复制的代码,则可以轻松地发现使用aiohttp库,您的机器人会安装一个http服务器并开始侦听为此端口分配的端口,而Python ssl模块负责加密和证书。 除了aiohttp外,还有其他类似的库,可以在此处找到示例。
这样啊 我们有一个带webhook的机器人。 它仍然可以将其上载到服务器并运行,同时接收数据以填充代码API_TOKEN,WEBHOOK_HOST,WEBHOOK_PORT,WEBHOOK_SSL_CERT,WEBHOOK_SSL_PRIV中的空值。 这些值的每个后面都是具有秘密含义的特定过程。
在电报中注册机器人
让我们从机器人令牌开始。 要获取它,请转到Telegram Messenger,并连接到@BotFather机器人。 输入命令“ / newbot”。 作为回应,BotFather提示我们输入机器人的名称和用户名,并发送令人垂涎的令牌,形式为“ 712308912:DLGSteczdUnPdnNYLzNikaGOhome7l9q3vova”(当然,您将拥有一个不同的令牌)。 我们保存令牌,请勿将其显示给任何人。 在代码中,我们将其分配给变量API_TOKEN。
在哪里发布? Google Cloud Platform与Heroku
关于选择云服务的痛苦的几句话。 Internet上有很多示例,其中电报机器人托管在Heroku上。 Heroku是PaaS平台(平台即服务)。 您将代码上传到GitHub,然后从那里上传到Heroku 。 您的机器人立即开始工作。 无需安装服务器,Python和库,一切都已经为您完成。 至少,理想情况下。 我的一位朋友也向我推荐了此解决方案。 但是我拒绝了。
据我了解,许多“ 30分钟机器人”手册中有关Heroku建议的主要信息是可在Heroku上获得免费的关税计划 。 但是,如果仔细观察,结果发现该计划非常有限,并且不允许您部署一个日夜工作的免费机器人。
与Heroku不同, Google Cloud Platform (GCP)在300美元以内的所有服务上提供了全年的免费工作。 对于这一年的费用,您可以尝试很多事情。 我认为这是一个了不起的礼物,特别是对于那些从事数据科学的人。 而且,当然,GCP也是PaaS,服务的完整列表在这里 。 和Heroku一样,有无服务器解决方案。 我为将来的控制选择了一条更为保守的路径,即GCP上的Compute Engine服务器解决方案。
谷歌云平台
项目,实例,静态ip,端口
创建一个项目和服务器
我们转到GCP,选择“免费入门”,然后按照说明进行操作。 如果我们做的一切正确,那么我们将拥有一个金额为300美元的帐户,甚至创建的第一个项目。 我们选择此项目或在顶部菜单中创建另一个项目,这并不困难。 然后转到打开的侧菜单中的“计算引擎/ VM实例”选项卡。
单击“ CREATE INSTANCE”,然后选择服务器配置,例如,如下面的屏幕快照所示。 您可以选择微型配置,然后每月只需花费$ 4。 您还可以改组,将从Google的礼物中扣除300美元的资金。
结果,我们得到了。
使IP地址静态
在“外部IP”列中,我们看到了我们在漫游器中驱动到WEBHOOK_HOST变量中的地址(在本示例中为35.224.231.90)。 稍后,我们将收到此地址的ssl证书。 如果您打算长时间使用该漫游器(即使您在GCP中更改了服务器),则我建议将此IP地址设为静态,以便在从一个实例切换到另一个实例时将其保存。 这是在“ VPC /外部IP地址”部分中完成的。
我们将“类型”字段从“星历”更改为“静态”,为静态地址命名,这样以后再打12个IP地址时就不会感到困惑。
开放端口
为了使Webhook正常工作,我们需要打开Telegram敲门的端口。 当前(2019年7月),Telegram支持以下端口:443、80、88、8443。有关更多详细信息,请参见Webhooks上的完整Telegram指南。 我们将打开端口8443。在我们的漫游器中,此值已分配给WEBHOOK_PORT变量。 仍然需要在GCP中为我们的webhook-bot实例配置防火墙规则。 怎么做? 转到“ VPC /防火墙规则”选项卡,然后单击“创建防火墙规则”。
并创建一个规则,如下面的屏幕截图所示。
我们连接到服务器,安装库
这样就完成了在Google Cloud Platform上的基本服务器设置。 我们在GCP上拥有一个帐户,创建了一个项目,在项目的一部分上创建了基于Ubuntu 19.04的服务器(实例),保留了IP地址,打开了端口8443。
剩下的很少。 希望我们可以在没有Python和库的安装部分详细说明的情况下进行操作。 因此,简要。
转到GCP标签“ Compute Engine / VM Instance”,然后在“ Connect”字段中单击“ SSH”。
终端应在您的本地计算机上打开,并可以访问GCP上的实例。 这是正常的Ubuntu环境。 安装conda或virtualenv ,创建一个虚拟环境并使用主库安装Python 3。 此外,我们安装了操作机器人所需的库:
点安装pyTelegramBotAPI
点安装aiohttp
安装后,请勿关闭终端,我们将需要它。
获取IP的自签名SSL证书
我必须说,在Internet上有关Telegram的ssl证书的话题令人震惊。 正如米哈伊尔·莱蒙托夫(Mikhail Lermontov)在这方面说的那样:
“人们把马堆成一堆,
和一千枪的抽射
陷入漫漫长啸...“
如果您阅读了他们在Internet上写的内容,事实证明,如果该漫游器无法在Webhooks上运行,则应归咎于错误接收的证书。 但是,它们不能在ip上注册。 通常,Telegram不接受自签名证书。 即使他接受了证书,这也不意味着您的机器人可以工作,而Telegram甚至不会发送错误。
这些都是恐怖的故事。 我为什么要写这个? 除了这些恐怖故事使我损失了又一天的事实之外,我什至不得不跳过看《霍比特人》。 我的机器人最初拒绝使用网络钩子。 发生这种情况是由于我将其放在服务器上时出错(当时我不知道)。 但是由于上述恐怖故事,我一直在寻找不存在的问题,重点是解决不存在的ssl证书问题。 但是我获得了宝贵的经验。 多年来,我以两个文件的形式和四个文件的形式注册了域名和IP上的自签名和付费证书。 我发现了哪些证书以及如何制作证书链。 我希望这能派上用场。
一件事是好的,您无需踩踏此耙,我已经为您做到了。 我完全承认,因为没有“不生烟的烟雾”,所以出现此类恐怖故事是有原因的。 但是就目前而言,情况似乎已经稳定下来。
现在,我们将以最方便的方式获得ssl证书,即ip(而不是域名),自签名(即免费)并且仅花费一行的费用,无需任何站点。
在终端(尚未关闭)中,准备一个单独的目录,用于保存证书文件和私钥。 进入该目录并从中调用以下命令。
$ openssl req -newkey rsa:2048 -sha256 -nodes -keyout url_private.key -x509 -days 3560 -out url_cert.pem
作为回应,您将收到填写多个简单字段的请求。 在下面的示例中填写它们。 但是,当然,请正确指出您所在国家,地区,城市,公司名称(如果有)的代码,并用您的IP和电子邮件代替。
结果,您将在运行此命令的目录中获得两个文件。 一个文件url_cert.pem是您的证书,第二个私钥是url_private.key。 在bot代码中,分别为变量分配了WEBHOOK_SSL_CERT和WEBHOOK_SSL_PRIV。 不要忘记输入这些文件的访问路径以及名称。 下载副本并保留以备将来参考。
不要关闭终端。
在电报中注册Webhook
使用自签名证书注册Webhook
也许这是“电报会说什么?”中最令人兴奋的部分。 没有任何前言,只需将以下命令驱动到终端即可。 用您的IP地址替换IP地址;请勿触摸端口8443。 将从BotFather收到的令牌插入“ / bot”和“ / setWebhook”之间,而不要插入YOUR-TOKEN。 从存储证书的目录中运行命令。
$ curl -F "url=https://35.224.231.90:8443" -F "certificate=@url_cert.pem" https://api.telegram.org/botYOUR-TOKEN/setWebhook
如果一切正确,您将在终端中从Telegram收到一条简明的消息,表明已安装Webhook。
用“正确的”证书注册一个webhook
如果没有自签名证书,则可以使用以下命令直接从浏览器安装webhook。
https://api.telegram.org/botYOUR-TOKEN/setWebhook?url=https://YOUR.DOMAIN:8443/YOUR-TOKEN/
请注意,您的令牌被两次显示。 此外,重要的是要指定证书中所示的YOUR.DOMAIN。 举个例子 我注册了mydreem.com域,注册服务商向我颁发了www.mydreem.com域的ssl证书。 您需要指定最后一个www.mydreem.com,而不是YOUR.DOMAIN。
如何检查webhook是否已安装?
您可以使用以下命令从浏览器检查是否安装了webhook:
https://api.telegram.org/botYOUR-TOKEN/getWebhookInfo
这适用于所有情况。 作为响应,万一安装了webhook并且机器人正在运行,您应该得到如下信息:
{"ok":true,"result":{"url":"https://35.224.231.90:8443/712308912:DLGSteczdUnPdnNYLzNikaGOhome7l9q3vova/","has_custom_certificate":true,"pending_update_count":0,"max_connections":40}}
或类似这样,当安装了webhook,但漫游器无法运行(未运行)时:
{"ok":true,"result":{"url":"https://35.224.231.90:8443/712308912:DLGSteczdUnPdnNYLzNikaGOhome7l9q3vova/","has_custom_certificate":true,"pending_update_count":2,"last_error_date":1564506964,"last_error_message":"Connection refused","max_connections":40}}
如何重置webhook?
有时,例如,在转移到另一个服务器(域)的情况下,可能需要更改僵尸程序的证书。 然后令牌仍然存在,并且证书更改(重新安装了Webhook)。 或者,有必要不在漫游器上而是在轮询上运行bot(如果已安装漫游器,则轮询将无法进行)。 在这两种情况下,“重置” webhook的命令都非常有用:
https://api.telegram.org/botYOUR-TOKEN/setWebhook
现在一切准备就绪,可以将代码上传到服务器并启动机器人了。 如果您是十根手指在命令行上的游戏高手,那么这对您来说并不困难。 一分钟后,您的机器人就可以使用了。 如果没有,那么下一节将有助于稍微简化将文件上载/下载到服务器并进行管理的任务。
云壳或“ Drop Dead Beautiful”
作为一个远离系统管理员的人,我很难理解为什么在人工智能时代,我们仍然像以前在EU / SM计算机上那样与命令行服务器通信。 假设有一些凡人都不知道的原因。 然后,必须非常高兴地接受GCP中的Cloud Shell之类的现象。 尽管带有拐杖,该工具仍允许,但在某种程度上方便了初学者的工作。 如果您不了解某些细微差别,可能会造成伤害。
Cloud Shell可直接从浏览器从命令行访问云资源。 你可以 容易的 无需在系统中安装Google Cloud SDK或其他工具即可管理您的项目和资源(最后两句话摘自其页面,我“很容易”将其划掉了)。 在此处可以找到如何从命令行管理项目的方法。 但是对我们而言,主要不是这个。 启动Cloud Shell(请参阅下面的gif,取自Google)。
您已登录Cloud Shell。 现在,如果您单击铅笔形式的按钮,“ beta版文本编辑器”将打开。
在“帮助/关于”菜单中,您可以找到它是“ theia-editor-for cloudshell-preview 0.0.1”。 在本文的结尾,我不会深入研究使用此编辑器的功能。 我将仅重点介绍关键点。 这不仅是几种语言的编辑器(仅使用Python检查),还是文件管理器。 您可以轻松地组织Cloud Shell与本地计算机之间的文件共享。 您可以使用鼠标在Cloud Shell空间中传输文件和目录。
请注意,除了使用编辑器可以编辑和管理服务器(实例)上的文件之外,我还没有写任何其他内容。 但这足以使我们的生活更轻松。 以及更多关于下面的内容。 现在,我将告诉您有关Cloud Shell的重要信息。 必须理解这一点,以免陷入我的困境。
Cloud Shell是基于Debian的服务器,具有5GB的磁盘空间和1.7GB的RAM。 已经预先安装了某些软件(包括Python)。 可以很容易地将Cloud Shell误认为您的实例,在其上安装conda,创建env并运行该bot。 而且,如果漫游器正在轮询,那么它将起作用。 如果在webhook上,则将无法使用,因为Cloud Shell上的所有端口均已关闭! 还有多少个实例未打开端口,它们将不会出现在Cloud Shell中。
由于我年轻的经验不足和粗心大意,我陷入了这个陷阱,并试图长时间了解了Telegram为什么看不到带有网络挂钩的机器人。 然后我很沮丧。 但是妻子变暖了,儿子们放心了,这篇文章出现了。
顺便说一句,Cloud Shell存在于时空之外(这是与事实相近的笑话)。 如果您从家中删除所有实例和所有项目,则您的Cloud Shell将会继续存在120天,其中包含您上传到其中的所有内容。 不要将其与备份服务器混淆。
这样啊 事先警告,然后武装。 现在我们可以讨论便利设施,并了解一些有用的命令。
例如,如果要使用Cloud Shell作为访问服务器的终端(例如,webhook-bot),则需要在命令行上激活实例:
$ gcloud compute ssh webhook-bot --zone us-central1-a
之后,您将在服务器的命令行中找到自己。 您可以使用“ exit”命令返回到Cloud Shell。 假设您要将一些文件从Cloud Shell复制到实例。 为此,在Cloud Shell命令提示符(不是实例)上,键入以下命令:
$ gcloud compute scp --recurse ~/telebot/my_favorite_robot.py webhook-bot:~/telebot --zone us-central1-a
如果您将源和目标一起更改,则将发生从实例到Cloud Shell的复制。 在下面的示例中,我们将文件“ ex1.py”从服务器“ webhook-bot”的目录“ / examples”复制到Cloud Shell的目录“ / telebot2”:
$ gcloud compute scp --recurse webhook-bot:~/examples/ex1.py --zone us-central1-a ~/telebot2
这些和其他文件共享命令可以在此处找到。 您不仅可以交换文件,还可以交换整个目录。 结果,我们得到了以下方案,使我们的生活更轻松。 在本地计算机上,我们通过编辑器“ theia-editor-for-cloudshell-preview 0.0.1”的文件管理器在Cloud Shell中单击鼠标上的几个按钮来复制文件。 然后,使用命令行将其重定向到我们的服务器(实例)。 如果需要快速编辑某些内容,可以在Cloud Shell的同一编辑器中进行操作,然后使用相同的命令将文件上传到服务器。 结果很快。
我相信在所有方面都存在更优雅,更便捷的方式来交换和管理GCP上的云服务器的文件(无需在本地计算机上安装其他程序)。 也许通过云存储 。 坦白说,我只花了几个小时就这个问题进行搜索和试验。 因此,如果您在评论中分享您的想法或可行的解决方案,我将不胜感激。
这样啊 我们将文件上传到服务器(实例)。 而且,如果您尚未启动该bot,那么该是通过转到服务器终端,激活必要的虚拟环境并键入诸如“ python my_webhook_bot.py”之类的命令来执行此操作的时候了。 一切都应该工作。 为了使机器人在终端关闭时能够继续工作,需要在后台启动它。 例如,“ nohup python my_webhook_bot.py&”。 除非您已经知道,否则我将寻求有关如何使流程脱离背景并完成流程的探索。
结论
我希望本文对您有所帮助,它有助于节省时间并避免我在编写带有Webhooks的电报机器人并将其放置在服务器上时犯的错误。 这篇文章中描述的所有内容我都经历了自己,在撰写本文时,即2019年7月至8月,它的工作原理就是这样。 我要特别感谢米哈伊尔·克鲁蒂科夫 ( Mikhail Krutikov)在GCP服务的广泛领域进行联合冲浪,并帮助实现了许多重要的真理。 我欢迎提出问题,进行讨论,对于本文评论中的建议,我将不胜感激。 或者随时通过Telegram @Eduard_Lanchev给我写信 。
直到最后一刻,我才开始问是否要链接到我的电报机器人。 朋友说服我,这是值得的。 您可以通过@AelitaSoccerBot与我的机器人聊天 。 机器人程序尚处于起步阶段,尚需进行大量工作。 因此,如果有问题,请写信,如果您想分享经验或提供建议,请写信。 我的感激之情不会在合理范围内。 注意事项 到2019年底,由于缺乏支持和开发时间,该机器人已被禁用。
最后,我谨祝所有botovods以及我的同事,数据科学家们取得成功!
有用的链接
- 电报Bot API
- Bot代码示例
- Python电报机器人
- pyTelegramBotAPI
- AIOGram
- ssl-套接字对象的TLS / SSL包装器
- Heroku
- 谷歌云平台
- 谷歌计算引擎
- 马文奇妙的万物指南Webhook
- 康达
- 虚拟环境
- 云壳
- gcloud计算命令行工具
- 使用gcloud命令行工具传输文件
- 谷歌云存储