Адмирал Преподаватель
Телеграм боты - это крутой способ взаимодействия с пользователем прямо в привычном ему мессенджере. Это гораздо быстрее и чаще удобнее, чем писать полноценное мобильное приложение. В этой статье мы постраемся создать собственного Telegram бота, который будет предлагать пользователю разыграть полноценный текстовый квест.
Нюансы сюжета вам придется продумать самостоятельно, ну а вся техническая часть - под катом!
Для начала давайте познакомимся с Telegram ботами, по ссылке представлено множество примеров таких программ, от прогноза погоды до общения с рандомным собеседником: https://uip.me/2016/04/50-popular-telegram-bots/.
> Учебник: https://groosha.gitbooks.io/telegram-bot-lessons/content/chapter1.html > Веб-версия Telegram: http://web.telegram.org/
Технически, телеграм бот - это программа, которая запущена на вашем компьютере и общается с серверами телеграма через интернет. Можно представить, что при регистрации бота, телеграм выделяет нам почтовый ящик, через который мы можем получать сообщения от пользователей и отправлять их им.
Чтобы создать собственного бота, сперва его надо зарегистрировать. Для этого в телеграме нужно добавить бота @BotFather
и следовать инструкциям. После того, как мы введем название бота, @BotFather
сообщит нам токен - пароль к нашему почтовому ящику.
После получения токена нам потребуется установить библиотеку pyTelegramBotApi, как и обычно, это делается через pip:
pip install pytelegrambotapi
Давайте сделаем нашего первого бота - бота-попугая. На все сообщения он будет отвечать повторением.
import telebot
token = "ВСТАВЬТЕ СЮДА ТОКЕН"
# Обходим блокировку с помощью прокси
telebot.apihelper.proxy = {'https': 'socks5h://geek:socks@t.geekclass.ru:7777'}
# подключаемся к телеграму
bot = telebot.TeleBot(token=token)
# content_types=['text'] - сработает, если нам прислали текстовое сообщение
@bot.message_handler(content_types=['text'])
def echo(message):
# message - входящее сообщение
# message.text - это его текст
# message.chat.id - это номер его автора
text = message.text
user = message.chat.id
#отправляем картинку с попугаем
bot.send_photo(user, "https://i.ytimg.com/vi/R-RbmqzRC9c/maxresdefault.jpg")
#отправляем сообщение тому же пользователю с тем же текстом
bot.send_message(user, text)
# поллинг - вечный цикл с обновлением входящих сообщений
bot.polling(none_stop=True)
Работает так:
Помимо текстовых сообщений, в телеграме есть команды, они начинаются со слэша, например, /start
или /help
. Их тоже можно обрабатывать.
Давайте добавим пояснение к нашему боту, которое объяснит пользователю, что он делает.
import telebot
token = "ВСТАВЬ СЮДА ТОКЕН"
# подключаемся к телеграму
bot = telebot.TeleBot(token=token)
# реагируем на команды /start и /help
@bot.message_handler(commands=['start', 'help'])
def help(message):
user = message.chat.id
bot.send_message(user, "Это бот попугай! Просто пришли и я повторю.")
# content_types=['text'] - сработает, если нам прислали текстовое сообщение
@bot.message_handler(content_types=['text'])
def echo(message):
# message - входящее сообщение
# message.text - это его текст
# message.chat.id - это номер его автора
text = message.text
user = message.chat.id
#отправляем картинку с попугаем
bot.send_photo(user, "https://i.ytimg.com/vi/R-RbmqzRC9c/maxresdefault.jpg")
#отправляем сообщение тому же пользователю с тем же текстом
bot.send_message(user, text)
# поллинг - вечный цикл с обновлением входящих сообщений
bot.polling(none_stop=True)
Предположим мы хотим сделать бота, которы будет запоминать какую-то фразу, а затем по просьбе пользователя напоминать ее ему. Чтобы решить эту задачу, нам понадобится где-то хранить последнее сообщение пользователя.
Если мы будем использовать переменную, то сможем сохранить сообщение только одного пользователя. Например, Вася попросил запомнить слово kitten
. Мы положим эту строку в переменную note
. А затем Петя, попросить запомнить слово puppy
, и мы снова положим это переменную note
. Когда Вася попросит нам напомнить его последнее сообщение, мы напишем ему puppy
вместо kitten
. Совершенно не годится!
> Удобнее всего хранить все данные, которые привязаны к конкретному пользователю в словаре. Ключем в этом словаре будет id пользователя, а значением - произвольные данные.
Предположим, что наш словарь называется notes
- заметки. Теперь, когда Вася (id88000) пришлет слово kitten
мы положим его в notes[88000]
, а слово puppy
от Пети (id5300) - в notes[5300]
. Посколько теперь мы используем разные переменные для хранения слова, сообщения от разных пользователей не будут путаться.
Реализация:
import telebot
token = "ВАШ ТОКЕН"
# Обходим блокировку с помощью прокси
telebot.apihelper.proxy = {'https': 'socks5h://geek:socks@t.geekclass.ru:7777'}
bot = telebot.TeleBot(token=token)
notes = {}
@bot.message_handler(commands=['remind'])
def remind(message):
user_id = message.chat.id
if user_id not in notes:
bot.send_message(user_id, "Вы мне еще не писали.")
else:
bot.send_message(user_id, notes[user_id])
@bot.message_handler(content_types=['text'])
def remember(message):
user_id = message.chat.id
notes[user_id] = message.text
bot.send_message(user_id, "Я запомнил")
bot.polling(none_stop=True)
Следующий пример демонстрирует, как добавить несколько кнопок к сообщению и реагировать на их нажатия.
import telebot
from telebot import types
token = "ВАШ ТОКЕН"
# Обходим блокировку с помощью прокси
telebot.apihelper.proxy = {'https': 'socks5h://geek:socks@t.geekclass.ru:7777'}
bot = telebot.TeleBot(token=token)
@bot.message_handler(commands=["start"])
def repeat_all_messages(message):
# создаем клавиатуру
keyboard = types.InlineKeyboardMarkup()
# добавляем на нее две кнопки
button1 = types.InlineKeyboardButton(text="Кнопка 1", callback_data="button1")
button2 = types.InlineKeyboardButton(text="Кнопка 2", callback_data="button2")
keyboard.add(button1)
keyboard.add(button2)
# отправляем сообщение пользователю
bot.send_message(message.chat.id, "Нажмите кнопку!", reply_markup=keyboard)
# функция запустится, когда пользователь нажмет на кнопку
@bot.callback_query_handler(func=lambda call: True)
def callback_inline(call):
if call.message:
if call.data == "button1":
bot.send_message(call.message.chat.id, "Вы нажали на первую кнопку.")
if call.data == "button2":
bot.send_message(call.message.chat.id, "Вы нажали на вторую кнопку.")
bot.polling(none_stop=True)
from telebot import TeleBot, types
from random import randint
from secret import token
pictures = {
0: "https://storage.geekclass.ru/images/760e484b-a099-4a7a-a722-5aec9a933614.jpg",
1: "https://storage.geekclass.ru/images/4637fc41-08df-466a-b112-aa577dba6c1d.jpg",
2: "https://storage.geekclass.ru/images/c2a2a60c-9c7b-4c3a-b663-42d2559bf869.jpg"
}
states = {}
inventories = {}
# Обходим блокировку с помощью прокси
telebot.apihelper.proxy = {'https': 'socks5h://geek:socks@t.geekclass.ru:7777'}
bot = TeleBot(token)
@bot.message_handler(commands=["start"])
def start_game(message):
user = message.chat.id
states[user] = 0
inventories[user] = []
bot.send_message(user, "Добро пожаловать в игру!")
process_state(user, states[user], inventories[user])
@bot.callback_query_handler(func=lambda call: True)
def user_answer(call):
user = call.message.chat.id
process_answer(user, call.data)
def process_state(user, state, inventory):
kb = types.InlineKeyboardMarkup()
bot.send_photo(user, pictures[state])
if state == 0:
kb.add(types.InlineKeyboardButton(text="пойти направо", callback_data="1"))
kb.add(types.InlineKeyboardButton(text="пойти налево", callback_data="2"))
bot.send_message(user, "Вы в оказались в темном подземелье, перед вами два прохода.", reply_markup=kb)
if state == 1:
kb.add(types.InlineKeyboardButton(text="переплыть", callback_data="1"))
kb.add(types.InlineKeyboardButton(text="вернуться", callback_data="2"))
bot.send_message(user, "Перед вами большое подземное озеро, а вдали виднеется маленький остров.", reply_markup=kb)
if state == 2:
bot.send_message(user, "Вы выиграли.")
def process_answer(user, answer):
if states[user] == 0:
if answer == "1":
states[user] = 1
else:
if "key" in inventories[user]:
bot.send_message(user,
"Перед вами закрытая дверь. Вы пробуете открыть ее ключем, и дверь поддается. Кажется, это выход.")
states[user] = 2
else:
bot.send_message(user, "Перед вами закрытая дверь, и, кажется, без ключа ее не открыть. Придется вернуться обратно.")
states[user] = 0
elif states[user] == 1:
if answer == "2":
bot.send_message(user,
"И правда, не стоит штурмовать неизвестные воды. Возвращаемся назад...")
states[user] = 0
else:
bot.send_message(user,
"Вы пробуете переплыть озеро...")
chance = randint(0, 100)
if chance > 30:
bot.send_message(user,
"Вода оказалось теплой, а в сундуке на острове вы нашли старый ключ. Стоит вернутся обратно.")
inventories[user].append("key")
states[user] = 0
else:
bot.send_message(user,
"На середине озера вас подхватывают волны и возвращают обратно.")
states[user] = 1
process_state(user, states[user], inventories[user])
bot.polling(none_stop=True)