Создаём Telegram-бота на Python с помощью pyTelegramBotAPI (telebot)

Создаём Telegram-бота на Python с помощью pyTelegramBotAPI (telebot)

Сегодня будем учиться создавать ботов в Telegram с помощью Python. 
Попробуем заставить бота присылать сводку погоды по нашему городу.

Нам потребуется:

  1. Компьютер или ноутбук (При должном усердии можно попробовать на телефоне).
  2. Python 3 (Мы будем работать на версии 3.10).
  3. Редактор кода (Я использую PyCharm).
  4. Соединение с интернетом.

У всех на слуху две библиотеки для разработки telegram-ботов, это: 
- telebot (он же pyTelegramBotAPI),
- aiogram. 

Мы будем использовать telebot как более простой инструмент для личного пользования. Посмотрим как запустить первого бота, что для этого нужно и на что он способен.

Как и aiogram, telebot является адаптацией API telegram для взаимодействия с ответами от сайта. Со справкой API telegram можно ознакомиться тут https://core.telegram.org/. Там же вы сможете узнать подробнее об ответах API.

Как создать telegram-бота на Python: краткий план

Перед погружением в код разложу как создать telegram-бота с нуля. Весь процесс состоит из 6 шагов:

  1. Получить токен через BotFather в Telegram. Без него ничего работать не будет.
  2. Установить библиотеку pyTelegramBotAPI через pip - это и есть telebot.
  3. Написать обработчик команды /start - базовая точка входа.
  4. Подключить API какого-нибудь сервиса - например, погоду или CRM.
  5. Настроить меню команд через BotFather для удобства пользователей.
  6. Запустить бота локально или задеплоить на сервер для постоянной работы.

Дальше пройдёмся по каждому шагу с кодом. Если вы хотите создать telegram-бота для простой задачи (отправка уведомлений, ответы по шаблону) - хватит первых трёх шагов. Если нужен полноценный сервис - пройдём весь путь до деплоя.

Получение токена для Telegram-бота

Чтобы создать нашего первого бота на Python надо обратиться к официальному боту от Telegram - BotFather. Там можно создать бота и получить его токен. Токен – это аналог пароля, который позволит нам управлять ботом изнутри и программировать его ответы.

Переходим в BotFather - https://t.me/BotFather и нажимаем «Запустить»:

Дальше выбираем команду /newbot и следуем всем указанием, и в конце мы получаем токен нашего бота:

Установка библиотеки telebot и знакомство с pyTelegramBotAPI

После получения токена нужно скачать библиотеку telebot:

pip install pyTelegramBotAPI 

если вы на macOS, то:

pip3 install pyTelegramBotAPI

Мы не будем раскладывать проект по модулям, поэтому у нас будет один исполнимый файл main.py. После создания файла надо импортировать библиотеку и наш токен:

import telebot
api_token = 'Ваш токен вставлять сюда'

Первым делом следует инициализировать бота, передав в него токен, полученный от BotFather:

bot = telebot.TeleBot(api_token)

Дальше убедимся, что все корректно работает и заставим отправлять полученное сообщение обратно:

@bot.message_handler(content_types=['text'])
def echo(message):
    bot.send_message(message.chat.id, text=f"{message.text}")

Бот работает за cчёт декораторов, которые указывают, что мы хотим от него. Message handler – это обработчик всех сообщений, которые отправляет пользователь. В списке content_types перечисляем типы сообщений, которые хотим принимать. Можно указать text, audio, image и document. 

У объекта bot есть множество методов, частью которых мы будем пользоваться. Основной из них - send message.

Чтобы заставить бота принимать сообщение, в конце файла пропишем:

bot.polling(none_stop=True)

Параметр none_stop указывает, что мы хотим принимать сообщения постоянно. 
В стандартном положении параметр равен False, но мы ставим True.

После всех манипуляций получаем свое же сообщение:

Работа с API Яндекс Погоды

Перейдем к добавлению нужных функций - получению данных о погоде. 

