Всем привет, в этой статье я расскажу как сделать простейшего телеграмм бота на Python для отправки текущей погоды в Москве.
Статья расчитана на новичков в Python, которые бы хотели узнать больше о том, как взаимодействовать с внешними сервисами по API.
Технологии и API:
- Python — язык программирования,
- Flask — фреймворк для создания веб-приложений,
- Telegram Bot API,
- Weatherstack API,
- Ngrok — сервис для создания туннеля к localhost.
Как все будет работать?
- Пользователь пишет сообщение тел��грамм боту.
- Telegram пересылает сообщение пользователя на сервер.
- Сервер запрашивает информацию о погоде у Weatherstack.
- Сервер отсылает информацию о погоде в Telegram.
- Пользователь получает информацию о погоде.
Регистрация телеграмм бота
На этом этапе нам нужно создать бота и получить к нему доступы. Для этого запускаем бота botfather в Telegram командой ниже.
/start
Создаем нового бота согласно инструкциям из сообщения от бота.
!
Бот создан, но если ему написать какое-нибудь сообщение, он никак на него не отреагирует. Исправим это.
Справка о Flask
Flask — фреймворк для создания веб-приложений на языке программирования Python, использующий набор инструментов Werkzeug, а также шаблонизатор Jinja2. Относится к категории так называемых микрофреймворков — минималистичных каркасов веб-приложений, сознательно предоставляющих лишь самые базовые возможности.
Поддерживается установка посредством пакетного менеджера PyPI, версия 1.0 совместима с Python 2.7, Python 3.3 и выше.
Установка Flask
Для изоляции зависимостей пакетов Python создадим папку проекта и виртуальное окружение. Для этого в терминале выполним команды ниже. Подробнее о виртуальных окружениях.
$ mkdir weather_bot $ cd weather_bot $ python3 -m venv venv
После завершения установки и активации виртуального окружения установим Flask.
(venv)$ pip install Flask
Подробнее на странице Installation.
Запуск простейшего приложения Flask
В директории weather_bot создадим файл app.py с содержимым.
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello, World!'
Запустим полученное приложение.
(venv)$ export FLASK_APP=app.py (venv)$ flask run * Running on http://127.0.0.1:5000/
Перейдем по адресу http://127.0.0.1:5000/ и убедимся, что отображается текст "Hello, World!".
Подробнее на странице Quickstart.
Создание туннеля к localhost с помощью ngrok
Ngrok — это сервис, позволяющий создавать туннели на локальный компьютер пользователя.
- Зарегистрируемся на сайте ngrok.
- Выполним установку по инструкции.
- Запустим HTTP туннель на 5000 порте с помощью команды терминала ниже.
$ ./ngrok http 5000
Получение сообщений из телеграмм бота
Для того, чтобы Telegram пересылал сообщения на наш сервер, нужно сообщить ему адрес. У нас уже создан туннель, поэтому передадим адрес туннеля в Telegram. Это делается с помощью метода POST setWebhook. Подробнее на странице документации.
$ curl --location --request POST 'https://api.telegram.org/bot{token}/setWebhook' \ --header 'Content-Type: application/json' \ --data-raw '{ "url": "{url}" }'
где {token} — токен вида 840446984:AAFuVTW-FYP5tJVu8mqhc9y4E0j1fr2lCD0, который нам прислал BotFather,
{url} — адрес вида https://32515a83.ngrok.io, который отобразился в консоли ngrok. Обратите внимание на протокол. Он должен быть https, иначе Telegram не примет url.
Подробнее о cURL на странице wiki.
Если получен ответ "ok": true, то все в порядке.
{ "ok": true, "result": true, "description": "Webhook was set" }
Проверим, что сообщения доходят до нашего локального сервера. Для этого в файле app.py обновим код.
from flask import Flask, request app = Flask(__name__) @app.route("/", methods=["GET", "POST"]) def receive_update(): if request.method == "POST": print(request.json) return {"ok": True}
Перезапустим Flask. Для этого остановим сервер из терминала комбинацией клавиш Ctrl+C и повторно запустим его.
(venv)$ flask run
Отправим нашему боту сообщение с произвольным текстом. В консоли должно отобразиться тело запроса из Telegram. Это признак того, что все в порядке.
!
Ответ на сообщения пользователей
Мы научились получать сообщения от пользователей, но еще не умеем их отправлять. Для проверки отправки сообщений будем отвечат�� текстом "pong" на все сообщения.
Для отправки сообщений пользователям в API Telegram используется метод sendMessage. Подробнее на странице документации.
Запросы будем делать с помощью библиотеки requests, которой нет в списке стандартных, поэтому установим ее. Для этого в терминале с активированным виртуальным окружением выполним команду нижу.
(venv)$ pip install requests
Добавим строку импорта requests сразу за строкой from flask import Flask, request в app.py.
import requests
Для отправки сообщений нам нужно знать id чата. Его можно вытащить из тела Telegram-запроса.
chat_id = request.json["message"]["chat"]["id"]
Напишем функцию для отправки сообщений, в которую будем передавать id чата и текст сообщения.
def send_message(chat_id, text): method = "sendMessage" token = "840446984:AAFuVTW-FYP5tJVu8mqhc9y4E0j1fr2lCD0" url = f"https://api.telegram.org/bot{token}/{method}" data = {"chat_id": chat_id, "text": text} requests.post(url, data=data)
Подробнее о библиотеке requests на странице.
Добавим вызов функции send_message() из receive_update().
send_message(chat_id, "pong")
Вот так выглядит код в файле app.py
from flask import Flask, request import requests app = Flask(__name__) def send_message(chat_id, text): method = "sendMessage" token = "840446984:AAFuVTW-FYP5tJVu8mqhc9y4E0j1fr2lCD0" url = f"https://api.telegram.org/bot{token}/{method}" data = {"chat_id": chat_id, "text": text} requests.post(url, data=data) @app.route("/", methods=["GET", "POST"]) def receive_update(): if request.method == "POST": print(request.json) chat_id = request.json["message"]["chat"]["id"] send_message(chat_id, "pong") return {"ok": True}
Отправка пользователю информации о погоде
Используем метод current Weatherstack API для получения информации о погоде.
Передадим 2 обязательных Query Params: access_key — секретный ключ вида 86a3fe972756lk34a6a042bll348b1e3, который можно получить после регистрации, и query — город, по которому получаем информацию о погоде, в нашем случае — Moscow.
Подробнее на странице документации.
Добавим функцию для получения текущей температуры в Москве после строки app = Flask(__name__).
def get_weather(): params = {"access_key": "86a3fe972756lk34a6a042bll348b1e3", "query": "Moscow"} api_result = requests.get('http://api.weatherstack.com/current', params) api_response = api_result.json() return f"Сейчас в Москве {api_response['current']['temperature']} градусов"
Внутри функции receive_update() вместо сообщения с текстом "pong" передадим погоду.
weather = get_weather() send_message(chat_id, weather)
Код всего Flask-приложения состоит из 3 функций: получения сообщений из Telegram, отправка сообщений в Telegram и получение информации о погоде из Weatherstack.
from flask import Flask, request import requests app = Flask(__name__) def get_weather(): params = {"access_key": "86a3fe972756lk34a6a042bll348b1e3", "query": "Moscow"} api_result = requests.get('http://api.weatherstack.com/current', params) api_response = api_result.json() return f"Сейчас в Москве {api_response['current']['temperature']} градусов" def send_message(chat_id, text): method = "sendMessage" token = "840446984:AAFuVTW-FYP5tJVu8mqhc9y4E0j1fr2lCD0" url = f"https://api.telegram.org/bot{token}/{method}" data = {"chat_id": chat_id, "text": text} requests.post(url, data=data) @app.route("/", methods=["GET", "POST"]) def receive_update(): if request.method == "POST": print(request.json) chat_id = request.json["message"]["chat"]["id"] weather = get_weather() send_message(chat_id, weather) return {"ok": True}
Вот и всё! Таким несложным образом мы научили наш бот информировать нас о погоде в Москве.
