聊天机器人目前非常流行,一些人预测它们将比移动应用程序更强大。聊天机器人的主要思想是,您无需深入研究尴尬的移动菜单和学习 UI,只需通过熟悉的方式与机器人进行对话即可。
即时通讯界面。如果您想订购披萨,您可以与 Domino's Pizza 机器人开始对话,并与它进行与人类对话相同的对话。

有一些不同的平台允许您构建自己的聊天机器人。其中之一是 Telegram,它可以说是最简单的使用方式,并且越来越受欢迎。

在本教程中,我们将逐步使用 Python 构建一个简单的 Telegram 机器人。首先,我们的机器人将简单地回显我们发送给它的任何消息,但随后我们将扩展它以添加数据库并在聊天会话中保留信息。

我们将使用 Python 来支持我们的 Bot 和 SQLite,以跨会话持久存储信息。总之,这是一个教程系列,它将:

  • 向您展示如何使用 Python 和 Telegram Bot API 从头开始​​编写简单的 Echo Bot(第 1 部分)
  • 将 Echo Bot 扩展为由 SQLite 数据库支持的 ToDo 列表管理机器人(第 2 部分)
  • 展示如何从 VPS 运行我们的机器人并允许其扩展到更多用户(第 3 部分)。

尽管创建 Echo Bot 非常简单,并且您可以在网上找到各种脚本和框架,这些脚本和框架将为您提供以此作为起点 - 我们将从头开始做所有事情并解释我们编写的每一段代码。我们还将研究 Telegram API 中的一些微妙之处,并讨论这些对我们作为开发人员意味着什么。如果您只是想尽快创建一个 Telegram 机器人,本教程可能不是您想要的,但如果您想更深入地了解聊天机器人的工作原理以及如何从头开始构建聊天机器人,那么您可以重新来对地方了。

你需要什么

您需要:

  • 学习本教程需要一些基本的 Python 知识
  • 您应该熟悉在 Linux Shell、MacOS 终端或 Windows 命令提示符中运行命令
  • 您应该能够使用 pip 包管理器(或者 conda,如果您对此更熟悉的话)安装 Python 包
  • 理想情况下,您之前应该至少编写过一条基本 SQL 语句,但这并不是绝对必要的(并且仅在第 2 部分中相关)。

所有代码都针对 Python 3.5,但它应该可以轻松适应其他版本的 Python。

为什么选择Python?

您可以用任何您想要的语言编写 Telegram 聊天机器人。除了 Python 之外,一些主要选项还有 Java、PHP 或 Ruby。如果您更熟悉另一种高级编程语言,那么您可能更喜欢使用它,但 Python 是一个不错的选择,原因如下:

  • Python通过requests模块可以非常简洁简单地发出HTTP请求。从 URL 获取内容(这就是我们控制 Telegram 机器人的方式)将需要比 Python 等价物更多的 Java 行。
  • Python 是自然语言处理和机器学习中最流行的语言:虽然我们不会在简单的机器人中使用这两种语言,但对于更高级的机器人来说,这两种语言都是必需的。因此,如果您想扩展 Bot,最好熟悉 Python。
  • Python 对提供 Web 内容有很好的支持:当我们想要扩展我们的 Bot 以允许其每秒接收许多消息时,Python 拥有 WSGI 等成熟的技术来达到“Web 规模”。
  • Python 是可移植的——我们可以轻松地在 Linux、MacOS 或 Windows 上运行相同的代码。

配置

requestsurllibpippip3--用户
pip3 安装请求

如果您通常为新的 Python 项目使用虚拟环境,那么首先设置其中一个,然后在其中安装请求。

创建 Telegram 机器人

第一步是告诉 Telegram 您想要创建一个新的机器人。我们的机器人发送和接收的所有消息都将通过 Telegram 的基础设施。我们的代码将定期发出请求,从 Telegram 的服务器检索所有新消息到我们的机器人,然后根据需要发送对每条消息的响应。为了使用 Telegram 注册机器人,您首先需要创建一个个人 Telegram 帐户。访问 web.telegram.org 并输入您的电话号码。 Telegram 将向您发送一条短信 (SMS),然后您可以按照屏幕上的说明创建一个帐户。如果您已经有 Telegram 帐户,那么您可以简单地使用该帐户,并且您还可以使用 telegram.org 上提供的任何 Telegram 桌面和移动应用程序,而不是我们将在所有示例中使用的 Web 应用程序。本教程。

