跳到主要内容
全部文章
开发5 分钟

用 aiogram 3 写第一个 Telegram 机器人

从在 BotFather 获取令牌,到做出一个带命令、键盘和回声功能的可用机器人,代码基于最新的 aiogram 3 API。

目录

Telegram 机器人是一个通过 Telegram 和人对话的小程序。这篇文章我们用 Python 和 aiogram 3(一个流行的异步机器人框架)来写一个:它会和用户打招呼、显示键盘,并把收到的消息原样发回去。本文适合懂一点 Python、但还没写过机器人的读者。整个过程大约二十分钟,而同样的结构以后也能扩展成真正的项目。

需要准备什么

  • Python 3.12 或更新版本。用 python3 --version 检查(Windows 上用 python --version)。如果你在 Windows 上从 python.org 安装 Python,记得在安装程序里勾选“Add python.exe to PATH”。
  • 一个 Telegram 账号。
  • 任意一个代码编辑器。

从 BotFather 获取令牌

所有机器人都要通过 @BotFather 创建,它是 Telegram 官方用来管理机器人的机器人。打开它,发送 /newbot,先起一个显示名称,再设置一个以 bot 结尾的用户名,例如 my_first_aiogram_bot。用户名必须独一无二,如果已被占用,多换几个试试。BotFather 会回复一个类似 123456789:AAH... 的令牌。你还可以顺便用 /setdescription 和 /setuserpic 给机器人设置简介和头像,用户第一次打开机器人时看到的就是这些。

令牌就是机器人的密码。谁拿到令牌,谁就能控制你的机器人,所以要像对待密码一样保管它。

准备项目

创建一个带虚拟环境的文件夹,让机器人用到的包和系统其他部分互不干扰,然后安装 aiogram:

Bash
mkdir my-bot && cd my-bot
python3 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -U aiogram

激活虚拟环境后,命令行前面会出现 (.venv),说明接下来安装的包只属于这个项目。之后可以用 pip freeze > requirements.txt 记录下确切的版本,这样在服务器上也能用完全相同的方式安装。

编写机器人

新建一个名为 bot.py 的文件:

Python
import asyncio
import logging
import os

from aiogram import Bot, Dispatcher, F, Router, html
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.filters import CommandStart
from aiogram.types import KeyboardButton, Message, ReplyKeyboardMarkup

router = Router()

menu = ReplyKeyboardMarkup(
    keyboard=[[KeyboardButton(text="关于"), KeyboardButton(text="帮助")]],
    resize_keyboard=True,
)


@router.message(CommandStart())
async def start(message: Message) -> None:
    name = html.quote(message.from_user.full_name)
    await message.answer(
        f"你好,<b>{name}</b>!随便发点文字给我吧。",
        reply_markup=menu,
    )


@router.message(F.text == "关于")
async def about(message: Message) -> None:
    await message.answer("我是一个用 aiogram 3 写的演示机器人。")


@router.message(F.text == "帮助")
async def help_(message: Message) -> None:
    await message.answer("随便发点什么,我会原样发回给你。")


@router.message(F.text)
async def echo(message: Message) -> None:
    await message.answer(html.quote(message.text))


async def main() -> None:
    bot = Bot(
        token=os.environ["BOT_TOKEN"],
        default=DefaultBotProperties(parse_mode=ParseMode.HTML),
    )
    dp = Dispatcher()
    dp.include_router(router)
    await dp.start_polling(bot)


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    asyncio.run(main())

它是怎么工作的

  • Router 用来给处理函数分组。很小的机器人可以把处理函数直接挂在 Dispatcher 上,但随着功能增加,路由器能让代码保持整洁:每个功能一个路由器,再统一接入调度器。
  • 处理函数是在装饰器里带有过滤器的异步函数。CommandStart() 匹配 /start,F.text == "关于" 只匹配这段文字,F.text 则匹配任何文本消息。aiogram 按注册顺序逐个检查处理函数,遇到第一个匹配的就停下,所以兜底的回声处理函数要放在最后。
  • DefaultBotProperties 让所有消息都使用 HTML 格式,所以 <b> 会显示为粗体。这也是用户发来的文字要经过 html.quote 的原因:否则一条包含 < 的消息会破坏格式,Telegram 就会拒绝这条回复。
  • start_polling 会不断向 Telegram 询问有没有新消息。这是运行机器人最简单的方式,不需要公网地址、域名或证书。
  • message.answer 会回复到消息所在的同一个聊天,不用手动传入聊天 ID。
  • async 让一个小小的进程就能同时服务很多人:一个处理函数在等待 Telegram 响应时,其他处理函数可以继续工作。

运行和停止

把令牌放进环境变量,然后启动机器人:

Bash
export BOT_TOKEN="123456789:AAH..."   # PowerShell: $env:BOT_TOKEN = "..."
python bot.py

在 Telegram 里打开你的机器人,点击“开始”(Start)。终端会记录收到的每一条更新。按 Ctrl+C 即可停止,aiogram 会正常关闭连接。关掉终端,机器人也会停止;要让它一直运行,就需要一台服务器,后面会讲到。如果忘了设置环境变量,os.environ["BOT_TOKEN"] 会立刻抛出 KeyError,这总比之后出现莫名其妙的错误要好。

有两件事常常让新手意外。第一,机器人不能主动给别人发消息:对方必须先打开机器人并点击“开始”,机器人才能给他发消息。第二,同一时间只能有一个机器人副本在轮询:如果同时启动第二个,比如在笔记本和服务器上各跑一个,Telegram 会返回冲突错误。

保管好令牌

永远不要把令牌写进代码,也不要提交到 Git。公开仓库一直有人在扫描泄露的密钥,谁找到令牌,谁就能控制你的机器人。

如果每次都输入 export 觉得麻烦,可以把令牌放在 .env 文件里,把 .env 加进 .gitignore,再用 python-dotenv 之类的库加载。.venv 文件夹也要加进 .gitignore,它不应该出现在仓库里。万一令牌泄露,给 BotFather 发送 /revoke 获取新令牌,旧令牌会立即失效。

下一步可以学什么

  • FSM(有限状态机),用于多步骤对话,比如先问名字、再问电话号码的表单。
  • 内联键盘和回调查询,用于直接附在消息下方的按钮。
  • Webhook,当机器人部署到支持 HTTPS 的服务器上后,用它代替轮询。
  • 数据库,例如 PostgreSQL 配合 SQLAlchemy,用来记住用户和他们的设置。
  • systemd 或 Docker,让机器人持续运行,并在崩溃或重启后自动恢复。

aiogram 官方文档 (在新标签页打开)对这些内容都有示例讲解。做一个你自己或朋友真正会用的小东西,这是学得最快的方法。

继续阅读

一起做点​了不起的东西吧。

无论是新项目、合作,还是只想聊聊技术,都欢迎来信。

  • 乌兹别克斯坦,塔什干接受远程工作

  • 塔什干现在 (GMT+5)