Bot API v2: Кнопки и редактирование сообщений
В начале апреля 2016 года вышло первое по-настоящему крупное обновление API для ботов. Изменений довольно много, поэтому материал я разобью на несколько частей. Сегодня поговорим об inline-кнопках и редактировании сообщений, а затем обсудим новые инлайн-режимы вместе со специальными кнопками для отправки геолокации и номера телефона.
Новые возможности
Начнём с двух важных изменений:
- Каждая кнопка, будь то обычная или инлайн, это теперь самостоятельный объект KeyboardButton или InlineKeyboardButton , не забудьте обновить своих ботов!
- В Inline-режиме все текстовые поля теперь представлены отдельными объектами InputMessageContent , которые, в свою очередь могут быть аж 4-х типов (подробности тут).
URL-кнопки
Итак, инлайн-кнопки. Что это такое? Это специальные объекты, которые “цепляются” к конкретным сообщениям и распространяют своё действие, в общем случае, только на них. Делятся такие кнопки на три типа: URL-кнопки, Callback-кнопки и Switch-кнопки. Самыми простыми являются кнопки-ссылки (URL). Как видно из названия, их цель — просто перекидывать пользователей по определенным веб-адресам. Давайте сразу напишем обработчик, который будет на любое сообщение отвечать каким-либо текстом и предложением перейти, например, на Яндекс.
Инлайн-клавиатура представляет собой объект InlineKeyboardMarkup , а каждая инлайн-кнопка – это объект InlineKeyboardButton . Чтобы получилась URL-кнопка, нужно указать значения параметров text (текст на кнопке) и url (валидный веб-адрес). В результате бот пришлет нам такое сообщение (см. рис.). В целях обеспечения безопасности, перед переходом по URL-кнопкам появляется всплывающее окно, в котором видна ссылка целиком.
Callback-кнопки и редактирование сообщений
Прежде, чем мы перейдем к другим кнопкам, давайте познакомимся с функциями редактирования сообщений, коих тоже три: editMessageText (редактирование текста), editMessageCaption (редактирование подписи к медиа) и editMessageReplyMarkup (редактирование инлайн-клавиатуры). В рамках этого урока рассмотрим только первую функцию, остальные работают аналогично и предлагаются для самостоятельного изучения.
Чтобы отредактировать сообщение, нам надо знать, про какое именно идёт речь. В случае, если оно было отправлено самим ботом, идентификаторами служит связка chat_id + message_id . Но если сообщение было отправлено в инлайн-режиме, то ориентироваться надо по параметру inline_message_id .
И вот теперь вернемся к нашим баранам кнопкам. На очереди – Callback. Это, на мой взгляд, самая крутая фича нового обновления. Колбэк-кнопки позволяют выполнять произвольные действия по их нажатию. Всё зависит от того, какие параметры каждая кнопка в себе несёт. Соответственно, все нажатия будут приводить к отправке боту объекта CallbackQuery , содержащему поле data , в котором написана некоторая строка, заложенная в кнопку, а также либо объект Message , если сообщение отправлено ботом в обычном режиме, либо поле inline_message_id , если сообщение отправлено в инлайн-режиме.
Приведу пример, после которого все вопросы должны отпасть: пусть, например, если сообщение отправлено ботом в обычном режиме, то нажатие на кнопку заменит текст сообщения на “Пыщь”, если в инлайн – то “Бдыщь”. При этом в обоих случаях значение callback_data будет равно test . Что для этого нужно сделать: во-первых, написать простейший хэндлер для всех входящих сообщений, во-вторых, написать простейший хэндлер для инлайн-сообщений, в-третьих, написать простейший хэндлер для колбэка, который определит, из какого режима пришло сообщение.
Запускаем бота, отправляем инлайн-сообщение, которое, в свою очередь, вызовет обычное:
Нажмем на обе кнопки, результат правильный:
После проверки
Таким образом, callback-кнопки – это очень мощный инструмент для взаимодействия пользователей с ботом, а редактирование сообщений дополнительно помогает в этом. Более того, нажатие на колбэк-кнопку может дополнительно тригернуть либо уведомление в верхней части экрана, либо всплывающее окно. Покажу первый вариант. Пускай помимо изменения сообщения на “Пыщь”, аналогичное слово показывается уведомлением. Для этого перепишем первое if-условие в хендлере колбэков:
Результат – на скриншоте. Попробуйте, кстати, изменить аргумент show_alert на True и посмотрите, что получится.
Всплывающее уведомление
Switch-кнопки
Наконец, остался последний тип кнопок — Switch (переключатель). Они нужны, чаще всего, для обучения пользователей работе с ботом в инлайн-режиме. Чтобы активировать сделать кнопку такого типа, нужно указать аргумент switch_inline_query либо пустой, либо с каким-либо текстом. В последнем случае этот текст будет сразу подставлен в поле ввода, например, для показа демонстрации инлайна. Как вообще работает такая кнопка? При нажатии на неё Telegram предложит выбрать чат, после чего подставит в поле ввода ник вашего бота и (если есть), текст, указанный вами в аргументе switch_inline_query . Давайте попробуем так сделать. Добавим кнопку, которая будет перенаправлять пользователя в какой-либо чат и предлагать в инлайн-режиме запрос “Telegram”. Код всего хендлера выглядит вот так:
Теперь, если мы нажмем на кнопку и выберем чат, вот что получится:
Итак, в этом уроке мы познакомились с новыми кнопками в Telegram Bot API, научились переписывать историю редактировать сообщения и отправлять небольшие уведомления по нажатию. В следующий раз продолжим изучать новые возможности для ботов. А исходники к этому уроку можно найти в этом репозитории.
Создаем бота в Telegram
В этом статье я покажу как создать Telegram бота с помощью Python, поскольку не нашел хорошей русскоязычной статьи по этой теме.
Создание бота
Бот создается с помощью BotFather через Telegram. После команды /newbot надо просто следовать инструкции.
В конце мы получаем токен для управления ботом и работы с Telegram API.
pyTelegramBotApi
Ссылки на документации всех библиотек будут в конце.
Создадим простого бота, отвечающего на команду /start , с помощью этой библиотеки:
pyTelegramBotApi является просто обёрткой для всего Telegram Bot API, но здесь разберутся только основные составляющие.
Взаимодействие с ботом происходит через переменную bot (токен надо вставить свой).
Декоратор @message_handler реагирует на входящие сообщение.
Message – это объект из Bot API, содержащий в себе информацию о сообщении. Полезные поля:
message.chat.id – идентификатор чата
message.from.id – идентификатор пользователя
message.text – текст сообщения
Функция send_message принимает идентификатор чата (берем его из сообщения) и текст для отправки.
Примеры функций
Отправка изображений
Можно отправлять фото из локального хранилища, но удобнее это делать по ссылке. Код аналогичен предыдущему:
Замена клавиатуры
У ботов есть функция замены стандартной клавиатуры на кнопочную. Для этого у всех функций есть опциональный аргумент reply_markup:
ReplyKeyboardMarkup – и есть та самая клавиатура. Метод row() создает ряд (максимум 12) из кнопок, передаваемых в качестве аргумента.
Также есть особенная клавиатура types.ReplyMarkupRemove(), которая меняет клавиатуру на стандартную.
Клавиатура для сообщений
Можно создавать клавиатуру для отдельного сообщения. Передавать его нужно так же в аргумент reply_markup:
У кнопок есть несколько режимов, в зависимости от второго аргумента. Подробнее можно прочитать в официальной документации, но я остановлюсь только на callback_data.
При нажатии на такую кнопку боту придет отдельный CallbackQuery, который нужно обрабатывать подобно сообщению:
Для обработки обязательно указать аргумент func для «отсеивания» Callback запросов.
После обработки каждого запроса нужно выполнить команду answer_callback_query, чтобы Telegram понял, что запрос обработан. В поле callback.data хранится информация из callback_data нажатой кнопки.
Изменение сообщений
У ботов есть функция изменения своих сообщений (можно использовать, чтобы сделать перелистывание страниц, например). Для этого нужно воспользоваться методом edit_message_text (edit_message_caption для картинок):
Смысл аргументов понятен из их названия.
Flask
Если запустить бота, то через какое-то время он упадет с ошибкой Connection to api.telegram.org timed out. Чтобы это исправить нужно использовать вебхук:
Этот код при запуске сначала удалит вебхук, если такой был, и установит его на желаемый. Все запросы, которые приходят в функцию getMessage будут направляться в bot с помощью метода process_new_updates. Этот код уже можно использовать для запуска, например, на Heroku.
Callback data telegram python что это

