扩展——你的第一个机器人(python-telegram-bot #1)
python-telegram-bot
是一个著名的Telegram bot第三方API库。考虑到这方面的中文资料还比较少,我就花了点时间把Extensions - Your first Bot这篇文章翻译了一下,顺便留着自己以后用。本文原链接:https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-Your-first-Bot
叠盾:我没有受过系统的计算机教育,英语水平近似于工地英语。欢迎你在评论区指出翻译错误,为此我将不胜感激。
官方的wiki上一共有四十多篇文章,我以后可能会挑几篇翻译出来。
扩展 —— 你的第一个机器人
⚠️这是v20.x版本的维基。对于v13.x版本,请看这里。
介绍
Telegram.ext
子模块建立在纯API实现之上。它提供了简单易用的接口(interface),减少了程序员的任务,使你不必重复工作。
它包含了一些类,但是最重要的是 telegram.ext.Application
。
Application
类负责从 update_queue
取得更新(update),这样, Updater
类不断从Telegram取得更新并加到队列里。如果你创建一个 Application
对象,使用 ApplicationBuilder
,这会自动创建一个 Updater
并且将它们与一个 asyncio.Queue
关联。然后,你可以在 Application
中注册(register)不同种类的处理程序(handler),这将会根据你注册的处理程序把从 Updater
取得的更新排序,并且将它们投送到你定义的回调函数。
每一个处理程序都是任何 telegram.ext.BaseHandler
类的任何子类的实例。这个库(library)提供了几乎所有使用情形的处理程序类,但是如果你需要特定的,你也可以自己创建 Handler
子类。
首先,你需要一个Access Token。如果你已经读了API介绍(Introduction to the API)并且照着做了,你可以使用你自己生成的。如果没有,为了生成一个Access Token,你需要与@BotFather对话并且照着做几个简单的步骤(介绍在这里)。虽然你真的应该先看介绍的。
你的第一个机器人,一步一步来
如果你想要找着这个教程做,请创建一个新文件。在教程中,我们会分几次在这个文件中添加新内容。为了简洁,当我们添加新东西的时候我们不会每时每刻重复每一件事。
好,让我们开始吧! 将下面的内容粘贴到你的文件中:
import logging
from telegram import Update
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!")
if __name__ == '__main__':
application = ApplicationBuilder().token('TOKEN').build()
start_handler = CommandHandler('start', start)
application.add_handler(start_handler)
application.run_polling()
现在有许多要消化的内容,那么让我们一步一步弄明白它吧。
import logging
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
这部分用于设置 logging
模块,以便让你知道什么时候(以及为什么)出了岔子:
注意: 阅读文章异常,警告与记录(Exceptions, Warnings and Logging)以了解更多。
application = ApplicationBuilder().token('TOKEN').build()
在这里,第一个真实魔法发生了:你必须创建一个 Application
对象。用你的Bot API token来替换 TOKEN
。想知道关于这个的工作原理的更多信息,看这页。
相关文档: telegram.ext.ApplicationBuilder
, telegram.ext.Application
单独的application什么也不做。为了添加功能,我们做两件事。首先,我们定义一个函数来处理特定类型的更新:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(
chat_id=update.effective_chat.id,
text="I'm a bot, please talk to me!"
)
这个的目的是,使机器人收到一条包含 /start
命令的Telegram消息后,调用这个函数。
如你所见,这个函数接收两个参数: update
,一个包含来自telegram信息和数据的对象(例如消息、发送命令的用户等); context
,另一个包含关于库本身的信息和数据的状态(像Bot
,Application
,job_queue
等等)。
相关文档: send_message
, telegram.ext.CallbackContext (context参数的种类)
, telegram.Update (update参数的种类)
为了让你的机器人监听 /start
命令,你可以使用 CommandHandler
(一个提供的 Handler
子类)并且在应用程序中注册:
from telegram.ext import CommandHandler
start_handler = CommandHandler('start', start)
application.add_handler(start_handler)
相关文档: telegram.ext.CommandHandler
, telegram.ext.Application.add_handler
这就是你所需要的全部。
最后,application.run_polling()
这一行使机器人运行起来,直到你按下CTRL+C
。
相关文档: telegram.ext.Application.run_polling
试试吧!和你的机器人开始对话,发送一个 /start
命令,如果一切正确的话,它将回复。
但是现在我们的机器人只回应 /start
命令。让我们添加另一个处理程序来监听常规消息。使用 MessageHandler
,另一个 Handler
子类,来复读所有文本消息。首先,按下 CTRL+C
来停下你的机器人,现在定义一个新函数并添加对应的处理程序:
from telegram import Update
from telegram.ext import filters, MessageHandler, ApplicationBuilder, CommandHandler, ContextTypes
...
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text=update.message.text)
if __name__ == '__main__':
...
echo_handler = MessageHandler(filters.TEXT & (~filters.COMMAND), echo)
application.add_handler(start_handler)
application.add_handler(echo_handler)
application.run_polling()
相关文档: telegram.ext.MessageHandler
, telegram.ext.filters
从现在开始,你的机器人应该复读所有它收到的非命令消息了。
注意: filters
模块包含许多所谓的过滤器(filter),用于过滤传入的文本、图片、状态更新(status update)等的消息。任何对至少一个过滤器返回 True
的、投送到 MessageHandler
的消息都会被接受。如果你想的话,也可以写自己的过滤器,参见Advanced Filters(高级过滤器)。
让我们给你的机器人加一些实际的功能吧。我们想要实现一个 /caps
命令,它把文本作为参数并把它们以大写形式回复。为了让事情简单些,你可以在回调函数里接收被传入命令的参数(作为一个 list(列表)
,用空格分割):
async def caps(update: Update, context: ContextTypes.DEFAULT_TYPE):
text_caps = ' '.join(context.args).upper()
await context.bot.send_message(chat_id=update.effective_chat.id, text=text_caps)
if __name__ == '__main__':
...
caps_handler = CommandHandler('caps', caps)
application.add_handler(start_handler)
application.add_handler(echo_handler)
application.add_handler(caps_handler)
application.run_polling()
注意:看一下 context.args
的用法。 CallbackContext
有一些属性,这取决于使用的处理程序。
另一个Telegram Bot API的很酷的功能是内联模式(inline mode)。如果你想为你的机器人实现内联功能,首先和@BotFather对话,并使用 /setinline
启用内联模式。有时候,你的机器人在你的客户端上注册为内联机器人之前,需要一点时间。通过重启你的Telegram App,你或许可以加速进程(或许有时,你只是需要等一会)。
显而易见,你的机器人已经是一个很大声的机器人了,让我们在内联模式上继续这个主题吧。到现在,你可能知道这个过程了,但是这里使用了很多新种类,所以注意:
from telegram import InlineQueryResultArticle, InputTextMessageContent
from telegram.ext import InlineQueryHandler
...
async def inline_caps(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.inline_query.query
if not query:
return
results = []
results.append(
InlineQueryResultArticle(
id=query.upper(),
title='Caps',
input_message_content=InputTextMessageContent(query.upper())
)
)
await context.bot.answer_inline_query(update.inline_query.id, results)
if __name__ == '__main__':
...
inline_caps_handler = InlineQueryHandler(inline_caps)
application.add_handler(inline_caps_handler)
application.run_polling()
相关文档: telegram.ext.InlineQueryHandler , answer_inline_query
不赖嘛!你的机器人现在可以根据命令通过内联模式大喊大叫了。(哈!)
一些感到困惑的用户可能试着给机器人发送一些它不理解的命令,那么你可以使用一个 MessageHandler
和一个 COMMAND
过滤器来回复在之前所有的处理程序中没有都被识别的命令。
...
async def unknown(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="Sorry, I didn't understand that command.")
if __name__ == '__main__':
...
# Other handlers
unknown_handler = MessageHandler(filters.COMMAND, unknown)
application.add_handler(unknown_handler)
application.run_polling()
注意:这个处理程序 必须 被放在最后。如果你把它放在其他的处理程序之前,它将会在 CommandHandlers
有机会查看更新前被触发。一旦一个更新被处理,其他的处理程序都将被忽略。为了避免这样,你可以把关键字参数 group (int)
以一个非0的值传递到 add_handler
。参看 telegram.ext.Application.add_handler
以及这个维基页获取更多细节。
如果你玩够了,按下 CTRL+C
使机器人停止运行吧。
接下来应该读什么呢?
看看这些准备好运行的例子吧。
在异常,警告与记录中学习库异常和最好的实践。
想要更多的功能吗?看看扩展————工作队列(Extension – JobQuene)吧!