Телеграм Бот на Python с нуля! | Telegram Bot на Aiogram для начинающих

Информация о загрузке и деталях видео Телеграм Бот на Python с нуля! | Telegram Bot на Aiogram для начинающих
Автор:
$ sudo teach IT ⚙️Дата публикации:
01.04.2024Просмотров:
206KОписание:
❤️ Учи Python и aiogram 3 здесь: ❤️ Не забудьте подписаться на канал, чтобы не пропускать новые видео-уроки по Python! Код на GitHub: 👉🏼 Telegram: 👉🏼 Наш чат: 👉🏼 Моя школа: 🧨 Арендуй облачный сервер timeweb на месяц и получай 300 рублей от меня на баланс: 00:00 Введение 1:00 Установка aiogram 5:45 Развёртывание проекта 12:00 Первый обработчик 17:15 Фильтры 22:05 Роутеры 26:20 Клавиатура 36:50 CallbackQuery 40:50 Состояния 52:05 Заключение Меня зовут Тимур, моя задача — вырастить из своих учеников профессионалов, которые пишут на Python. 🐍 Музыка 💗 Rain, Book And Cup Of Tea by | e s c p | Music promoted by Creative Commons / Attribution 4.0 International (CC BY 4.0)
Транскрибация видео
Добро пожаловать на канал Sudo Teach IT.
Telegram становится востребованием с каждым днем.
И каждый день повышается спрос на создание Telegram ботов.
Сегодня я расскажу, как создавать Telegram ботов, используя язык программирования Python.
Мы будем использовать специальную библиотеку под названием Iogram Telegram.
Третья версия.
Если вы не знаете язык программирования Python, то вы можете посмотреть видео с его основами у меня на канале или пройти бесплатный курс на моем сайте sudoteach.com.
Что касаемо библиотеки Iogram, то это некий готовый код, который позволяет нам легче обращаться к Telegram для того, чтобы выполнять те или иные действия.
Например, ловить сообщения от пользователя, отправлять ему их, выводить клавиатуру и тому подобное.
Это видео подойдет для новичков, которые не разбираются в программировании и только хотят начать свой путь.
Многие термины, понятия и методы написания кода упрощены в целях понимания и более легкого освоения.
Давайте начнем с того, что на моем компьютере установлен Python версии 3.11, а также для кодинга я использую программу Visual Studio Code.
И, конечно же, мы начнем развертывать наш проект.
Для этого я открою новый терминал.
Кстати, вы вполне можете использовать программу PyCharm, например, но я использую VS Code.
И здесь мы создадим новое виртуальное окружение.
Вопрос, зачем нужно использовать виртуальное окружение?
Его нужно использовать для того, чтобы отделить все ваши проекты друг от друга, потому что нет смысла, нельзя устанавливать пакеты в один глобальный интерпретатор.
Представьте, что у вас, например, два бота, один на второй версии айограмма, второй бот на третьей версии.
И как быть, как их запускать одновременно или поочередно, постоянно переустанавливать версию, что ли?
Нет, конечно.
Просто у каждого проекта свое виртуальное окружение и в каждом проекте свои модули, свои пакеты.
Так, я его установил, точнее создал.
И у меня создался вот файл, папка .venv.
И теперь мне нужно его активировать.
Я пишу venv script activate.
Он у меня говорит, что не нашел venv.
Ну, возможно, я все-таки допустил где-то ошибку.
Вот, я написал еще раз и, в общем-то, все заработало.
Вот здесь зелененьким загорелся venv.
Это значит, что...
Все за работу.
У вас может не зеленым, другим цветом.
Главное, что в самом начале написано .venv.
Давайте почистим терминал.
И командой pip list я посмотрю, что у меня установлено.
Какие пакеты установлены.
И мы видим, что есть сам pip и есть setup tools, то есть это специальные утилиты для установки.
И нам говорят, что можно обновить с 23 на 24 версию.
Давайте это сделаем.
Вот этой командой обновим pip, для того, чтобы все версии, которые мы устанавливаем в будущем, они были самые-самые свежие и актуальные.
Вот, и после этого мы наконец-таки с помощью команды pip можем установить нужный нам пакет.
А какой нам пакет нужен?
Это, конечно же, iogram.
Сейчас третья версия уже последняя, актуальная.
Поэтому нам, в общем-то, ничего сюда добавлять не надо.
Мы можем написать, например, iogram docs.
Вот таким образом.
И посмотреть, какая сейчас версия актуальна.
Только что это такое?
Это чуть не то.
Куда-то пропал в Яндексе iogram.
Или он его не проиндексировал, этот сайт.
Ну-ка посмотрим вот отсюда.
Здесь должно быть documentation, да?
Да, есть вот она, документация.
Почему-то в Яндексе не выходит эта страница.
Очень странно.
Видимо, она не проиндексирована или заблокирована, или разработчики Яндекса не любят айограмм.
ну понятно да потому что у них там свои взгляды не будем лезть политику вот но мы видим в общем документацию то что здесь последняя версия 341 вот и соответственно у нас давайте запустим установку установится самая последняя актуальная версия ну документации обычно они спешат на одну версию там 343 возможно
здесь еще написано 341 до 33 возможно вполне я думаю что уже пиплись давайте напишем и видим что не только а я грамм здесь появился появилось много всего вот 341 общем сам актуальная версия но кроме него установился а ее файл да это тоже дополнительный модуль для работы с файлами асинхронно когда вы будете скачивать там какие-то картинки со своего бота
io.http, чтобы делать запросы, то же самое io.signal, какие-то дополнительные модули для того, чтобы все правильно работало.
В общем, с установкой какого-то фреймворка у вас дополнительно устанавливаются еще модули, он их сам загружает автоматически.
Это нужно знать, потому что иногда вот установишь, например, два фреймворка, и второй фреймворк установил точно такой же
модуль дополнительный, но с другой версией, из-за чего, например, первый перестал работать.
Бывает такое, что они друг с другом не контактят, и это все нужно учитывать, тоже смотреть, проверять эти версии.
Закрывать терминал не буду, он нам еще пригодится, я его просто вскрою.
Теперь давайте я сделаю чуть-чуть побольше экран, чтобы было видно, и создам новый файл.
Назову его просто main.py.
Это будет самый основной файл.
У меня здесь написано 3.12.
Давайте я поменяю на 3.11.7.
Вот этот вот мне нравится.
Но это нам ничего не дает.
Все равно я буду запускать через терминал, с помощью которого я создал виртуальное окружение.
А если здесь посмотреть, какая у нас версия, то выходит 3.11.7.
Вот, в общем-то, какая здесь версия, не важно особо, потому что я через вот это запускать не буду все равно.
Окей, хотя здесь мы можем выбрать, мы ведь создали виртуальное окружение, вот, вот теперь вот это правильно.
То есть он будет учитывать все библиотеки, которые я установил.
Дальше, нам нужно начать развертывать наш проект.
И давайте вот я сразу буду показывать именно как работают программисты, может быть не там Google программисты, да, но просто обычный стандартный программист.
Как он работает?
Смотрит документацию, конечно же.
И всегда, всегда, почти во всех документациях есть как бы быстрый старт.
Да, вот просто пример, на вот бери и все работает.
И вот мы смотрим, здесь точно такой же есть пример, что они нам показывают.
Что есть диспетчер, что есть роутеры, что есть функция main, в которой создается бот и есть старт полинг.
Много непонятных слов, возможно, сейчас, но в будущем для вас это будет основа основ.
Давайте мы это сделаем.
В первую очередь из Iogram я импортирую класс Bot Dispatcher.
Пока этого достаточно.
И я сразу создам два экземпляра класса.
Это так называется.
Если вы не знаете объектно-ориентированное программирование, то опять же некоторые слова могут быть непонятны.
Но нужно учиться, очень быстро стараться все вникать, все понимать.
Я создаю два объекта.
Первый объект это бот, второй объект это диспетчер.
В первый объект бот вы можете заметить, что я передаю токен.
Токен этого бота и соответственно в этой переменной хранится, грубо говоря, бот.
А диспетчер, он занимается хендлерами.
То есть что такое хендлер?
Приходит какое-то обновление, скажем, человек написал вам сообщение.
И это сообщение получает диспетчер, и мы будем прописывать то, как диспетчер будет обрабатывать это сообщение.
И давайте пока что создадим достаточно такую пустую функцию, но в будущем в ней будет много всего.
Функция main также будет называться как этот файл.
Кстати, файл я бы еще переименовал немножко по-другому.
Пока тоже пойдет.
dp start polling.
И в polling я должен передать как раз таки бота.
Поэтому я так и пишу.
Bot.
Да, та самая переменная, которая у меня была создана выше.
Именно не переменная, а это называется объект.
Или экземпляр класса, это можно назвать как угодно.
Дальше.
if name равно main.
Я создаю дополнительную конструкцию.
Для чего?
Для того, чтобы запускать функцию main, которую я написал выше.
if name равно main означает, что то, что написано внутри, будет запускаться только в том случае, если я запустил именно этот файл.
Но если я этот файл, например, импортировал, то то, что находится внутри, запускаться не будет.
А что у меня находится внутри?
Давайте импортируем.
Import asyncio.
Вот так.
async run и функция main значит что здесь происходит представим мы импортировали этот файл main опять же кто хорошо разбирается но не хорошо он более-менее до разбирается то у нас этот модуль весь будет грубо говоря интерпретирован не интерпретирован а проверен проверенный ну да скорее все интерпретирован вот и в этом случае запустится функция main если я ее не добавлю сюда
сработает вот эта часть, значит запустится полинг еще один, значит запустится еще один бот с таким же токеном, а значит произойдет ошибка.
Нам это не нужно.
И вообще импортировать отсюда тоже я не советую, потому что все равно в любом случае произойдет ошибка импорта, так как туда-сюда одно и то же импортировать нельзя.
И здесь как раз таки вот это if name равно main помогает нам обезопасить и избавить нас от ошибки.
Вот.
И следующим этапом нам нужно вот сюда вот токен подставить от Telegram бота.
Давайте я сейчас зайду в Telegram и создам этого бота.
Итак, мы можем наблюдать такую картину.
Я нашел вот такого бота.
Botfather.
У него вот такой вот никнейм Botfather.
И смотрите обязательно, чтобы у него была галочка.
Это был бот, а не пользователь.
Я отправляю сюда старт, он мне отправляет список своих команд.
И у него вот есть такая команда, самая первая, new bot, то есть создать нового бота.
Все, как вы его будете называть?
Например, sudo shop, скажем так.
Окей, давайте выберем юзернейм.
sudo shop bot, например.
Так, такой уже занят, конечно же.
sudo test shop bot.
В конце обязательно должно быть bot.
все он говорит отлично ваш бот готов и выдает нам вот такой вот токен он прям так и пишет для доступа для с помощью http api копируем его одним нажатием и подставляем сюда все по сути у нас все готово и наш бот будет подключаться но пока что никаких действий он не выполняет вот и в этом есть проблема вся
Давайте мы это исправим.
Каким образом мы можем это исправить?
Я напишу обработчик.
Обработчик будет, скажем, ловить все сообщения.
То есть я написал декоратор, диспетчер.
У него есть метод message.
И давайте asyncdef, напишем cmd start, команда start.
И вот здесь мы должны написать, а что мы ловим.
Мы ловим сообщение.
А значит, давайте from iogram types, то есть типы.
Какие есть типы данных в iogram?
Есть такой тип данных, как message.
И мы скажем, создадим переменную message и подскажем, что это тип message.
И будем отвечать message answer.
Привет.
Привет.
То есть запоминаем сразу.
Я написал декоратор, то есть мы говорим, что мы обрабатываем сообщение.
Потом я создал асинхронную функцию, где определил, что на вход функции будет приходить также тип сообщения.
Для того, чтобы в будущем мне было легче с ним взаимодействовать, я видел там все методы, например, которые могут быть использованы.
И вот, когда я пишу месседж, я вижу, что у него есть метод «answer».
То есть на пришедшее сообщение мы отвечаем, мы даем ответ «answer».
И мы даем ответ «Привет».
Есть еще один метод, который мы можем также рассмотреть.
Например, «Reply».
Как дела?
Давайте посмотрим, как это работает.
Запустим бота.
Что он нам скажет?
Я так и напишу «python main.py».
и все если он молчит значит все окей значит никаких ошибок не выходит давайте я зайду в этого батан нажму старт вот он не пишет привет
Как дела?
То есть в чем отличие?
Давайте уберу пока терминал.
В чем отличие?
Когда я написал «answer», он мне просто отправил сообщение, ответил на мое.
А когда я написал «reply», то он зареплайил мое сообщение.
Он прям выделил вот так вот «start» и на него ответил «как дела?».
Что мы здесь в итоге видим?
Мы в первую очередь подключаемся к боту, потом создаем диспетчер, то есть это наш обработчик, это наш роутер, наш помощник.
И мы говорим, что вот этот диспетчер должен ловить сообщения.
Мы сами себе как бы подсказываем, что нам приходят сообщения.
И у сообщения есть несколько методов.
Мы на него, например, можем ответить вот такими двумя способами.
Вот и передаем в кавычках, что мы хотим ему ответить.
Все.
Далее у нас есть функция main, внутри которой с помощью диспетчера мы начинаем полинг.
Что такое полинг?
Это когда наш скрипт...
Каждый промежуток времени обращается к серверу Telegram.
Этот промежуток времени очень-очень маленький.
Он обращается к серверу Telegram и спрашивает, а не пришло ли там какое-то обновление.
Что такое обновление?
Обновление это вот, когда я отправил сообщение или его отредактировал, или отправил там картинку какую-то, музыку и так далее.
Это все обновление.
Вот он говорит, а не пришло ли обновление?
Когда я отправил это сообщение, Telegram сказал, да, пришло, и отправил это диспетчеру.
Диспетчер посмотрел, сказал, да, это месседж.
И так как мы никаких фильтров не указывали, то есть он сейчас нам отвечает на абсолютно все, не только на команду старт,
Что угодно мы ему напишем, он нам будет вот так вот отвечать.
Он нам на абсолютно все отвечает таким образом.
Вот и все.
И вот это async run main запускает эту функцию.
Хорошо, давайте вернем терминал.
Я напишу ctrl-c, нажму точнее ctrl-c для того, чтобы выключить этого бота.
И мы видим, что происходит вот такая ошибка.
Это все из-за того, что у нас опять же используется тот самый polling.
И мы можем это исправить.
Каким образом словить именно вот эту ошибку?
Keyboard interrupt.
Я здесь напишу try.
И вот здесь допишу.
А, ну просто try точнее сначала.
А потом допишу accept.
Какой accept?
Какая ошибка?
Keyboard interrupt.
Все.
И напишу print.
Bot выключен, например.
Все.
И теперь такой ошибки происходить не будет.
Точнее, вообще правильнее сказать, да, она будет происходить, но она в терминале у нас отображаться не будет, вместо этого будет выходить вот это.
И вот и все.
Хорошо, мы немножечко разобрались, что импортировать, что такое диспетчер, что такое if name равно main, как выглядит обработчик.
И давайте мы все-таки создадим фильтр, чтобы у нас бот отвечал не на каждое сообщение, а на какое-то определенное.
Для этого из iogram, получается from iogram filters, я импортирую, давайте command start, я хочу, чтобы на command start у меня какие-то были сообщения, потом хочу только на какую-то команду.
И вот отсюда давайте еще я импортирую F. F это от слова фильтр.
Вообще это называется Magic Filter, не знаю почему так называется.
И к Magic Filter нет нормальной документации, там нужно просто нащупывать.
Ну она есть, но она самая минимальная.
Давайте посмотрим, может быть ее дописали, не знаю.
А вот они, Filtering Events называется оказывается.
Вот здесь, видите, есть много вариантов.
Мы можем создавать либо свои фильтры, то есть проверять, например, на администратора, создать какую-то свою систему.
Либо мы можем использовать уже готовые варианты.
То есть, видите, здесь используется как раз таки F. И мы можем проверять текст, не начинается ли он с какого-то слова.
Но пока это может тоже показаться непонятным, но мы сейчас разберемся.
встроенные фильтры первое это видео команд команд например старт может быть команда старт еще из чего-то она может состоять то есть какой-то набор может быть символов вот есть такой вариант кроме этого есть надо дать вот это пропустим пока что потому что это относится к немножко другому более сложному
magic filters есть который мы также сегодня рассмотрим ведь это просто мы ловим какой-то текст или ловим какого-то определенного пользователя ну вот или наоборот у нас текст не равен чему-то такое тоже возможно и кроме этого
У нас есть всякий callback data factory, magic data.
Мы обязательно это тоже рассмотрим.
Не знаю, на этом уроке или нет, но сейчас мы углубимся именно в основу.
И давайте воспользуемся command start.
Сюда ничего не нужно передавать.
Просто теперь это будет выполняться только в случае, если я напишу команду start.
Мне этого недостаточно, я хочу добавить сюда, например, еще одну команду в свой бот.
Пусть это будет command, только не start теперь, а, например, help.
И когда я буду писать async dev cmd help, неважно как называется функция, кстати, без разницы, хоть они будут называться одинаково, вы нажали на кнопку помощи.
Вот так вот.
И давайте опять же запустим, посмотрим, как это все работает.
Я запускаю файл mainpy.
И теперь смотрите, я опять пишу команду start.
Он мне отвечает также, все правильно.
Теперь я пишу что-то непонятное.
Он мне не отвечает ничего, потому что мы это больше не обрабатываем.
Я ему пишу команду help, которую я создал.
И он мне говорит, вы нажали на кнопку помощи.
то есть теперь у нас обрабатывается два вида события это команда старт и команда help кроме этого я могу ему написать скажем если человек отправил сообщение у меня все хорошо это просто очень грубый пример конечно
7 дина из просто найс назовем так функцию да это все ради примера на самом деле так не бывает сразу предупреждаю просто чтобы вы знали что есть такой функционал просто он будет чуть-чуть усложняться в процессе вот а так это основы я очень рад
Давайте я скопирую это сообщение.
То есть теперь не забывайте также перезапускать бота.
Смотрите, я нажимаю опять Ctrl-C, он мне не говорит, он мне больше не дает вот эту ошибку, он пишет бот выключен.
Теперь я снова запускаю и я отправляю ему эту же команду.
Например, у меня... Нет, давайте вот так для красоты.
Я пишу старт.
Он мне говорит, привет, как дела?
Я говорю, у меня все хорошо.
Он говорит, я очень рад.
Видите, уже получился такой небольшой диалог с ботом.
Вот.
И у нас есть вот три вариации того, как мы можем обрабатывать эти сообщения.
Пока что эти вариации, конечно, минимальные, но мы будем сейчас над этим еще работать.
Очень многое.
Теперь нам нужно подумать о структуре нашего проекта, потому что представьте, что если у вас будет очень много этих роутеров, точнее этих обработчиков, то проект будет немного захламленный, потому что здесь у вас будет увеличиваться, представьте, у вас появится еще база данных, это все в один файл, будет большая каша, ничего не понятно.
Поэтому мы за красоту, за эстетику, потому что Python это же самый красивый язык программирования.
Значит, мы должны этому соответствовать.
Поэтому я предлагаю создать здесь папку app от слова application, приложение, и внутри...
App создать еще одну папку и назвать ее handlers.py, то есть это обработчики, если говорить на русском, обработчики, то есть вот эти dp-месседж, которые я создавал, будут храниться теперь в этом файле, но только немного в другом формате.
кроме этого мы сейчас еще с вами создадим клавиатуру вот это интересный keyboards .
пай я создаю еще один один файл что нам может пригодиться еще ну думаю в процессе этого урока пока достаточно
Вот.
Мы, конечно, будем еще усложнять, когда мы будем создавать такие middleware, там, кастомные фильтры, базу данных.
Для этого у них будут свои папки, свои файлы.
Вот я знаю людей, которые любят там ради одного файла создавать отдельную папку.
Ну...
Мы до этого обязательно дойдем.
И теперь что мы делаем?
Вот эти хендлеры нужно переместить отсюда, убрать их просто отсюда, сюда.
Но мы, конечно же, видим, что возникают ошибки, поэтому мы должны опять же вот эти импорты тоже переместить вот сюда.
И немножечко еще дописать.
Давайте вот так вот допишем.
Я чуть-чуть промахиваюсь по клавиатуре из-за микрофона.
From iogram import f нам не хватает.
Но ошибка с диспетчером.
Да, многие так делают, начинающие.
И им говорят, блин, а диспетчера-то нету.
И делают вот так.
From main import dp.
И при запуске получается ошибка.
Потому что так делать нельзя.
И на этот случай есть прекрасный класс, который называется роутер.
И мы можем разделять всю эту систему, всю эту иерархию на роутеры.
И есть роутер, который обслуживает пользователя, есть роутер, который обслуживает администратора.
И это очень удобно.
Давайте я создам объект от этого класса.
Он будет просто называться также роутер, например.
Потому что у нас больше пока что ничего нету.
И вот этот dp я заменю на переменную router.
Вот так.
И все просто.
Но окей, я создал роутер.
Я ловлю, получается, все эти сообщения через роутер.
Но диспетчер-то не знает о том, что у меня этот роутер есть.
Мы должны ему об этом сообщить.
Поэтому from app.handlers import router.
Я импортирую этот роутер в основной файл.
Дальше диспетчеру говорю включить роутеры, да, include router, как бы добавить.
И, в общем-то, у меня эта перемена уже есть.
Все.
И так как больше хендлеров у нас нету в этом файле, мы имеем полное право переместить вот эти две переменные внутрь этой функции.
Вот таким образом.
Вот и все.
Теперь все выглядит намного-намного красивее.
И хочу заметить, что видите, у меня отделены.
Но я бы его так вот сделал, но не очень.
Можно его так сделать.
Но я все-таки люблю оставлять пробелы, потому что видите, здесь у меня обычный импорт.
Здесь у меня будут импорты по айограмму.
И отдельно у меня импорты по моему проекту.
Здесь получается у нас подключается все.
Мы добавляем роутер.
Дальше срабатывает этот роутер и обрабатывает именно эти месседжи.
Все отлично.
В общем-то, наши роутеры мы подключили.
И давайте теперь перейдем к созданию клавиатуры.
Представим, что мы делаем какой-то интернет-магазин.
И, конечно, пока что базы данных у нас нет, но давайте будем просто импровизировать и делать все достаточно статично.
Но в будущем, когда мы познакомимся с вами с базами данных, мы, конечно же, будем доставать все оттуда, потому что так нужно делать.
И никто не прописывает товар заранее в клавиатуру.
Конечно, она берется из базы данных и генерируется динамически.
Но сейчас нам нужно научиться делать просто обычную клавиатуру для начала.
И для этого опять нужно импортировать.
Из iogram опять тот же самый types мы импортируем.
Давайте сначала начнем с reply кнопок.
Reply keyboard markup и keyboard button.
Два вот таких класса нам нужно.
Что вообще клавиатура, какая бывает клавиатура?
Давайте я открою список ботов, которые у меня есть.
И смотрите, я нашел бот, тоже как интернет-магазин.
Видимо, я делал какой-то тестовый проект на видео.
И мы здесь можем наблюдать два вида клавиатуры.
Первый вид это Inline, а второй вид это Reply.
То есть те кнопки, которые находятся снизу, называются Reply клавиатуры.
Почему Reply?
Потому что при нажатии отправляется сообщение в бот.
Поэтому она называется Reply, потому что она как бы отвечает.
И есть Inline.
Это Inline клавиатура, она не отправляет сообщения, она отправляет какой-то запрос, например, callback в бота.
И мы, конечно же, сначала познакомимся с вот этой Reply клавиатурой.
Мы сегодня познакомимся с двумя видами сразу.
Ну вот начнем именно с нее, потому что то, что она легче, возможно, не знаю.
И давайте у нас будет Main клавиатура.
Reply Keyboard Markup.
Я создаю класс.
А точнее Main у нас является экземпляром класса.
Что я делаю?
Reply Keyboard Markup.
Представим, что таким образом я создаю цельную клавиатуру.
И в эту клавиатуру теперь я добавляю кнопки с помощью класса Keyboard Button.
Вот так вот.
Keyboard Button я пишу.
Но не все так просто.
Мы видим, что вот у меня Keyword Argument.
Keyboard.
И он принимает в себя список, внутри которого находится еще один список, внутри которого находится KeyboardButton.
То есть список это сама клавиатура, внутри этой клавиатуры есть ряды и внутри этого ряда я создаю кнопку.
Например, у меня будет первый каталог.
Вот таким образом.
Получается, каждый список это один ряд.
Давайте я создам три ряда.
Кейборд баттон у меня будет еще один.
Например, корзина.
И еще один кейборд баттон.
Это контакты.
И давайте в этом же ряду я создам еще один кейборд баттон.
Пусть будет так.
Кроме контактов у нас еще будет анас.
Например, why not.
Все, получилась такая клавиатура.
Получается у меня будет 3 ряда, в каждом ряде по одной кнопке, но в последнем третьем ряду у меня будет 2 кнопки, потому что они находятся в одном списке.
Получается этот оранжевый список это как бы один ряд, а вот этот зеленый список это уже вся целая клавиатура.
Это все реплай клавиатура, которая высвечивается снизу.
И давайте в хендлере мы ее подставим.
Я сначала должен импортировать, from app, я импортирую все по отношению к файлу main, то есть с main я смотрю, я захожу в папку app, оттуда захожу в keyboards, давайте не from, а прям так и напишем импорт, потому что у нас другого ничего нету, skb.
То есть я упростил это название, импортировал полностью файл Keyboards и дал ему короткое название.
Теперь, клавиатура всегда цепляется к какому-то апдейту, который вы отправляете.
Какой апдейт вы можете отправлять?
Это сообщение, конечно же.
И вот, например, когда мы отправляем сообщение «Привет!»
мы можем прицепить туда как раз таки этот апдейт reply markup kb.main, по-моему, называется, да?
kb.main.
Получается, что для того, чтобы прикрепить вот эту клавиатуру, я использую reply markup и потом обращаюсь к этой переменной.
reply markup равно kb.main, это значит открыть клавиатуру main, когда я буду отправлять сообщение привет.
Вот и все.
И давайте самое время для того, чтобы это протестировать, как оно работает, я снова перезапущу бота.
Не забывайте также сохранять все файлы.
Вот, я захожу, я уже забыл, Sudo Shop, по-моему, да.
Я написал, получается, старт, и мы здесь видим, что у нас вышла вот эта вся клавиатура.
Также, как я говорил, каталог, корзина в один ряд и контакты о нас, это уже в один ряд две кнопки.
Кнопки на самом деле немного большеваты, потому что если мы смотрим куда-нибудь сюда, то мы здесь видим, что кнопки, видите, такие маленькие, а здесь они большие.
И надо это исправить.
Каким образом?
Мы можем добавить сюда пару фич.
Я поставлю запятую и добавлю еще пару аргументов.
Например, Resize Keyboard.
Как раз таки он делает клавиатуру маленькой.
И еще мы сюда можем добавить, например, Input Field Placeholder.
Placeholder.
Выберите пункт Menu.
Что такое Placeholder?
Это, видите, здесь написано Write a Message.
Вот вместо Write a Message будет написано Выберите пункт Menu.
Я думаю, это очень удобно, если у вас какой-то там кастомный бот с подсказками.
Крутая фишка.
Вот.
И...
Попробуем еще раз.
Пишу снова старт.
И мы видим, да, выберите пункт меню.
Кнопочки стали поменьше, поминиатюрней.
Не знаю, кому как больше нравится.
Но есть такой вариант, есть такая возможность их уменьшить.
Вот и все.
И давайте теперь inline клавиатура.
Она создается абсолютно так же.
Представим, что при нажатии кнопки каталог, давайте обработаем как раз эту кнопку, у нас будет открываться inline клавиатура.
Пока что если я нажимаю на эти кнопки, то видите, ничего не происходит.
Я сделаю так, что когда я нажимаю на «Каталог», у меня будет открываться inline клавиатура, и там будет написано категория, например, что у нас есть в каталоге.
Давайте сначала создадим клавиатуру.
Я создам ее, а так и назову «Каталог».
Но только для начала нам нужно, конечно же, импортировать все, что нужно.
Inline Keyboard Markup и Inline Keyboard Button.
Вот так вот.
Мы видим, что за границу уже выходят импорты.
По правилу PEP мы не проходим.
Соответственно, я беру их скобки и переношу.
Вот так вот.
Теперь я пишу сюда Inline Keyboard Button.
текст, ой, извиняюсь, inline keyboard markup, и сюда мы добавляем inline keyboard, и точно таким же образом, как до этого, мы создаем баттоны.
Пишем сюда текст, равно, например, футболки, давайте сделаем сюда inline keyboard button текст кроссовки, и что еще у нас будет?
Давайте здесь аккуратно, чтобы не то не вписать.
Вот.
Футболки, кроссовки и пусть будут, например, кепки.
Why not?
Кто-нибудь носит кепки?
Значит, что мы здесь видим?
По сути, точно так же, по такой же аналогии были созданы кнопки.
Но чтобы не тратить время, я даже не буду запускать и показывать ошибку.
На самом деле здесь произойдет ошибка.
Почему?
Потому что Inline не может создаваться просто с текстом.
Если Keyboard Button нас отправляет текст в чат, и мы можем его словить и обработать,
то смысл от текста в inline кнопки, потому что она ведь не отправляется в чат.
И нам нужно как-то понять, что мы отправили именно это сообщение.
Поэтому сюда, к inline, мы должны добавить еще callback, callback data.
Футболка – это у нас t-shirt.
У меня очень плохой акцент.
Callback – это кроссовки.
Сникерс.
И кепки.
Кстати, не знаю, как будет кепка на английском.
Кто знает, как будет кепка?
Давайте как настоящие программисты воспользуемся Translate.
Вот.
И напишу кепка.
И выйдет... А, ну кеп.
Это же гениально.
Колпачок, крышка.
Вот у нас не только программируемый, у нас еще и английский язык сразу.
В идеале сделать вот так.
это у нас все переносится сюда теперь видите и для того чтобы слишком длинный не было можно еще вот так сделать но это прям не знаю для кого меня вот так тоже устраивает некоторые любят так некоторые чего так сделать нет
как-нибудь вот так, наверное.
Вот как-нибудь вот так.
Не знаю.
Мне и так норм.
Не будем зря тратить место для экономии.
Как по пепу правильно.
Можно отформатировать, конечно, но смысл.
Окей.
Значит, у нас есть теперь вот такая inline клавиатура.
И нам нужен вот этот каталог.
обработать то есть когда я нажму на эту кнопку должна открыться эта клавиатура каким образом я должен видеть у меня есть f текст давайте его переделаем и теперь получается когда мы нажимаем каталог у нас сообщение отправляется в чат каталог мы ловим здесь давайте переименую также функцию каталог будем отправлять ему выберите категорию
товара и здесь reply markup kb .
каталог вот таким образом получается я нажимаю сюда каталог отправляется сообщение каталог я его ловлю говорю выберите категорию товара и открываю клавиатуру каталог который является у нас inline вот такой план получился
Сработает ли он?
Сейчас мы проверим.
Давайте запустим.
Main, пишу старт.
Видим, что привет, как дела?
Я нажимаю каталог.
И у нас выходит, выберите категорию товара.
Футболки, кроссовки, кепки.
Все, супер.
Теперь я нажимаю, например, на футболки.
И, конечно же, тоже ничего не происходит.
Это действие тоже нужно обработать.
Каким образом?
Словить callback.
Если до этого мы с вами научились ловить message, то теперь нужно научиться ловить callback.
В этом нет ничего страшного и нет, по сути, каких-то огромных отличий.
И, кстати, если вам в какие-то моменты становится сложно понимать, что здесь происходит, или вы хотите получить более углубленные знания, то я приглашаю вас посетить мой сайт sudoteach.com и присоединиться к курсу по ботостроению в Telegram.
Вот он этот курс «Ботостроение Telegram».
Он не только рассматривает все намного глубже и детальнее, но еще и бонусом к нему вам выдается эксклюзивный чат, где есть все другие участники курса, а их уже больше 100.
И при возникновении вопросов я и мои помощники постараются помочь с вашим вопросом в кратчайшие сроки.
Курс содержит в себе не только абсолютно всю нужную информацию по созданию ботов,
Ну и готовые проекты, шаблоны.
Поэтому я жду всех.
А теперь мы возвращаемся к callback.
Каким образом мы можем их ловить?
Для этого я точно так же обращаюсь к роутеру и говорю сюда просто callback query.
И пишу теперь не ftext, а fdata, потому что это callback data.
И, например, я ловлю здесь, что у нас написано в футболках.
Вот это название.
Давайте вот мы ловим футболки.
И теперь я точно так же создаю функцию, назову ее таким образом.
И здесь мы уже ловим не message, а callback.
Я называю переменную по-другому, можно ее и message назвать.
Главное, что тип данных, который вы ловите, должен быть callback query.
Вы можете написать message callback query, но лучше написать callback query.
И теперь await message, тоже я не напишу, я напишу await callback, ой, callback, а потом message, а потом answer.
И здесь напишем, например, вы выбрали категорию футболок.
Но пока что мы ему футболки выводить не можем, потому что у нас их как бы...
Нету, да, то есть, ну, в базе данных их нет, а вручную нам забивать их смысла тоже нету.
Вот, поэтому мы лучше научимся сразу потом, как работать с базами данных.
Давайте запустим просто и проверим, как оно все работает.
Я снова пишу старт, хотя мог бы и сюда сразу нажать, но давайте сначала пройдем весь путь.
Каталог.
Нажимаю футболки.
Вы выбрали категорию футболок.
Но вот эта штука горит.
И это плохо.
Нам нужно на callback отвечать callback, а не сообщением.
Поэтому здесь я должен написать await callback answer.
Вы выбрали, например, категорию.
Callback answer отправляет уведомление.
Сейчас вы увидите, если успеете это уведомление.
Давайте я опять просто нажму сюда футболки.
И вот мы видим, вы выбрали категорию, видите, выходит уведомление.
Мы можем сделать другое немножко такое, более навязчивое уведомление, если написать show alert true.
Теперь...
Давайте опять перезапустим ботан.
Надо как-то сделать, да, чтобы это происходило более автоматически, более быстрее.
Снова нажимаю на футболки.
И уже выходит вот такое уведомление, да, более навязчивое.
Нажимаю кнопку «Ок».
Вот, все так же отправляет сообщение.
Вы выбрали категорию футболок, но уже не подсвечивается.
Вот, следите сзади.
Видите, как только я получил ответ, он сразу перестает подсвечивать.
Потому что на «Callback» он получил ответ «Callback».
Вот, так и должно быть всегда.
Но информации о том, как обрабатывать сообщения, на них отвечать и добавлять клавиатуру может быть не всегда достаточно.
Например, у нас в боте происходит процесс регистрации.
Представьте такое.
Нам нужно собирать какую-то информацию у пользователя и ее каким-то образом обрабатывать, сохранять у себя.
То есть вести какой-то полноценный диалог.
При этом, чтобы другие команды
Не срабатывали и не мешали нам.
И давайте я приведу опять же пример с регистрацией.
И создам вот такую команду.
Router.
Буду обрабатывать Message.
Здесь Command.
Register, например.
И при регистрации...
Я буду запрашивать у него какие-то данные.
А именно, введите ваше имя, например.
Сейчас у меня, видите, закончилась память.
Оказывается, я ее чуть почищу.
Итак, значит, я делаю команду регистр.
Ловлю такое сообщение в виде команды.
И говорю ему, введите ваше имя.
И вот сейчас он напишет свое имя.
А имя-то, оно не одинаковое.
У всех разное имя.
И я никак не смогу ни с помощью f-текст его словить, ни с помощью команды.
Никак.
И вот в этом случае я уже должен использовать состояние.
Что такое состояние?
Когда пользователь напишет команду регистр, я ему присвою состояние регистрации и скажу, что вот сейчас он находится в процессе регистрации и он должен написать свое имя.
И в таком случае, когда он напишет свое имя, я проверю в каком состоянии он находится и пойму, что сейчас он отправил свое имя и ничего другое.
Для этого я должен сначала создать и прописать эти состояния.
Я не буду делать для этого отдельный файл, но вообще в идеале, если у вас состояний много, то лучше это сделать.
Вот, просто сейчас я показываю опять же самый быстрый и легкий вариант.
Значит, from iogram, fsm, давайте state, import, получается state, и states, groups нам нужен, а также from iogram, fsm, context, import, fsm, context.
И теперь создаем те самые состояния.
Я создаю класс, так и назову его регистр.
И он должен быть дочерним по отношению к StatesGroup.
И что здесь есть?
Мы у него спросим имя.
Давайте это у нас состояние.
Мы у него спросим возраст.
Давайте без лишних пробелов, чтобы тоже состояние.
И что мы у него спросим?
А давайте номер телефона мы у него спросим.
Number.
Да, вот так вот стоит.
Все супер.
И заодно я покажу, как сделать кнопку, которая запрашивает номер.
Все.
И в первую очередь, конечно, вот когда мы говорим ему «Видите ваше имя?», мы кроме этого передаем сюда «State» вот таким образом.
И это состояние ему присваиваем.
То есть я говорю «State» «Установить состояние» «Register.name».
И вот теперь, когда он нажмет отправить, точнее вот эту команду регистр, ему присвоится вот это состояние.
И следующим хендлером я буду ловить уже не его имя, а буду ловить это состояние.
Вот таким вот образом.
DevRegisterName я напишу, потому что он нам в этот момент отправляет свой name.
Вот это я скопирую для того, чтобы легче сюда подставлять.
И теперь я информацию, которую он нам прислал, должен сохранить.
UpdateData пишу name равно MessageText.
Что это значит?
Я сохраняю информацию под ключом name.
То, что он нам прислал.
То, что он нам прислал, хранится в сообщении в поле текст.
Дальше я меняю это состояние.
Await state.
Set state опять.
Регистр на age меняю.
И говорю await message answer.
Уже введите ваш возраст, например.
Точно так же человек отправляет свой возраст.
И мы уже ловим не его возраст, который может быть любой, а его состояние.
И точно так же asyncdef register age.
Точно таким же образом давайте сделаем.
Я сохраняю его age.
Я изначально мог так сделать.
И здесь пишем number.
И уже говорим отправьте возраст.
Отправьте ваш номер телефона.
И что мы здесь сделаем?
Такой интересный моментик.
Чтобы отправить номер телефона, он может его написать вручную, а может нажать на кнопку «Просто отправить номер», которую мы заготовим заранее.
И все, для его удобства.
Давайте так и сделаем.
Get number будет называться клавиатура.
Это будет reply клавиатура, который будет keyboard.
И всего лишь одна кнопка.
Keyboard button.
Отправить номер.
И мы здесь сделаем request contact true.
То есть, когда он нажмет на эту кнопку, мы у него запросим его контакт.
Вот и все.
И, конечно же, здесь добавим еще resize keyboard true, чтобы она не была огромная.
Все.
И сюда, в Reply Markup, эту кнопку подставим.
kb.getNumber.
Все, теперь он отправит свой номер, и мы его увидим.
И здесь есть два варианта, когда мы создаем новый роутер.
Мы можем написать регистр number просто так.
То есть он нам может отправить любой номер.
Может свой отправить, может сам написать.
А если мы хотим, чтобы он нам отправил именно через нажатие этой кнопки, то мы можем добавить сюда еще и фильтр.
fcontact.
Вот таким образом.
То есть 100% он нам отправит только контакт.
Может быть свой, может чужой.
Регистр number.
Все.
Ой.
Давайте уже руками напишу.
Message, Message.
И получается State, Face and Context.
Все.
И здесь точно так же мы сохраняем всю вот эту информацию.
Уже здесь менять состояние вообще-то не нужно.
Это у нас, давайте, Number.
И теперь сохраненную информацию нам нужно достать.
Каким образом?
Давайте достанем ее в переменную data.
Я напишу await state get data.
То есть, наоборот, достать информацию.
И выведем эту информацию, собранную этому же пользователю.
Каким образом?
Через зап-строчку напишем ваше имя.
Я уже забыл, чем мы запрашивали.
По-моему, имя.
Data name.
Потом ваш возраст.
дата и последнее чем у него запрашивали контакт номер получается дата контакт вот и все вот таким образом мы работаем мы запросили эту информацию пользователю обратно вывели и в самом конце
Состояние очистили.
Вот таким образом.
Чтобы пользователь дальше смог спокойно пользоваться этим ботом.
Давайте протестируем.
Возможно вылезут какие-то ошибки.
Может быть не вылезут.
Не знаю.
Посмотрим.
Проверим.
Как же это работает.
Я пишу команду регистр.
Он мне говорит, введите ваше имя, пишу имя.
Он говорит, введите ваш возраст.
Пишу свой возраст.
И он говорит, отправьте номер телефона.
Отправляю номер.
Share.
И да, происходит ошибочка.
Почему?
Потому что контакт не нашел, потому что я гений.
И вместо number написал контакт.
Здесь будьте осторожны в такие моменты.
Да, теперь запустим еще раз.
Спойлер, если вы разрабатываете ботов, у вас будет очень много таких моментов, когда вы повторяете, грубо говоря, одно и то же, тестируете там.
Опять же, отправляю свой номер.
И все.
И он вывел мне вот эту информацию.
Только номер он мне вывел на... Почему?
Потому что это не message текст, видите, тоже, а message contact тоже.
То есть, контакт, который он нам отправил, мы его и ловим.
Все правильно.
Давайте еще раз попробуем, чтобы все правильно было.
Start.
Register.
Еще раз тестируем.
Отправляем номер.
И видим вот такую информацию.
То, что у нас есть phone number, есть first name, видите, есть last name, user id и даже v-card какой-то.
И здесь мы можем message-contact.
написать phone number, например.
И получается вот этот phone number, который я отправил, он подставится сюда.
Видите, сколько здесь методов, и эти методы всегда меняются.
Поэтому если вы изучаете какой-то фреймворк, например, то вот эта страница будет просто базой.
Вы будете заходить сюда постоянно и смотреть, а что же там поменялось, что же изменилось, чтобы мой бот не сломался и так далее.
вот и давайте финальную проверку сделаем регистр вот я также напишу имя возраст и номер телефона отправлю и вот мы видим что номер телефона уже подставляется нормально вся эта информация есть и если у вас есть база данных то конечно же в эту информацию в базу данных свою сохраняете все я закрываю терминал
вот такой вот у нас очень быстрый обзор основ айограмма да все что нужно как ловить команду старт как создавать свои команды как обрабатывать текст и кнопки как обрабатывать кубики как работать состояниями менять состояние сохранять информацию
потом доставать информацию, потом как с этой информацией работать.
То есть, видите, это у нас дикшенери, это словарь, и мы по ключу обращаемся к нужной информации, которую мы изначально до этого сохраняли.
Вот, и в конце очищаем.
Это называется FSM, машина состояния.
Также мы создали кейборды, видите, один реплай кейборд, один инлайн кейборд.
И, в общем-то, тоже развернули вот так вот бота.
Вот такое прям мини-мини приложение получилось.
Ну, даже не приложение, а просто, я надеюсь, вы взяли отсюда что-то полезное.
Мы обязательно продолжим, и будет вторая часть уже более профессиональная, как создать свои фильтры, как создать свои middleware.
Вот, и много таких более профессиональных фич, которые могут пригодиться уже для больших каких-то ботов, больших проектов.
На этом мы закончим.
Не забывайте посещать сайт sudoteach.com, ведь там есть все возможные курсы, в том числе и по базам данных.
Лучшей благодарностью для меня будет ваш лайк.
Оставляйте свое мнение в комментариях и подписывайтесь на канал, чтобы не потерять полезный контент.
Жду вас на следующем уроке.
Похожие видео: Телеграм Бот на Python с нуля

Клавиатура в Телеграм Ботах - Inline Reply и Builder на AIOGRAM 3.4 | 4 УРОК

PostgreSQL + Скрытие Токена в .env - Aiogram 3

База Данных и Выгрузка на Сервер Телеграм Бота на Python - Aiogram 3

Создание Telegram ботов на AIOGRAM 3.4 | 1 УРОК

CallbackQuery на AIOGRAM 3.4 | 5 УРОК