/
/纽博特
待办事项机器人
待办事项机器人
botexampletodo_bot

现在 Bot Father 将向您发送一条“恭喜”消息,其中包含一个令牌。令牌应该看起来像这样:

2483457814:AAHrlCx234_VskzWEJdWjTsdfuwejHyu5mI

记下该令牌,因为我们将在即将编写的代码中需要它。

通过网络浏览器与我们的机器人交互

我们可以通过向 Telegram 发送 HTTPS 请求来控制我们的机器人。这意味着与我们的机器人交互的最简单方法是通过网络浏览器。通过访问不同的 URL,我们向机器人发送不同的命令。最简单的命令是我们获取有关机器人的信息的命令。在浏览器中访问以下 URL(替换您之前获得的机器人令牌)

https://api.telegram.org/bot/getme
/bot/getme
{“ok”:true,“result”:{“id”:248718785,“first_name”:“待办事项机器人”,“username”:“exampletodo_bot”}}

检索发送到我们的机器人的消息

getUpdateshttps://api.telegram.org/bot/获取更新
getUpdatestelegram.me/@/开始
https://api.telegram.org/bot/获取更新
{“确定”:true,“结果”:[{“update_id”:625407400,“消息”:{“message_id”:1,“来自”:{“id”:24860000,“first_name”:“Gareth”,” last_name":"Dwyer (sixhobbits)","用户名":"sixhobbits"},"聊天":{"id":24860000,"first_name":"Gareth","last_name":"Dwyer (sixhobbits)","用户名":"sixhobbits","类型":"私人"},"日期":1478087433,"文本":"\/start","实体":[{"类型":"bot_command","偏移量": 0,"length":6}]}},{"update_id":625407401,"message":{"message_id":2,"from":{"id":24860000,"first_name":"Gareth"," last_name":"Dwyer (sixhobbits)","用户名":"sixhobbits"},"聊天":{"id":24860000,"first_name":"Gareth","last_name":"Dwyer (sixhobbits)","用户名":"sixhobbits","类型":"私人"},"日期":1478087624,"文本":"测试"}}]}
结果

从我们的机器人发送消息

获取更新idchat
https://api.telegram.org/bot/sendMessage?chat_id=&text=TestReply

访问此 URL 后,您应该会看到一条从您的机器人发送到您的消息,上面写着“TestReply”。

现在我们知道如何使用 Telegram API 发送和接收消息,我们可以通过用 Python 编写一些逻辑来自动化此过程。

为我们的机器人编写 Python 代码

回声机器人
import json import requests TOKEN = "" URL = "https://api.telegram.org/bot{}/".format(TOKEN) def get_url(url): response = requests.get( url) content = response.content.decode("utf8") 返回内容 def get_json_from_url(url): content = get_url(url) js = json.loads(content) return js def get_updates(): url = URL + "getUpdates" js = get_json_from_url(url) 返回 js def get_last_chat_id_and_text(updates): num_updates = len(updates["结果"]) last_update = num_updates - 1 text = 更新["结果"][last_update]["消息"]["文本" ] chat_id = 更新["结果"][last_update]["消息"]["聊天"]["id"] return (text, chat_id) def send_message(text, chat_id): url = URL + "sendMessage?text= {}&chat_id={}".format(text, chat_id) get_url(url) text, chat = get_last_chat_id_and_text(get_updates()) send_message(text, chat)

让我们分解一下这段代码的作用:

requestsjsonget_url.decode("utf8")get_json_from_urljson.loads()loadsget_updatesget_last_chat_id_and_textchat_idtextsend_messagetextchat_idsendMessage
发信息

目前,我们的脚本不会侦听新消息并立即回复。相反,当我们运行它时,我们的机器人将仅获取发送到该消息的最新消息并回显它。我们可以通过向机器人发送消息然后运行脚本来测试它。试一试吧!

我们的机器人存在缺陷

我们的 Bot 最明显的问题是,每次我们想要与其交互时,都必须手动运行 Python 脚本。此外,如前所述,我们总是下载 Telegram 提供的整个消息历史记录。这既低效又不可靠,因为如果我们只想要一条消息,我们不想不必要地下载整个消息历史记录,而且 Telegram 只保留此更新列表 24 小时。另一个问题是,我们将消息作为字符串传递,但由于该消息在发送到 Telegram 之前会转换为 URL,因此您会注意到,如果您向机器人发送带有特殊字符的消息(例如, + 符号将从所有回显消息中消失)。最后,如果我们尝试在没有新消息接收的情况下运行它,机器人会抛出索引错误。

我们现在将机器人更新为:

  • 不断聆听新消息并回复每条消息。
  • 收到每条消息后予以确认,并告诉 Telegram 不要再向我们发送该消息。
  • 使用长轮询,这样我们就不必发出太多请求。
  • 正确编码我们的消息以考虑 URL 格式。

监听新消息

mainif __name__ == '__main__'
时间
导入时间

并将文件的最后两行更改为如下:

def main(): last_textchat = (None, None) while True: text, chat = get_last_chat_id_and_text(get_updates()) if (text, chat) != last_textchat: send_message(text, chat) last_textchat = (text, chat) 时间。睡眠(0.5)如果 __name__ == '__main__': main()
最后的文本聊天

确认我们已经看到的消息

getUpdatesupdate_idgetUpdatesoffsetupdate_idupdate_id

修改我们的机器人如下:

抵消
def get_updates(offset=None): url = URL + "getUpdates" if offset: url += "?offset={}".format(offset) js = get_json_from_url(url) return js
  • 添加一个函数,计算我们从 getUpdates 收到的所有更新的最高 ID。这应该如下所示。
def get_last_update_id(updates): update_ids = [] 用于更新 update["result"]: update_ids.append(int(update["update_id"])) return max(update_ids)
获取更新
  • 添加一个函数来为我们收到的每条消息发送回显回复。这应该如下所示:
def echo_all(updates): 对于更新中的更新["结果"]: 尝试: text = update["message"]["text"] chat = update["message"]["chat"]["id"] send_message (文本、聊天)例外为 e: print(e)
主要的()
def main():last_update_id = None while True:updates = get_updates(last_update_id) if len(updates["result"]) > 0:last_update_id = get_last_update_id(updates) + 1 echo_all(updates) time.sleep(0.5)

我们的主代码不再需要担心重复的消息,因为每次收到新消息时,我们都会将最大的 update_id 与下一个请求一起发送,确保我们只收到以前从未见过的消息。

主要的()

通过重新启动 Python 脚本并向您的机器人发送一些消息来尝试更改 - 您应该看到它像以前一样工作,但现在发送重复消息或发送消息太快都没关系,这两者都是很大的改进。

使用长轮询

获取更新超时
获取更新
def get_updates(offset=None): url = URL + "getUpdates?timeout=100" if offset: url += "&offset={}".format(offset) js = get_json_from_url(url) return js
超时?偏移={}&偏移={}?&
print("获取更新")while Truemaintimeout

正确编码我们的消息文本

网址库

在 .py 文件的顶部添加以下行

导入urllib
发信息
def send_message(text, chat_id): text = urllib.parse.quote_plus(text) url = URL + "sendMessage?text={}&chat_id={}".format(text, chat_id) get_url(url)

再次重新启动 Bot,并向其发送一些之前有问题的消息,例如:

+ 你好+ 你好&测试

现在它应该能够完美地回复所有这些消息(以及您向其发送的几乎所有其他消息,包括表情符号)。

第 1 部分结束

本教程的第一部分到此结束。我们从头开始使用 Telegram Bot API 构建了一个简单的 Echo Bot,并实现了一些更高级的功能,例如跟踪我们已经处理的消息、使用长轮询以及正确编码 URL 消息。在下一部分中,我们将添加一个数据库并将我们的机器人变成更有用的东西 - 待办事项列表。

此处介绍的 Echo Bot 的最终代码清单可以在 https://github.com/sixhobbits/python-telegram-tutorial 中找到。

本教程的第 2 部分可以在此处找到。

本教程的第 3 部分是如何将机器人部署到 VPS 的现场演示。