Всем привет, в этой статье я расскажу как сделать простейшего телеграмм бота на 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}
Вот и всё! Таким несложным образом мы научили наш бот информировать нас о погоде в Москве.
Tinkz
Здравствуйте, теперь поместите бота, например, в heroku или яндекс функции. Ngrok мне кажется не надёжно.
ko_0n Автор
Спасибо за предложение. Посмотрю насколько эта тема уже описана, потом прикину стоит ли писать.