Загрузка...

Aiogram. Python. Writing a multifunctional bot #1 Initial project setup.

Thread in Articles created by gwaap Apr 17, 2022. (bumped Sep 2, 2024) 12,810 views

  1. gwaap
    gwaap Topic starter Apr 17, 2022 159 Apr 14, 2022
    Всех приветствую дорогие форумчане! Сегодня я начну серию уроков по созданию функционального Telegram бота на такой фреймворке как aiogram. По ходу серии уроков мы научимся с вами работать с командами, кнопками, сообщениями, FSM состояниями (о ней я говорил в прошлой статье), а также научимся работать с базой данных (PostgreSQL, Gino ORM) и многое другое. Давайте же начнем:smile:

    В первом уроке мы сделаем:
    - разработаем архитектуру проекта
    - настроим стандартные команды бота
    - настроим уведомление о запуске бота
    - полностью настроим и запустим бота


    Для начала я создал новый проект в PyCharm с такой архитектурой (статья на отдельную тему структуризации проекта также скоро выйдет):
    [IMG]

    Файл app.py будет у нас как точка входа. Из него будет запускаться весь бот. В loader.py мы будем хранить Dispatcher, а также MemoryStorage для работы с FSM.

    В файле config.py устанавливаем токен бота, а также в массив admins_id передаём id администратора, чтобы в будущем уведомлять о запуске бота:
    Python
    import os

    from dotenv import load_dotenv

    load_dotenv()

    BOT_TOKEN = str(os.getenv("BOT_TOKEN"))

    admins_id = [
    1782886979,
    ]
    Конструкция os.getenv("BOT_TOKEN") позволяет загрузить переменную окружения BOT_TOKEN с файлика .env

    Теперь настроим фал loader.py. Тут мы создаём Dispatcher для нашего бота, где BOT_TOKEN берём с ранее настроенного config.py
    Python
    from aiogram import Bot, Dispatcher, types

    from data import config

    bot = Bot(config.BOT_TOKEN, parse_mode=types.ParseMode.HTML)

    dp = Dispatcher(bot)
    В папке utils создаём два файла с названиями
    notify_admins.py (для уведомления администраторов о запуске бота) и
    set_bot_commands.py (для установки стандартных команд для бота).
    [IMG]

    Файл notify_admins.py. Здесь мы отправляем сообщение о запуске бота администратору(-ам) (в зависимости сколько id в массиве admins_id).
    Python
    import logging

    from aiogram import Dispatcher

    from data.config import admins_id


    async def on_startup_notify(dp: Dispatcher):
    for admin in admins_id:
    try:
    text = 'Bot was started!'
    await dp.bot.send_message(admin, text)
    except Exception as err:
    logging.exception(err)
    Файл set_bot_commands.py. В этом файле мы устанавливаем стандартные команды для бота с которыми пользователь может легко взаимодействовать.
    Python
    from aiogram import types


    async def set_default_commands(dp):
    await dp.bot.set_my_commands(
    [
    types.BotCommand('start', 'Запустить бота'), # пока добавляем только одну команду
    ]
    )
    Отлично! Теперь нам осталось настроить запуск бота. Это мы сделаем в файлике app.py
    Python
    async def on_startup(dp):
    from utils.notify_admins import on_startup_notify
    await on_startup_notify(dp)

    from utils.set_bot_commands import set_default_commands
    await set_default_commands(dp)

    print("Бот запущен!")


    if __name__ == '__main__':
    from aiogram import executor
    from handlers import dp

    executor.start_polling(dp, on_startup=on_startup, skip_updates=True)
    Итак, давайте разбираться что тут написано.
    Python
    from utils.notify_admins import on_startup_notify
    await on_startup_notify(dp)
    Эта функция уведомляет администратора о запуске бота, её мы прописывали выше.

    Следующей функцией мы устанавливаем стандартные команды для бота, я думаю тут всё понятно, всё аналогично как и с
    await on_startup_notify(dp)

    На передаваемый аргумент dp пока не обращаем внимание, к нему мы ещё вернемся.

    Далее мы выводим в консоль уведомление о том, что бот запущен.

    После чего запускаем конструкцию if __name__ == "__main__" где импортируем executor, dp from handler, а также запускаем бота с помощью

    executor.start_polling(dp, on_startup=on_startup, skip_updates=True)


    Теперь давайте разберёмся с тем самым dp (Dispatcher).
    В файлах handlers/__init__.py и handlers/users/__init.py__ прописываем данную конструкцию

    __all__ = ['dp']

    Что делает __all__? Он объявляет семантически "общедоступные" имена из модуля. В нашем случае, общедоступным станет dp.
    Однако сейчас у нас горит ошибка, это потому что мы не указали из которого нужно импортировать dp.[IMG]

    В папке handlers/users создадим файл start.py, где опишем команду /start. С loader импортируем dp (Dispather)
    [IMG]

    Файл handlers/users/start.py
    Python
    from aiogram import types

    from loader import dp


    @dp.message_handler(commands=['start'])
    async def command_start(message: types.Message):
    await message.answer(f"Привет {message.from_user.first_name}")

    Теперь нам нужно инициализировать этот файл. Для начала заходим в handlers/__init__.py. В самое начало прописываем

    from .users import dp

    Далее заходим в handlers/users/__init__.py и также в самое начало добавляем

    from .start import dp


    ИТОГ

    Отлично! Теперь наш бот полностью готов к запуску. Обязательно запускаем его в файла app.py! Если при первом запуске у вас вылезла такая ошибка, то это нормально. При запуске бота у нас запускается функция
    on_startup_notify() где сообщение отправляется в чат администратору, а так как администратор ещё ни разу не писал боту, а бот первым написать не может, то у нас выскакивает ChatNotFound (чат не найден), однако когда администратор запустит бота, всё будет хорошо.
    [IMG]

    Давайте напишем нашему боту.
    [IMG]
    Теперь перезапустим бота.
    [IMG]
    Как видите ошибок уже нет, а сообщение Updates were skipped successfully говорит нам о том, что все ранее отправленные сообщения боту, когда он был выключен, пропущены. Этого мы добились с помощью skip_updates = True

    executor.start_polling(dp, on_startup=on_startup, skip_updates=True)

    После чего в консоли нам пишется о том, что бот запущен, а также в личные сообщения администратору (мне) бот прислал оповещение:
    [IMG]

    Также внизу появляется кнопка Меню, при нажатии которой, выпадает наша с вами раннее добавленная команда /start в
    set_default_commands()

    [IMG]

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

    Полезные ссылки:

    GitHub - https://github.com/Kolini77/aiogram-lessons

    Наш Telegram чат Python программистов - https://t.me/+q9HNGuHpkpA1Y2Y6
     
    This article was useful for you?
    You can thank the author of the topic by transferring funds to your balance
    Thank the author
  2. Falley
    Falley Jun 24, 2022 Разработка софта https://lolz.live/threads/7325736/ 1208 Aug 28, 2021
    Тема полезная для людей, которые знакомятся с разработкой ботов на aiogram, я максимум писал на telebot, на aiogram не делал. Вот не знаю обязательно ли юзать асинхронный python?Хочу перейти с telebot на более продвинутый уровень, а вот с асинхронностью не знаком:zachto:
     
    1. grtyu_inactive3100454
      Falley, условно перед всем добавляешь await
  3. SotW
    SotW Jun 24, 2022 1 May 29, 2022
    Хорошая статья, но думаю новичкам будет сложновато разобраться
     
    1. Liby
      SotW, так и есть, я ищу как сделать курсивный текст, по этому увидев первый скрин нахуй ****нул статью
      яп вообще не знаю
  4. Volkov
    Volkov Aug 18, 2022 4523 May 26, 2021
    помог, тут только +реп за хорошую статью
     
  5. Bdhdh737
    Bdhdh737 Oct 12, 2022 1 Sep 25, 2022
    Крутая статья
     
  6. aloaloalo12345
    А подскажи пож, для каждого нового хэндлера, который я напишу, необходимо в инит прописывать точно также?
     
    1. View previous comments (1)
    2. gwaap Topic starter
      aloaloalo12345, нет, в данном случае я инициализировал не хендлер, а файл с хендлерами
    3. neo_noir
      gwaap, не знаю ответишь ли, но такой вопрос, насколько критично делать бота с разными Python Packages? Я приведу пример своего, чтобы ты лучше понял. Есть бот, я запускаю его из main.py, в этом же файле содержатся абсолютно все месседж хендлеры и коллбеки. Я создал еще пару файлов: inline_keyboard.py и messages.py, т.к. мой бот в основном выполняет функцию навигации и там куча кнопок и сообщений, я просто в main.py импортирую все кнопки и текст сообщений. Так вот, насколько критична такая структура? Бот коммерческий, я например спрячу токен в окружении, но в остальном, главное чтобы работало или лучше сейчас сразу заморочиться и все прописать красиво?
    4. febqij
      neo_noir, мое мнение что если не горит, то можно и заморочиться, приручая себя к корректной структуре. От вредных привычек потом будет труднее отучиться. С другой стороны коммерческая говорите: работает и работает, главное к дедлайну успеть))
  7. febqij
    febqij Nov 28, 2022 2 Nov 28, 2022
    Комментарий в поддержку и в благодарность автору. Лайк почему-то не ставится, видимо из-за того что новый аккаунт ^)
     
  8. katsuyorii
    Всё было понятно ровно до момента, когда начинают создаваться __init__ файлы в хендлере. для чего там нужно прописывать from .users, потом в users from .start? Почему в app нельзя напрямую обратиться к loader и оттуда взять диспатчер? мы же делаем это в start, берем напрямую.
     
  9. gpt
    Я ничего не хочу сказать, но лучше уже прочитать документацию, чем так говнокодить
     
Top
Loading...