• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Telegram-бот на aiogram 3x: Часть I — создание первого бота

1mpossible City

CD-диск
Пользователь
Регистрация
04.06.2022
Сообщения
13
Реакции
6
Начало

Приветствую, дамы и господа. Это моя первая статья на этом форуме, и, быть может, она будет полезна для вас. Так вот, я решил ввести новые статьи про Telegram-ботов, поскольку мессенджер становится популярным с каждым днем, и экосистема расширяется новыми возможностями. Почему именно aiogram? Эта библиотека вполне идеальна, поскольку она построена на асинхронной библиотеке asyncio и может обрабатывать множество запросов быстро и эффективно.
https://xss.pro/threads/85709/#post-599362 ->в этой теме описывалось создание ботов (ещё была статья от network work), но всё, что там описывалось, уже устарело: там использовалась версия Aiogram 2, в то время как Aiogram 3 давно вышел и кардинально изменился.

Как новичок на этом форуме, я буду создавать полезные статьи по разным разделам, надеюсь, вам понравится.

> Цели статьи
  • Знакомство с Aiogram
  • Подготовка окружения
    • установка python
    • установка aiogram через pip
    • создание бота через BotFather(отец всех ботов)
  • Использование простого бота
    • минимальный код, который отвечает на команды /start и /echo

Знакомство с aiogram
Как я и писал выше, aiogram— это асинхронная библиотека на базе asyncio, которая позволяет обрабатывать множество запросов без заглушки.
Он прост в использовании. С первого взгляда может показаться сложным (особенно если вы работали с telebot), но если у вас есть как минимум представление об асинхронности (asyncio), то не будет трудно.
Отличий между aiogram 2 и aiogram 3 много. Например: диспетчер создавался с объектом bot (то есть передавали bot в Dispatcher в качестве аргумента) — в новой версии этого не нужно делать.

В aiogram 2 для запуска бота использовался другой метод: executor.start_polling(). В новой версии это чуть изменилось — теперь start_polling выступает в качестве асинхронной функции: await dp.start_polling(bot). Также в aiogram 3 улучшили систему фильтрации (фото, сообщения, стикеры и т.п.).
Сильно углубляться не буду, но это я описал лишь базовые моменты.
Полные отличия описаны здесь -> тык)


Установка Python

Если вы еще не установили Python, то вам следует это сделать. Я покажу пример на шиндовс, в линуксе вам этого не надо, он по умолчанию там установлен.

1) Переходим - https://python.org и выбираем раздел Downloads -> Windows
1751322547912.png

2) Далее ищем версию Python'a выше 3.8+! для aiogram 3.
1751322759043.png

3)
Скачиваем. После этого запускаем EXE-файл, обязательно ставим галочку на Add PATH — это опционально, но удобно, когда хотите запускать Python, не указывая путь.


4) Well done

Установка aiogram 3x и других библиотек

После того как установили Python, вам следует установить сам aiogram и ещё одну библиотеку decouple(позже расскажу для чего она нужна):
Bash:
pip install aiogram python-decouple

На всякий случай пропишите следующую команду - она выведет список установленных зависимостей. Если в списке присутствуют aiogram и decouple, значит, всё в порядке.

Bash:
pip list


Создаём бота на BotFather

Непосредственно нужно создать бота и получить его токен. Для этого перейдите к боту BotFather (специальный бот для создания ботов и не только) и введите команду /newbot, затем укажите название вашего бота.

1751323647085.png

Далее бот попросит указать юзернейм для бота, который должен оканчиваться префиксом bot.
После этого у вас создастся бот, и BotFather выдаст вам токен для подключения к боту.

1751323953478.png

⚠️ Никогда не распространяйте токен Telegram-бота - это как пароль к вашему боту. Если кто-то получит токен, он сможет полностью управлять ботом от вашего имени, рассылать спам, удалять данные или даже заблокировать бота у Telegram.


Пишем простенького бота

