Polling и long polling
Чат-боты должны получать уведомления от соцсети моментально. Они не могут проверять обновления каждую секунду, это неэффективно. Большинство ответов от сервера будут неинформативны, вроде «У вас пока нет новых сообщений».
Такой подход, когда раз в n секунд опрашивается сторонний сервис, называется polling.
Чтобы сэкономить на ресурсах, можно использовать long polling. Устроен он так же, как и polling, с одним отличием: сервер дольше отвечает. Вообще, при лонг-поллинге сервер отвечает в двух случаях: или потому, что пришло новое сообщение, или потому, что соединение пора разрывать.
У каждого запроса есть timeout — время, в течении которого нужно ответить. Если на запрос не ответили за это время, считается, что сервер не ответит вообще. Поэтому сервер смотрит на timeout и решает так:
- Если за это время у меня не появится обновлений для клиента, я отвечу ему, что их нет.
- Если появятся, я отправлю ему обновления сразу, не дожидаясь таймаута.
Чтобы реализовать long polling на стороне клиента, нужно выставить большой timeout: 30 или 60 секунд.
Вот так выглядит polling со стороны клиента на Python:
from time import sleep import requests while True: response = requests.get("http://someurl.com") for message in response: bot.answer(message) sleep(1)
А вот так выглядит long polling:
import requests while True: response = requests.get("http://someurl.com", timeout=60) for message in response: bot.answer(message)
Попробуйте бесплатные уроки по Python
Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.
Переходите на страницу учебных модулей «Девмана» и выбирайте тему.
Bot polling что делает
Скачай курс
в приложении
Перейти в приложение
Открыть мобильную версию сайта
© 2013 — 2024. Stepik
Наши условия использования и конфиденциальности
Public user contributions licensed under cc-wiki license with attribution required
Разбираемся с Tg ботом вместе. Python
Решил разобраться с написанием телеграмм бота и поделиться успехами с Вами.
Как уже было сказано ранее основная цель освоить телеграмм бота и создать некоторые шаблоны которые могут пригодиться в будущем для создания полноценного бота.
Всё начинается с малого
Ⅰ. Регистрация бота
- Поиск в tg @BotFather
- Регистрация
- Запомнить токен(Ваш доступ к боту)
Ⅱ. Подготовка
Пишем на Python’е с использованием библиотеки PyTelegramBotAPI. Я использую PyCharm, его можно скачать на официальном сайте https://www.jetbrains.com/ru-ru/pycharm/. Так же для установки библиотеки PyTelegramBotAPI вводим следующую команду в командной строке
pip install pytelegrambotapi
Ⅲ. Базовые элементы. Привет
Импортируем библиотеку и подключаем нашего бота
import telebot bot = telebot.TeleBot('%токен%')
Описываем метод получения текстовых сообщений:
@bot.message_handler(content_types=['text', 'document', 'audio']) #получает def get_text_messages(message): #обрабатывает
Опишем функцию обработки полученного сообщения. При получении слова «Паника» бот будет отвечать «заразна !». Для помощи пользователю будем выводить ещё текст о том что надо делать.
if message.text == "Паника": bot.send_message(message.from_user.id, "Заразна!") else: bot.send_message(message.from_user.id, "Напиши Паника")
Обратим внимание на переменную message.from_user.id она хранит уникальный для каждого пользователя id, именно с помощью него мы сможем отвечать нужному человеку и его я планирую в будущем хранить в базе данных пользователей
Наш бот будет у сервера Telegram постоянно спрашивать «Мне кто-нибудь написал?» Если это случится, наш бот получит переданное сообщение. Для этого допишем:
bot.polling(none_stop=True, interval=0)
Работает !
Ⅳ. Диалог
Давайте научим нашего бота вести диалог с пользователем. В будущем я планирую это использовать как шаблон для регистрации. Бот будет задавать человеку ряд вопросов, получать на них ответы и сохранять
Заведем ряд переменных в которых будем хранить данные регистрации:
name = '' surname = '' city = '' age = 0
Аналогично как в предыдущем пункте опишем функцию начала регистрации start по команде /reg
@bot.message_handler(content_types=['text']) def start(message): if message.text == '/reg': bot.send_message(message.from_user.id, "Как тебя зовут?") bot.register_next_step_handler(message, get_name) #следующий шаг – функция get_name else: bot.send_message(message.from_user.id, 'Напиши /reg')
Далее опишем ряд последовательных функций — этапов нашей регистрации:
def get_name(message): #получаем имя global name name = message.text bot.send_message(message.from_user.id, 'Какая у тебя фамилия?') bot.register_next_step_handler(message, get_surname) #следующий шаг – функция get_surname def get_surname(message): #получаем фамилию global city name = message.text bot.send_message(message.from_user.id, 'Из какого ты города?') bot.register_next_step_handler(message, get_city) def get_city(message): #получаем город global city city = message.text bot.send_message(message.from_user.id,'Сколько тебе лет?') bot.register_next_step_handler(message, get_age) def get_age(message): #получаем возраст global age try: age = int(message.text) #проверяем, что возраст введен корректно except Exception: bot.send_message(message.from_user.id, 'Цифрами, пожалуйста') bot.register_next_step_handler(message, get_age)
В каждой из этих функций мы с помощью переменной message получаем интересующие нас данные, сохраняя их и с помощью bot.register_next_step_handler переходим к следующей функции. В функции get_age проверяем чтобы полученное значение действительно было числом.
В следующей части рассмотрим работу с кнопками и сохранение данных в базе данных.
- Python
- Мессенджеры
- Программирование
- Социальные сети и сообщества
Создаем собственный текстовый квест в Telegram
Телеграм боты — это крутой способ взаимодействия с пользователем прямо в привычном ему мессенджере. Это гораздо быстрее и чаще удобнее, чем писать полноценное мобильное приложение. В этой статье мы постраемся создать собственного Telegram бота, который будет предлагать пользователю разыграть полноценный текстовый квест.
Нюансы сюжета вам придется продумать самостоятельно, ну а вся техническая часть — под катом!
Для начала давайте познакомимся с Telegram ботами, по ссылке представлено множество примеров таких программ, от прогноза погоды до общения с рандомным собеседником: https://uip.me/2016/04/50-popular-telegram-bots/.
Технически, телеграм бот — это программа, которая запущена на вашем компьютере и общается с серверами телеграма через интернет. Можно представить, что при регистрации бота, телеграм выделяет нам почтовый ящик, через который мы можем получать сообщения от пользователей и отправлять их им.
Чтобы создать собственного бота, сперва его надо зарегистрировать. Для этого в телеграме нужно добавить бота @BotFather и следовать инструкциям. После того, как мы введем название бота, @BotFather сообщит нам токен — пароль к нашему почтовому ящику.
После получения токена нам потребуется установить библиотеку pyTelegramBotApi, как и обычно, это делается через pip:
pip install pytelegrambotapi
Пробуем создать бота
Давайте сделаем нашего первого бота — бота-попугая. На все сообщения он будет отвечать повторением.
import telebot token = "ВСТАВЬТЕ СЮДА ТОКЕН" # Обходим блокировку с помощью прокси telebot.apihelper.proxy = # подключаемся к телеграму 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 = 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 = 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 = 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)