Featured image of post [新手篇] 如何写一个简单的上膛机器人

[新手篇] 如何写一个简单的上膛机器人

介绍

一个检测关键词并自动回复表情包的 Telegram 机器人。

开发

注册一个机器人

  1. 访问 Telegram 的官方注册机器人 @BotFather

  2. 使用 /newbot 命令创建一个新的机器人。它会询问你所要创建机器人的名字 (nickname) 和用户名 (username, 以_bot结尾),注册成功后会将机器人的 TOKEN 返回给你,而这个 TOKEN 用于告知服务器这个机器人就是(大明湖畔那个夏雨荷)对应注册的机器人。

botfather

1
2
3
4
...
Use this token to access the HTTP API:
`<1145141919810:TheWholeSentenceIsToken>`
Keep your token secure and store it safely, ...

安装 Python 环境

官方网站: https://www.python.org/downloads

对于绝大多数 Linux 发行版来说从其自己的包管理器中安装 Python 即可(2021 年了应该都默认 Python3?)

Windows 则 Python 官方提供了安装器,记得把 Python 加到环境变量 (PATH) 的框给勾选上。

为了避免开发环境不干净对后续开发和使用系统造成影响,建议创建一个用于该机器人项目的虚拟环境(virtual environment)

1
$ python -m venv .venv // 创建了一个名为 .venv 的隐藏文件夹

对于国内使用 PyPi 源速度不是很给力的情况,可以考虑替换镜像源为清华源

也可以写入默认配置文件 ~/.config/pip/pip.conf(如果没有则创建

1
2
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple

可以查看设置是否生效

1
2
3
$ pip config list 

global.index-url='https://pypi.tuna.tsinghua.edu.cn/simple'

创建虚拟环境后,您可以激活它,进入项目所在目录。

  • 在 Windows 上,运行:
1
tutorial-env\Scripts\activate.bat
  • 在 Unix 或 MacOS 上,运行:
1
$ source tutorial-env/bin/activate

对于 cshfish shell 分别对应名为 activate.cshactivate.fish 的脚本

安装软件包依赖

python telegram bot 项目地址

1
$ pip install python-telegram-bot --upgrade

也可以将依赖导出到文件,便于开发迁移

1
$ pip freeze > requirements.txt 

Coding Time

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def main():
    # 从环境变量中读取 TOKEN 减少硬编码可能带来的泄漏风险
    # 如果只是本地测试的话可以直接把 TOKEN 粘贴到程序中
    TOKEN = os.getenv('TELEGRAM_BOT_TOKEN')

    # Updater 是 Dispatcher 的实现,用于机器人数据交互的前端,
    # 负责更新消息队列并交付给其他调度程序
    updater = Updater(token=TOKEN, use_context=True)
    dispatcher = updater.dispatcher

    # 开始拉取信息
    updater.start_polling()

    # 响应终止信号 Ctrl+C
    updater.idle()

if __name__ == "__main__":
    main()

上述几行代码构成了整个机器人的基本框架,包含了机器人身份认证和开启机器人服务等。我们还需要向该框架内注册具体的方法,以实现所需功能。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def start(update: Update, context: CallbackContext) -> None:
    """Send a message when the command /start is issued."""
    reply_text = "你好~\n"
    user = update.message.from_user

    if user.username is not None:
        reply_text += f"您的用户名是: {user.username}\n"

    reply_text += f"ID: {user.id}"

    update.message.reply_text(reply_text)

def help_command(update: Update, context: CallbackContext) -> None:
    """Send a message when the command /help is issued."""
    update.message.reply_text('这里是帮助命令')

def echo(update: Update, context: CallbackContext) -> None:
    """Echo the user message."""
    update.message.reply_text(update.message.text)

def main():
    token = os.getenv('TELEGRAM_BOT_TOKEN')
    updater = Updater(token=token, use_context=True)
    dispatcher = updater.dispatcher
    dispatcher.add_handler(CommandHandler("start", start_command))
    dispatcher.add_handler(CommandHandler("help", help_command))
    dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, echo))
    updater.start_polling()
    updater.idle()

Update 中可以拿到消息的类型、具体内容、发送者等关键信息,从 CallbackContext 中可以获取机器人本身的一些信息等。在使用 \ 开头的对应命令后就能进入到对应的方法,也可以对此进行类封装。

注意到除了 CommandHandler 之外还有其他类型的句柄如常规消息类的 MessageHandler、用于行内输入的的 InlineQueryHandler 等,请详见上游 API 文档

回到需求,我们需要的检测关键词部分也是从 Update 中来,用关键词列表简单演示,当消息中包含关键词的时候发送一个表情,或者其他类型的回复详见 Message 类文档

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from telegram import Update, Sticker

# 临时创建一个表情量
sticker = Sticker(file_id="CAACAgUAAxkBAAIMOV_jA7I0IAABMbqNVNGkJWZNiDRT6QACiwIAArL6ew6tFsY1eQy9Lx4E",
    file_unique_id="AgADiwIAArL6ew4", width=480, height=512, is_animated=False)

def echo(update: Update, context: CallbackContext) -> None:
    keys_list = ["上膛", "车主", "特斯拉"]
    for item in keys_list:
        if item in update.message.text:
            msg = update.message
            msg.reply_sticker(sticker)

echo

至此初步效果已经达成,剩下要解决的两个疑问就是:

  • Sticker 的信息是怎么来的?
  • 如何回复指定消息

Sticker 信息

可以添加一个专用于获取表情包信息的句柄

1
2
3
4
5
6
7
8
def get_sticker(update: Update, context: CallbackContext) -> None:
    logger.info(update.message.sticker)

def main():
    ...
    dispatcher.add_handler(MessageHandler(Filters.sticker & ~Filters.command,       
        get_sticker))
    ...

为了便于理解这里在服务端后台直接输出表情包信息作为日志,对于一些要动态添加表情包和对应关键字的需求来说,一个轻便的可持久化数据才是更好的选择。创建 Sticker 实例的时候注意不要遗漏必要的传入参数。

sticker_info

如何回复指定的消息

简单来说这就是一个套娃过程,从包含关键字消息的 reply_to_message 成员可以判断并拿到上一条回复的消息,回复拿到的上一条消息即可,从而实现精准打击(x

1
2
3
4
5
6
    ...
    msg = update.message.reply_to_message

    if msg is not None:
        msg.reply_sticker(sticker)
    ...

reply to your reply

结束

以简单的案例来介绍 Telegram 机器人的玩法,希望能够帮助到入门的萌新打造属于自己的机器人。(撒花 ~=o(^▽^)o~♪

comments powered by Disqus
Ariel AxionL's Blog
Built with Hugo
主题 StackJimmy 设计