Наконец-то всё установлено, и можно приступать к коду. Нам понадобятся два файла: Python-файл и .env. В Python-файле мы будем писать бота, а в .env хранятся все конфиденциальные данные (токен, айдишники, IP и т.п.). Кстати, для работы с .env как раз-таки нужна библиотека decouple, чтобы извлекать значения из переменных окружения. Конечно, есть альтернативные варианты, но мне decouple больше нравится.

Python:
import asyncio
import logging
import sys

from decouple import config

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

# извлекаем токен из .env файла
TOKEN = config("BOT_TOKEN")

dp = Dispatcher()

# создаём первый и базовый хэндлер: /start
@dp.message(CommandStart())
async def command_start_handler(message: Message) -> None:
    await message.answer(f"Hello, {html.bold(message.from_user.full_name)}!")


# второй хэндлер называемой "эхо", который реагирует на любые сообщения
@dp.message()
async def echo_handler(message: Message) -> None:
    try:

        await message.send_copy(chat_id=message.chat.id)
    except TypeError:
        await message.answer("Nice try!")

# асинхронная функция "точка входа"
async def main() -> None:
    bot = Bot(token=TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))

    await dp.start_polling(bot)

# небольшое условие
if __name__ == "__main__":
    # включаем логи
    logging.basicConfig(level=logging.INFO, stream=sys.stdout)
    asyncio.run(main())
Создайте ENV-файл с названием .env и пропишите:
Код:
BOT_TOKEN=токен вашего бота

Результат кода:

1751324777760.png


как видите, всё идеально работает. Наш бот реагирует на команду /start и на эхо-сообщений.

Объяснение

Начнём с библиотек:
Python:
import asyncio
import logging
import sys
from decouple import config
from aiogram import Bot, Dispatcher, html
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.filters import CommandStart
from aiogram.types import Message

logging — очень полезный модуль, но не обязателен. С его помощью мы можем отслеживать ошибки и работу программы. Я бы советовал использовать его постоянно, xd.
sys — стандартная библиотека для работы с системными параметрами и потоками ввода-вывода.
decouple — сторонняя библиотека, которая позволяет извлекать значение из переменных окружения (в нашем случае — "BOT_TOKEN").

from aiogram import Bot, Dispatcher, html — мы импортировали важные классы из Aiogram. Первый из них — Bot, он позволяет нам взаимодействовать с Telegram. Далее Dispatcher отвечает за маршрутизацию входящих сообщений к нужным хэндлерам (обработчикам). И последний, но не менее важный — html, который позволяет форматировать наш текст с помощью HTML-тегов (есть ещё MarkdownV2).
from aiogram.client.default import DefaultBotProperties — настройки по умолчанию для бота (например, форматирование сообщений).
from aiogram.enums import ParseMode — указывает Telegram, в каком формате он будет воспринимать сообщения (HTML, MarkdownV2).
from aiogram.filters import CommandStart — фильтр, который ловит команду /start и запускает соответствующий обработчик.
from aiogram.types import Message — тип объекта, представляющий входящее сообщение от пользователя.

Переменные и 1-ый хэндлер(обработчик)
Python:
# извлекаем токен из .env файла
TOKEN = config("BOT_TOKEN")

dp = Dispatcher()

# создаём первый и базовый хэндлер: /start
@dp.message(CommandStart())
async def command_start_handler(message: Message) -> None:
    await message.answer(f"Hello, {html.bold(message.from_user.full_name)}!")

Мы создали переменную TOKEN, в которой хранится токен нашего бота, соответственно, извлекаем его из переменных окружения.
Объект dp создан на основе класса Dispatcher, он позволит нам обрабатывать все наши будущие сообщения и хэндлеры.

И наконец, сам хэндлер. Мы его назвали command_start_handler, над этим хэндлером мы установили декоратор, указывающий на то, что хэндлер сработает только тогда, когда пользователь отправит команду /start.
В command_start_handlerмы передали параметр message, то есть наш хэндлер работает исключительно с сообщениями.
Внутри этой функции мы вызвали интересную асинхронную функцию message.answer, которая отвечает пользователю текстом, который мы указали внутри в качестве аргумента.

