Перейти к основному содержимому

pyTelegramBot — боты в Telegram

Разработчику

pyTelegramBotAPI устанавливается как pip install pytelegrambotapi, в коде чаще пишут import telebot. Библиотека обращается к Telegram Bot API: бот — это программа на вашем компьютере или сервере, которая получает обновления (сообщения, команды, нажатия кнопок) и отправляет ответы.

Telegram-бот — быстрый способ дать пользователю интерфейс без веб-сайта. Типичные сценарии:

  • опросы и викторины;
  • напоминания;
  • FAQ;
  • уведомления об ошибках;
  • мини-игры.
ТерминСмысл
TokenСекретный ключ доступа к API (выдаёт @BotFather)
UpdateСобытие от Telegram (сообщение, callback кнопки и т.д.)
Long pollingБот сам периодически запрашивает новые обновления
WebhookTelegram отправляет обновления POST-запросом на ваш HTTPS-URL

Путеводитель: Инструменты и среды. HTTP в Python: requests, файлы и JSON: Работа с файлами, сетью и внешними API.


Подготовка окружения

  1. В Telegram откройте @BotFather.
  2. Команда /newbot → имя и username (должен оканчиваться на bot).
  3. Сохраните токен. Это пароль бота — не публикуйте его в репозитории.

Виртуальное окружение изолирует зависимости проекта:

python -m venv bot_env
# Windows
bot_env\Scripts\activate
# Linux / macOS
source bot_env/bin/activate
pip install pytelegrambotapi

Токен храните в переменной окружения:

# Windows PowerShell
$env:BOT_TOKEN="123456:ABC..."

# Linux / macOS
export BOT_TOKEN="123456:ABC..."
Утечка токена

При попадании токена в git выполните /revoke в BotFather, создайте новый токен и добавьте .env в .gitignore.

Проверка: напишите боту /start в Telegram после первого запуска скрипта.


Минимальный бот

Код ITЗагрузка примера кода…

  • TeleBot(...) создаёт экземпляр бота.
  • @bot.message_handler(...) связывает тип сообщения с функцией-обработчиком.
  • infinity_polling() держит процесс активным и забирает обновления с серверов Telegram.

Запуск: python bot.py.


Команды, меню и текстовые фразы

Обработчики

ДекораторСрабатывает когда
@bot.message_handler(commands=["ping"])Сообщение /ping
@bot.message_handler(content_types=["photo"])Фото
@bot.message_handler(func=lambda m: m.text and "привет" in m.text.lower())Свой фильтр

Объект message содержит chat.id, from_user, text, document и др. — см. типы Bot API.

Меню команд в клиенте Telegram

Список команд в меню бота (кнопка "/" у поля ввода) задаётся через Bot API:

from telebot import types

bot.set_my_commands([
types.BotCommand("start", "Запуск"),
types.BotCommand("help", "Справка"),
types.BotCommand("menu", "Главное меню"),
])

Вызовите set_my_commands один раз при старте (в if __name__ == "__main__" перед polling).

Реакция на ключевые слова

Текст без слэша обрабатывается отдельным handler или веткой внутри общего:

@bot.message_handler(func=lambda m: m.text and m.text.lower() in ("привет", "здравствуйте"))
def greet(message):
bot.reply_to(message, "Привет! Команды: /help")

Порядок регистрации handlers важен: узкие фильтры регистрируйте раньше общего func=lambda m: True.


Клавиатуры

Reply-клавиатура (кнопки под полем ввода)

from telebot import types

@bot.message_handler(commands=["menu"])
def menu(message):
kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
kb.add("Игра", "О боте", "Помощь")
bot.send_message(message.chat.id, "Выберите пункт:", reply_markup=kb)

@bot.message_handler(func=lambda m: m.text == "Помощь")
def help_btn(message):
bot.send_message(message.chat.id, "Команды: /start, /menu")

Нажатие кнопки приходит в бот как обычное текстовое сообщение с подписью кнопки — для него нужен свой message_handler.

