Телеграм-бот на Python. Полный гид по написанию с нуля бота с курсом валют

Боты в Телеграм – это программы, помогающие установить контакт с аудиторией или упростить действия, которые ранее приходилось выполнять вручную. Эти программы пишутся специально для платформы мессенджера. Боты работают таким образом: пользователь отправляет команду через строку ввода, а система отвечает текстовым или интерактивным сообщением. Иногда программа даже имитирует действия реального человека – такой бот вызывает больше доверия у клиентов.

Существует несколько видов систем для автоматической помощи пользователям. Одни боты просто общаются с клиентами, другие – регулярно поставляют информацию. Четко разделить программы на типы нельзя – разработчики нередко сочетают несколько функций в одном боте.

Написать несложный бот для Телеграма с интерактивными элементами в виде экранных кнопок можно за 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:

Телеграм-бот на Python. Полный гид по написанию с нуля бота с курсом валют

Шаг 6: добавление обработчика команды /exchange

Этот шаг нужен, чтобы в чате отображались кнопки с обозначениями доступных валют. Экранная клавиатура с вариантами поможет избежать ошибок. ПриватБанк предоставляет информацию о рубле, долларе и евро. Параметр InlineKeyboardButton работает следующим образом:

  1. Пользователь кликает по кнопке с нужным обозначением.
  2. В getUpdates поступает обратный вызов (CallbackQuery).
  3. Становится известно, как обработать нажатие на клавиатуру – передается информация о нажатой кнопке.

Код обработчика /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  
    )

Результат работы кода в Телеграме:

Телеграм-бот на Python. Полный гид по написанию с нуля бота с курсом валют

Шаг 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:

Телеграм-бот на Python. Полный гид по написанию с нуля бота с курсом валют

Шаг 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. Разберем эту процедуру по шагам:

  1. Загрузка актуальной информации о состоянии валютного рынка (exchange_now = pb.get_exchange(data[‘c’]).
  1. Написание нового сообщения через сериализатор с diff.
  2. Добавление подписи (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>'

В результате обновленное сообщение от бота при стабильном курсе выглядит так:

Телеграм-бот на Python. Полный гид по написанию с нуля бота с курсом валют

Когда курс меняется, различия между значениями отображаются в сообщении благодаря прописанным параметрам.

Телеграм-бот на Python. Полный гид по написанию с нуля бота с курсом валют

Шаг 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

Теперь, если написать в строке @<имябота> и пробел, на экране появятся результаты поиска – варианты конвертирования в три доступные валюты.

Телеграм-бот на Python. Полный гид по написанию с нуля бота с курсом валют

Пользователи могут отфильтровать результаты, если введут обозначение нужной валюты.

После клика по нужной валюте из списка в чат приходит такое же сообщение, какие получают пользователи бота. Кнопкой Update тоже можно пользоваться. На изображении ниже изображено обновленное сообщение, которое отправили через бот:

Телеграм-бот на Python. Полный гид по написанию с нуля бота с курсом валют

Заключение

Теперь вам известно, как создать бот для Телеграма. Вы сможете добавить в свою программу полезные инструменты: кнопки обновления и отправки результата другим пользователям мессенджера и встроенный режим, позволяющий пользоваться функциями бота вне чата с ним. На основе этой инструкции можно создать любой простой бот с другими функциями – не только тот, который покажет курсы валют. Не бойтесь экспериментировать с библиотеками, API и кодом, чтобы создать автоматического помощника, который пообщается с клиентами в Телеграме и укрепит связь заинтересованных людей с компанией.

ОфисГуру
Adblock
detector