Создаем бота в Telegram
В этом статье я покажу как создать Telegram бота с помощью Python, поскольку не нашел хорошей русскоязычной статьи по этой теме.
Создание бота
Бот создается с помощью BotFather через Telegram. После команды /newbot надо просто следовать инструкции.
В конце мы получаем токен для управления ботом и работы с Telegram API.
pyTelegramBotApi
Ссылки на документации всех библиотек будут в конце.
Создадим простого бота, отвечающего на команду /start , с помощью этой библиотеки:
import telebot bot = telebot.TeleBot('1408700689:AAGVqcqscWWK7DnuNHahd0w1eNklfjPEVxE') @bot.message_handler(commands=['start']) def start(message): bot.send_message(message.chat.id, 'It works!') bot.polling()
pyTelegramBotApi является просто обёрткой для всего Telegram Bot API, но здесь разберутся только основные составляющие.
Взаимодействие с ботом происходит через переменную bot (токен надо вставить свой).
Декоратор @message_handler реагирует на входящие сообщение.
Message – это объект из Bot API, содержащий в себе информацию о сообщении. Полезные поля:
message.chat.id – идентификатор чата
message.from.id – идентификатор пользователя
message.text – текст сообщения
Функция send_message принимает идентификатор чата (берем его из сообщения) и текст для отправки.
Примеры функций
Отправка изображений
Можно отправлять фото из локального хранилища, но удобнее это делать по ссылке. Код аналогичен предыдущему:
@bot.message_handler(commands=['start']) def start(message): bot.send_photo(message.chat.id, photo=photo_url, caption='It works!')
Замена клавиатуры
У ботов есть функция замены стандартной клавиатуры на кнопочную. Для этого у всех функций есть опциональный аргумент reply_markup:
from telebot import types @bot.message_handler(commands=['start']) def start(message): markup = types.ReplyKeyboardMarkup() buttonA = types.KeyboardButton('A') buttonB = types.KeyboardButton('B') buttonC = types.KeyboardButton('C') markup.row(buttonA, buttonB) markup.row(buttonC) bot.send_message(message.chat.id, 'It works!', reply_markup=markup)
ReplyKeyboardMarkup – и есть та самая клавиатура. Метод row() создает ряд (максимум 12) из кнопок, передаваемых в качестве аргумента.
Также есть особенная клавиатура types.ReplyMarkupRemove(), которая меняет клавиатуру на стандартную.
Клавиатура для сообщений
Можно создавать клавиатуру для отдельного сообщения. Передавать его нужно так же в аргумент reply_markup:
from telebot import types @bot.message_handler(commands=['start']) def start(message): markup = types.InlineKeyboardMarkup() buttonA = types.InlineKeyboardButton('A', callback_data='a') buttonB = types.InlineKeyboardButton('B', callback_data='b') buttonC = types.InlineKeyboardButton('C', callback_data='c') markup.row(buttonA, buttonB) markup.row(buttonC) bot.send_message(message.chat.id, 'It works!', reply_markup=markup)
У кнопок есть несколько режимов, в зависимости от второго аргумента. Подробнее можно прочитать в официальной документации, но я остановлюсь только на callback_data.
При нажатии на такую кнопку боту придет отдельный CallbackQuery, который нужно обрабатывать подобно сообщению:
@bot.callback_query_handler(func=lambda call: True) def handle(call): bot.send_message(call.message.chat.id, 'Data: <>'.format(str(call.data))) bot.answer_callback_query(call.id)
Для обработки обязательно указать аргумент func для «отсеивания» Callback запросов.
После обработки каждого запроса нужно выполнить команду answer_callback_query, чтобы Telegram понял, что запрос обработан. В поле callback.data хранится информация из callback_data нажатой кнопки.
Изменение сообщений
У ботов есть функция изменения своих сообщений (можно использовать, чтобы сделать перелистывание страниц, например). Для этого нужно воспользоваться методом edit_message_text (edit_message_caption для картинок):
@bot.callback_query_handler(lambda call: True) def handle(call): bot.send_message(chat_id=call.message.chat.id, message_id=call.message.id, text='It works!') bot.answer_callback_query(call.id)
Смысл аргументов понятен из их названия.
Flask
Если запустить бота, то через какое-то время он упадет с ошибкой Connection to api.telegram.org timed out. Чтобы это исправить нужно использовать вебхук:
from flask import Flask, request import telebot token = '1408700689:AAGVqcqscWWK7DnuNHahd0w1eNklfjPEVxE' bot = telebot.TeleBot(token) app = Flask(__name__) @bot.message_handler(commands=['start']) def start(message): bot.send_message(message.chat.id, 'It works!') @app.route("/" + token, methods=['POST']) def getMessage(): bot.process_new_updates([telebot.types.Update.de_json(request.stream.read().decode("utf-8"))]) return "!", 200 bot.remove_webhook() bot.set_webhook('https://test.com/' + token) app.run()
Этот код при запуске сначала удалит вебхук, если такой был, и установит его на желаемый. Все запросы, которые приходят в функцию getMessage будут направляться в bot с помощью метода process_new_updates. Этот код уже можно использовать для запуска, например, на Heroku.
P.S. Чтобы работать с длинными диалогами, я хранил для каждого пользователя в базе данных его текущее состояние.
ReplyKeyboardMarkup¶
class telegram. ReplyKeyboardMarkup ( keyboard , resize_keyboard = None , one_time_keyboard = None , selective = None , input_field_placeholder = None , is_persistent = None , * , api_kwargs = None ) [source] ¶ Bases: telegram.TelegramObject This object represents a custom keyboard with reply options. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their size of keyboard and all the buttons are equal.
- telegram.Bot.copy_message()
- telegram.Bot.send_animation()
- telegram.Bot.send_audio()
- telegram.Bot.send_contact()
- telegram.Bot.send_dice()
- telegram.Bot.send_document()
- telegram.Bot.send_location()
- telegram.Bot.send_message()
- telegram.Bot.send_photo()
- telegram.Bot.send_poll()
- telegram.Bot.send_sticker()
- telegram.Bot.send_venue()
- telegram.Bot.send_video_note()
- telegram.Bot.send_video()
- telegram.Bot.send_voice()
An another kind of keyboard would be the telegram.InlineKeyboardMarkup .
- Example usage: A user requests to change the bot’s language, bot replies to the request with a keyboard to select the new language. Other users in the group don’t see the keyboard.
- Conversation Bot
- Conversation Bot 2
- keyboard (Sequence[Sequence[ str | telegram.KeyboardButton ]]) – Array of button rows, each represented by an Array of telegram.KeyboardButton objects.
- resize_keyboard ( bool , optional) – Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to False , in which case the custom keyboard is always of the same height as the app’s standard keyboard.
- one_time_keyboard ( bool , optional) – Requests clients to hide the keyboard as soon as it’s been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat — the user can press a special button in the input field to see the custom keyboard again. Defaults to False .
- selective ( bool , optional) – Use this parameter if you want to show the keyboard to specific users only. Targets:
- Users that are @mentioned in the text of the telegram.Message object.
- If the bot’s message is a reply (has reply_to_message_id ), sender of the original message.
Array of button rows, each represented by an Array of telegram.KeyboardButton objects.
Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to False , in which case the custom keyboard is always of the same height as the app’s standard keyboard.
Optional. Requests clients to hide the keyboard as soon as it’s been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat — the user can press a special button in the input field to see the custom keyboard again. Defaults to False .
Optional. Show the keyboard to specific users only. Targets:
- Users that are @mentioned in the text of the telegram.Message object.
- If the bot’s message is a reply (has reply_to_message_id ), sender of the original message.
Optional. The placeholder to be shown in the input field when the keyboard is active; 1 — 64 characters.
Optional. Requests clients to always show the keyboard when the regular keyboard is hidden. If False , the custom keyboard can be hidden and opened with a keyboard icon.
classmethod from_button ( button , resize_keyboard = False , one_time_keyboard = False , selective = False , input_field_placeholder = None , is_persistent = None , ** kwargs ) [source] ¶
ReplyKeyboardMarkup([[button]], **kwargs)
Return a ReplyKeyboardMarkup from a single KeyboardButton.
- button ( telegram.KeyboardButton | str ) – The button to use in the markup.
- resize_keyboard ( bool , optional) – Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to False , in which case the custom keyboard is always of the same height as the app’s standard keyboard.
- one_time_keyboard ( bool , optional) – Requests clients to hide the keyboard as soon as it’s been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat — the user can press a special button in the input field to see the custom keyboard again. Defaults to False .
- selective ( bool , optional) – Use this parameter if you want to show the keyboard to specific users only. Targets:
- Users that are @mentioned in the text of the Message object.
- If the bot’s message is a reply (has reply_to_message_id ), sender of the original message.
ReplyKeyboardMarkup([[button] for button in button_column], **kwargs)
Return a ReplyKeyboardMarkup from a single column of KeyboardButtons.
- Users that are @mentioned in the text of the Message object.
- If the bot’s message is a reply (has reply_to_message_id ), sender of the original message.
ReplyKeyboardMarkup([button_row], **kwargs)
Return a ReplyKeyboardMarkup from a single row of KeyboardButtons.
- Users that are @mentioned in the text of the Message object.
- If the bot’s message is a reply (has reply_to_message_id ), sender of the original message.