Inline-кнопки (под сообщением)

Кнопка со ссылкой:

markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton("Сайт", url="https://example.com"))
bot.send_message(message.chat.id, "Ссылки:", reply_markup=markup)

Кнопки с callback (викторина, "Да/Нет") — в чат текст не уходит, приходит CallbackQuery:

Код ITЗагрузка примера кода…

  • callback_data — короткая строка (до 64 байт), по ней различают нажатия.
  • edit_message_text меняет текст исходного сообщения вместо нового.
  • answer_callback_query обязателен, иначе клиент долго показывает индикатор загрузки.

Медиа

Бот может отправлять не только текст:

# Фото с диска
with open("meme.jpg", "rb") as photo:
bot.send_photo(message.chat.id, photo, caption="Мем дня")

# Фото по URL (если Telegram может его скачать)
bot.send_photo(message.chat.id, "https://example.com/image.jpg")

# Документ, голос, стикер
bot.send_document(message.chat.id, open("manual.pdf", "rb"))
bot.send_voice(message.chat.id, open("hint.ogg", "rb"))

Приём медиа от пользователя — через content_types:

@bot.message_handler(content_types=["photo"])
def on_photo(message):
file_id = message.photo[-1].file_id # наибольшее разрешение
bot.reply_to(message, f"Получил фото, file_id={file_id}")

Лимиты и форматы — в документации Bot API.


Пошаговый диалог (состояния)

Состояние — этап сценария — бот ждёт имя, потом возраст, потом подтверждение. В telebot для коротких анкет удобен register_next_step_handler:

Код ITЗагрузка примера кода…

Для длинных сценариев и продакшена чаще берут словарь состояний по user_id, Redis или БД. В python-telegram-bot тот же смысл даёт ConversationHandler — пример в лаборатории / Примеры / 122.


Хранение данных

В памяти процесса

SCORES: dict[int, int] = {} # user_id → очки

@bot.message_handler(commands=["score"])
def show_score(message):
points = SCORES.get(message.from_user.id, 0)
bot.reply_to(message, f"Ваш счёт: {points}")

Подходит для демо. После перезапуска скрипта данные пропадают.

JSON-файл


import json

from pathlib import Path

DB_PATH = Path("scores.json")

def load_scores() -> dict:
if not DB_PATH.exists():
return {}
return json.loads(DB_PATH.read_text(encoding="utf-8"))

def save_scores(data: dict) -> None:
DB_PATH.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")

Ключи в JSON для user_id лучше хранить строками: str(user_id).

SQLite

Для десятков и сотен пользователей надёжнее встроенная SQLite:

Код ITЗагрузка примера кода…

Подробнее про слой доступа к данным — Работа с базами данных в Python и кейс Telegram Bot MVP (шаг с storage/sqlite.py).


Внешние API

Бот часто показывает данные с другого сервиса — погода, курс, случайная цитата:


import requests

@bot.message_handler(commands=["quote"])
def random_quote(message):
try:
r = requests.get("https://api.quotable.io/random", timeout=10)
r.raise_for_status()
data = r.json()
text = f"«{data['content']}» — {data['author']}"
except requests.RequestException:
text = "Сервис временно недоступен. Попробуйте позже."
bot.reply_to(message, text)

Правила:

  • всегда задавайте timeout;
  • оборачивайте сетевой вызов в try/except и сообщайте пользователю понятный текст;
  • ключи внешних API (OpenWeatherMap и т.д.) — только в переменных окружения.

Теория HTTP и контрактов API — интеграционное взаимодействие.


Ошибки и логирование

Без логов бот "молча" падает при обрыве сети или неверном токене:


import logging

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)

@bot.message_handler(commands=["start"])
def start(message):
logger.info("user %s started", message.from_user.id)
bot.reply_to(message, "Привет!")

Оборачивайте рискованные места (файлы, HTTP, БД) в try/except, логируйте исключение и отправляйте пользователю короткое сообщение вместо трассировки.


