153712

Простой Telegram бот на Python всего за 1 час

С помощью языка Python и сервера Heroku мы напишем бот для мессенджера Telegram. Процесс создания простой, а помощник действительно полезный.

Вынуждены разочаровать тех, кто представляет ботов, как инструмент исключительно для автоответов и искусственной активности. Думайте о Telegram боте как об автоматизированной учетной записи, которая может выполнять для вас некоторые действия. Например, вы хотите поделиться ссылкой YouTube в групповом чате, но у вас пока нет ссылки.

Без бота это выглядело бы так:

  1. Вы открываете в веб-браузере YouTube.
  2. Ищете видео, которым хотите поделиться.
  3. Выбираете общий доступ.
  4. Возвращаетесь в мессенджер и, наконец, делитесь ссылкой.

Конечно, большинство из нас привыкло к вышеуказанному алгоритму, и это неплохо работает. Однако...

С ботом:

  1. Вы находитесь в мессенджере.
  2. Вводите @vid, а затем видео, которым хотите поделиться.

И это всего лишь одна из возможностей ботов. Разработчики Telegram проделали отличную работу и позволили пользователям создавать своих собственных ботов. Отвечая на вопрос, почему это может быть интересно, я могу сказать, что это самый простой способ получить представление об API.

Как насчет создания первого Telegram бота?

Прежде всего, зарегистрируйтесь. Рекомендую использовать веб-клиент. Откройте кроссплатформенный мессенджер, найдите @BotFather и запустите чат. Отправьте в сообщении /newbot и следуйте инструкциям. После завершения начальных шагов вы получите:

- токен;
- API URL;
- ссылку на документацию.

На момент создания бот 100% пассивен. Вам нужно инициализировать разговор. Для этого откройте поиск и введите имя своего бота, а после начните разговор, нажав /start. Введите что-то вроде «Hello». Это сообщение важно, поскольку это первое обновление, которое получит ваш бот.

Если это первый опыт, откройте новую вкладку в своем браузере и используйте URL-адрес: так вы отправите запрос на сервер Telegram. Пришедший ответ будет в формате JSON и чем-то напоминающим словарь Python. Вы должны увидеть что-то вроде этого:

{"ok":true,"result":[{"update_id":523349956,
"message":{"message_id":51,"from":{"id":303262877,"first_name":"YourName"},"chat":{"id":303262877,"first_name":"YourName","type":"private"},"date":1486829360,"text":"Hello"}}]}

Если вы откроете документацию и заглянете на раздел /sendMessage, то заметите, что требуется 2 дополнительных параметра: chat_id и text. В строке поиска браузера можно использовать ? для первого параметра и & для остальных. Отправка сообщения будет выглядеть следующим образом:

/sendMessage?chat_id=303262877&text=test

Для ответа от бота замените chat_id на значение, которое получите с вызовом /getUpdates.  У нас это 303262877. Текстовый параметр зависит от вас. Запрос должен выглядеть так:

https://api.telegram.org/bot<token>/sendMessage?chat_id=303262877&text=Hello

Подготовка к кодингу

Если ваша операционная система – Windows, но еще не установлен Python, скачайте его здесь. Без разницы, будет это версия 2.x или 3.x. Для примера мы будем использовать Python 3.x. На macOS и Linux обе версии уже установлены (либо минимум Python 2.x), поэтому нет необходимости дополнительно скачивать что-либо.

Следующий шаг – установка системы управления пакетами pip. Для Python 2.7.9 и выше, а также Python 3.4 и выше они уже предустановленны (равно как и для операционных систем macOS/Linux). Если нужно, вы всегда можете проверить это, используя в терминале команду pip –version. При отсутствии данной системы установите ее с помощью команды:

$ sudo apt-get install python-pip.

Интересная штука: разные версии Python работают с разными pip. Для обладателей macOS подойдет эта инструкция. Если же у вас ОС Windows, загрузите get-pip.py, откройте cmd, перейдите к скачанным файлам (директория) и выполните следующее:

$ python get-pip.py

Это было самое сложное. Осталось воспользоваться pip и установить пакет requests:

$ pip install requests

Дополнительно можно скачать PyCharm, хотя этот шаг и не относится к обязательным.

Начинаем кодить

Если принцип API понятен, и у вас есть все необходимые инструменты, давайте создадим скрипт Python, который будет проверять наличие обновлений и отвечать на них желаемым текстом.

Прежде всего, наш Telegram бот должен проверять наличие обновлений. Сообщение можно рассматривать как самое последнее из них. Так или иначе, getUpdates вернет все обновления за последние 24 часа. Давайте создадим небольшой скрипт, чтобы получить последнее обновление:

import requests

url = "https://api.telegram.org/bot<token>/"


