Загрузка...

Aiogram. Python. Пишем многофункционального бота #1 Первоначальная настройка проекта.

Тема в разделе Статьи создана пользователем gwaap 17 апр 2022. (поднята 2 сен 2024) 12 807 просмотров

  1. gwaap
    gwaap Автор темы 17 апр 2022 159 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
     
    Этот материал оказался полезным?
    Вы можете отблагодарить автора темы путем перевода средств на баланс
    Отблагодарить автора
  2. Falley
    Falley 24 июн 2022 Разработка софта https://lolz.live/threads/7325736/ 1208 28 авг 2021
    Тема полезная для людей, которые знакомятся с разработкой ботов на aiogram, я максимум писал на telebot, на aiogram не делал. Вот не знаю обязательно ли юзать асинхронный python?Хочу перейти с telebot на более продвинутый уровень, а вот с асинхронностью не знаком:zachto:
     
    24 июн 2022 Изменено
    1. grtyu_inactive3100454
      Falley, условно перед всем добавляешь await
  3. SotW
    SotW 24 июн 2022 1 29 май 2022
    Хорошая статья, но думаю новичкам будет сложновато разобраться
     
    1. Liby
      SotW, так и есть, я ищу как сделать курсивный текст, по этому увидев первый скрин нахуй ****нул статью
      яп вообще не знаю
  4. Volkov
    Volkov 18 авг 2022 4523 26 май 2021
    помог, тут только +реп за хорошую статью
     
  5. Bdhdh737
    Bdhdh737 12 окт 2022 1 25 сен 2022
    Крутая статья
     
  6. aloaloalo12345
    А подскажи пож, для каждого нового хэндлера, который я напишу, необходимо в инит прописывать точно также?
     
    1. Посмотреть предыдущие комментарии (1)
    2. gwaap Автор темы
      aloaloalo12345, нет, в данном случае я инициализировал не хендлер, а файл с хендлерами
    3. neo_noir
      gwaap, не знаю ответишь ли, но такой вопрос, насколько критично делать бота с разными Python Packages? Я приведу пример своего, чтобы ты лучше понял. Есть бот, я запускаю его из main.py, в этом же файле содержатся абсолютно все месседж хендлеры и коллбеки. Я создал еще пару файлов: inline_keyboard.py и messages.py, т.к. мой бот в основном выполняет функцию навигации и там куча кнопок и сообщений, я просто в main.py импортирую все кнопки и текст сообщений. Так вот, насколько критична такая структура? Бот коммерческий, я например спрячу токен в окружении, но в остальном, главное чтобы работало или лучше сейчас сразу заморочиться и все прописать красиво?
    4. febqij
      neo_noir, мое мнение что если не горит, то можно и заморочиться, приручая себя к корректной структуре. От вредных привычек потом будет труднее отучиться. С другой стороны коммерческая говорите: работает и работает, главное к дедлайну успеть))
  7. febqij
    febqij 28 ноя 2022 2 28 ноя 2022
    Комментарий в поддержку и в благодарность автору. Лайк почему-то не ставится, видимо из-за того что новый аккаунт ^)
     
  8. katsuyorii
    katsuyorii 6 янв 2023 0 2 фев 2022
    Всё было понятно ровно до момента, когда начинают создаваться __init__ файлы в хендлере. для чего там нужно прописывать from .users, потом в users from .start? Почему в app нельзя напрямую обратиться к loader и оттуда взять диспатчер? мы же делаем это в start, берем напрямую.
     
  9. gpt
    Я ничего не хочу сказать, но лучше уже прочитать документацию, чем так говнокодить
     
    6 янв 2023 Изменено
Top
Загрузка...