Как сделать кнопки в Телеграмм боте python aiogram

Прошлая статья оказалась провальной, именно поэтому хочу улучшить ситуацию путем написания продолжения. Ну буду отвлекаться на самые простые вещи, приступим!

Ну для начала, если вы из прошлой статьи, установите PyCharm. Думаю с установкой сложностей не возникнет, во всяком случае я на это надеюсь.

Открываем PyCharm, создаем файл main.py и начинаем писать.

  1. Импортируем необходимые библиотеки:

from aiogram import Bot, Dispatcher, executor, types from aiogram.contrib.fsm_storage.memory import MemoryStorage from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup from aiogram.types import Message import logging import sqlite3
logging.basicConfig(level=logging.INFO) storage = MemoryStorage() bot = Bot(token=API_TOKEN) dp = Dispatcher(bot, storage=storage)
conn = sqlite3.connect(‘db.db’) cur = conn.cursor() cur.execute(«»»CREATE TABLE IF NOT EXISTS users(user_id INTEGER, block INTEGER);»»») conn.commit()
class dialog(StatesGroup): spam = State() blacklist = State() whitelist = State()

Это первые приготовления, теперь мы готовы начинать писать основную логику

Как сделать меню для Телеграм бота на aiogram Python

Обработка команды «/start»

Тут мы добавляем три кнопки в админ-панель

Давайте напишем функцию обработки кнопки «Рассылка»

Теперь давайте обработаем кнопку «Рассылка»

Но тут мы только спрашиваем у админа что за текст рассылки

Теперь давайте обработаем этот текст и отправим его пользователям

Тут мы получаем пользователей из Базы и отправляем каждому сообщение

Теперь давайте сделаем добавление пользователей в ЧС

Сейчас мы будем обрабатывать кнопку «Добавить в ЧС»

Но опять же, сейчас бот ничего не сделает с полученным ID. Давайте будем банить пользователей)

Вот теперь, после того как Вы отправите ему ID пользователя, он проверить его, и если нашел этого пользователя в Базе не забаненый, то банит! В остальных случаях возвращает в главное меню

Теперь давайте будем Удалять пользователей из ЧС

Для начала, по стандарту, обработаем кнопку

И снова бот ничего не делает, сейчас исправим это!

Теперь добавим статистику для нашего бота

В отличии от других функций, эта будет самая простая.

Тут мы будем получать количество пользователей в боте, не активных, ни каких других, просто тех кто зашел хоть раз в бот

Теперь у вас есть еще и статистика для бота

В конце файла мы должны добавить две строчки

if __name__ == ‘__main__’: executor.start_polling(dp, skip_updates=True)

Теперь просто запускаем и идем проверять!
Понимаю функционал не большой, не то что говорилось в названии, но я принимаю предложения что же добавить еще! В будущем ваще предложения я скорее всего реализую, и буду добавлять в эту статью, либо в новую!

Весь код выложен на GITHUB

Источник: habr.com

Telegram бот на python aiogram #5 Клавиатуры и кнопки

Как сделать кнопку с выпадающим списком команд в aiogram?

Как сделать кнопку, после нажатия которые показывается весь список команд с описанием? Пример введите сюда описание изображения введите сюда описание изображения

Отслеживать
задан 14 июн 2022 в 8:12
31 4 4 бронзовых знака

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Для этого нужно написать в Botfather в Телеграм. Вводите команду /mybots , открывается список ваших ботов. Выбираете нужный. У вас открывается меню. Здесь нужно выбрать Edit Bot, а затем Edit Commands.

Ну или можно организовать следующим образом. Создать словарь с командами и описанием.

commands =

И уже из него вытягивать инфу в сообщение. Либо выводить на нового члена чата, либо на определённую команду.

Можно и клавиатуру сразу прикрутить в сообщение. Собрать из ключей словаря.

Источник: ru.stackoverflow.com

Кнопки Aiogram

Этот вид кнопок появился вместе с Bot API в далёком 2015 году и представляет собой не что иное, как шаблоны сообщений (за исключением нескольких особых случаев, но о них позже). Принцип простой: что написано на кнопке, то и будет отправлено в текущий чат. Соответственно, чтобы обработать нажатие такой кнопки, бот должен распознавать входящие текстовые сообщения.

