Python 编写 Telegram机器人

Telegram机器人 可以实现强大的自动化功能,能实现丰富的交互和定制化选项,同时具备高度的安全性和稳定性。

本文的目标是,在您实际配置环境、运行代码、走通全流程之后,就会了解 tg机器人 能够干什么,进而根据需求有针对地查找文档,然后开发。作为入门教程,能让读者掌握“自力更生”的方法和方向,就是最高的追求,所谓“授之以”。

I might have made some mistakes, please let me know if I’ve gotten anything wrong!


先自荐一个 tg 转发机器人,避免存入 tg 收藏夹然后吃灰。

项目地址: AhFeil/extract_forward_tgbot: 存储转发给它的消息,并能推送到网页,方便查看编辑信息,附带拼接图片、视频转 GIF 功能。(github.com)

它的最基本使用: (更多请查看 GitHub 项目首页)

  1. 把消息转发给它,或者直接发消息
  2. 它会提取其中的文本和内链网址并将之保存,内链网址会按照顺序放到文本后面。
  3. 发送指令 /push ,它会将保存的全部内容推送网页记事本,并返回网址。
  4. 在电脑访问网页,查看并高效处理。

注册 Telegram机器人 和配置

注册一个机器人(Bot)

注册过程很简单,在 telegram 中向“机器人之父”发消息,即 https://t.me/BotFather

  1. 打开与 @BotFather 的对话框
  2. 发送 /start (开始)
  3. 发送 /newbot
  4. 发送 Bot 的 name(昵称)
  5. 指定 Bot 的 username(用户名、ID),注意这个用户名必须以 bot 结尾,而且不能更改
  6. 如果没重名,注册完成,发来的消息中有 Bot 的 token,格式是这样的: 6111111110:AAxxxxxvfly2xxxx9iGxxLa_atxxcomxuNU

保存好 token ,不要泄露

register-Telegram-Bot.png

By the way, when you’ve finished creating your cool bot, ping our Bot Support if you want a better username for it. Just make sure the bot is fully operational before you do this.

好像可以这么改用户名

获取 chat_id

先注册好机器人,点 start 后,向新注册的机器人随意发送消息,然后打开网址:

# 修改里面的 token 部分,开头的 bot 别删了
https://api.telegram.org/bot6111111110:AAxxxxxvfly2xxxx9iGxxLa_atxxcomxuNU/getupdates

其中 "chat" 里的 "id" 就是给机器人发消息的账户的 chat_id,保存。

机器人可以通过其他账户的 chat id 发消息,前提是这个用户先主动跟机器人发过消息。

向 Bot 添加指令

指令的本质是以 / 开头的文本,因此可以直接发送 /command 触发,而不必通过点菜单

通过 BotFather 来为 Bot 设置指令,流程是,发送 /setcommands ,然后选中要修改的机器人,接着按照格式发送指令列表即可,格式为 command - 介绍

start - 看看我能干什么
push - 推送到网页
emsg - 保存里的最早的一条消息
dmsg - 删最新的一条并返回文本
clear - 清空转存信息

之后点 Bot 输入框左边的 M,即可看见设置的指令列表。

配置 Bot 的个性化介绍

发送 /mybots ,选择一个机器人,接着【Edit Bot】,这里面能编辑名称、头像和介绍,还有指令。

其中 About 编辑的是下面界面展示的

customize-About-Telegram-Bot.png

Description 则是第一次进入机器人时的这个界面:

customize-Description-Telegram-Bot.png

实际上,也可以在机器人的对话框处找到编辑介绍信息的选项,电脑、手机皆可,更方便。


Telegram Bot 官方

官方文档: Bots: An introduction for developers (telegram.org)
API 文档: Telegram Bot API
tg 官方列的一些库: Bot API Library Examples (telegram.org)

当然,这些底层 API 文档是给开发库的工作人员准备的,我们要开发机器人的话,是通过成熟的机器人框架进行的,开发更快、程序更可靠。

一些限制

不完整,仅是记录

注意: 机器人必须设置为频道管理员,否则无法在频道里发送消息

机器人在频道可以通过 @name 向用户发消息,但是直接向个人对话只能通过 chat_id 才行

并且,机器人只能在用户向它发过消息,或将机器人加入一个群组之后,才能主动向用户发消息。机器人不能向陌生用户主动发消息。

custom keyboard & inline keyboard

Customer keyboard 和 inline keyboard 有以下几点区别:

  1. inline keyboard 出现在输入区之上,而custom keyboard出现在键盘输入区之下;
  2. 按下inline keyboard 会返回给bot一个callback query,而按下custom keyboard只后只会给bot发送一条文本信息,本质和同为文本的command是一样的。