- Регистрируем бота в Телеграме.
- Устанавливаем Python-библиотеку для работы с Телеграмом.
- Добавляем библиотеку в программу с гороскопом и учим программу реагировать на сообщения в чате.
- Пишем там же код, который покажет кнопки для выбора знаков зодиака.
- Сделаем так, чтобы по кнопкам появлялся гороскоп для этого знака.
Первый в списке со специальным значком подтверждения — это он.
С третьей попытки нам дали нового бота и токен для управления. Токен нужен для управления ботом, поэтому на экране его нет.
В конце видим сообщение об успешной установке, значит всё сделали правильно.
Бот отвечает именно так, как мы запрограммировали. Класс.
Такая ошибка во время запуска программы означает, что компьютер не может соединиться с сервером telegram.org, потому что его блокирует Роскомнадзор. Что делать? Сложно сказать. Если бы вы жили в другой стране, этой проблемы бы не было. Ещё можно использовать какие-то средства, которые направляют ваш трафик через другую страну, но рассказ об этих средствах является в России преступлением, поэтому тут мы вам ничего не можем подсказать.
Кнопки есть, но пока не работают. Сейчас исправим.
Нажимаем на кнопку — получаем текст гороскопа.
CallbackQuery¶
This object represents an incoming callback query from a callback button in an inline keyboard.
If the button that originated the query was attached to a message sent by the bot, the field message will be present. If the button was attached to a message sent via the bot (in inline mode), the field inline_message_id will be present.
Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their id is equal.
In Python from is a reserved word. Use from_user instead.
Exactly one of the fields data or game_short_name will be present.
After the user presses an inline button, Telegram clients will display a progress bar until you call answer . It is, therefore, necessary to react by calling telegram.Bot.answer_callback_query even if no notification to the user is needed (e.g., without specifying any of the optional parameters).
If you’re using telegram.ext.ExtBot.callback_data_cache , data may be an instance of telegram.ext.InvalidCallbackData . This will be the case, if the data associated with the button triggering the telegram.CallbackQuery was already deleted or if data was manipulated by a malicious client.
New in version 13.6.
id ( str ) – Unique identifier for this query.
chat_instance ( str ) – Global identifier, uniquely corresponding to the chat to which the message with the callback button was sent. Useful for high scores in games.
message ( telegram.Message , optional) – Message with the callback button that originated the query. Note that message content and message date will not be available if the message is too old.
data ( str , optional) – Data associated with the callback button. Be aware that the message, which originated the query, can contain no callback buttons with this data.
inline_message_id ( str , optional) – Identifier of the message sent via the bot in inline mode, that originated the query.
game_short_name ( str , optional) – Short name of a Game to be returned, serves as the unique identifier for the game.
Unique identifier for this query.
Global identifier, uniquely corresponding to the chat to which the message with the callback button was sent. Useful for high scores in games.
Optional. Message with the callback button that originated the query. Note that message content and message date will not be available if the message is too old.
Optional. Data associated with the callback button. Be aware that the message, which originated the query, can contain no callback buttons with this data.
The value here is the same as the value passed in telegram.InlineKeyboardButton.callback_data .
Optional. Identifier of the message sent via the bot in inline mode, that originated the query.
Optional. Short name of a Game to be returned, serves as the unique identifier for the game.
New in version 13.2.
For the documentation of the arguments, please see telegram.Bot.answer_callback_query() .
On success, True is returned.
async copy_message ( chat_id , caption = None , parse_mode = None , caption_entities = None , disable_notification = None , reply_to_message_id = None , allow_sending_without_reply = None , reply_markup = None , protect_content = None , message_thread_id = None , * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
For the documentation of the arguments, please see telegram.Message.copy() .
On success, returns the MessageId of the sent message.
async delete_message ( * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
For the documentation of the arguments, please see telegram.Message.delete() .
On success, True is returned.
async edit_message_caption ( caption = None , reply_markup = None , parse_mode = None , caption_entities = None , * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
Shortcut for either:
On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
async edit_message_live_location ( latitude = None , longitude = None , reply_markup = None , horizontal_accuracy = None , heading = None , proximity_alert_radius = None , * , location = None , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
Shortcut for either:
On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
async edit_message_media ( media , reply_markup = None , * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
Shortcut for either:
On success, if edited message is not an inline message, the edited Message is returned, otherwise True is returned.
async edit_message_reply_markup ( reply_markup = None , * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
Shortcut for either:
On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
async edit_message_text ( text , parse_mode = None , disable_web_page_preview = None , reply_markup = None , entities = None , * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
Shortcut for either:
On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
async get_game_high_scores ( user_id , * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
Shortcut for either:
async pin_message ( disable_notification = None , * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
For the documentation of the arguments, please see telegram.Message.pin() .
On success, True is returned.
async set_game_score ( user_id , score , force = None , disable_edit_message = None , * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
Shortcut for either:
On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
async stop_message_live_location ( reply_markup = None , * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶
Shortcut for either:
On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
async unpin_message ( * , read_timeout = None , write_timeout = None , connect_timeout = None , pool_timeout = None , api_kwargs = None ) [source] ¶