Еще по теме:  Как в Телеграмме посмотреть все каналы если ты очистил историю

Напишем хэндлер, который будет при нажатии на команду /start отправлять сообщение с двумя кнопками:

Несмотря на то, что Telegram Bot API допускает указывать просто строки вместо объектов KeyboardButton , при попытке использовать строку aiogram 3.x выкинет ошибку валидации и это не баг, а фича.
Живите теперь с этим

Что ж, запустим бота и обалдеем от громадных кнопок:

Очень большие обычные кнопки

Как-то некрасиво. Во-первых, хочется сделать кнопки поменьше, а во-вторых, расположить их горизонтально.
Почему вообще они такие большие? Дело в том, что по умолчанию «кнопочная» клавиатура должна занимать на смартфонах столько же места, сколько и обычная буквенная. Для уменьшения кнопок к объекту клавиатуры надо указать дополнительный параметр resize_keyboard=True .
Но как заменить вертикальные кнопки на горизонтальные? С точки зрения Bot API, клавиатура — это массив массивов кнопок, а если говорить проще, массив рядов. Перепишем наш код, чтобы было красиво, а для пущей важности добавим параметр input_field_placeholder , который заменит текст в пустой строке ввода, когда активна обычная клавиатура:

Смотрим — действительно красиво:

Кнопки в один ряд

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

Реакция на нажатие кнопок

Чтобы удалить кнопки, необходимо отправить новое сообщение со специальной «удаляющей» клавиатурой типа ReplyKeyboardRemove . Например: await message.reply(«Отличный выбор!», reply_markup=types.ReplyKeyboardRemove())

Keyboard Builder

Для более динамической генерации кнопок можно воспользоваться сборщиком клавиатур. Нам пригодятся следующие методы:

  • add() — добавляет кнопку в память сборщика;
  • adjust(int1, int2, int3. ) — делает строки по int1, int2, int3. кнопок;
  • as_markup() — возвращает готовый объект клавиатуры;
  • button() — добавляет кнопку с заданными параметрами, тип кнопки (Reply или Inline) определяется автоматически.

Создадим пронумерованную клавиатуру размером 4×4:

Результат работы сборщика кнопок

У объекта обычной клавиатуры есть ещё две полезных опции: one_time_keyboard для автоматического скрытия кнопок после нажатия и selective для показа клавиатуры лишь некоторым участникам группы. Их использование остаётся для самостоятельного изучения.

Специальные обычные кнопки

На момент написания этой главы в Telegram существует три специальных вида обычных кнопок, не являющихся обычными шаблонами сообщений. Это кнопки для:

  • отправки текущей геолокации (флаг request_location );
  • отправки своего контакта с номером телефона (флаг request_contact );
  • создания опроса/викторины (объект KeyboardButtonPollType).

Для первых двух типов достаточно установить булевый флаг, а для опросов и викторин нужно передать специальный тип KeyboardButtonPollType и, по желанию, указать тип создаваемого объекта.

Впрочем, проще один раз увидеть код:

Специальные обычные кнопки

Инлайн-кнопки

URL-кнопки¶

В отличие от обычных кнопок, инлайновые цепляются не к низу экрана, а к сообщению, с которым были отправлены. В этой главе мы рассмотрим два типа таких кнопок: URL и Callback. Ещё один — Switch — будет рассмотрен в главе про инлайн-режим.

Login- и Pay-кнопки в книге рассматриваться не будут вообще. Если у кого-то есть желание помочь хотя бы с рабочим кодом для авторизации или оплаты, пожалуйста, создайте Pull Request на GitHub. Спасибо!

Самые простые инлайн-кнопки относятся к типу URL, т.е. «ссылка». Поддерживаются только протоколы HTTP(S) и tg://