用浏览器直接查看(webhook)

在编写代码之前,推荐先手动用 webhook 查看机器人收到的信息,有个直观的认识

Telegram 的 API 接口形式是 URL,它和我们平常使用的网址是类似的。

可以将以下的 URL 复制在浏览器的网址栏中,将 Your Token 替换为实际的 Token,然后访问:

https://api.telegram.org/botYour Token/getupdates

# 就比如,这样
https://api.telegram.org/bot6111111110:AAxxxxxvfly2xxxx9iGxxLa_atxxcomxuNU/getupdates

向 bot 发送一条消息之后,刷新浏览器,你会得到以下类似下面的 Message:

{'chat': {'first_name': 'Jean',
          'id': 24601,
          'last_name': 'Valjean',
          'type': 'private',
          'username': 'MonsierMadeleine'},
 'date': 17691833,
 'from': {'first_name': 'Jean',
          'id': 24601,
          'is_bot': False,
          'last_name': 'Valjean',
          'username': 'MonsierMadeleine'},
 'message_id': 7417,
 'text': 'I am warning you Javert'}

message 以 json 的形式被包装和发送,它的本质是 nested dictionary,嵌套字典。


如果你在地址栏中键入如下 URL:

https://api.telegram.org/botYour Token/sendMessage?chat_id="Some Chat id"&text="Hello"

https://api.telegram.org/bot6111111110:AAxxxxxvfly2xxxx9iGxxLa_atxxcomxuNU/sendMessage?chat_id=2066666604&text="Hello"

替换为实际的 Token 和 chat ID,编辑 text,回车后,你的Bot就会将”Hello“发送给指定用户。

形式类似地,Telegram规定了很多功能,比如 sendMessage,sendPhoto 等。

message 的 key 包括 chat(用户的名字,ID和聊天的种类),date(消息发送的日期),from(发送者的信息),message_id(指向特定的一条信息),而 text 就是用户所发送消息的文本。

在telegram中,聊天的种类分为三种,private, group 以及 channel


开始编程 python-telegram-bot

Python 库使用 python-telegram-bot ,其相关网站如下:


推荐创建三个文件,比如 main.pytgbotBehavior.py ,前一个用来设置路由和注册以启动路由,后一个放具体的函数(定义机器人对接收的数据做出什么反应)。

还有 config.py ,用来配置 token 等配置信息的。

流程图来了!

实际编写

我是看这个库 wiki 入门的: Extensions Your first Bot (github.com)

可以看一遍下面 AhFei 写的小例子,对于母语为中文的比官方 wiki 好理解一些。更多的也没必要写,库官方的文档才是最好的参考。

这个例子只需要填入 bot_token ,剩下的完全复制粘贴就能运行(如果是国内网络,还需要配置代理地址)。

推荐有兴趣的可以先跑一遍,成功的话再修改。


先拉库(Python 3.7+)

pip3 install python-telegram-bot~=20.3

先看 config.py ,配置 bot_token ,还有代理地址即可。

# config.py
import platform
import os
import sys

# 将参数值赋给变量
bot_token = "6111111110:AAxxxxxvfly2xxxx9iGxxLa_atxxcomxuNU"

# 下面跟机器人没什么关系,主要作用方便开发,比如在 Windows 开发,配置代理和修改一些变量的值,如果是国外 Linux 作为生产环境,就不需要代理了

system = platform.system()  # 获取操作系统名字
if system == 'Windows':
    # 处于开发环境
    os.environ["http_proxy"] = "http://127.0.0.1:10809"
    os.environ["https_proxy"] = "http://127.0.0.1:10809"
elif system == 'Linux':
    # 处于生产环境
    pass
else:
    sys.exit('Unknown system.')

再看 main.py ,这里就导入三个动作,start, myid, other_command ,并配置路由,也就是

  1. 机器人收到 ‘/start’ 后,就执行 start 函数
  2. 机器人收到 ‘/myid’ 后,就执行 myid 函数
  3. 机器人收到指令之外的内容,就执行 other_command 函数
# main.py
from telegram import Update   # 获取消息队列的
from telegram.ext import filters, MessageHandler, ApplicationBuilder, CommandHandler

import config
# 从 tgbotBehavior.py 导入定义机器人动作的函数
from tgbotBehavior import start, other_command, myid

if __name__ == '__main__':  
    # 创建机器人实例的,在这里放入 token
    application = ApplicationBuilder().token(config.bot_token).build()  

    # 类似路由,接收到 /start 执行哪个函数,左边是指令,右边是定义动作的函数
    application.add_handler(CommandHandler('start', start))
    # 返回用户 chat id 的
    application.add_handler(CommandHandler('myid', myid))
    # (~filters.COMMAND)  filters 是过滤,~ 是取反,就是所有非指令的消息  
    application.add_handler(MessageHandler((~filters.COMMAND), other_command))

    # 启动,直到按 Ctrl-C
    application.run_polling(allowed_updates=Update.ALL_TYPES)

