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

Telegram-бот на Python: от токена до продакшена

Чтобы создать Telegram-бота на Python, получите токен у @BotFather командой /newbot и отправляйте HTTPS-запросы к Bot API. Обновления приходят двумя способами: через getUpdates (long polling) или вебхук — но только одним из них одновременно. В продакшене защищайте вебхук параметром secret_token, соблюдайте лимиты и при ошибке 429 ждите retry_after секунд.

Обновлено:

Как устроен Telegram-бот?

Бот — специальный аккаунт Telegram, которым управляет ваша программа. Любое действие — обычный HTTPS-запрос вида https://api.telegram.org/bot<token>/ИМЯ_МЕТОДА. Когда пользователь пишет боту, Telegram сохраняет событие как update: вы забираете его через getUpdates, либо Telegram сам отправляет его POST-запросом на ваш вебхук. Ответ — ещё один запрос, например sendMessage.

Бот отличается от обычного пользователя: он не может первым начать диалог — человек должен сначала написать боту или добавить его в группу. В группах по умолчанию бот видит только адресованные ему сообщения (privacy mode, подробнее ниже).

Специальная библиотека для Python не обязательна: Bot API — это HTTP поверх JSON. Но готовый клиент берёт на себя маскировку токена, загрузку файлов (multipart), классификацию ошибок и повторные попытки. Примеры ниже написаны на клиенте Telegram асинхронного Python SDK Socialift (pip install socialift, Python 3.11+).

Создание бота в BotFather: 5 шагов

  1. Откройте @BotFather

    Найдите в Telegram официального бота @BotFather и отправьте команду /newbot.

  2. Задайте имя

    Имя (name) видно в карточке контакта, его можно поменять позже — например, «Помощник магазина».

  3. Выберите username

    Username — 5–32 символа: латиница, цифры и подчёркивание, в конце обязательно «bot» (например, shop_uz_bot). Изменить его потом нельзя — выбирайте внимательно.

  4. Сохраните токен

    BotFather выдаст токен вида 110201543:AAHdqTc... У кого токен — тот управляет ботом. Не храните его в коде: используйте переменную окружения TELEGRAM_BOT_TOKEN или хранилище секретов.

  5. Проверьте токен

    Если запрос getMe (в SDK — bot.get_me()) возвращает профиль бота, токен рабочий. При утечке выпустите новый командой /token в BotFather — старый перестанет работать.

Первый запрос: проверка токена и отправка сообщения

Токен не в коде — Telegram.from_env() читает его из TELEGRAM_BOT_TOKEN.

hello_bot.py
import asyncio
from socialift import Telegram

async def main():
    async with Telegram.from_env() as bot:
        me = await bot.get_me()
        print("Бот:", me["username"])

        # chat_id — числовой ID или @username для канала
        await bot.send_message("@my_channel", "<b>Привет!</b> Бот запущен.",
                               parse_mode="HTML")

asyncio.run(main())

Чтобы писать в канал, бот должен быть его администратором. В личный чат можно писать только пользователю, который уже нажал /start, — его числовой ID приходит в update.

Текст сообщения — 1–4096 символов, подпись к медиа (caption) — 0–1024 символа. Длинный текст разбивайте на несколько сообщений.

getUpdates или вебхук: что выбрать?

Способы взаимоисключающие: пока установлен вебхук, getUpdates не работает. Незабранные обновления хранятся на сервере Telegram не дольше 24 часов.

getUpdates или вебхук: что выбрать? — Таблица возможностей по платформам
КритерийgetUpdates (long polling)Вебхук
Как работаетПрограмма сама запрашивает Telegram и ждёт ответ до timeout секундTelegram отправляет каждый update POST-запросом на ваш HTTPS-адрес
Требования к серверуПубличный адрес не нужен — работает даже на ноутбукеПубличный HTTPS и валидный SSL-сертификат; редиректы не поддерживаются
ПортыНе важныТолько 443, 80, 88 или 8443
ПараллельностьОдин процесс читает очередьmax_connections 1–100, по умолчанию 40
Подтверждениеoffset = последний update_id + 1Ответ 2XX; иначе Telegram повторяет доставку
Когда удобноЛокальная разработка, небольшие ботыПродакшен, serverless, несколько ботов

Локальная разработка: цикл getUpdates

polling.py
from socialift import Telegram

async def run_polling():
    async with Telegram.from_env() as bot:
        await bot.delete_webhook()  # при активном вебхуке getUpdates не работает
        offset = None
        while True:
            updates = await bot.get_updates(offset=offset, timeout=25)
            for update in updates:
                offset = update["update_id"] + 1
                msg = update.get("message") or {}
                if msg.get("text") == "/start":
                    await bot.send_message(msg["chat"]["id"], "Добро пожаловать!")

Пересчитывайте offset после каждого ответа — иначе те же обновления придут снова. По умолчанию timeout в Telegram равен 0 (короткий опрос); в рабочем режиме задавайте положительное значение.

Защита вебхука через secret_token

Telegram не подписывает тело вебхука. Вместо этого secret_token, переданный в set_webhook, приходит в каждом запросе в заголовке X-Telegram-Bot-Api-Secret-Token — по нему вы отсекаете поддельные запросы.

webhook.py
import os
from aiohttp import web
from socialift import Telegram
from socialift.webhooks import verify_telegram_request

SECRET = os.environ["TG_WEBHOOK_SECRET"]  # 1–256 символов: A-Z, a-z, 0-9, _ и -

async def setup(bot: Telegram) -> None:
    await bot.set_webhook("https://example.com/tg/webhook", secret_token=SECRET,
                          allowed_updates=["message", "callback_query"])
    info = await bot.get_webhook_info()
    print(info["pending_update_count"], info.get("last_error_message"))

async def handle(request: web.Request) -> web.Response:
    if not verify_telegram_request(request.headers, SECRET):
        return web.Response(status=403)
    update = await request.json()
    await queue.put(update)  # тяжёлую работу — в очередь, ответ не задерживаем
    return web.Response(text="ok")

verify_telegram_request сравнивает заголовок за постоянное время. Секрет генерируйте через secrets.token_urlsafe(32) — он состоит только из разрешённых символов.

Если вебхук молчит, сначала смотрите last_error_message и pending_update_count в ответе get_webhook_info(). Telegram повторяет неудачную доставку, поэтому отбрасывайте дубли по update_id.

Фото, inline-кнопки и клавиатура-меню

keyboards.py
async def send_catalog(bot, chat_id: int) -> None:
    inline = {"inline_keyboard": [[
        {"text": "Каталог", "url": "https://example.com/catalog"},
        {"text": "Оформить заказ", "callback_data": "order:42"},
    ]]}
    await bot.send_photo(chat_id, "https://example.com/banner.jpg",
                         caption="Новая коллекция", reply_markup=inline)

    menu = {"keyboard": [[{"text": "Контакты"}, {"text": "Корзина"}]],
            "resize_keyboard": True}
    await bot.send_message(chat_id, "Выберите раздел:", reply_markup=menu)

async def on_callback(bot, query: dict) -> None:
    await bot.answer_callback_query(query["id"], text="Принято")

callback_data — 1–64 байта: кладите туда короткий ключ, а не весь объект. На нажатие кнопки обязательно вызывайте answer_callback_query, иначе пользователь будет видеть индикатор загрузки на кнопке.

Клавиатура-меню (ReplyKeyboardMarkup) не работает в каналах. Фото можно передать как file_id, HTTPS-ссылку или байты.

Лимиты на размер файлов и сообщений

Значения для официального сервера Bot API (api.telegram.org).

Лимиты на размер файлов и сообщений — Таблица возможностей по платформам
СитуацияЛимит
Текст сообщения1–4096 символов
Подпись к медиа (caption)0–1024 символа
Фото, загрузка multipart10 МБ; сумма ширины и высоты не больше 10000, соотношение сторон не больше 20
Другие файлы, загрузка multipart50 МБ
Отправка по HTTPS-ссылкефото 5 МБ, прочие файлы 20 МБ
Повторная отправка по file_idбез ограничений (file_id уникален для каждого бота)
Скачивание файла (getFile)20 МБ; ссылка действует минимум 1 час
Собственный локальный сервер Bot APIзагрузка до 2000 МБ, скачивание без ограничений

Почему бот не видит сообщения в группе (privacy mode)

Любой бот, добавленный в группу, по умолчанию работает в privacy mode. В этом режиме он получает только адресованные ему команды (/command@имя_бота), сообщения, отправленные через бота, и ответы на его сообщения. Служебные сообщения, сообщения из личных чатов и посты каналов, где бот состоит, приходят независимо от режима.

Если боту нужны все сообщения группы, есть два пути: сделать его администратором (боты-админы получают всё) или отключить режим командой /setprivacy в BotFather. После смены режима бота нужно удалить из группы и добавить заново — иначе изменение не вступит в силу.

Telegram рекомендует отключать режим только при реальной необходимости. Часто хватает принудительного ответа (force reply) на сообщение бота. Текущий режим бота виден всем в списке участников группы.

Лимиты массовой рассылки

Бесплатные лимиты из Bot FAQ. При превышении Telegram возвращает HTTP 429 и parameters.retry_after в ответе.

Лимиты массовой рассылки — Таблица возможностей по платформам
КудаЛимит
В один чатрекомендуется не больше 1 сообщения в секунду; короткие всплески допускаются
В группуне больше 20 сообщений в минуту
Массовые уведомления разным пользователямоколо 30 сообщений в секунду
С платными рассылкамидо 1000 сообщений в секунду; каждое сообщение сверх 30 в секунду — 0,1 Stars
Примечания и ограничения

Чтобы включить платные рассылки в BotFather, на балансе бота должно быть не меньше 100 000 Stars и не меньше 100 000 активных пользователей в месяц. Без них Telegram советует растягивать рассылку на более длинный интервал, например 8–12 часов.

Правильная обработка ошибки 429

broadcast.py
import asyncio
import socialift

async def broadcast(bot, chat_ids: list[int], text: str) -> None:
    for chat_id in chat_ids:
        try:
            await bot.send_message(chat_id, text)
        except socialift.RateLimitError as exc:
            await asyncio.sleep(exc.retry_after or 5)
            await bot.send_message(chat_id, text)
        except socialift.PermissionError:
            mark_inactive(chat_id)  # пользователь заблокировал бота (403)
        await asyncio.sleep(0.05)  # ~20 сообщений/с — ниже порога в 30/с

SDK превращает ответ 429 в RateLimitError и сам повторяет запрос по стандартной RetryPolicy (3 попытки); если попытки исчерпаны, ошибка поднимается к вам. Если retry_after нет, делайте резервную паузу.

Ошибка 403 (например, пользователь заблокировал бота) повтором не лечится — исключайте такой чат из рассылки.

Перед выходом в продакшен

  • Токен в переменной окружения или хранилище секретов; в логах его нет.
  • Вебхук на HTTPS, с secret_token, заголовок проверяется в каждом запросе.
  • В allowed_updates только нужные типы (например, message и callback_query).
  • Повторные update отбрасываются по update_id.
  • Ответ вебхуку уходит быстро, тяжёлая обработка — в очереди.
  • Ошибки 429 и 403 обрабатываются отдельно, рассылка идёт медленнее 30 сообщений в секунду.
  • Для сценариев в группах настроен privacy mode или права администратора.

← Назад в блог

Частые вопросы

Создать Telegram-бота — это платно?

Нет. Создание бота в BotFather и использование Bot API бесплатны. Платить приходится только за опциональные функции, например за платные рассылки быстрее 30 сообщений в секунду — они оплачиваются Telegram Stars.

Может ли бот написать пользователю первым?

Нет. По правилам Telegram пользователь должен сначала написать боту или добавить его в группу. Поэтому распространяйте ссылку t.me/имя_бота через сайт, рекламу или QR-код и сохраняйте chat ID после /start.

Что делать, если токен бота утёк?

Выпустите новый токен командой /token в BotFather — старый перестанет работать. Затем обновите переменную окружения на сервере и переустановите вебхук. Никогда не кладите токен в git или во фронтенд-код.

Вебхук установлен, но обновления не приходят. Что проверить?

Сначала прочитайте last_error_message в ответе getWebhookInfo. Затем проверьте, что порт — 443, 80, 88 или 8443, SSL-сертификат валиден, а адрес не делает редирект. И помните: пока вебхук активен, getUpdates не работает.

Как боту читать все сообщения в группе?

Сделайте бота администратором группы или отключите privacy mode командой /setprivacy в BotFather и добавьте бота в группу заново. Сообщения других ботов он всё равно не получит, а метода для чтения истории чата в Bot API нет — бот видит только новые обновления.

Какая библиотека нужна для Telegram-бота на Python?

Bot API — это HTTPS и JSON, поэтому подойдёт любой HTTP-клиент. Готовый клиент решает загрузку файлов, разбор ошибок и повторы: в SDK Socialift это асинхронный клиент Telegram, а для методов без отдельной обёртки есть bot.call("имяМетода").

Источники

  1. Telegram Bot API
  2. Telegram Bot Features: BotFather и privacy mode
  3. Telegram Bots FAQ: лимиты и вебхуки
  4. Telegram Bots: чем боты отличаются от пользователей

Связанные страницы