def get_updates_json(request):  
    response = requests.get(request + 'getUpdates')
    return response.json()


def last_update(data):  
    results = data['result']
    total_updates = len(results) - 1
    return results[total_updates]

Словарь обновлений состоит из двух элементов - «ok» и «results». Нам нужен второй, который представляет собой список всех обновлений за последние 24 часа. Здесь вы можете посмотреть дополнительную информацию о библиотеке запросов. Основная идея заключается в том, что всякий раз, когда вам нужно получать, обновлять или удалять информацию на сервере, вы отправляете запрос и принимаете ответ.

Следующий шаг – добавление еще 2-х функций. Первая получит chat_id от обновления, а вторая отправит сообщение:

def get_chat_id(update):  
    chat_id = update['message']['chat']['id']
    return chat_id

def send_mess(chat, text):  
    params = {'chat_id': chat, 'text': text}
    response = requests.post(url + 'sendMessage', data=params)
    return response

chat_id = get_chat_id(last_update(get_updates_json(url)))

send_mess(chat_id, 'Your message goes here')

Помните, как мы привязывали параметры с помощью ? и &? Вы можете сделать то же самое, добавив dict в качестве второго необязательного параметра для запросов get/post.

Telegram скрипт готов

Однако он еще далек от идеала. Главный недостаток заключается в том, что вам нужно запускать скрипт каждый раз, когда вы хотите обменяться сообщениями с ботом. Давайте исправим это. Чтобы заставить нашего бота слушать сервер для получения обновлений, необходимо запустить главный цикл. Добавьте from time import sleep после import requests и замените 2 последние строки на:

def main():  
    update_id = last_update(get_updates_json(url))['update_id']
    while True:
        if update_id == last_update(get_updates_json(url))['update_id']:
           send_mess(get_chat_id(last_update(get_updates_json(url))), 'test')
           update_id += 1
    sleep(1)       

if __name__ == '__main__':  
    main()

Хотя мы добавили «тайм-аут» в 1 секунду, приведенный выше пример должен использоваться только в целях тестирования, поскольку он использует частые опросы. Это не очень хорошо для серверов Telegram. Есть еще два способа получить обновления через API – вебхуки и длинные опросы. Но так как мы проверяем обновления с использованием метода getUpdates, запросы будут частыми.

Поскольку мы использовали основной цикл, следует переключиться на длинные опросы. Изменим первую функцию, добавив параметр timeout. Тайм-аут сам по себе не сделает проверку скрипта для обновления реже. Кроме того, тайм-аут будет работать только в том случае, если последние обновления отсутствуют. Для отметки просмотренных обновлений нужно добавить параметр offset:

def get_updates_json(request):  
    params = {'timeout': 100, 'offset': None}
    response = requests.get(request + 'getUpdates', data=params)
    return response.json()

Теперь бот должен работать нормально, но немного изменим код

Неплохо было бы инкапсулировать использованные функции в класс. Модифицированная версия скрипта будет выглядеть таким образом:

import requests  
import datetime

class BotHandler:

    def __init__(self, token):
        self.token = token
        self.api_url = "https://api.telegram.org/bot{}/".format(token)

    def get_updates(self, timeout=30):
        method = 'getUpdates'
        params = {'timeout': timeout}
        resp = requests.get(self.api_url + method, params)
        result_json = resp.json()['result']
        return result_json

    def send_message(self, chat_id, text):
        params = {'chat_id': chat_id, 'text': text}
        method = 'sendMessage'
        resp = requests.post(self.api_url + method, params)
        return resp

    def get_last_update(self):
        get_result = self.get_updates()

        if len(get_result) > 0:
            last_update = get_result[-1]
        else:
            last_update = get_result[len(get_result)]

        return last_update

Ну и последний штрих – объявить переменные и научить нашего бота некоторым манерам. Идея состоит в том, чтобы сделать Telegram бота, который будет приветствовать вас раз в день. В зависимости от времени суток сообщение должно быть разным. Если вы хотите попробовать этот скрипт, добавьте строку import datetime после import requests , а также дополните скрипт данным кодом:

greet_bot = BotHandler(token)  
greetings = ('hello', 'hi', 'greetings', 'sup')  
now = datetime.datetime.now()


def main():  
    new_offset = None
    today = now.day
    hour = now.hour

    while True:
        greet_bot.get_updates(new_offset)

        last_update = greet_bot.get_last_update()

        last_update_id = last_update['update_id']
        last_chat_text = last_update['message']['text']
        last_chat_id = last_update['message']['chat']['id']
        last_chat_name = last_update['message']['chat']['first_name']

        if last_chat_text.lower() in greetings and today == now.day and 6 <= hour < 12:
            greet_bot.send_message(last_chat_id, 'Good Morning  {}'.format(last_chat_name))
            today += 1

        elif last_chat_text.lower() in greetings and today == now.day and 12 <= hour < 17:
            greet_bot.send_message(last_chat_id, 'Good Afternoon {}'.format(last_chat_name))
            today += 1

        elif last_chat_text.lower() in greetings and today == now.day and 17 <= hour < 23:
            greet_bot.send_message(last_chat_id, 'Good Evening  {}'.format(last_chat_name))
            today += 1

        new_offset = last_update_id + 1