最后看 tgbotBehavior.py ,就是定义机器人的各种动作。

# tgbotBehavior.py
from telegram import Update  
from telegram.ext import ContextTypes  

import config  

# 回复固定内容  
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):  
    # 定义一些行为
    pass
    # 向发来 /start 的用户发送消息,chat_id 后跟用户的 chat_id,text 就是发送的内容
    await context.bot.send_message(chat_id=update.effective_chat.id,  
                                   text=f"这是一个转存机器人")  

# 返回 ID
async def myid(update: Update, context: ContextTypes.DEFAULT_TYPE):  
    # update.effective_chat.id 就是向机器人发消息的那个用户的 chat id
    your_chat_id = update.effective_chat.id  
    await context.bot.send_message(chat_id=your_chat_id, text=f'你的 chat id 是 {your_chat_id}')  

async def other_command(update: Update, context: ContextTypes.DEFAULT_TYPE):  
    # 定义一些行为
    # 省略
    pass

运行主程序 python3 extract_forward_tgbot.py ,然后试试效果

  • 发送 /start ,就会收到“这是一个转存机器人”,
  • 发送 /myid,就会收到“你的 chat id 是 123456789”
  • 其他信息则没有任何回应

其实这个库的结构蛮清晰的,先编写定义动作的函数,再配置路由和使能。
参考文档就能编写出功能丰富的机器人啦!

使用 systemd 守护进程

实际在 Linux 上运行机器人时,可以使用 systemd 使之持久运行、开机自启,具体配置可以参考本站的这篇文章: Telegram 转发机器人 的部署流程

CheatSheet

如果你看过「用浏览器直接查看(webhook)」这一节的内容并实操过,就会发现下面的结构与网页上的是一一对应的,可以查看网页来查找怎么获取信息。

  • 用户 ID : update.effective_chat.id

  • 转发来源: update.message.forward_from_chat.title 和 update.message.forward_from_chat.username ,前者是频道名称,后者是 @用户名

  • 转发的消息源 ID: update.message.forward_from_message_id

  • 文本消息内容: update.message.text

  • 图片消息的文字内容: update.message.caption

获得图片的 URL

bot = Bot(token="")
file_id = message.photo[-1].file_id   # 这是取分辨率最高的那一张
the_file = await bot.get_file(file_id)
url = the_file.file_path

这个网址是由机器人申请的,而不是永久连接,保证在 1 小时内有效

后记

当你的机器人功能变得丰富时,可能要依靠很多参数,比如一些 API 的端点,数据库的配置;另外,还可能有保存用户配置的需求。这些可以归纳为配置管理和数据读写,也就是程序与外部的数据交互。

如果是零散地在代码中保存配置、将参数硬编码到代码中,将来代码会变得越来越难以阅读和维护,增加功能将会遇到很多困难。AhFei 的转发机器人就是这样的情况,由于先天缺少 Data 类,很难增添用户的个性化配置,功能受限,它是 AhFei 第一个真正的 Python 项目,一开始没什么经验。

为此,我在之后的项目中,都特别看重配置管理和数据读写,推荐有一定项目经验的人看看我的这篇文章: 中小型 Python 项目配置和数据读写的最佳实践 – 技焉洲 (yanh.tech) ,希望一起交流,探讨最好用的中小项目程序结构。


原文链接: https://yanh.tech/2023/08/register-telegram-bot-and-build-a-bot-using-python/

版权声明:本博客所有文章除特別声明外,均为 AhFei 原创,采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 技焉洲 (yanh.tech)

保持更新 ٩(•̤̀ᵕ•̤́๑)ᵒᵏᵎᵎᵎᵎ 清晰恒益的实用技能,欢迎使用 RSS 订阅,如果能留言互动就更好了。

可在 Telegram 群组 https://t.me/vfly2 交流依文章步骤遇到的问题。

评论

  1. cofo
    4 月前
    2024-8-08 22:34:20

    想要知道机器人回复的时候如何 一条消息中包含图片和文本

    • cofo
      3 月前
      2024-8-11 0:46:09

      实质上,这种包含图文的消息依然是图片 photo 消息类型,其中的文字被称为 caption ,在发送图片的时候传参 caption 应该就可以,官方文档链接是: https://docs.python-telegram-bot.org/en/v21.4/telegram.bot.html#telegram.Bot.send_photo

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