Боты в Телеграм – это программы, помогающие установить контакт с аудиторией или упростить действия, которые ранее приходилось выполнять вручную. Эти программы пишутся специально для платформы мессенджера. Боты работают таким образом: пользователь отправляет команду через строку ввода, а система отвечает текстовым или интерактивным сообщением. Иногда программа даже имитирует действия реального человека – такой бот вызывает больше доверия у клиентов.
Существует несколько видов систем для автоматической помощи пользователям. Одни боты просто общаются с клиентами, другие – регулярно поставляют информацию. Четко разделить программы на типы нельзя – разработчики нередко сочетают несколько функций в одном боте.
Написать несложный бот для Телеграма с интерактивными элементами в виде экранных кнопок можно за 9 шагов. Рассмотрим каждый из них в подробностях и ответим на несколько вопросов:
- как запустить бот;
- как прописать встроенную клавиатуру из одной или нескольких кнопок;
- как запрограммировать кнопки на нужные функции;
- что такое встроенный режим и как настроить его для уже существующего бота.
- Шаг 0: теоретическая база об API Telegram-ботов
- Шаг 1: реализация запросов курсов валют
- Шаг 2: создание Telegram-бота с помощью @BotFather
- Шаг 3: настройка и запуск бота
- Шаг 4: написание обработчика команды /start
- Шаг 5: создание обработчика команды /help
- Шаг 6: добавление обработчика команды /exchange
- Шаг 7: написание обработчика для кнопок встроенной клавиатуры
- Шаг 8: реализация обработчика кнопки обновления
- Шаг 9: реализация встроенного режима
- Заключение
Шаг 0: теоретическая база об API Telegram-ботов
Основной инструмент, который используют при создании Телеграм-ботов – это интерфейс прикладного программирования HTML, или API HTML. Этот элемент принимает запросы посетителей и отправляет ответы в виде информации. Готовые конструкции упрощают работу над программой. Чтобы написать бот для Телеграма, необходимо воспользоваться этим электронным адресом: https://api.telegram.org/bot<token>/METHOD_NAME
Для правильного функционирования бота также нужен токен – комбинация символов, защищающая программу и открывающая доступ к ней доверенным разработчикам. Каждый токен уникален. Строка присваивается боту при создании. Методы могут быть разными: getUpdates, getChat и прочие. Выбор метода зависит от того, какого алгоритма работы разработчики ожидают от бота. Пример токена:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
В ботах используются запросы GET и POST. Параметры методов нередко приходится дополнять – к примеру, когда по задумке метод sendMessage должен отправить id чата и какой-либо текст. Параметры для доработки метода можно передать строкой запроса URL с помощью application/x-www-form-urlencoded или через application-json. Эти способы не подходят для загрузки файлов. Также обязательна кодировка UTF-8. Отправив запрос к API, можно получить результат в JSON-формате. Взгляните на ответ программы на извлечение информации через метод getME:
GET https://api.telegram.org/bot<token>/getMe{ ok: true, result: { id: 231757398, first_name: "Exchange Rate Bot", username: "exchangetestbot" } }
Результат будет получен, если ok равняется true. В ином случае система укажет на ошибку.
Существует два способа получить пользовательские сообщения в ботах. Обе методики действенны, но подходят в разных случаях. Чтобы получить сообщения, можно вручную написать запрос с методом getUpdates – программа выдаст на экран массив данных Update. Запросы нужно отправлять регулярно, после анализа каждого массива отправка повторяется. Избежать повторного появления проверенных объектов поможет offset – параметр, определяющий количество пропущенных записей перед загрузкой нового результата. Преимущества метода getUpdates проявятся, если:
- нет возможности настроить HTTPS;
- используются сложные языки сценариев;
- сервер бота время от времени меняется;
- бот нагружен пользователями.
Второй метод, который можно прописать для получения пользовательских сообщений – setWebhook. Он используется один раз, не нужно постоянно отправлять новые запросы. Webhook пересылает обновления данных на указанный адрес URL. Для применения этого способа потребуется SSL-сертификат. Webhook будет полезен в этих случаях:
- используются веб-языки программирования;
- бот не перегружен, пользователей не слишком много;
- сервер не меняется, программа остается на одном сервере на долгое время.
В дальнейших инструкциях применим getUpdates.
Telegram-сервис @BotFather предназначен для создания чат-ботов. Основные настройки также устанавливаются через эту систему – BotFather поможет сделать описание, поставить фотографию профиля, добавить инструменты поддержки. Библиотеки – наборы HTML-запросов для Телеграм-ботов – доступны в интернете, их достаточно много. При создании программы-примера применена pyTelegramBotApi.
Шаг 1: реализация запросов курсов валют
Для начала необходимо написать код, выполняющий запросы. Воспользуемся при написании API ПриватБанка, ниже расположена ссылка на него: https://api.privatbank.ua/p24api/pubinfo?json&exchange&coursid=5. В коде нужно использовать эти методы:
- load_exchange – находит курсы валют и выводит закодированную информацию;
- get_exchange – выводит данные об определенной валюте;
- get_exchanges – показывает перечисление валют согласно образцу.
В результате код в файле pb.py выглядит так:
import re import requests import json URL = 'https://api.privatbank.ua/p24api/pubinfo?json&exchange&coursid=5' def load_exchange(): return json.loads(requests.get(URL).text) def get_exchange(ccy_key): for exc in load_exchange(): if ccy_key == exc['ccy']: return exc return False def get_exchanges(ccy_pattern): result = [] ccy_pattern = re.escape(ccy_pattern) + '.*' for exc in load_exchange(): if re.match(ccy_pattern, exc['ccy'], re.IGNORECASE) is not None: result.append(exc) return result
Программа может выдать такой ответ на указанные запросы:
[ { ccy:"USD", base_ccy:"UAH", buy:"25.90000", sale:"26.25000" }, { ccy:"EUR", base_ccy:"UAH", buy:"29.10000", sale:"29.85000" }, { ccy:"RUR", base_ccy:"UAH", buy:"0.37800", sale:"0.41800" }, { ccy:"BTC", base_ccy:"USD", buy:"11220.0384", sale:"12401.0950" } ]
Шаг 2: создание Telegram-бота с помощью @BotFather
Создать программу для приема сообщений и ответа на них можно через сервис @BotFather. Переходим на его страницу в Telegram и вводим команду /newbot. В чате появятся инструкции, согласно которым нужно записать сначала имя бота, а после – его адрес. Когда аккаунт-бот будет создан, на экране появится приветственное сообщение, содержащее токен. Для дальнейшей настройки воспользуемся этими командами:
- /setdescription – описание;
- /setabouttext – информация о новом боте;
- /setuserpic – фотография профиля;
- /setinline – встроенный режим;
- /setcommands – описание команд.
На последнем шаге настройки описываем /help и /exchange. Когда все этапы пройдены, пора перейти к составлению кода.
Шаг 3: настройка и запуск бота
Создадим файл config.py. В нем нужно указать уникальный код бота и часовую зону, в которой программа найдет информацию.
TOKEN = '<bot token>' # заменить на токен своего ботаTIMEZONE = 'Europe/Kiev' TIMEZONE_COMMON_NAME = 'Kiev'
Далее создаем еще один файл с импортом ранее написанного pb.py, библиотек и других необходимых компонентов. Недостающие библиотеки устанавливаются из системы управления пакетами (pip).
import telebotimport configimport pbimport datetimeimport pytzimport jsonimport traceback P_TIMEZONE = pytz.timezone(config.TIMEZONE) TIMEZONE_COMMON_NAME = config.TIMEZONE_COMMON_NAME
Воспользуемся содержимым pyTelegramBotApi, чтобы создать бот. Отправляем полученный токен с помощью такого кода:
bot = telebot.TeleBot(config.TOKEN) bot.polling(none_stop=True)
Параметр none_stop обеспечивает постоянную отправку запросов. На действие параметра не повлияют ошибки метода.
Шаг 4: написание обработчика команды /start
Если все предыдущие шаги выполнены правильно, бот начал работать. Программа регулярно создает запросы, потому что в ней использован метод getUpdates. Перед строкой с элементом none_stop нужна часть кода, обрабатывающая команду /start:
@bot.message_handler(commands=['start']) def start_command(message): bot.send_message( message.chat.id, 'Greetings! I can show you exchange rates.\n' + 'To get the exchange rates press /exchange.\n' + 'To get help press /help.' )
При commands=[‘start’] равном True вызывается start_command. Содержимое сообщения переходит туда. Далее нужно реализовать функцию send_message по отношению к конкретному сообщению.
Шаг 5: создание обработчика команды /help
Команду /help можно реализовать в виде кнопки. Нажав на нее, пользователь попадет в аккаунт разработчика в Telegram. Присвоим кнопке имя – например «Ask the developer». Установим параметр reply_markup, перенаправляющий пользователя по ссылке, для метода send_message. Пропишем в коде параметр, создающий клавиатуру (InlineKeyboardMarkup). Понадобится только одна кнопка (InlineKeyboardButton).
Финальный код обработчика команды выглядит так:
@bot.message_handler(commands=['help']) def help_command(message): keyboard = telebot.types.InlineKeyboardMarkup() keyboard.add( telebot.types.InlineKeyboardButton( 'Ask the developer', url='ваша ссылка на профиль' ) ) bot.send_message( message.chat.id, '1) To receive a list of available currencies press /exchange.\n' + '2) Click on the currency you are interested in.\n' + '3) You will receive a message containing information regarding the source and the target currencies, ' + 'buying rates and selling rates.\n' + '4) Click “Update” to receive the current information regarding the request. ' + 'The bot will also show the difference between the previous and the current exchange rates.\n' + '5) The bot supports inline. Type @<botusername> in any chat and the first letters of a currency.', reply_markup=keyboard )
Действие кода в чате Telegram:
Шаг 6: добавление обработчика команды /exchange
Этот шаг нужен, чтобы в чате отображались кнопки с обозначениями доступных валют. Экранная клавиатура с вариантами поможет избежать ошибок. ПриватБанк предоставляет информацию о рубле, долларе и евро. Параметр InlineKeyboardButton работает следующим образом:
- Пользователь кликает по кнопке с нужным обозначением.
- В getUpdates поступает обратный вызов (CallbackQuery).
- Становится известно, как обработать нажатие на клавиатуру – передается информация о нажатой кнопке.
Код обработчика /exchange:
@bot.message_handler(commands=['exchange']) def exchange_command(message): keyboard = telebot.types.InlineKeyboardMarkup() keyboard.row( telebot.types.InlineKeyboardButton('USD', callback_data='get-USD') ) keyboard.row( telebot.types.InlineKeyboardButton('EUR', callback_data='get-EUR'), telebot.types.InlineKeyboardButton('RUR', callback_data='get-RUR') ) bot.send_message( message.chat.id, 'Click on the currency of choice:', reply_markup=keyboard )
Результат работы кода в Телеграме:
Шаг 7: написание обработчика для кнопок встроенной клавиатуры
В пакете pyTelegramBot Api размещена функция-декоратор @bot.callback_query_handler. Этот компонент предназначен для перевода обратного вызова в функцию – API разворачивает и снова создает вызов. Это прописывается так:
@bot.callback_query_handler(func=lambda call: True) def iq_callback(query): data = query.data if data.startswith('get-'): get_ex_callback(query)
Пропишем также метод get_ex_callback:
def get_ex_callback(query): bot.answer_callback_query(query.id) send_exchange_result(query.message, query.data[4:])
Существует и другой полезный метод – answer_callback_query. Он помогает убрать загрузку между нажатием кнопки и выводом результата на экран. В send_exchange_query можно отправить сообщение, передав код какой-либо валюты и Message. Запишем send_exchange_result:
def send_exchange_result(message, ex_code): bot.send_chat_action(message.chat.id, 'typing') ex = pb.get_exchange(ex_code) bot.send_message( message.chat.id, serialize_ex(ex), reply_markup=get_update_keyboard(ex), parse_mode='HTML' )
Пока чат-бот получает результат запроса из банковского API, посетитель видит надпись «набирает сообщение». Это выглядит так, будто отвечает реальный человек. Чтобы вывести такой индикатор на экран, потребуется добавить строки о состоянии ввода. Далее воспользуемся get_exchange – с его помощью программа получит обозначение валюты (рублей, евро или долларов). В send_message используются добавочные методы: serialize_ex переводит валюту в другой формат, а get_update_keyboard устанавливает экранные клавиши, обновляющие информацию и пересылающие данные о валютном рынке в другие чаты.
Напишем код для get_update_keyboard. Нужно упомянуть две кнопки – t и e обозначают тип и обмен. Пункт switch_inline_query для кнопки Share нужен, чтобы пользователю открывался выбор из нескольких чатов. Посетитель сможет выбрать, кому отправить актуальный курс доллара, рубля или евро.
def get_update_keyboard(ex): keyboard = telebot.types.InlineKeyboardMarkup() keyboard.row( telebot.types.InlineKeyboardButton( 'Update', callback_data=json.dumps({ 't': 'u', 'e': { 'b': ex['buy'], 's': ex['sale'], 'c': ex['ccy'] } }).replace(' ', '') ), telebot.types.InlineKeyboardButton('Share', switch_inline_query=ex['ccy']) ) return keyboard
Иногда необходимо увидеть, насколько изменился курс валют за короткое время. Напишем два метода для кнопки Update, чтобы пользователи могли увидеть курсы в сравнении.
Разница между курсами валют передается в сериализатор через параметр diff.
Прописанные методы срабатывают только после обновления данных, они не повлияют на первое отображение курса.
def serialize_ex(ex_json, diff=None): result = '<b>' + ex_json['base_ccy'] + ' -> ' + ex_json['ccy'] + ':</b>\n\n' + \ 'Buy: ' + ex_json['buy'] if diff: result += ' ' + serialize_exchange_diff(diff['buy_diff']) + '\n' + \ 'Sell: ' + ex_json['sale'] + \ ' ' + serialize_exchange_diff(diff['sale_diff']) + '\n' else: result += '\nSell: ' + ex_json['sale'] + '\n' return result def serialize_exchange_diff(diff): result = '' if diff > 0: result = '(' + str(diff) + ' <img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="<img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="<img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="<img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="<img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="↗️" src="https://s.w.org/images/core/emoji/2.3/svg/2197.svg">" src="https://s.w.org/images/core/emoji/2.3/svg/2197.svg">" src="https://s.w.org/images/core/emoji/2.3/svg/2197.svg">" src="https://s.w.org/images/core/emoji/72x72/2197.png">" src="https://s.w.org/images/core/emoji/72x72/2197.png">)' elif diff < 0: result = '(' + str(diff)[1:] + ' <img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="<img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="<img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="<img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="<img draggable="false" data-mce-resize="false" data-mce-placeholder="1" data-wp-emoji="1" class="emoji" alt="↘️" src="https://s.w.org/images/core/emoji/2.3/svg/2198.svg">" src="https://s.w.org/images/core/emoji/2.3/svg/2198.svg">" src="https://s.w.org/images/core/emoji/2.3/svg/2198.svg">" src="https://s.w.org/images/core/emoji/72x72/2198.png">" src="https://s.w.org/images/core/emoji/72x72/2198.png">)' return result
Представим, что посетитель захотел узнать курс доллара. Вот что произойдет, если выбрать в сообщении USD:
Шаг 8: реализация обработчика кнопки обновления
Напишем код для обработки действий с кнопкой Update и дополним его часть iq_callback_method. Когда пункты программы начинаются с параметра get‒, необходимо прописать get_ex_callback. В других ситуациях разбираем JSON и пытаемся получить ключ t.
@bot.callback_query_handler(func=lambda call: True) def iq_callback(query): data = query.data if data.startswith('get-'): get_ex_callback(query) else: try: if json.loads(data)['t'] == 'u': edit_message_callback(query) except ValueError: pass
Если t равняется u, потребуется создать программу для метода edit_message_callback. Разберем эту процедуру по шагам:
- Загрузка актуальной информации о состоянии валютного рынка (exchange_now = pb.get_exchange(data[‘c’]).
- Написание нового сообщения через сериализатор с diff.
- Добавление подписи (get_edited_signature).
Если начальное сообщение не меняется, вызовем метод edit_message_text.
def edit_message_callback(query): data = json.loads(query.data)['e'] exchange_now = pb.get_exchange(data['c']) text = serialize_ex( exchange_now, get_exchange_diff( get_ex_from_iq_data(data), exchange_now ) ) + '\n' + get_edited_signature() if query.message: bot.edit_message_text( text, query.message.chat.id, query.message.message_id, reply_markup=get_update_keyboard(exchange_now), parse_mode='HTML' ) elif query.inline_message_id: bot.edit_message_text( text, inline_message_id=query.inline_message_id, reply_markup=get_update_keyboard(exchange_now), parse_mode='HTML' )
Пропишем метод get_ex_from_iq_data, чтобы разобрать JSON:
def get_ex_from_iq_data(exc_json): return { 'buy': exc_json['b'], 'sale': exc_json['s'] }
Понадобится еще несколько методов: например, get_exchange_diff, который считывает старую и новую информацию о стоимости валют и выводит разницу.
def get_exchange_diff(last, now): return { 'sale_diff': float("%.6f" % (float(now['sale']) - float(last['sale']))), 'buy_diff': float("%.6f" % (float(now['buy']) - float(last['buy']))) }
Последний – get_edited_signature – показывает время последнего обновления курса.
def get_edited_signature(): return '<i>Updated ' + \ str(datetime.datetime.now(P_TIMEZONE).strftime('%H:%M:%S')) + \ ' (' + TIMEZONE_COMMON_NAME + ')</i>'
В результате обновленное сообщение от бота при стабильном курсе выглядит так:
Когда курс меняется, различия между значениями отображаются в сообщении благодаря прописанным параметрам.
Шаг 9: реализация встроенного режима
Встроенный режим нужен для быстрой отправки информации из программы в любой чат – теперь не нужно добавлять бот в беседу как участника. Когда пользователь Telegram водит название бота со знаком @ перед ним, над строкой ввода должны появиться варианты конвертирования. Если кликнуть по одному из пунктов, бот вышлет в беседу сообщение с результатами и кнопками для обновления и пересылки данных. В имени отправителя окажется подпись «via <имя бота>».
InlineQuery передается в query_text через библиотеку. В коде применяется функция answer_line – она извлекает результаты поиска в виде массива данных и элемент inline_query_id. Используем get_exchanges, чтобы бот находил несколько валют по запросу.
@bot.inline_handler(func=lambda query: True) def query_text(inline_query): bot.answer_inline_query( inline_query.id, get_iq_articles(pb.get_exchanges(inline_query.query)) )
Передаем массив данных в get_iq_articles, чтобы через этот метод вернуть объекты из InlineQueryResultArticle.
def get_iq_articles(exchanges): result = [] for exc in exchanges: result.append( telebot.types.InlineQueryResultArticle( id=exc['ccy'], title=exc['ccy'], input_message_content=telebot.types.InputTextMessageContent( serialize_ex(exc), parse_mode='HTML' ), reply_markup=get_update_keyboard(exc), description='Convert ' + exc['base_ccy'] + ' -> ' + exc['ccy'], thumb_height=1 ) ) return result
Теперь, если написать в строке @<имябота> и пробел, на экране появятся результаты поиска – варианты конвертирования в три доступные валюты.
Пользователи могут отфильтровать результаты, если введут обозначение нужной валюты.
После клика по нужной валюте из списка в чат приходит такое же сообщение, какие получают пользователи бота. Кнопкой Update тоже можно пользоваться. На изображении ниже изображено обновленное сообщение, которое отправили через бот:
Заключение
Теперь вам известно, как создать бот для Телеграма. Вы сможете добавить в свою программу полезные инструменты: кнопки обновления и отправки результата другим пользователям мессенджера и встроенный режим, позволяющий пользоваться функциями бота вне чата с ним. На основе этой инструкции можно создать любой простой бот с другими функциями – не только тот, который покажет курсы валют. Не бойтесь экспериментировать с библиотеками, API и кодом, чтобы создать автоматического помощника, который пообщается с клиентами в Телеграме и укрепит связь заинтересованных людей с компанией.