[Python, Flask] Телеграмм-бот на Python

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
12-Апр-2021 21:31

Недавно я попал на стажировку в новую для себя IT-компанию и наш (моей команды) проект был - бот для телеграмма, который автоматизирует часть работы hr-менеджеров. Первую неделю нам дали на самостоятельное изучение всего, что мы посчитаем нужным (а я убежден, что лучший способ что-то изучить - это практика), так что я начал действовать. Язык программирования был выбран python (наверное понятно из обложки почему), так что в этой статьи я разберу пример именно с ним.BotFatherЧтобы создать телеграмм-бота, достаточно написать пользователю @BotFather команду /newbot. Он запросит название и @username для будущего бота. Тут ничего сложного - он все подсказывает (главное, чтобы @username был не занят и заканчивался на "bot"). BotFather пришлет HTTP API токен, который мы и будем использовать для работы с ботом.
Создание ботаTelebot и сила pythonМне всегда казалось, что создавать бота - это не так просто. Честно говоря, давно хотел попробовать, но то ли не хватало времени (думал, что это займет не один вечер), то ли не мог выбрать технологию (как-то смотрел туториал для c#), ну а скорее всего было просто лень. Но тут мне понадобилось это для работы, так что я больше не смел откладывать.Сила python заключается в его популярности. А, как следствие, в появлении огромного количества сторонних библиотек практически под все нужды. Именно это сделало возможным написание примитивного бота (который просто отвечает однотипно на сообщения) в 6 (ШЕСТЬ!) строчек кода. А именно:
import telebot
bot = telebot.TeleBot('1111105161:AAHIjyAKY4fj62whM5vEAfotuixC5syA-j8')
@bot.message_handler(commands=['start'])
def start_command(message):
    bot.send_message(message.chat.id, "Hello!")
bot.polling()

Первое сообщениеНа самом деле бот будет отвечать только на команду /start, но для начала неплохо. Здесь все довольно просто: в первой строчке импортируется библиотека telebot (для ее работы необходимо установить пакет pyTelegramBotAPI командой pip install pyTelegramBotAPI (НЕ pip install telebot!), далее создаем объекта бот, используя токен, который нам прислал BotFather. Третья строчка проверяет, что присылают пользователи (в данном случае это только команда “/start”), и, если проверка пройдена, то бот отправляет ответ с текстом “Hello!”. Последняя строчка, наверное, самая сложная для понимания, и в следующих разделах я ее подробно разберу. Сейчас же я только скажу о ее предназначении - она заставляет бота работать, то есть "реагировать" на полученные сообщения.Flask & RequestsTelebot, конечно, круто, но есть одно важное “НО”. По предположению нашего проекта, у hr-ов должен быть сервис (сайт), где они будут работать и через него отправлять/получать информацию пользователям/от них. Соответственно, нам нужно самим контролировать сервер и обрабатывать запросы. На мой взгляд самый простой способ создания сервера на python - фреймворк flask. Так выглядит простейший сервер, запускаемый локально на 5000-ом порту (http://localhost:5000/):
from flask import Flask
app = Flask(__name__)
@app.route("/", methods=["GET"])
def index():
    return "Hello, World!"
if __name__ == "__main__":
    app.run()
Для работы бота нужно немного больше, а именно нужно добавить функцию отправки сообщений. Я не хочу полностью переписывать статью (habr), а воспользуюсь результатом и пойду с конца. Так выглядит программа, которая заставляет бота посылать “Hello!” на любое входящее сообщение:
from flask import Flask, request
import requests
app = Flask(__name__)
def send_message(chat_id, text):
    method = "sendMessage"
    token = "1111105161:AAHIjyAKY4fj62whM5vEAfotuixC5syA-j8"
    url = f"https://api.telegram.org/bot{token}/{method}"
    data = {"chat_id": chat_id, "text": text}
    requests.post(url, data=data)
@app.route("/", methods=["POST"])
def receive_update():
    chat_id = request.json["message"]["chat"]["id"]
    send_message(chat_id, "Hello!")
    return "ok"
if __name__ == "__main__":
    app.run()
К сожалению, в таком варианте программа работать не будет. Точнее будет, но не сразу. Проблема заключается в том, что телеграмм пока что не знает, куда посылать информацию о полученных сообщениях. Для ее решения у telegram API есть метод setWebhook. Суть метода заключается в том, что мы просто отправляем телеграмму url, по которому мы хотим получать информацию о новых обращениях к боту (в нашем случае это http://localhost:5000/). Однако, мы не можем просто сказать телеграмму: "Посылай запросы на localhost", ведь для каждого сервера localhost будет разным. Еще одна проблема заключается в том, что метод setWebhook поддерживает только https url-ы. Для решения этих проблем можно воспользоваться программой ngrok, которая строит туннель до локального хоста. Скачать ее можно по ссылке ngrok, а для запуска туннеля достаточно ввести команду “ngrok http 5000”. Должно получиться так:
ngrokТеперь можно задействовать метод setWebhook, например, через postman. Нужно отправить post запрос на https://api.telegram.org/bot<ТОКЕН>/setWebhook с указанием в теле нужного url. Должно получиться аналогично:
setWebhookСоединениеЧем больше я работал с библиотекой telebot, тем больше она мне нравилась. Хотелось бы, используя приложение на flask’e, не терять эту возможность. Но как это сделать? Во-первых, мы можем вместо нашей функции send_message использовать готовую из библиотеки. Это будет выглядеть так:
from flask import Flask, request
import telebot
app = Flask(__name__)
bot = telebot.TeleBot('1111105161:AAHIjyAKY4fj62whM5vEAfotuixC5syA-j8')
@app.route("/", methods=["POST"])
def receive_update():
    chat_id = request.json["message"]["chat"]["id"]
    bot.send_message(chat_id, "Hello!")
    return "ok"
if __name__ == "__main__":
    app.run()
Но, если присмотреться, можно заметить, что мы потеряли часть функционала, а именно @bot.message_handler - декораторы, которые отслеживают тип введенного боту сообщения (картинка, документ, текст, команда и т. д.). Получается, что если мы используем в качестве сервера наше flask приложение, то мы теряем некоторый функционал библиотеки telebot. Если же мы используем bot.polling(), то мы не можем обращаться к серверу “со стороны”. Конечно, хотелось бы как-то все соединить без потерь. Для этого я нашел немного костыльный способ, однако рабочий:
from flask import Flask, request
import telebot
bot = telebot.TeleBot('1111105161:AAHIjyAKY4fj62whM5vEAfotuixC5syA-j8')
bot.set_webhook(url="https://8c6f687b75c9.ngrok.io")
app = Flask(__name__)
@app.route('/', methods=["POST"])
def webhook():
    bot.process_new_updates(
        [telebot.types.Update.de_json(request.stream.read().decode("utf-8"))]
    )
    return "ok"
@bot.message_handler(commands=['start'])
def start_command(message):
    bot.send_message(message.chat.id, 'Hello!')
if __name__ == "__main__":
    app.run()
Здесь мы пользуемся методом set_webhook, аналогично тому, как мы делали это ранее через postman, а на пустом роуте прописываем "немного магии", чтобы успешно получать обновления бота. Конечно, это не очень хороший способ, и в дальнейшем лучше самостоятельно прописывать функционал для обработки входящих сообщений. Но для начала, я считаю, это лучшее решение.ЗаключениеНаписать телеграмм-бота на python и правда не так уж сложно, однако есть и подводные камни, о которых я постарался рассказать в данной статье. Конечно, это только начало, но последний фрагмент кода вполне можно использовать, как шаблон для серверной части, которая будет работать с телеграмм-ботом. Дальше остается только наращивать функционал по Вашему усмотрению.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_python, #_flask, #_telegram, #_bot, #_python, #_flask, #_python, #_flask
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 23:53
Часовой пояс: UTC + 5