Hello, {html.bold(message.from_user.full_name)} — мы использовали мета-заполнители (наподобие функции format), чтобы вывести имя пользователя, который вызвал команду. Мы из объекта message извлекаем свойство (или атрибут) from_user, а потом из него — full_name.
Существует много свойств внутри message, таких как: id, last_name, full_name и т.п.

2-ой хэндлер
Python:
# второй хэндлер называемой "эхо", который реагирует на любые сообщения
@dp.message()
async def echo_handler(message: Message) -> None:
    try:

        await message.send_copy(chat_id=message.chat.id)
    except TypeError:
        await message.answer("Nice try!")

Здесь то же самое, что и в предыдущем хэндлере, но стоит заметить, что в декораторе мы ничего не передали, а значит, что наш хэндлер (обработчик) будет срабатывать при любом событии: отправке стикеров, сообщений, документов и т.д.
Внутри блока мы создали обработку исключений при помощи конструкции try/except. Логика такова: мы копируем исходное сообщение, которое отправил пользователь, и сразу отправляем его обратно. Всё это делается через метод send_copy. В качестве аргумента нужно указать, какое именно сообщение скопировать — для этого мы прописали id того сообщения, которое отправил пользователь. В случае ошибки с типом данных нам отправят сообщение с текстом Nice Try!

main() - основная асинхронная функция
Python:
# асинхронная функция "точка входа"
async def main() -> None:
    bot = Bot(token=TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))

    await dp.start_polling(bot)

main() — это главная функция, которая по сути ничего не возвращает. Внутри неё мы создаём объект bot на основе класса Bot, передаём в качестве аргумента сам токен и устанавливаем параметры по умолчанию.
Далее интересный метод start_polling(bot), который запускает прослушивание входящих апдейтов от Telegram и передаёт их диспетчеру для обработки.

И собственно, запуск с условием
Python:
# небольшое условие
if __name__ == "__main__":
    # включаем логи
    logging.basicConfig(level=logging.INFO, stream=sys.stdout)
    asyncio.run(main())

Мы использовали условную конструкцию if, чтобы узнать, запускается ли исходный файл напрямую, а не через другой модуль. Насколько я знаю, это сделано для защиты от лишних атак.
Внутри этого блока мы включаем логи, передавая туда необходимые аргументы. Мы установили уровень INFO, который будет показывать нам небольшую информацию при каждом действии бота.
И последняя строчка кода asyncio.run(main()) запускает нашу асинхронную функцию main.

Заключение
Мы познакомились с интересным фреймворком aiogram, узнали разницу между старой и новой версией и написали простенького бота.
Напишите в коментах, как вам статья? Если есть опечатки или ошибки, опишите их ниже, буду очень благодарен. Надеюсь, подобные статьи будут полезны.

Спасибо за внимания!
 
Последнее редактирование:
Привет, хорошая статья! Если у тебя хватит усидчивости и терпения от начала до конца сделать цикл статей по разработке тг ботов, где в конце уже на практике будет действительно хороший пример того как выглядит полноценный отказоустойчивый тг бот изнутри, со всеми сопутствующими решениями для стабильной работы (фильтры, мидлвари, структура проекта и тд) будет классно! Отпишу в ЛС на форуме, предложение есть к тебе
 
Привет, хорошая статья! Если у тебя хватит усидчивости и терпения от начала до конца сделать цикл статей по разработке тг ботов, где в конце уже на практике будет действительно хороший пример того как выглядит полноценный отказоустойчивый тг бот изнутри, со всеми сопутствующими решениями для стабильной работы (фильтры, мидлвари, структура проекта и тд) будет классно! Отпишу в ЛС на форуме, предложение есть к тебе
Привет. Во второй статье я опишу о эффективной структуре любого бота, включая: мидлвари, кейбоардс, фильтры, хэндлерс и т.д :)
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх