Введение
Telegram – крайне популярный в настоящее время мессенджер, который используют во всём мире. Приложение постоянно развивается и обрастает новыми фичами и сейчас уже не ограничивается только передачей сообщений между людьми. В частности, Telegram предоставляет пользователям удобный функционал для автоматизации различных процессов. К примеру, можно настроить регистрацию пользователей через Telegram для своего стороннего сервиса. Или получать различные уведомления извне. Их также можно интегрировать в различные сервисы или использовать в качестве утилит.
Всё это можно реализовать с помощью специальных ботов. Боты – это специальные аккаунты Telegram, которые способны автоматически получать или отправлять сообщения. Пользователи могут взаимодействовать с ботами посредством чата, как с людьми, при этом боты способны выполнять самые разные команды, какие только способен реализовать разработчик. Для работы с ботами используется специальный Telegram Bot API, в котором описана вся логика.
В этой статье мы разберёмся, как создать и настроить своего бота для Telegram. По задумке этот бот будет по запросу получать данные из стороннего API и отображать в чате в удобном для пользователя виде.
Создание бота
Перед тем, как начать писать код для бота, нужно создать его непосредственно в Telegram. Для этого нам понадобится специальный бот, именуемый @BotFather.
Важно! Обратите внимание, что в Telegram существует специальное правило для именования ботов. Имя бота должно обязательно заканчиваться на “bot“. BotFather, в свою очередь, специально является исключением, чтобы выделить его среди прочих и отсеять возможных мошенников. Кроме того, у этого аккаунта должна стоять галочка, уведомляющая, что аккаунт подтверждён. Поэтому, перед передачей каких-либо конфиденциальных данных, убедитесь, что вы пишете в чат именно BotFather.
После начала диалога с ботом будет предложен список команд, доступных для работы. Там присутствуют также команды для веб-приложений и игр, но в данном случае нас интересуют следующие:
- /newbot – Создать нового бота
- /setname – Изменение имени бота
- /setdescription – Изменение описания бота
- /setabouttext – Изменение информации о боте
- /setuserpic – Изменение аватарки бота
- /setcommands – Изменение списка доступных команд
- /token – Сгенерировать токен
Для того, чтобы начать создание бота, введём команды /newbot. После этого нам будет предложено придумать название для нашего бота, которое будут видеть пользователи. Название может быть произвольным. К примеру, назовём нашего бота News Bot.
Теперь нужно придумать имя бота. Как уже говорилось выше, оно должно заканчиваться на “bot” и быть уникальным: нельзя создать двух ботов с одинаковым именем. В нашем случае имя бота будет android_tools_news_bot.
Если бот с таким же именем уже существует, мы получим ошибку и предложение придумать другое. В противном случае бот будет успешно создан в Telegram.
Также BotFather сразу сгенерирует для нас специальный токен. Этот токен является крайне важным, поскольку с его помощью будет происходить всё дальнейшее взаимодействие с Telegram Bot API. Поэтому его следует надёжно хранить и не передавать третьим лицам.
Теперь можно добавить дополнительное описание и установить изображение, используя перечисленные выше команды.
Создание бота завершено и теперь можно перейти к написанию логики работы.
Логика работы
Если мы начнём диалог с только что созданным ботом, то обнаружим, что он никак не реагирует на сообщения. Всё потому, что чат бота это, по сути, всего лишь интерфейс, через который происходит взаимодействие. Чтобы получать, обрабатывать и отвечать на команды, нам нужно написать программу, которая будет всё это делать.
Одним из преимуществ Telegram ботов является то, что их можно написать практически на любом языке программирования, способном работать с сетевыми запросами. Поэтому, если вы уже знаете какой-нибудь из языков, вам не требуется дополнительно что-либо изучать.
Однако самым популярным вариантом является написание ботов на Python. Это обусловлено несколькими причинами:
- Имеет низкий порог вхождения, поэтому предпочтителен для новичков;
- Отлично подходит для написания лёгких и простых приложений с минимумом логики;
- Не зависит от каких-либо фреймворков (как C# от .NET), за счёт чего можно легко развернуть на любом удалённом сервере с минимальной конфигурацией.
Для примера возьмём Python 3 и попробуем написать на нём нашего бота.
Создадим пустой проект. Перед началом работы нам нужно будет создать виртуальное окружение в папке с проектом. Это виртуальное окружение будет использоваться для хранения установленных библиотек, различного кеша и интерпретатора Python, который будет обрабатывать наш код. Создание виртуального окружения является хорошей практикой, поскольку изолирует проект от глобального окружения и исключает конфликт версий одной и той же библиотеки между разными приложениями. Сделать это можно с помощью следующей команды:
python -m venv .\.venv
В начале работы нам нужно будет каждый раз активировать виртуальное окружение, чтобы работать в нём. Для этого потребуется использовать следующую команду:
# Windows
.\.venv\Scripts\activate
# Linux/MacOS
source .venv/bin/activate
Теперь определимся с библиотеками, которые будем использовать.
Мы можем отправлять запросы напрямую в Telegram Bot API, но это может быть неудобно. Поэтому существуют различные библиотеки-обёртки, которые выполняют все эти запросы под капотом и предоставляют удобный интерфейс для работы. Для нашего бота возьмёт одну из таких библиотек python-telegram-bot. Она написана поверх модуля asyncio, реализовывающего асинхронное программирование в Python на основе корутин.
Также нам понадобятся библиотеки python-dotenv и requests.
Первая позволяет считывать данные из .env файла, в котором мы будем хранить токен бота, и загружать их в переменные среды. Этот файл должен оставаться скрытым и исключаться из git.
Вторая библиотека предоставляет удобный и мощный механизм для работы с сетевыми запросами.
Создадим файл requirements.txt и добавим в него перечисленные выше библиотеки.
python-telegram-bot
python-dotenv
requests
Этот файл нужен для того, чтобы упростить дальнейшее развёртывание на удалённом сервере. Вместо того, чтобы устанавливать каждую библиотеку по отдельности, нам достаточно теперь прописать следующую команду:
pip install -r .\requirements.txt --upgrade
Мы также можем прописать в файле конкретные версии требуемых библиотек. Если этого не сделать, то pip установит самые свежие версии.
Теперь создадим в папке проекта файл .env. Как уже было сказано ранее, в нём мы будем хранить токен бота, необходимый для работы.
TELEGRAM_TOKEN=<токен бота Telegram>
Первоначальная настройка завершена и теперь можно приступить к написанию логики.
Создадим папку app, в которой будут находиться все скрипты программы. В ней создадим файл main.py. Этот скрипт будет точкой входа в программу.
from bot import start_bot
from logger import get_logger
logger = get_logger(__name__)
if __name__ == '__main__':
logger.info(" Starting...")
start_bot()
Для большей наглядности подключим логирование событий. Для этого создадим скрипт logger.py и добавим в него конфигурацию логов.
import logging
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.INFO,
)
logging.getLogger("httpx").setLevel(logging.WARNING)
def get_logger(name: str) -> logging.Logger:
return logging.getLogger(name)
Теперь создадим файл bot.py, в котором опишем инициализацию бота.
from telegram import Update
from telegram.ext import (
ApplicationBuilder,
)
from config import get_telegram_token
def start_bot():
token = get_telegram_token()
app = ApplicationBuilder().token(token).build()
app.run_polling(allowed_updates=Update.ALL_TYPES)
ApplicationBuilder требует токен бота для инициализации. Получение токена вынесем в отдельный скрипт config.py. Создадим его и добавим следующий код:
import os
from dotenv import load_dotenv
def get_telegram_token():
load_dotenv()
token = os.getenv("TELEGRAM_TOKEN")
if not token:
raise ValueError(
"Токен бота не найден. Убедитесь, что TELEGRAM_TOKEN указан в .env файле."
)
return token
Загружаем содержимое файла .env в переменные среды, затем получаем из них TELEGRAM_TOKEN.
Когда бот проинициализирован, вызываем метод run_polling(). Этот метод берёт на себя всю работу по запуску и остановке бота. Также он запускает запрос и ожидание обновлений из Telegram для получения входящих команд.
Попробуем запустить программу. В логах мы должны увидеть сообщение от библиотеки, что приложение запущено.
Теперь мы ожидаем команды от пользователей, но всё ещё никак на них не реагируем. Для этого библиотека предоставляет функционал обработчиков, которые при заданных условиях будут реагировать на команды и сообщения. В API описаны различные обработчики под все сценарии работы, вот пример некоторых из них:
- MessageHandler – обрабатывает входящее сообщение. Это может быть как текст, так и медиа.
- CommandHandler – обрабатывает команду (сообщение, начинающееся с символа / ).
- ConversationHandler – обрабатывает диалог (конкретную последовательность команд или сообщений) между ботом и пользователем. Для реализации работы использует другие обработчики и контролирует их выполнение.
Допустим, нам надо при команде /start выводить какое-то приветственное сообщение. Поскольку это команда, а не простое сообщение, то нам понадобится CommandHandler. Добавим его.
from telegram import Update
from telegram.ext import (
ApplicationBuilder, CommandHandler
)
from config import get_telegram_token
from handlers import say_hello
def start_bot():
token = get_telegram_token()
app = ApplicationBuilder().token(token).build()
app.add_handler(CommandHandler("start", say_hello))
app.run_polling(allowed_updates=Update.ALL_TYPES)
CommandHandler принимает в качестве параметров текст команды и функцию обратного вызова, внутри которой будет происходить обработка.
Создадим файл handlers.py, в котором будем описывать обработку команд, и добавим функцию say_hello().
from telegram import Update
from telegram.ext import ContextTypes
async def say_hello(update: Update, context: ContextTypes.DEFAULT_TYPE):
user_name = update.message.from_user.first_name
await update.message.reply_text(f" Добро пожаловать, {user_name}!")
Функция обратного вызова должна иметь два параметра: Update и ContextTypes. Первый содержит данные о входящем обновлении, а второй различную полезную информацию. Например, в ContextTypes мы можем сохранять промежуточные данные в ходе диалога, чтобы использовать их в других функциях.
Update содержит в себе все данные о сообщении, которые передаёт Telegram Bot API. В том числе мы можем узнать имя пользователя, от которого пришла команда. Попробуем вернуть это имя в ответном сообщении от бота.
Чтобы отправить сообщение в чат, можно воспользоваться методом reply_text(), который принимает текст сообщения. Под капотом этого метода происходит формирование JSON с нужными данными (ID чата, текст сообщения, вложения и т.д.) и его отправка посредством метода API. Без использования библиотеки, нам пришлось бы каждый раз формировать запрос следующим образом:
https://api.telegram.org/bot<токен бота>/sendMessage?chat_id=<ID чата>&text=<сообщение>
Стоит также отметить, что, поскольку библиотека использует асинхронный подход, все коллбэки должны содержать ключевое слово async, а обращения к Telegram API – await.
Попробуем запустить программу и получить ответ от бота.
Теперь бот способен обрабатывать команду и отвечать пользователю на неё.
В зависимости от того, какие задачи должен выполнять бот, могут потребоваться самые разные обработчики. Их можно добавлять в любом количестве, настраивать условия их срабатывания и создавать последовательный диалог между пользователем и ботом.
Пока что бот умеет лишь здороваться в ответ на стартовую команду, что не делает его особо полезным. Попробуем интегрировать в бота какое-нибудь стороннее API, к которому он будет слать запросы, получать результаты и возвращать в чат пользователю. Для примера возьмём API для получения списка последних новостей.
Примечание: существует множество различных бесплатных и открытых API, с которыми вы можете попробовать поработать. Некоторые из них можно найти тут или тут.
Создадим файл api.py, в котором будет обращаться к новостному API.
from http import HTTPStatus
import requests
API_KEY = "ключ API"
BASE_URL = "https://newsapi.org/v2"
URL_TOP_HEADLINES = "/top-headlines"
def get_top_headlines():
url = f"{BASE_URL}{URL_TOP_HEADLINES}?country=us&category=science&apiKey={API_KEY}"
response = requests.get(url)
code = response.status_code
if code == HTTPStatus.OK:
data = response.json()
return get_data_from_response(data)
else:
return None
def get_data_from_response(data):
status = data["status"]
if status == "ok":
articles = data["articles"][:5]
result = []
for article in articles:
news = {
"author": article["author"],
"title": article["title"],
"description": article["description"],
"url": article["url"],
}
result.append(news)
return result
else:
return None
Теперь нам нужно отправить этот запрос по команде от пользователя. Добавить ещё один CommandHandler.
app.add_handler(CommandHandler("get_top_headlines", get_top_headlines))
И соответствующий коллбэк для него:
async def get_top_headlines(update: Update, context: ContextTypes.DEFAULT_TYPE):
top_headlines = api.get_top_headlines()
if top_headlines is None:
return
message = ""
for headline in top_headlines:
title = headline["title"]
author = headline["author"]
description = headline["description"]
url = headline["url"]
message += f"{title}\n\n{author}\n{description}\n\nПодробнее: {url}\n\n-----------------\n\n"
await update.message.reply_text(message)
Попробуем отправить новую команду в чат и посмотрим результат.
Мы можем также прописать нашу команду в настройках бота в Telegram, чтобы иметь более удобный доступ к ней. Для этого нужно вернуться к BotFather и отправить команду /setcommands.
Вот так, используя минимум кода, мы написали небольшого новостного бота.
Заключение
Мы рассмотрели на примере, как можно быстро и легко написать Telegram бота, собирающего новости со сторонних сервисов.
В дальнейшем созданного бота можно либо держать запущенным на локальной машине, либо разместить на удалённом сервере. Существуют различные специализированные хостинги для ботов, как платные, так и бесплатные, обеспечивающие постоянную работу бота.
Telegram Bot API предоставляет довольно обширный функционал, благодаря чему можно найти ботам применение во множестве сфер и выполнять самые разные задачи. Низкий порог вхождения же облегчает их создание и позволяет писать ботов большому количеству разработчиков.