Для погоды мы будем пользоваться услугами бесплатного API от Яндекс Погоды: 
https://yandex.ru/dev/weather/. Следует отметить, что бесплатный API от Яндекса ограничен 50 запросам в сутки. Если вас такое количество не устраивает, можно воспользоваться OpenWeather. 

Запрос будет выглядеть так:

https://api.weather.yandex.ru/v2/informers?lat=55.75222&lon=37.61556

Запрос состоит из местоположения - в данном случае указаны координаты Москвы. Далее можно просить у пользователя геолокацию и присылать ему погоду по его координатам.

Для отправки GET-запроса к API Яндекс.Погоды нам поможет библиотека requests, а для обработки ответа - библиотека json. 

Устанавливаем requests:

pip install requests

для macOS:

pip3 install requests 

Библиотека requests предназначена для работы с GET и POST запросами, которые обычный пользователь делает через браузер. Теперь же мы можем общаться с сервером через python оставляя браузер за скобками. Часто используют requests вместе с BS4 (beautiful soup 4), чтобы удобно получать и анализировать информацию из html кода. Но в наш случае другая задача.

[TGBLOCK]

API Яндекс.Погоды отдаёт данные в формате JSON, поэтому библиотека json подойдёт лучше всего. JSON основан на JavaScript объекте и часто используется при обмене данными. Раньше он использовался только на сайтаx для работы с текстовыми данными. Сейчас его используют почти везде для удобного обмена данными. JSON принимают все языки программирования, что является его большим плюсом. В python библиотека json уже установлена и не требует отдельной команды.

Добавляем импорт нужных библиотек:

import requests
import json

До этого мы не затрагивали тему, как именно обрабатывать команды через слеш. Для этого у декоратора есть метод message_handlers, внутрь которого мы передаем название команд:

@bot.message_handler(commands=['get_weather', 'weather', 'pogoda']):
def get_weather(message):
    pass

Для удобства выносим токен Яндекс.Погоды и ссылку в отдельные переменные:

url = "https://api.weather.yandex.ru/v2/informers?lat=55.75222&lon=37.61556"
headers = {"X-Yandex-API-Key": "weather token"}

Отправим себе в Telegram полный ответ от API Яндекс.Погоды и проверим что все работает:

@bot.message_handler(commands=['get_weather', 'weather', 'pogoda'])
def get_weather(message):
    r = requests.get(url=url, headers=headers)
    bot.send_message(message.chat.id, r.text)

После получения ответа сформируем нормальный ответ для пользователя. Сразу сделаем проверку на status_code, чтобы оповестить пользователя, если проблемы на стороне API. После получения ответа от API в текстовом формате, надо перевести его в словарь. Для этого подключаем библиотеку json - в функцию loads мы передаем текст ответа, а на выходе получаем объект типа dict (словарь):

@bot.message_handler(commands=['get_weather', 'weather', 'pogoda'])
def get_weather(message):
    r = requests.get(url=url, headers=headers)
    bot.send_message(message.chat.id, r.text)
    if r.status_code == 200:
        data = json.loads(r.text)
        fact = data["fact"]
        bot.send_message(message.chat.id, text=f'Now in Moscow {fact["temp"]}°, feels like {fact["feels_like"]}°. Now on the street {fact["condition"]}')
    else:
        bot.send_message(message.chat.id, 'Problems on weather API')

Теперь бот отправляет температуру, как она ощущается и какая сейчас погода:

Настройка команд для telegram-бота

Нам осталось сделать реакцию на команду /start. Она будет выводить команду для получения данных о погоде:

@bot.message_handler(commands=['start'])
def get_weather(message):
	bot.send_message(message.chat.id, text=f'Hello,	
	{message.from_user.username}!
	\n\nI can show you the weather with: 
	\n/weather\n/pogoda\n/get_weather')

Мы обращаемся к информации, которая приходит нам в сообщении пользователя, чтобы получить из нее имя пользователя. Подробнее узнать о сообщениях пользователей можно тут https://core.telegram.org/constructor/message.

Теперь создадим подсказки для пользователей. Библиотека pyTElegramBotAPI не позволяет из кода редактировать подсказки для написания команды. Чтобы это сделать нам потребуется несколько операций в BotFather: 

  1. кликаем на меню
  2. выбираем команду /mybots
  3. ищем нашего бота
  4. edit bot
  5. и выбираем edit commands
  6. дальше вводим нашу команду (Пример: команда – описание)

  После всех манипуляций у нас появится всплывающая менюшка с командами:

Финальный код Telegram-бота на Python

Мы с вами затронули лишь малу часть того, что можно сделать с помощью python и Telegram. Telebot - не самая лучшая библиотека для создания ботов под большую аудитории. Если вы хотите писать бот для магазинов, вам потребуется более сильные инструменты разработки, которые есть в aiogram. 

Если вам хочется потренироваться самостоятельно - попробуйте написать бота со следующими функциями: конвертор валюты, сводка по курсу валюты.

Весь код из урока:

import telebot
import requests
import json

api_token = '5347819163:********lZu1qWQc5f55DPk'

url = "https://api.weather.yandex.ru/v2/informers?lat=55.75222&lon=37.61556"
headers = {"X-Yandex-API-Key": "43e3e725-*******-0750c87d0d54"}

bot = telebot.TeleBot(api_token)

@bot.message_handler(commands=['start'])
def get_weather(message):
    bot.send_message(message.chat.id, text=f'Hello, 
    {message.from_user.username}!
    \n\nI can show you the weather with: 
    \n/weather\n/pogoda\n/get_weather')

@bot.message_handler(commands=['get_weather', 'weather', 'pogoda'])
def get_weather(message):
    r = requests.get(url=url, headers=headers)
    bot.send_message(message.chat.id, r.text)
    if r.status_code == 200:
        data = json.loads(r.text)
        fact = data["fact"]
        bot.send_message(message.chat.id, text=f'Now in Moscow {fact["temp"]}°, feels like {fact["feels_like"]}°. Now on the street {fact["condition"]}')
    else:
        bot.send_message(message.chat.id, 'Problems on weather API')

bot.polling(none_stop=True)

Inline-кнопки и callback_query в telebot

Обычные команды через слэш /start - это базовый уровень. Гораздо круче когда у пользователя есть кнопки прямо под сообщением. Это inline-кнопки, и в telebot они делаются буквально в 10 строк:

from telebot import types

@bot.message_handler(commands=['menu'])
def show_menu(message):
    keyboard = types.InlineKeyboardMarkup()
    btn1 = types.InlineKeyboardButton('Погода', callback_data='weather')
    btn2 = types.InlineKeyboardButton('Курс валют', callback_data='currency')
    keyboard.add(btn1, btn2)
    bot.send_message(message.chat.id, 'Выбери действие:', reply_markup=keyboard)

@bot.callback_query_handler(func=lambda call: True)
def handle_callback(call):
    if call.data == 'weather':
        bot.send_message(call.message.chat.id, 'Сегодня солнечно')
    elif call.data == 'currency':
        bot.send_message(call.message.chat.id, 'USD: 95 руб')
    bot.answer_callback_query(call.id)

Что тут важно: callback_data - это идентификатор нажатой кнопки, по нему вы определяете что делать. bot.answer_callback_query обязательно вызывайте в конце - иначе у пользователя будет крутиться индикатор загрузки.

Помимо inline-кнопок в telebot есть и обычные кнопки клавиатуры через types.ReplyKeyboardMarkup. Они появляются в нижней части экрана как замена обычной клавиатуры. Удобно для простых меню типа 'Да / Нет' или выбора из списка.

Деплой telegram-бота на сервер: systemd и Docker

Бот написан, работает локально - что дальше? Если не задеплоить на сервер, бот будет жить только пока у вас включён компьютер. Два рабочих варианта:

Вариант 1: systemd на VPS. Самый простой и надёжный путь. Покупаете VPS за 200-300 рублей в месяц (Hostland, Reg.ru, Selectel, Beget), кидаете туда питон-скрипт с telebot, создаёте systemd-юнит и забываете о боте.

[Unit]
Description=Telegram Bot on telebot
After=network.target

[Service]
WorkingDirectory=/opt/mybot
ExecStart=/usr/bin/python3 /opt/mybot/bot.py
Restart=always
User=botuser

[Install]
WantedBy=multi-user.target

Сохраните как /etc/systemd/system/telebot.service, запустите systemctl enable --now telebot - и всё. Бот сам перезапускается при падении и при перезагрузке сервера.

Вариант 2: Docker. Удобно если у вас несколько ботов или нужна изоляция. Dockerfile из 5 строк:

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY bot.py .
CMD ["python", "bot.py"]

Собираете docker build -t mybot ., запускаете docker run -d --restart=always mybot - и telegram-бот работает в изолированном контейнере.

Что НЕ стоит делать: запускать python bot.py в screen или nohup и надеяться на лучшее. Бот упадёт через неделю и вы об этом узнаете последним. Systemd с Restart=always - минимум для прода.

Типичные ошибки при создании telegram-бота на telebot

Вот что чаще всего ломает работу telegram-бота на Python:

  1. Токен закоммитили в Git. Классика. BotFather сразу его деактивирует если палится в публичном репозитории. Храните токен в переменных окружения или в .env файле и добавьте .env в .gitignore.
  2. Бот молчит при bot.polling(). Скорее всего токен невалидный или есть второй экземпляр бота который перехватывает обновления. Telegram отдаёт апдейты только одному получателю.
  3. Бот падает на каждом сообщении. Не оборачиваете обработчики в try/except - любой неожиданный апдейт убивает поток. Минимум try: ... except Exception as e: print(e) в каждом обработчике.
  4. Длинные операции блокируют бота. Если в обработчике делаете запрос к медленному API, бот замораживается. Решение - либо bot.infinity_polling(num_threads=4) для многопоточности, либо использовать асинхронную версию pytelegrambotapi (AsyncTeleBot).
  5. Слишком много сообщений в минуту. Telegram ограничивает: 30 сообщений в секунду на чат, 20 одинаковых в минуту в группу. Если массово рассылаете - делайте задержку или используйте broadcast-сервис.
  6. Не используется webhook для нагруженных ботов. Polling каждые несколько секунд тратит ресурсы. Если бот популярный, переключайтесь на webhook через flask или FastAPI - бот реагирует мгновенно и потребляет меньше CPU.

FAQ: pyTelegramBotAPI и telebot

В чём разница между pyTelegramBotAPI и telebot?

Это одно и то же. pyTelegramBotAPI - официальное название библиотеки, а telebot - это имя модуля в коде (import telebot). На pip установка идёт через pip install pyTelegramBotAPI, а в Python обращаетесь как telebot. Просто наследие истории проекта.

Можно ли создать telegram-бота без программирования?

Да - через no-code конструкторы типа BotMother, Salebot, ManyChat. Но для гибкости и контроля проще написать своего бота на Python с telebot - это не сложнее чем настроить конструктор, а возможностей в разы больше.

telebot или aiogram - что выбрать?

telebot (pyTelegramBotAPI) проще и подходит для большинства задач - синхронный код, понятный API, минимум магии. aiogram асинхронный, быстрее, но порог входа выше из-за async/await. Если делаете первого бота - берите telebot. Если бот будет обслуживать тысячи пользователей одновременно - aiogram.

Сколько стоит запустить telegram-бота?

Сам Telegram Bot API бесплатный. Затраты только на хостинг: VPS от 200 руб/мес, или вообще бесплатно если деплоить на Railway / Fly.io в рамках бесплатного лимита. Маленькому боту хватит самого дешёвого VPS.

Как защитить telegram-бота от спама?

Несколько подходов: ограничение по chat_id (только конкретные пользователи), rate-limit на количество сообщений в минуту, защита через captcha при первом старте. В telebot легко сделать middleware через декоратор - проверять каждое сообщение перед обработкой.

Полезные ссылки:

Yandex Weather: https://yandex.ru/dev/weather/

Документация Yandex API: https://yandex.ru/dev/weather/doc/dg/concepts/forecast-info.html

pyTealegramBotAPI на Guthub: https://github.com/eternnoir/pyTelegramBotAPI