Сообщить об ошибке.

Типы обработчиков модуля python-telegram-bot

Внимание! Пакеты python-telegram-bot версии 13.x будут придерживаться многопоточной парадигмы программирования (*на данный момент актуальна версия 13.15). Пакеты версий 20.x и новее предоставляют чистый асинхронный Python интерфейс для Telegram Bot API. Дополнительно смотрите основные изменения в пакете python-telegram-bot версии 20.x.

Обработчик сообщений - это экземпляр, производный от базового класса telegram.ext.Handler, который отвечает за передачу различных видов сообщений (текст, звук, встроенный запрос, нажатия кнопок и т. д.) в соответствующую функцию обратного вызова.

Например, если надо, чтобы бот отвечал на команду /start, нужно использовать обработчик telegram.ext.CommandHandler, который сопоставляет ввод команды пользователя /start с обратным вызовом с именем start_callback:

Например, обработка команды /start для python-telegram-bot версии 13.x:

...
def start_callback(update, context):
    update.message.reply_text("Welcome to my awesome bot!")
...

updater = Updater('TOKEN')
dispatcher = updater.dispatcher
dispatcher.add_handler(CommandHandler("start", start_callback))

Пример обработки команды /start для асинхронного python-telegram-bot версии 20.x:

...
async def start_callback(update, context):
    await update.message.reply_text("Welcome to my awesome bot!")
...

application = ApplicationBuilder().token('TOKEN').build()
application.add_handler(CommandHandler("start", start_callback))

Обработчики сообщений пакета python-telegram-bot:

