Как стать автором
Обновить

Создаем бота в 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. Чтобы работать с длинными диалогами, я хранил для каждого пользователя в базе данных его текущее состояние.

Полезные ссылки

https://flask.palletsprojects.com/en/1.1.x/ – Flask
https://pypi.org/project/pyTelegramBotAPI/ – pyTelegramBotApi
https://core.telegram.org/bots/api – Telegram Bot API

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.