楔子
Telegram(电报)置信大家都知道,关于它的引见和注册方式这里就跳过了,我假定你曾经注册好了。本篇文章来聊一聊Telegram 提供的机器人,以及如何用 Python 为机器人成功各种各样的性能。
创立机器人
首先咱们经常使用阅读器关上,而后用手机上的 APP 扫码登录。
登录之后搜查 BotFather,机器人须要经过 BotFather 来创立,当然BotFather 自身也是一个机器人,但它同时治理着其它的机器人。
咱们点击BotFather,上方将经过和它聊天的方式来创立机器人,环节如下。
1)在页面中输入命令 /newbot 并回车,相当于给 BotFather 发指令,示意要创立机器人。注:命令要以 / 扫尾。
2)BotFather 收到之后会将机器人创立好,并揭示咱们给机器人起一个名字,这里我起名为:古明地觉。
3)回车之后,BotFather 会继续让咱们给机器人起一个用户名,这个用户名会作为机器人的惟一标识,用于定位和查找。这里我起名为Satori_Koishi_bot,注:用户名必需以 Bot 或 bot 开头。
上方来实践演示一下。
咱们点击 t.me/Satori_Koishi_bot,看看结果如何。
点击 t.me/Satori_Koishi_bot 之后,再点击屏幕中的 start(相当于发送了一条 /start 指令),就可以和机器人聊天了。由于咱们还没有编写代码,来为机器人参与相应的性能,所以目前不会有任何事情出现。
而后咱们给自定义的机器人参与一些形容信息,显然这依赖于 BotFather。向其发送 /mybots 指令,会前往咱们创立的一切的机器人,当然这里目前只要一个。
咱们点击它,看看结果:
外面提供了很多的选项,这里咱们再点击 Edit Bot,来编辑机器人的关系信息。
不难发现,咱们除了给机器人一个名字之外,其它的信息就没有了,所以 Telegram 提供了一系列按钮,供咱们启动编辑。比如咱们点击 Edit Botpic,编辑头像。
而后机器人的头像会出现扭转,当然这些都属于精益求精的物品,最关键的是 Edit Commands,它是机器人能够发生行为的**,否则的机器人就是个绣花枕头,中看不中用。
上方咱们点击 Edit Commands,参与一个 /help 命令。
参与格局为命令 - 形容,可同时参与多个。
目前机器人便支持了 /help 命令,另外假设点击 Edit Command 之后再输入 /empty,那么也可以将机器人现有的命令清空掉。
只管 /help 命令有了,但发送这个命令之后,机器人不会有任何的反响,由于咱们还没有给命令绑定相应的处置函数,上方就来看看如何绑定。当然啦,机器人不光要对命令做出反响,就算是普通的文本、表情、图片等信息,也应该做出反响。至于命令实质上就是一个纯文本,只不过它应该以 / 扫尾。
接纳信息并处置
咱们可以经常使用 Python 衔接 Telegram 机器人,为它绑定处置函数,首先须要装置一个第三方库。
装置:pip3 install "python-telegram-bot[all]"
而后失掉机器人的 Token,这个 Token 怎样失掉呢?
像 BotFather 发送 /mybots 命令,点击指定机器人的 API Token 即可失掉。
有了这个 Token 之后,就可以和机器人建设衔接了。
import asyncioimport telegramfrom telegram.request import HTTPXRequest# 代理,由于不繁难展现,因此我定义在了一个独自的文件中# 这里的 PROXY 是一个字符串,相似于 "http://username:password@ip:port"from proxy import PROXYBOT_API_TOKEN = "6485526535:AAEvGr9EDqtc4QPehkgohH6gczOTO5RIYRE"async def main():# 传递机器人的 Token,外部会智能和它建设衔接bot = telegram.Bot(BOT_API_TOKEN,# 指定代理request=HTTPXRequest(proxy=PROXY),get_updates_request=HTTPXRequest(proxy=PROXY),)async with bot:# 测试衔接能否成功,假设成功,会前往机器人的信息print(await bot.get_me())asyncio.run(main())"""User(api_kwargs={'has_main_web_app': False},can_connect_to_business=False,can_join_groups=True,can_read_all_group_messages=False,first_name='古明地觉',id=6485526535,is_bot=True,supports_inline_queries=False,username='Satori_Koishi_bot')"""
前往值蕴含了机器人的详细信息,还是比拟繁难的,只需指定一个 Token 即可访问。当然啦,由于网络的要素还须要经常使用代理。
而后经过该模块还可以给机器人发信息,但这显然不是咱们的重点,由于信息必需是经过 APP 或许阅读器发送的。咱们要做的是,定义机器人的回复逻辑,当用户给它发信息时,它应该做些什么事情。
先来一个繁难的案例,当用户输入/start命令时,回复一段文本。
from telegram import Updatefrom telegram.ext import ApplicationBuilder, ContextTypes, CommandHandlerfrom proxy import PROXYBOT_API_TOKEN = "6485526535:AAEvGr9EDqtc4QPehkgohH6gczOTO5RIYRE"# 定义一个处置函数# update 封装了用户发送的信息数据# context 则封装了 Bot 对象和一些会话数据# 这两个对象十分关键,前面还会详细说async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):# context.bot 便是机器人,可以调用它的 send_message 方法回复信息await context.bot.send_message(# 关于 chat_id 稍后解释chat_id=update.message.chat.id,# 回复的文本内容text="欢迎到来地灵殿")# 构建一个运行application = ApplicationBuilder().token(BOT_API_TOKEN).proxy(PROXY).build()# 创立一个 CommandHandler 实例,当用户输入 /start 的时刻,口头 start 函数start_handler = CommandHandler("start", start)# 将 start_handler 加到运行当中application.add_handler(start_handler)# 开启有限循环,监听事情application.run_polling()
咱们来测试一下:
显然结果是成功的,不过目前这个机器人只能处置 /start 命令,假设宿愿它支持更多的命令,那么就定义多个 CommandHandler 即可。然而疑问来了,假设咱们宿愿这个机器人能处置普通文本的话,该怎样办呢?
from telegram import Updatefrom telegram.ext import (ApplicationBuilder, ContextTypes,MessageHandler, filters)from proxy import PROXYBOT_API_TOKEN = "6485526535:AAEvGr9EDqtc4QPehkgohH6gczOTO5RIYRE"async def reply(update: Update, context: ContextTypes.DEFAULT_TYPE):await context.bot.send_message(chat_id=update.message.chat.id,# 经过 update.message.text 可以拿到用户发送的信息text=f"古明地觉已收到,你发的内容是:{update.message.text}")application = ApplicationBuilder().token(BOT_API_TOKEN).proxy(PROXY).build()# 前面经常使用了 CommandHandler,它专门用来处置命令,第一个参数应该是字符串# 比如第一个参数是 "start",那么就给机器人参与了一个回复 /start 命令的性能# 而 MessageHandler 可以用于回复一切类型的信息,比如文本、表情、图片、视频等等# 详细能回复哪些,经过第一个参数指定。这里示意只需用户发送了文本信息,就口头 reply 函数reply_handler = MessageHandler(filters.TEXT, reply)application.add_handler(reply_handler)application.run_polling()
测试一下:
结果没有疑问,并且 /start 命令也被当成普通的文本处置了,由于命令实质上就是一个文本。而后辈码中的 filters,它外面除了有示意文本类型的 TEXT,还有很多其它类型。
# 命令filters.COMMAND# 普通文本(包括 emoji)filters.TEXT# Telegram 贴纸包中的贴纸filters.Sticker.ALL# 图片文件filters.PHOTO# 音频文件filters.AUDIO# 视频文件filters.VIDEO# 文档(例如 PDF、DOCX 等等)filters.Document.ALL# 语音(经常使用 Telegram 录制的语音)filters.VOICE# 天文位置filters.LOCATION# 咨询人filters.CONTACT# 动画,通常是 GIFfilters.ANIMATION# 经过 Telegram 的视频笔记过能录制的视频filters.VIDEO_NOTE# 假设宿愿同时支持多种类型,那么可以经常使用 | 启动衔接# 比似乎时支持 "文本" 和 "图片"filters.TEXT | filters.PHOTO# 当然也可以取反,~filters.TEXT 示意除了文本以外的类型~filters.TEXT# | 和 ~ 都出现了,显然还剩下 &,而 & 也是支持的# 咱们知道命令实质上就是一个以 / 扫尾的文本# 假设咱们宿愿只处置普通文本,不处置命令,该怎样办呢?# 很繁难,像上方这样指定即可,此时以 / 扫尾的文本(命令)会被疏忽掉filters.TEXT & ~filters.COMMAND# 除了以上这些,filters 还支持其它类型,有兴味可以看一下# 当然 filters 还提供了一个 ALL,示意一切类型filters.ALL
而后留意一下外面的 filters.Sticker 和 filters.Document,这两个类型比拟不凡,它们外部还可以细分,这里咱们就不细分了,间接 .ALL 即可。
咱们来测试一下,看看这些类型信息都长什么样子。
from telegram import Updatefrom telegram.ext import (ApplicationBuilder, ContextTypes,MessageHandler, filters)from proxy import PROXYBOT_API_TOKEN = "6485526535:AAEvGr9EDqtc4QPehkgohH6gczOTO5RIYRE"async def get_message_type(update: Update, context: ContextTypes.DEFAULT_TYPE):# 失掉信息message = update.message# 失掉信息类型if message.text:if message.text[0] == "/":message_type = "filters.COMMAND"else:message_type = "filters.TEXT"elif message.sticker:message_type = "filters.Sticker"elif message.photo:message_type = "filters.PHOTO"elif message.audio:message_type = "filters.AUDIO"elif message.video:message_type = "filters.VIDEO"elif message.document:message_type = "filters.Document"elif message.voice:message_type = "filters.VOICE"elif message.location:message_type = "filters.LOCATION"elif message.contact:message_type = "filters.CONTACT"elif message.animation:message_type = "filters.ANIMATION"elif message.video_note:message_type = "filters.VIDEO_NOTE"else:message_type = "filters.<OTHER TYPE>"await context.bot.send_message(chat_id=update.message.chat.id,text=f"你发送的信息的类型是 {message_type}")application = ApplicationBuilder().token(BOT_API_TOKEN).proxy(PROXY).build()reply_handler = MessageHandler(filters.ALL, get_message_type)application.add_handler(reply_handler)application.run_polling()
咱们发几条信息,让机器人通知咱们信息的类型。
至于其它类型,感兴味可以测试一下。
update 和 context
处置函数外面有两个参数,区分是 update 和 context。它们十分关键,咱们来打印一下,看看长什么样子。
async def reply(update: Update, context: ContextTypes.DEFAULT_TYPE):pprint(update.to_dict())await context.bot.send_message(chat_id=update.message.chat.id,text="不想谈话")application = ApplicationBuilder().token(BOT_API_TOKEN).proxy(PROXY).build()reply_handler = MessageHandler(filters.ALL, reply)application.add_handler(reply_handler)application.run_polling()
上方发送一条文本信息。
而后检查 update.to_dict() 的输入是什么,为了繁难了解,我将字段顺序调整了一下。
{'message': {# 能否创立了频道,由于是私聊,所认为 False'channel_chat_created': False,# 聊天照片能否已被删除,私聊普通也为 False'delete_chat_photo': False,# 能否创立了群组,由于是私聊,所认为 False'group_chat_created': False,# 能否创立了超级群组,由于是私聊,所认为 False'supergroup_chat_created': False,# "发送者" 发送的信息# 由于发送的是文本,所以这里是 text 字段'text': '这是一条文本信息',# 信息发送的期间'date': 1722623118,# 信息的 ID'message_id': 84,# 信息发送者的信息'from': {'first_name': '小云','id': 6353481551,'is_bot': False,'language_code': 'zh-hans','last_name': '同窗'},# chat 示意会话环境,机器人要经过 chat 判别信息应该回复给谁# 由于目前是和机器人私聊,所以机器人的回复对象就是信息的发送者# 因此外面的 first_name、last_name、id 和信息发送者是分歧的# 但假设是群聊,那么外面的 id 字段则示意群组的 id# 此外还会蕴含一个 title 字段,示意群组的称号'chat': {'first_name': '小云','last_name': '同窗',# 不论 chat 的类型是什么,外面必定会蕴含 id 字段# 这个 id 或许是用户的 id,也或许是群组的 id# 总之有了这个 id,机器人就知道要将信息回复给谁# 所以代码中的 send_message 方法至少要蕴含两个参数# 区分是 chat_id(发送给谁)和 text(发送的内容)'id': 6353481551,# chat 的类型,定义在 filters.ChatType 中# ChatType.PRIVATE:公家对话# ChatType.GROUP:普通群组聊天# ChatType.SUPERGROUP:超级群组聊天# ChatType.GROUPS:普通群组聊天或超级群组聊天# ChatType.CHANNEL:频道,用于向订阅者广播信息'type': '<ChatType.PRIVATE>'},},# 每发送一条信息,会话都在降级,所以 update_id 示意降级的惟一标识符# 用于跟踪降级,以确保信息处置没有失落或重复'update_id': 296857735}
以上就是 update.to_dict() 的输入结果,当用户向 bot 发送信息时,Telegram 主机会将这些数据以 JSON 的方式发送给的运行程序,以便 bot 可以处置和照应这些信息。当然啦,咱们这里经常使用的库会将数据封装成 Update 对象,因此失掉数据时,可以有以下两种失掉方式。
chat_id = update.to_dict()["message"]["chat"]["id"]chat_id = update.message.chat.id
以上是当用户发送文本信息时,Telegram 发送的数据,咱们再试一下其它的,比如上行一个文档。
{'message': {'channel_chat_created': False,'delete_chat_photo': False,'group_chat_created': False,'supergroup_chat_created': False,'chat': {'first_name': '小云','id': 6353481551,'last_name': '同窗','type': '<ChatType.PRIVATE>'},'date': 1722628661,# 由于发送的是文档,所以这里是 document 字段'document': {'file_id': 'BQACAgUAAxkBAANgZq06NVL6......','file_name': 'OpenAI.pdf','file_size': 2279632,'file_unique_id': 'AgADLw8AAn36cFU','mime_type': 'application/pdf','thumb': {'file_id': 'AAMCBQADGQEAA2BmrTo1Uv......','file_size': 22533,'file_unique_id': 'AQADLw8AAn36cFVy','height': 320,'width': 243},'thumbnail': {'file_id': 'AAMCBQADGQEAA2BmrTo1U......','file_size': 22533,'file_unique_id': 'AQADLw8AAn36cFVy','height': 320,'width': 243}},'from': {'first_name': '小云','id': 6353481551,'is_bot': False,'language_code': 'zh-hans','last_name': '同窗'},'message_id': 96,},'update_id': 296857741}
至于其它的类型也是相似的,可以自己试一下,比如上行一段视频,看看打印的输入是什么。
不过还有一个疑问,就是当用户上行音频、视频、文档等,bot 如何失掉它们呢?显然要依赖外面的 file_id。
async def download(update: Update, context: ContextTypes.DEFAULT_TYPE):document = update.message.documentfile_id = document.file_id# 文件 idfile_size = document.file_size# 文件大小file_name = document.file_name# 文件名# 用户上行的文件会保留在 Telegram 主机,咱们可以基于文件 id 失掉file_obj = await context.bot.get_file(file_id)# file_obj.file_path 便是文件的地址,间接下载即可with open(file_name, "wb") as f:resp = httpx.get(file_obj.file_path, proxy=PROXY)f.write(resp.content)await context.bot.send_message(chat_id=update.message.chat.id,text=f"{file_name} 下载终了,大小 {file_size} 字节")application = ApplicationBuilder().token(BOT_API_TOKEN).proxy(PROXY).build()download_handler = MessageHandler(filters.Document.ALL, download)application.add_handler(download_handler)application.run_polling()
咱们上行几个文件试试。
结果没有疑问,用户上行的文件也下载到了本地。
回复富文本信息
目前机器人回复的都是普通的纯文本,但也可以回复富文本信息。
async def rich_msg(update: Update, context: ContextTypes.DEFAULT_TYPE):message = update.messageif message.text == "baidu":text = '<a href="https://www.baidu.com">点击进入百度页面</a>'elif message.text == "zhihu":text = '<a href="https://www.zhihu.com">点击进入知乎页面</a>'elif message.text == "bilibili":text = '<a href="https://www.bilibili.com">点击进入 B 站页面</a>'else:text = 'Unsupported Website'await context.bot.send_message(chat_id=update.message.chat.id,text=text,# 依照 HTML 启动解析parse_mode="HTML")
测试一下:
结果没有疑问,另外咱们看到 a 标签自带预览性能,假设不宿愿预览,那么也可以禁用掉。
将disable_web_page_preview 参数指定为 False,即可禁用 a 标签的预览性能。另外发送的信息除了可以依照 HTML 格局解析,还可以依照 Markdown 格局解析,将 parse_mode 参数指定为 "Markdown" 或许 "MarkdownV2" 即可。
回复其它类型的信息
目前机器人回复的都是文本,那么能不能回复音频、视频、图片呢?显然是可以的,并且它们还可以和文本一同前往。
# 发送图片await context.bot.send_photo(chat_id=update.message.chat.id,# 可以是门路、句柄、bytes 对象# 曾经上行到 Telegram 主机的文件会有一个 file_id# 指定 file_id 也是可以的photo="path/to/image.jpg",)# 发送音频await context.bot.send_audio(chat_id=update.message.chat.id,# 可以是 门路、句柄、bytes 对象、file_idaudio="path/to/audio.mp3")# 发送视频await context.bot.send_video(chat_id=update.message.chat.id,# 可以是 门路、句柄、bytes 对象、file_idvideo="path/to/video.mp4")# 发送文档await context.bot.send_document(chat_id=update.message.chat.id,# 可以是 门路、句柄、bytes 对象、file_iddocument="path/to/document.pdf")# 发送语音await context.bot.send_voice(chat_id=update.message.chat.id,# 可以是 门路、句柄、bytes 对象、file_idvoice=r"path/to/voice.ogg",)# 发送位置await context.bot.send_location(chat_id=update.message.chat.id,latitude=40.4750280, lnotallow=116.2676535)# 发送咨询人from telegram import Contactcontact = Contact(phone_number='+8618510286802',first_name='芙兰朵露',# 以下两个参数也可以不指定last_name='斯卡雷特',user_id=5783657687)await context.bot.send_contact(chat_id=update.message.chat.id,cnotallow=contact)# 发送贴纸await context.bot.send_sticker(chat_id=update.message.chat.id,# 可以是 门路、句柄、bytes 对象、file_idsticker="CAACAgIAAxkBAAO5Zq5kRNKkIGZpH......")# 发送 GIFawait context.bot.send_animation(chat_id=update.message.chat.id,# 可以是 门路、句柄、bytes 对象、file_idanimatinotallow="CgACAgIAAxkBAAPBZq5lekVT95I......")
除了以上这些,还可以发送其它类型的信息,不过不罕用,有兴味的话可以自己看一下,这些方法都以 send_ 扫尾。而后咱们来发几条信息,测试一下。
结果没有疑问。
媒体组
如今咱们曾经知道如何让机器人回复不同种类的信息了,但假设我想成功更复杂的性能,比似乎时发送多张图片、多个视频,并且还配带文字,要怎样做呢?或许有人觉得这还不繁难,写个循环不就行了,比如要发送 5 个视频,那么调用 5 次 send_video 方法不就好了。
首先这是一种方法,但循环 5 次,那么这 5 个视频是作为不同的信息分开发送的。更多时刻,咱们是宿愿作为一个全体发送,那么此时可以经常使用媒体组性能。
from telegram import Update, InputMediaPhotofrom telegram.ext import (ApplicationBuilder,ContextTypes,CommandHandler)from proxy import PROXYBOT_API_TOKEN = "6485526535:AAEvGr9EDqtc4QPehkgohH6gczOTO5RIYRE"async def send_media_group(update: Update,context: ContextTypes.DEFAULT_TYPE):media_group = [# 可以是 URL、bytes 对象、文件句柄、file_idInputMediaPhoto(open('satori1.png', "rb"), captinotallow="古"),InputMediaPhoto(open('satori2.png', "rb"), captinotallow="明"),InputMediaPhoto(open('satori3.png', "rb"), captinotallow="地"),InputMediaPhoto(open('satori4.png', "rb"), captinotallow="觉")]# 发送媒体组await context.bot.send_media_group(chat_id=update.message.chat.id,media=media_group)application = ApplicationBuilder().token(BOT_API_TOKEN).proxy(PROXY).build()download_handler = CommandHandler("satori", send_media_group)application.add_handler(download_handler)application.run_polling()
咱们输入命令 /satori,应该会前往 4 张图片。
结果没有疑问,并且这 4 张图片是全体作为一条信息发送的。而后咱们在代码中还指定了一个 caption 参数,它是做什么的呢?咱们点击一下图片就知道了。
点击图片加大检查时,captaion 会显示在图片下方。另外,假设发送了多张图片,但只要一张图片指定了 caption 参数,那么该 caption 会和图片一同显示,咱们举例说明。
async def send_media_group(update: Update,context: ContextTypes.DEFAULT_TYPE):caption = "+v ❥(^_-) 解锁地灵殿暗藏福利"media_group = [# 可以是 URL、bytes 对象、文件句柄、file_idInputMediaPhoto(open('satori1.png', "rb")),InputMediaPhoto(open('satori2.png', "rb")),InputMediaPhoto(open('satori3.png', "rb"), captinotallow=caption),InputMediaPhoto(open('satori4.png', "rb"))]# 发送媒体组await context.bot.send_media_group(chat_id=update.message.chat.id,media=media_group)
只要一张图片指定了 caption 参数,咱们看看成果。
此时图片会和文字一同显示,当然你也可以不指定 caption 参数,而是在发送完图片之后,再调用一次性 send_message。这种做法也是可以的,只不过此时图片和文字会作为两条信息分开显示。
以上是发送图片,除了图片之外还可以发送音频、视频、文档,并且只支持这 4 种。但要留意:它们不能混在一同发,只要图片和视频可以,咱们测试一下。
from telegram import (Update,InputMediaPhoto,InputMediaAudio,InputMediaVideo,InputMediaDocument)from telegram.ext import (ApplicationBuilder,ContextTypes,CommandHandler)from proxy import PROXYBOT_API_TOKEN = "6485526535:AAEvGr9EDqtc4QPehkgohH6gczOTO5RIYRE"async def send_media_group(update: Update,context: ContextTypes.DEFAULT_TYPE):video_caption = ("这游戏我玩不下去了,装备喂养和贴膜就算了,""但自定义词条我是真忍不了,洗不进去,基本洗不进去。")media_group = [InputMediaPhoto(open("satori1.png", "rb")),InputMediaVideo(open("DNF 装备销毁.mp4", "rb"),captinotallow=video_caption),# 也支持发送音频和文档,但不能混在一同# InputMediaAudio(open("3rd eye.mp3", "rb")),# InputMediaDocument(open('OpenAI.pdf', 'rb'))]# 发送媒体组await context.bot.send_media_group(chat_id=update.message.chat.id,media=media_group)application = ApplicationBuilder().token(BOT_API_TOKEN).proxy(PROXY).build()download_handler = CommandHandler("test_media_group", send_media_group)application.add_handler(download_handler)application.run_polling()
测试一下:
结果反常,只是由于视频和图片是一同前往的,所以没有预览性能,须要点击之后才会播放。并且咱们只给视频指定了 caption 参数,所以文字间接显示在了下方,假设媒体组中有多个 caption,那么就不会独自显示了,须要点击加大之后能力看到。
当然啦,假设你不须要同时发送多个媒体文件,那么就没必要调用 send_media_group 方法了,间接经常使用之前的方法即可。
这些方法一次性性只能发送一个媒体文件,比如发送视频。
async def send_video(update: Update, context: ContextTypes.DEFAULT_TYPE):video_caption = ("这游戏我玩不下去了,装备喂养和贴膜就算了,""但自定义词条我是真忍不了,洗不进去,基本洗不进去。")await context.bot.send_video(chat_id=update.message.chat.id,video="DNF 装备销毁.mp4",captinotallow=video_caption,# 让 caption 显示在上方,自动显示在下方show_caption_above_media=True,)application = ApplicationBuilder().token(BOT_API_TOKEN).proxy(PROXY).build()download_handler = CommandHandler("destroy", send_video)application.add_handler(download_handler)application.run_polling()
测试一下:
怎样样,是不是很幽默呢?另外 caption 还可以是富文本,只需将 parse_mode 参数指定为"HTML"、"Markdown" 或 "MarkdownV2" 即可。
比如创立一个命令:/get,它的性能如下。
而后在代码中参与一个CommandHandler("get", get_table),便可让用户经过 Telegram 查问数据库表,当然这里只是打个比如,详细怎样做取决于你的想法。另外多说一句,假设你宿愿输入 / 之后能像上方那样有揭示,那么须要经过 BotFather 启动设置。
要强调的是,这种方式只是起到一个揭示作用,揭示机器人支持 /get 命令。但机器人实践上能否支持,取决于代码中能否为机器人成功了 /get。所以当咱们在代码中为机器人参与完命令之后,可以再经过 Edit Commands 启动设置,这样当用户输入 / 之后,机器人有哪些命令以及形容都会显示进去。
当然啦,假设你不经过Edit Commands 启动设置的话,也是可以的,只是用户输入 / 之后不会有揭示罢了,但命令是会回复的,只需在代码中成功了。同理,假设经过Edit Commands 设置了,但代码中没成功,那么该命令也不会有成果。
自定义按钮
只管目前的机器人曾经很弱小了,然而还不够,咱们看一下 BotFather。
你会发现它上方带了很多的按钮,点击按钮之后会口头相应的逻辑,那咱们要怎样成功这些按钮呢?
from telegram import (Update,InlineKeyboardMarkup,InlineKeyboardButton,)from telegram.ext import (ApplicationBuilder,ContextTypes,CommandHandler)from proxy import PROXYBOT_API_TOKEN = "6485526535:AAEvGr9EDqtc4QPehkgohH6gczOTO5RIYRE"async def add_button(update: Update, context: ContextTypes.DEFAULT_TYPE):text = "作为<i>程序猿</i>,你最青睐哪种编程言语呢?"# 设置按钮reply_markup = InlineKeyboardMarkup([# 第一行[InlineKeyboardButton(text="Python", url="https://www.python.org")],# 第二行[InlineKeyboardButton(text="Golang", url="https://golang.org")],# 第三行[InlineKeyboardButton(text="Rust", url="https://www.rust-lang.org")],# 第四行[InlineKeyboardButton(text="Zig", url="https://ziglang.org")],])await context.bot.send_message(chat_id=update.message.chat.id,text=text,parse_mode="HTML",reply_markup=reply_markup)application = ApplicationBuilder().token(BOT_API_TOKEN).proxy(PROXY).build()download_handler = CommandHandler("language", add_button)application.add_handler(download_handler)application.run_polling()
测试一下:
此时按钮就成功了,由于在InlineKeyboardButton 外面指定的是 url,所以这是跳转按钮,点击之后会关上指定的页面。并且按钮的右上角还有一个小箭头,示意按钮是跳转按钮。
但除了跳转按钮之外,还有回调按钮,也就是点击按钮之后会口头回调函数,咱们举例说明。
from telegram import (Update,InlineKeyboardMarkup,InlineKeyboardButton,)from telegram.ext import (ApplicationBuilder,ContextTypes,CommandHandler,CallbackQueryHandler,)from proxy import PROXYBOT_API_TOKEN = "6485526535:AAEvGr9EDqtc4QPehkgohH6gczOTO5RIYRE"async def add_button(update: Update, context: ContextTypes.DEFAULT_TYPE):text = "o(╥﹏╥)o