Для разных типов пользовательского ввода в полученных от telegram.Update сообщениях будут установлены разные атрибуты. Например, входящее сообщение приведет к update.message, содержащему отправленное сообщение. Нажатие встроенной кнопки приведет к установке update.callback_query. Чтобы различать все эти сообщения, модуль telegram.ext содержит следующие обработчики:

  • Класс MessageHandler(filters, callback) предназначен для обработки всех сообщений Telegram. Они могут содержать текст, мультимедиа или обновления статуса и т.д.

    Будете использовать в 70% случаев совместно с фильтрами сообщений.

  • Класс CommandHandler(command, callback, filters=None) предназначен для обработки команд. Команды представляют собой сообщения, которые начинаются с /.

    Будете использовать в 20% случаев.

  • Класс CallbackQueryHandler(callback) предназначен для обработки запросов обратного вызова Telegram (нажатие кнопок встроенной клавиатуры).

  • Класс ConversationHandler(entry_points, states, fallbacks) предназначен для ведения разговора с одним или несколькими пользователями через сообщения Telegram путем управления четырьмя коллекциями других обработчиков. Пример использования данного обработчика можно посмотреть в разделе создания меню из кнопок (Пример встроенной клавиатуры с 2-мя состояниями).

    • entry_points - список обработчиков сообщений, которые используются для инициирования разговора, например, с CommandHandler или MessageHandler.

    • state - представляет собой словарь dict, который в качестве ключей хранит состояния/этапы разговора, а в качестве значений этих ключей один или несколько (список) связанных обработчиков сообщений, которые должны быть использованы, если пользователь отправляет сообщение, когда разговор с ними в настоящее время находится в этом состоянии/этапе. Здесь также можно определить состояние TIMEOUT для определения поведения при превышении conversation_timeout.

    • fallbacks - это список обработчиков сообщений, которые используются, если пользователь в данный момент находится в разговоре, но состояние либо не имеет связанного обработчика, либо обработчик, связанный с состоянием, не подходит для обновления, например, если обновление содержит команду, но ожидается обычное текстовое сообщение. Это поведение можно использовать для отмены разговора или сообщения пользователю, что его сообщение не было распознано.

    Чтобы изменить состояние разговора, функция обратного вызова обработчика должна вернуть новое состояние после ответа пользователю. Если она ничего не возвращает (по умолчанию), то состояние не изменится. Если функция обратного вызова точки входа возвращает None, разговор заканчивается сразу же после выполнения этой функции обратного вызова. Чтобы завершить разговор, функция обратного вызова должна вернуть END или -1. Для обработки тайм-аута разговора используйте TIMEOUT или -2.

    Пример фрагмента кода определения обработчика разговора ConversationHandler:

    conv_handler = ConversationHandler(
            # точка входа в разговор
            entry_points=[CommandHandler('start', start)],
            # словарь состояний разговора, возвращаемых callback функциями
            states={ 
                # Этап `FIRST` - т.е. функция обработчик сообщения в этом разговоре явно 
                # вернула константу FIRST (return `FIRST`), а так же послала/ответила 
                # на сообщение. Ответ пользователя на это сообщение будет 
                # обрабатываться обработчиками определенными в этом списке 
                FIRST: [
                    CallbackQueryHandler(one, pattern='^' + str(ONE) + '$'),
                    CallbackQueryHandler(two, pattern='^' + str(TWO) + '$'),
                    CallbackQueryHandler(three, pattern='^' + str(THREE) + '$'),
                    CallbackQueryHandler(four, pattern='^' + str(FOUR) + '$'),
                ],
                # Этап `SECOND` - происходит то же самое, что и в описании этапа `FIRST`
                SECOND: [
                    CallbackQueryHandler(start_over, pattern='^' + str(ONE) + '$'),
                    CallbackQueryHandler(end, pattern='^' + str(TWO) + '$'),
                ],
            },
            # точка выхода из разговора 
            fallbacks=[CommandHandler('start', start)],
        )
    
  • Класс InlineQueryHandler(callback) предназначен для обработки встроенных inline-запросов. Как работать с этим обработчиком, можно посмотреть в вводном материале в подразделе "Режим встроенных запросов".

  • Класс ChosenInlineResultHandler(callback) предназначен для обработки обновлений Telegram, содержащих выбранный inline-результат.

    Например: необходимо передать параметры пользовательского встроенного запроса для логирования, для этого можно обработать обновление с выбранным результатом следующим образом:

    from telegram.ext import ChosenInlineResultHandler
    
    def result_chosen(update, _):
        print(update.to_dict())
        # результат inline запроса
        result = update.chosen_inline_result
        # параметры результата
        result_id = result.result_id
        query = result.query
        user = result.from_user.id
        print(result_id)
        print(user)
        print(query)
        print(result.inline_message_id)
    
    result_chosen_handler = ChosenInlineResultHandler(result_chosen)
    dispatcher.add_handler(result_chosen_handler)
    
  • Класс PollAnswerHandler(callback) предназначен для обработки сообщений Telegram, содержащих ответ на опрос.

    Пример работы с обработчиком сообщения PollAnswerHandler(), которое представляет ответ на опрос/викторину, можно посмотреть в материале "Работа с опросами из python-telegram-bot на примере бота"

  • Класс PollHandler(callback) предназначен для обработки сообщений Telegram, содержащих опрос.

    Пример работы с обработчиком сообщения PollHandler(), представляющего из себя опрос/викторину, можно посмотреть в материале "Работа с опросами из python-telegram-bot на примере бота"

  • Класс PrefixHandler(prefix, command, callback) предназначен для обработки пользовательских префиксных команд (начинающихся с префикса, отличного от '/').

    Это промежуточный обработчик между MessageHandler и CommandHandler. Он поддерживает настраиваемые команды с теми же опциями, что и CommandHandler. Он реагирует на каждую комбинацию prefix и command.

    По умолчанию обработчик прослушивает сообщения, а также отредактированные сообщения. Чтобы изменить это поведение, используйте фильтр ~Filters.update.edited_message.

    # сработает на команду '!test'.
    PrefixHandler('!', 'test', callback)
    
    # сработает на команды '!test' и '#test'.
    PrefixHandler(['!', '#'], 'test', callback)
    
    # сработает на команды '!test', '#test', '!help' и '#help'.
    PrefixHandler(['!', '#'], ['test', 'help`], callback)
    
  • Класс ChatMemberHandler предназначен для обработки сообщений Telegram, содержащих обновления участников чата (покинул, присоединился и т. д.).

  • Класс ShippingQueryHandler(callback) предназначен для обработки запросов обратного вызова доставки Telegram. Другими словами, запускает функцию обратного вызова callback, если сообщение доставлено и прочитано.

  • Класс ChatJoinRequestHandler(callback) предназначен для обработки запросов на вступление в чат. Чтобы получать эти обновления, бот в чате должен иметь права администратора telegram.ChatPermissions.can_invite_users.

  • Класс PreCheckoutQueryHandler(callback) предназначен для обработки запросов обратного вызова Telegram PreCheckout.

В некоторых случаях полезно обрабатывать сообщения, поступающие не из Telegram. Например. можно обрабатывать уведомления от сторонней службы и пересылать их своим пользователям. Для таких случаев python-telegram-bot предоставляет следующие обработчики:

  • Класс TypeHandler() предназначен для обработки обновлений пользовательских типов. Тип type - тип сообщения, которые должен обрабатывать этот обработчик, как определено isinstance().
  • Класс StringRegexHandler(pattern, callback) предназначен для обработки обновлений строк на основе регулярного выражения, которое проверяет содержимое сообщения.
  • Класс StringCommandHandler(command, callback) предназначен для обработки пользовательских строковых команд. Команды представляют собой сообщения, которые начинаются с /.

Эти обработчики не используется для обработки Telegram.Update, но строки вручную помещаются в очередь. Например, чтобы отправлять сообщения с ботом, используя командную строку или API.

Обработка сообщений обработчиком MessageHandler.

Особенностью MessageHandler является то, что существует такое огромное разнообразие типов сообщений (текст, gif, изображение, документ, стикер и т. д.), что невозможно предоставить отдельный обработчик для каждого типа. Вместо этого MessageHandler сочетается с так называемыми фильтрами, которые позволяют проводить мелкие различия: MessageHandler(Filters.all, callback) будет обрабатывать все сообщения, которые содержат:

  • update.message;
  • update.edited_message;
  • update.channel_post;
  • update.edited_channel_post.

Вы можно использовать различные фильтры, чтобы сузить круг сообщений, которые будет обрабатывать конкретный MessageHandler. Смотрите также раздел по использованию фильтров.

Обработка команд обработчиком CommandHandler.

Команды - это сообщения Telegram, которые начинаются с символа /, за которым могут следовать @ и имя бота и / или некоторый дополнительный текст. Обработчик добавит список в context с именем CallbackContext.args. Он будет содержать список строк, который представляет собой текст, следующий за командой, разделенной на одиночные или последовательные символы пробела.

По умолчанию обработчик прослушивает все сообщения, а также отредактированные сообщения. Чтобы изменить это поведение, используйте ~Filters.update.edited_message в аргументе фильтра.

Класс telegram.ext.CommandHandler не обрабатывает отредактированные сообщения на канале.

Для примера использования обработчика CommandHandler, расширим функцию start_callback() некоторыми аргументами, чтобы пользователь мог предоставить дополнительную информацию:

Для многопоточной версии 13.x библиотеки:

...
def start_callback(update, context):
    # обработка аргументов, переданных с командой
    user_says = " ".join(context.args)
    update.message.reply_text("User said: " + user_says)
...

updater = Updater('TOKEN')
dispatcher = updater.dispatcher
dispatcher.add_handler(CommandHandler("start", start_callback))

Для асинхронной версии 20.x библиотеки:

...
async def start_callback(update, context):
    # обработка аргументов, переданных с командой
    user_says = " ".join(context.args)
    await update.message.reply_text("User said:" + user_says)
...

application = ApplicationBuilder().token('TOKEN').build()
application.add_handler(CommandHandler("start", start_callback))

Отправка команды '/start Hello World!' приведет к тому, что бот разделит все, что находится после /start, на список слов по пробелам и передаст его параметру args контекста: ['Hello', 'World!']. Мы объединяем эти фрагменты вместе, вызывая ''.join(context.args), и выводим полученную строку обратно пользователю.

Старт Telegram бота с параметрами.

Описанная выше передача аргументов работает точно так же, когда пользователь нажимает на глубоко связанный начальный URL, например этот:

https://t.me/roolsbot?start=Hello_World!

Щелчок по этой ссылке откроет Telegram-клиент и покажет большую кнопку СТАРТ. При ее нажатии параметры URL-адреса Hello_World! будут переданы в аргументы объекта контекста.

Обратите внимание, поскольку Telegram не поддерживает пробелы в параметрах URL для запуска ботов таким образом, то придется вручную разделить единственный аргумент Hello_World на ['Hello', 'World!'], например используя вызов context.args[0].split('_').

Также обратите внимание на максимальную длину, принимаемую самим Telegram. Как указано в документации, максимальная длина параметра start в URL составляет не более 64 символа.

Кроме того, так как это параметр URL-адреса, то необходимо правильно передавать значения, чтобы избежать зарезервированных символов URL-адреса. Рассмотрим использование base64.urlsafe_b64encode.

Соответствие шаблону: Filters.regex(pattern)

Для более сложных входных данных можно использовать telegram.ext.MessageHandler с фильтром telegram.ext.Filters.regex, который внутренне использует модуль re для сопоставления текстового ввода пользователя с предоставленным шаблоном.

Имейте в виду, что для извлечения URL-адресов, #Hashtags, @Mentions и других объектов Telegram нет необходимости, потому что Bot AP уже присылает их нам с каждым сообщением.

Сущности сообщения MessageEntity.

Для использования MessageEntity, сначала необходимо извлечь сущности и соответствующий им текст из объекта Message с помощью метода parse_entities.

Примечание. Этот метод всегда следует использовать вместо атрибута сущностей, поскольку он вычисляет правильную подстроку из текста сообщения на основе кодовых точек UTF-16, то есть извлекает правильную строку даже при работе со странными символами, такими как Emojis.

entity = message.parse_entities()