Отдельно остановимся на среднем блоке кода. Дело в том, что в марте 2019 года разработчики Telegram добавили возможность отключать переход к профилю пользователя у пересланного сообщения. При попытке создать URL-кнопку с ID юзера, у которого отключен переход по форварду, бот получит ошибку Bad Request: BUTTON_USER_PRIVACY_RESTRICTED . Соответственно, прежде чем показывать такую кнопку, необходимо выяснить состояние упомянутой настройки. Для этого можно вызвать метод getChat и в ответе проверить состояние поля has_private_forwards . Если оно равно True , значит, попытка добавить URL-ID кнопку приведёт к ошибке.

Еще по теме:  Телеграм архив как оттуда вытащить

Колбэки

Напишем хэндлер, который по команде /random будет отправлять сообщение с колбэк-кнопкой:

Но как же обработать нажатие? Если раньше мы использовали хэндлер на message для обработки входящих сообщений, то теперь будем использовать хэндлер на callback_query для обработки колбэков. Ориентироваться будем на «значение» кнопки, т.е. на её data:

Несмотря на то, что параметр кнопки callback_data , а значение data лежит в одноимённом поле data объекта CallbackQuery, собственный фильтр aiogram называется text .

Реакция на нажатие колбэк-кнопки

Ой, а что это за часики? Оказывается, сервер Telegram ждёт от нас подтверждения о доставке колбэка, иначе в течение 30 секунд будет показывать специальную иконку. Чтобы скрыть часики, нужно вызвать метод answer() у колбэка (или использовать метод API answer_callback_query() ). В общем случае, в метод answer() можно ничего не передавать, но можно вызвать специальное окошко (всплывающее сверху или поверх экрана):

Всплывающее окно при нажатии на колбэк-кнопку

В функции send_random_value мы вызывали метод answer() не у message , а у callback.message . Это связано с тем, что колбэк-хэндлеры работают не с сообщениями (тип Message), а с колбэками (тип CallbackQuery), у которого другие поля, и само сообщение — всего лишь его часть. Учтите также, что message — это сообщение, к которому была прицеплена кнопка (т.е. отправитель такого сообщения — сам бот). Если хотите узнать, кто нажал на кнопку, смотрите поле from (в вашем коде это будет callback.from_user , т.к. слово from зарезервировано в Python)

Когда вызывать answer() ?

В общем случае, главное — просто не забыть сообщить Telegram о получении колбэк-запроса, но я рекомендую ставить вызов answer() в самом конце, и вот почему: если вдруг в процессе обработки колбэка случится какая-то ошибка и бот нарвётся на необработанное исключение, пользователь увидит неубирающиеся полминуты часики и поймёт, что что-то не так. В противном случае, часики исчезнут, а пользователь останется в неведении, выполнился его запрос успешно или нет.

Перейдём к примеру посложнее. Пусть пользователю предлагается сообщение с числом 0, а внизу три кнопки: +1, -1 и Подтвердить. Первыми двумя он может редактировать число, а последняя удаляет всю клавиатуру, фиксируя изменения. Хранить значения будем в памяти в словаре (про конечные автоматы поговорим как-нибудь в другой раз).

И, казалось бы, всё работает:

Всё работает?

Но теперь представим, что ушлый пользователь сделал следующее: вызвал команду /numbers (значение 0), увеличил значение до 1, снова вызвал /numbers (значение сбросилось до 0) и отредактировал и нажал кнопку “+1” на первом сообщении. Что произойдёт? Бот по-честному отправит запрос на редактирование текста со значением 1, но т.к. на том сообщении уже стоит цифра 1, то Bot API вернёт ошибку, что старый и новый тексты совпадают, а бот словит исключение: Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message

Всё работает?

С этой ошибкой вы, скорее всего, будете поначалу часто сталкиваться, пытаясь редактировать сообщения. Вообще говоря, подобная ошибка часто говорит о проблемах с логикой генерации/обновления данных в сообщении, но иногда, как в примере выше, может быть ожидаемым поведением.

Еще по теме:  Бот для напоминаний в Телеграм

В данном случае проигнорируем ошибку целиком, т.к. нам важен лишь итоговый результат, который точно будет правильным. Ошибка MessageNotModified относится к категории Bad Request, поэтому у нас есть выбор: проигнорировать весь подобный класс ошибок, либо отловить весь класс BadRequest и попытаться по тексту ошибки опознать конкретную причину. Чтобы не слишком усложнять пример, обойдёмся первым способом и немного обновим функцию update_num_text() :