if __name__ == '__main__':  
    try:
        main()
    except KeyboardInterrupt:
        exit()

Теперь у вас есть тысячи различных способов улучшать своего бота! Можно добавить дополнительные кнопки или даже настроить отправку медиафайлов.

Переходим к развертыванию

Последний шаг – это как вишенка на торте, которая позволит сделать из вашего Telegram бота настоящего помощника: его необходимо развернуть на сервере. Скорее всего, у вас нет собственного сервера, и уж вряд ли вы захотите покупать для этого дорогостоящую аппаратуру. К счастью, существует множество облачных сервисов, на которых можно бесплатно разместить приложение. Давайте развернем небольшой скрипт на Heroku.

Прежде всего, вам нужна учетная запись на GitHub. Переходите на главную страницу и регистрируйтесь: это обязательный шаг для любого, кто действительно заинтересован в программировании. Помимо учетной записи GitHub, вам также необходимо установить Git.

Если у вас Linux, выполните следующую команду:

$ sudo apt-get install git-all

Для macOS и Windows можно произвести ручную установку программы. И, конечно же, не забудьте завести аккаунт на Heroku.

Устанавливаем virtualenv, используя команду:

$ pip install virtualenv

Теперь вам нужно немного упорядочить свои файлы. Создайте новую папку, откройте терминал/cmd и перейдите в нее. Для инициализации в созданной папке virtualenv введите:

$ virtualenv my_env

Название не имеет особого значения, однако лучше делать его максимально понятным. Перейдите в папку my_env. Следующий шаг – клонировать ваш репозиторий Git. Введите следующую команду:

$ git clone https://github.com/yourprofilename/yourreponame

Поместите свой скрипт в папку и вернитесь в my_env, чтобы запустить virtualenv.

Windows:

$ scripts\activate.bat

Linux/macOS:

$ source bin/activate

При успешном запуске virtualenv командная строка должна начинаться с (my_env). Установите модуль requests, перейдя в папку репозитория:

$ pip install requests

Для создания зависимостей Heroku введите:

$ pip freeze > requirements.txt

Создайте файл Procfile. В нем вы найдете инструкции для работы со своим скриптом. Имя должно быть Procfile или Procfile.windows, если это Windows. Не стоит включать в название .txt, .py или любые другие расширения. Содержимое файла должно быть следующим (измените my_bot на название вашего скрипта):

web: python my_bot.py

Добавьте файл __init__.py в свою папку. Файл может быть пустым, но он должен находиться там. Введите такую команду:

$ git init
$ git add .
$ git commit -m ‘short message that describe changes to commit’
$ git push -u https://github.com/yourusername/nameofrepo

А теперь развернем нашего Telegram бота на Heroku. Потренируемся делать это через консоль. При возникновении проблем, обратитесь к руководству. Для Windows и macOS нужно установить интерфейс командной строки, используя этот гайд. Для Ubuntu используем команды:

$ sudo add-apt-repository "deb https://cliassets.heroku.com/branches/stable/apt ./"
$ curl -L https://cli-assets.heroku.com/apt/release.key |
$ sudo apt-key add -
$ sudo apt-get update
$ sudo apt-get install heroku

Интересный факт: на моем домашнем компьютере все прошло без сучка и задоринки, а вот на ноутбуке последний шаг выполнить не удалось. Если вы столкнулись с такой же проблемой, проверьте терминал на наличие всех зависимостей. После выполните команды:

$ heroku login
$ heroku create
$ git push heroku master
$ heroku ps:scale web=1
$ heroku open

С этого момента ваше приложение должно работать на сервере Heroku. Если по какой-либо причине оно не работает, проверьте журналы, используя следующую команду:

$ heroku logs --trail

Коды ошибок можно посмотреть здесь.

Да, используя бесплатный аккаунт, вы столкнетесь с определенными ограничениями. Но даже так после проделанных действий у вас будет полностью функциональный бот.

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

admin
11 декабря 2018

ООП на Python: концепции, принципы и примеры реализации

Программирование на Python допускает различные методологии, но в его основе...
admin
28 июня 2018

3 самых важных сферы применения Python: возможности языка

Существует множество областей применения Python, но в некоторых он особенно...
admin
13 февраля 2017

Программирование на Python: от новичка до профессионала

Пошаговая инструкция для всех, кто хочет изучить программирование на Python...