Напоминания и отложенные сообщения

В python-telegram-bot есть встроенный job_queue. В telebot для учебных задач достаточно threading.Timer или библиотеки schedule:


import threading

def remind(chat_id: int, text: str, delay_sec: int) -> None:
def job():
bot.send_message(chat_id, text)
threading.Timer(delay_sec, job).start()

@bot.message_handler(commands=["remind"])
def cmd_remind(message):
remind(message.chat.id, "Напоминание сработало!", 10)
bot.reply_to(message, "Через 10 секунд пришлю сообщение.")

Ограничение Telegram: бот не может первым написать пользователю, который ещё не нажал /start в этом чате. Массовая "рассылка всем" без согласия нарушает правила платформы.

Ежедневные задачи (цитата в 9:00) на сервере удобнее вешать на cron или планировщик ОС, который вызывает отдельный скрипт с send_message.


Long polling и webhook

Учебные боты обычно используют infinity_polling() — библиотека сама опрашивает getUpdates.

РежимКогда уместен
PollingЛокальная разработка, демо, небольшая нагрузка
WebhookПродакшен, низкая задержка, стабильная нагрузка, есть HTTPS

Для webhook нужен публичный HTTPS-URL и настройка на стороне Bot API. Пошагово — в Примеры / 122 и кейсе MVP.

Пока скрипт не запущен (или сервер выключен), бот не отвечает — процесс должен работать постоянно или перезапускаться (systemd, Docker, PaaS).


Выбор библиотеки

БиблиотекаСтильКому подходит
pyTelegramBot (telebot)Синхронный, декораторыПервый бот, кружок, простые сценарии
python-telegram-bot (PTB v20+)async/await, ApplicationУчебные курсы, структурированные проекты, ConversationHandler
aiogramasync/await, FSMПродвинутые async-боты, высокая нагрузка

Один и тот же Bot API — меняется только обёртка на Python. Уведомления без входящих команд (мониторинг) — в Веб-разработка и REST API на Python.


Деплой учебного бота

ВариантПлюсыМинусы
Локальный ПКБесплатно, просто отладкаБот офлайн, когда компьютер выключен
VPS (минимальный сервер)Полный контроль, systemdНужна базовая админка
PaaS (Replit, PythonAnywhere и аналоги)Быстрый стартЛимиты бесплатного тарифа

Минимум на сервере:

  1. скопировать проект и .env с BOT_TOKEN;
  2. python -m venv .venv && pip install -r requirements.txt;
  3. запуск через systemd или Docker, чтобы процесс поднимался после сбоя;
  4. для webhook — reverse proxy (Nginx, Caddy) с TLS — пример конфига nginx.

Продакшен-чеклист (Docker, webhook, тесты handlers) — Примеры решений для Python бота.


Безопасность и ограничения

  • Токен = полный доступ к боту; при утечке — /revoke в BotFather.
  • Бот в группе по умолчанию видит не все сообщения (режим Privacy в BotFather).
  • Лимиты отправки — порядка 30 сообщений/сек в один чат; при превышении API вернёт RetryAfter.
  • Соблюдайте FAQ Telegram для ботов.

Админ-команды защищайте списком разрешённых user_id, а не "секретной" командой в тексте помощи.


Частые ошибки новичков

  1. Токен в коде и в истории git.
  2. Нет try/except на сеть и файлы — процесс завершается.
  3. Общий fallback перехватывает команды, зарегистрированные позже.
  4. Состояние диалога только в RAM — после рестарта пользователь "застревает" в сценарии.
  5. Inline-кнопки без answer_callback_query.

Как масштабировать учебного бота

Идеи финальных проектов — викторина с очками, "угадай число", бот-расписание, мем по кнопке, FAQ с inline-меню.


См. также


Основа по протоколу

Базовый разбор HTTP и HTTPS — HTTP как основа веб-интеграций.