# Новые импорты! from contextlib import suppress from aiogram.exceptions import TelegramBadRequest async def update_num_text(message: types.Message, new_value: int): with suppress(TelegramBadRequest): await message.edit_text( f»Укажите число: «, reply_markup=get_keyboard() )

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

Фабрика колбэков

Когда вы оперируете какими-то простыми колбэками с общим префиксом, типа order_1 , order_2 … вам может показаться, что довольно легко вызывать split() и делить строку по какому-то разделителю. А теперь представьте, что вам нужно хранить не одно значение, а три: order_1_1994_2731519 . Что здесь артикул, цена, количество? А может быть, тут вообще год выпуска? Да и разбиение строки начинает выглядеть страшно: .split(«_»)[2] . А почему не 1 или 3?

В какой-то момент возникает необходимость структурировать содержимое таких callback data, и в aiogram есть решение! Вы создаёте объекты типа CallbackData , указываете префикс, описываете структуру, а дальше фреймворк самостоятельно собирает строку с данными колбэка и, что важнее, корректно разбирает входящее значение. Снова разберёмся на конкретном примере; создадим класс NumbersCallbackFactory с префиксом fabnum и двумя полями action и value . Поле action определяет, что делать, менять значение (change) или зафиксировать (finish), а поле value показывает, на сколько изменять значение. Оно помечено как Optional[int] , т.к. если action равен “finish”, то значение указывать бессмысленно. Код:

# новые импорты! from typing import Optional from aiogram.dispatcher.filters.callback_data import CallbackData class NumbersCallbackFactory(CallbackData, prefix=»fabnum»): action: str value: Optional[int]

Наш класс обязательно должен наследоваться от CallbackData и принимать значение префикса. Префикс — это общая подстрока в начале, по которой фреймворк будет определять, какая структура лежит в колбэке.

Теперь напишем функцию генерации клавиатуры. Здесь нам пригодится метод button() , который автоматически будет создавать кнопку с нужным типом, а от нас требуется только передать аргументы. В качестве аргумента callback_data вместо строки будем указывать экземпляр нашего класса NumbersCallbackFactory :

def get_keyboard_fab(): builder = InlineKeyboardBuilder() builder.button( text=»-2″, callback_data=NumbersCallbackFactory(action=»change», value=-2) ) builder.button( text=»-1″, callback_data=NumbersCallbackFactory(action=»change», value=-1) ) builder.button( text=»+1″, callback_data=NumbersCallbackFactory(action=»change», value=1) ) builder.button( text=»+2″, callback_data=NumbersCallbackFactory(action=»change», value=2) ) builder.button( text=»Подтвердить», callback_data=NumbersCallbackFactory(action=»finish») ) # Выравниваем кнопки по 4 в ряд, чтобы получилось 4 + 1 builder.adjust(4) return builder.as_markup()

Методы отправки сообщения и его редактирования оставляем теми же (в названиях и командах добавим суффикс _fab ):

Наконец, переходим к главному — обработке колбэков. Для этого в декоратор надо передать класс, колбэки с которым мы ловим, с вызванным методом filter() . Также появляется дополнительный аргумент с названием callback_data (имя должно быть именно таким!), и имеющим тот же тип, что и фильтруемый класс:

Ещё немного конкретизируем наши хэндлеры и сделаем отдельный обработчик для числовых кнопок и для кнопки «Подтвердить». Фильтровать будем по значению action и в этом нам помогут «магические фильтры» aiogram 3.x. Серьёзно, они так и называются: Magic Filter. Подробнее сие чародейство рассмотрим в другой главе, а сейчас просто воспользуемся «магией» и примем это на веру:

Фабрика колбэков

На первый взгляд то, что мы сделали, может показаться сложным, но в действительности фабрика колбэков позволяет создавать продвинутые колбэк-кнопки и удобно дробить код на логические сущности.

Источник: aiogram.ru

Рейтинг
( Пока оценок нет )
Загрузка ...