Создание Telegram-бота на Python с использованием aiogram 3.x
Введение
Telegram-боты становятся все более популярными для автоматизации задач, взаимодействия с пользователями и предоставления различных услуг. В этом руководстве мы подробно рассмотрим процесс создания Telegram-бота на Python с использованием библиотеки aiogram 3.x. Мы пройдем все этапы от установки необходимых библиотек до деплоя бота на Ubuntu Server.
Почему я пишу про ботов
Сразу честно скажу: этот бот я писал для своей реальной задачи, а не ради абстрактного примера. Мне нужно было автоматизировать оповещения с домашнего сервера: чтобы уведомления о событиях приходили прямо в Telegram, а не терялись в почте. Поэтому в статье будет не только сухая теория, но и то, что я узнал на практике, пока доводил бота до рабочего состояния.
Если вы никогда не писали ботов, не пугайтесь объёма кода. По сути, всё сводится к простой схеме: бот получает событие от Telegram, обрабатывает его и отвечает. Библиотека aiogram берёт на себя всю «тяжёлую» работу по связи с API. Остаётся писать логику своих обработчиков.
1. Установка библиотек
Для начала работы нам понадобятся несколько библиотек, которые можно установить с помощью pip. Откройте терминал и выполните следующие команды:
pip install aiogram python-dotenv
aiogram — это современная асинхронная библиотека для создания Telegram-ботов, которая поддерживает все возможности API Telegram. python-dotenv поможет нам хранить конфиденциальные данные (например, токен бота) в файле .env, что улучшает безопасность и удобство разработки.
Получение токена бота
Прежде чем писать код, нужно создать самого бота в Telegram. Для этого я открыл чат с @BotFather, отправил ему команду /newbot и следовал подсказкам. БотFather выдаёт токен — длинную строку, которая является паролем от вашего бота. Её нужно хранить в тайне, и именно для этого мы используем файл .env.
Когда я впервые получил токен, я случайно засветил его в коде и выложил в репозиторий. Ничего страшного не случилось, но я понял, что это плохая практика. С тех пор токены я всегда храню в переменных окружения или в файлах, которые не попадают в систему контроля версий. В статье этот момент закрыт файлом .env — и это правильно.
2. Создание структуры проекта
Создадим базовую структуру нашего проекта:
- Создайте папку для вашего бота, например,
telegram_bot. - Внутри этой папки создайте следующие файлы и папки:
mkdir telegram_bot
cd telegram_bot
touch main.py handlers.py keyboards.py .env
mkdir data
Файл .env будет хранить токен вашего бота, а папка data — данные, которые бот может использовать (например, базы данных или временные файлы).
Почему я разбил код на несколько файлов
Начинал я с одного большого файла, где была и регистрация, и обработчики, и клавиатуры. Бот был маленький, и это работало. Но как только я добавил вторую команду и третью, файл распух, и стало тяжело находить нужное место. Я переписал всё на структуру, как в статье: main.py — запуск, handlers.py — логика, keyboards.py — кнопки.
Разделение кода на модули окупается почти сразу. Когда бот упал у меня на сервере, я за пару минут нашёл проблемный обработчик, потому что он лежал в понятном месте. Держите логику и интерфейс отдельно — потом спасибо себе скажете.
3. Полный код файла main.py с комментариями
import os
from dotenv import load_dotenv
from aiogram import Bot, Dispatcher, Router, FSMContext, types
from aiogram.filters import CommandStart
from handlers import register_handlers
from keyboards import setup_keyboards
# Загружаем переменные окружения из файла .env
load_dotenv()
# Получаем токен бота из переменной окружения
BOT_TOKEN = os.getenv('BOT_TOKEN')
# Создаем экземпляры Bot и Dispatcher
bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()
# Регистрируем обработчики команд и сообщений
register_handlers(dp)
# Настраиваем клавиатуры
setup_keyboards(dp)
async def main():
await dp.start_polling(bot)
if __name__ == '__main__':
import asyncio
asyncio.run(main())
В этом файле мы:
- Импортируем необходимые модули.
- Загружаем переменные окружения из файла
.env. - Создаем экземпляры Bot и Dispatcher.
- Регистрируем обработчики команд и сообщений, вызывая функции из модулей
handlers.pyиkeyboards.py. - Запускаем бота с помощью асинхронной функции
main().
4. Полный код файла handlers.py
from aiogram import Router, types
from aiogram.filters import CommandStart
from keyboards import get_main_menu_keyboard
# Создаем маршрутизатор для обработчиков
router = Router()
@router.message(CommandStart())
async def command_start(message: types.Message):
await message.answer(
"Привет! Я ваш Telegram-бот, созданный с помощью aiogram 3.x.",
reply_markup=get_main_menu_keyboard()
)
@router.message()
async def echo_message(message: types.Message):
await message.answer(f"Вы написали: {message.text}")
# Регистрируем маршрутизатор в главном диспетчере
def register_handlers(dp):
dp.include_routers(router)
В этом файле мы:
- Создаем маршрутизатор router, который будет обрабатывать входящие сообщения.
- Определяем обработчик для команды
/start, который приветствует пользователя и отправляет главное меню с кнопками. - Добавляем обработчик, который повторяет любое полученное сообщение (эхо-сообщение).
- Регистрируем маршрутизатор в главном диспетчере
dp.
5. Полный код файла keyboards.py
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
from aiogram.filters import Text
# Создаем кнопки для главного меню
main_menu_keyboard = ReplyKeyboardMarkup(
keyboard=[
[KeyboardButton(text='Привет')],
[KeyboardButton(text='Пока')]
],
resize_keyboard=True,
input_field_placeholder="Выберите действие"
)
# Создаем маршрутизатор для обработчиков клавиатуры
keyboard_router = Router()
@keyboard_router.message(Text(equals='Привет'))
async def greet_user(message: types.Message):
await message.answer("Здравствуйте! Как я могу вам помочь?")
@keyboard_router.message(Text(equals='Пока'))
async def goodbye_user(message: types.Message):
await message.answer("До свидания! Если понадобятся мои услуги, не стесняйтесь обращаться.")
# Функция для настройки клавиатур
def setup_keyboards(dp):
dp.include_routers(keyboard_router)
В этом файле мы:
- Создаем главное меню с кнопками ‘Привет’ и ‘Пока’.
- Определяем обработчики для этих кнопок, которые отвечают соответствующими сообщениями.
- Регистрируем маршрутизатор клавиатуры в главном диспетчере.
Как я отлаживал бота
Когда бот не отвечал, я первым делом проверял логи. У aiogram есть хороший инструмент — включить логирование через logging. В консоли сразу видно, какие сообщения пришли и какие ошибки произошли. Этот простой приём спас меня не один раз.
Ещё один момент: у бота был свой собственный веб-хук, который я когда-то настроил, а потом забыл. Из-за этого бот переставал реагировать на сообщения. Решение простое — в aiogram есть команда для сброса веб-хука. Если бот вдруг «замолчал», первым делом проверяю именно это.
6. Настройка конечного автомата (FSM)
Конечный автомат (Finite State Machine, FSM) позволяет боту переходить между различными состояниями и выполнять разные действия в зависимости от текущего состояния. В aiogram 3.x это реализовано с помощью класса FSMContext. Давайте создадим пример FSM для бота, который запрашивает имя пользователя.
6.1. Обновляем handlers.py
from aiogram import Router, types, FSMContext
from aiogram.filters import CommandStart, StateFilter
from aiogram.fsm.state import StatesGroup, State
from keyboards import get_main_menu_keyboard
# Определяем состояния FSM
class Form(StatesGroup):
waiting_for_name = State()
# Создаем маршрутизатор для обработчиков FSM
fsm_router = Router()
@fsm_router.message(CommandStart())
async def command_start(message: types.Message, state: FSMContext):
await state.set_state(Form.waiting_for_name)
await message.answer("Привет! Как вас зовут?")
@fsm_router.message(StateFilter(Form.waiting_for_name))
async def process_name(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['name'] = message.text
await Form.next()
await message.answer(f"Приятно познакомиться, {data['name']}!")
@fsm_router.message()
async def echo_message(message: types.Message):
await message.answer(f"Вы написали: {message.text}")
def register_handlers(dp):
dp.include_routers(router, fsm_router)
В этом примере мы:
- Определяем класс Form, который наследуется от StatesGroup и содержит состояние waiting_for_name.
- Создаем маршрутизатор для обработчиков FSM.
- Обработчик команды
/startустанавливает состояние waiting_for_name и запрашивает имя пользователя. - Обработчик состояния waiting_for_name сохраняет полученное имя в контексте FSM и переходит к следующему состоянию (хотя в этом примере мы не используем его, но это может быть полезно для более сложных сценариев).
Мои замечания по деплою
Раздел про systemd — это как раз то, что спасло мой бот. В первое время я запускал его просто в терминале, и как только закрывал окно, бот умирал. Потом я завёл сервис через systemd, как в статье, и бот стал жить сам по себе, перезапускаясь при сбоях. Отдельный пользователь для бота — тоже правильный шаг: так он не имеет лишних прав на сервере.
Отмечу ещё удобный приём: команда journalctl -f показывает логи бота в реальном времени. Когда я добавлял новые функции, я открывал этот лог, писал боту сообщение и сразу видел результат. Такой цикл «изменил — проверил» сильно ускоряет разработку. Рекомендую всем, кто деплоит бота на сервер.
7. Деплой на Ubuntu Server
Теперь давайте разберемся, как деплоить наш бот на Ubuntu Server.
7.1. Подготовка сервера
# Обновляем пакеты
sudo apt update && sudo apt upgrade -y
# Устанавливаем Python и pip
sudo apt install python3 python3-pip python3-venv -y
# Создаем пользователя для бота (например, 'botuser')
sudo adduser botuser
# Переключаемся на этого пользователя
su - botuser
# Клонируем репозиторий с ботом (предположим, что он лежит на GitHub)
git clone https://github.com/yourusername/telegram_bot.git
# Переходим в папку бота
cd telegram_bot
# Создаем виртуальное окружение
python3 -m venv venv
# Активируем виртуальное окружение
source venv/bin/activate
# Устанавливаем зависимости
pip install -r requirements.txt
Если у вас еще нет файла requirements.txt, создайте его с помощью команды:
pip freeze > requirements.txt
7.2. Настройка бота для работы в фоновом режиме
Для того чтобы бот работал в фоновом режиме, мы будем использовать systemd. Создадим сервис:
# Создаем файл конфигурации сервиса
sudo nano /etc/systemd/system/telegram_bot.service
Добавьте следующий контент в этот файл (не забудьте заменить пути на ваши):
[Unit]
Description=Telegram Bot Service
After=network.target
[Service]
User=botuser
WorkingDirectory=/home/botuser/telegram_bot
Environment="PATH=/home/botuser/telegram_bot/venv/bin"
ExecStart=/home/botuser/telegram_bot/venv/bin/python /home/botuser/telegram_bot/main.py
Restart=always
[Install]
WantedBy=multi-user.target
Затем выполните следующие команды для управления сервисом:
# Перезагружаем systemd, чтобы применить изменения
sudo systemctl daemon-reload
# Запускаем сервис
sudo systemctl start telegram_bot.service
# Проверяем статус сервиса
sudo systemctl status telegram_bot.service
# Включаем автозагрузку сервиса
sudo systemctl enable telegram_bot.service
7.3. Логирование и мониторинг
Для удобного просмотра логов бота мы можем использовать journalctl:
# Просмотр последних 50 строк лога
sudo journalctl -u telegram_bot.service -n 50
# Просмотр лога в реальном времени
sudo journalctl -u telegram_bot.service -f
Если вам нужно изменить конфигурацию бота или добавить новые функции, просто обновите файлы в репозитории и перезапустите сервис:
# Переходим в папку бота
cd /home/botuser/telegram_bot
# Обновляем репозиторий (если используется Git)
git pull
# Переустанавливаем зависимости
pip install -r requirements.txt
# Перезапускаем сервис
sudo systemctl restart telegram_bot.service
Заключение
В этом руководстве мы подробно рассмотрели процесс создания Telegram-бота на Python с использованием библиотеки aiogram 3.x. Мы:
- Установили необходимые библиотеки.
- Создали структуру проекта и написали код для основных файлов:
main.py,handlers.pyиkeyboards.py. - Научились работать с конечными автоматами (FSM) для управления состояниями бота.
- Разобрали процесс деплоя бота на Ubuntu Server, включая настройку сервиса systemd и мониторинг логов.
Теперь у вас есть полное руководство по созданию Telegram-бота, которое можно использовать как основу для более сложных проектов. Не стесняйтесь экспериментировать с aiogram 3.x и добавлять новые функции в свой бот!