Pull to refresh

Создаем бота в 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

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.