Небольшим офлайн- и онлайн-бизнесам всё чаще нужен простой канал связи с клиентами: записать на услугу, принять заявку, ответить на типовые вопросы, не написав при этом собственный «личный кабинет» с авторизацией и фронтендом. Telegram-боты хорошо ложатся в этот сценарий: они доступны с телефона, поддерживают кнопки, формы, платежи и работают поверх знакомого интерфейса мессенджера.
В этой статье разбирается, как с нуля собрать минимально полезного бота для малого бизнеса (например, магазина одежды или студии услуг) на Python и библиотеке aiogram 3.x: от получения токена до развёртывания на сервере. Статья рассчитана на разработчиков, которые уже базово знакомы с Python, но ещё не работали с Telegram Bot API или современными фреймворками для ботов.
Что будет уметь бот
Рассматривается небольшой, но жизненный функционал, вокруг которого можно потом наращивать более сложные сценарии.
Бот будет:
Показывать приветствие и короткое меню по команде
/start.Давать пользователю быстрые кнопки с типичными действиями: «Каталог», «Оформить заявку», «Связаться с менеджером».
Принимать простую заявку (имя, контакт, выбранная позиция) и отправлять её менеджеру в отдельный служебный чат.
Логировать базовые события, чтобы потом понимать, как люди пользуются ботом.
Такой функционал уже закрывает типовую потребность малого бизнеса в «цифровом ресепшене» без разработки полноценного веб-приложения.
Технологический стек
Для реализации подойдёт минимальный набор инструментов, которые легко повторить на любой машине разработчика.
Понадобится:
Python версии не ниже 3.10 (большинство современных гайдов по aiogram опираются именно на эти версии).
Библиотека aiogram 3.x — асинхронный фреймворк, упрощающий работу с Telegram Bot API.
Любой текстовый редактор или IDE (VS Code, PyCharm, Vim — на усмотрение разработчика).
Учётная запись Telegram и доступ к боту BotFather для регистрации собственного бота.
Для продакшн-развёртывания — виртуальный или физический сервер с установленным Python и возможностью запустить длительный процесс (VPS у любого хостера, своё железо и т.п.).
Дополнительно можно использовать Redis или любую СУБД для хранения заявок и состояний, но в базовом примере демонстрируется простой файловый или «памятный» подход, чтобы не перегружать первый запуск.
Шаг 1. Регистрируем бота через BotFather
Telegram предоставляет отдельный служебный бот BotFather, через которого создаются и настраиваются все остальные боты.
Минимальный путь выглядит так:
В поиске Telegram найти пользователя
@BotFatherи открыть с ним диалог.Нажать кнопку
/startили ввести эту команду вручную.Выбрать команду
/newbotи следовать подсказкам: указать название (видимое пользователям) и уникальное имя, оканчивающееся наbot.В ответ BotFather пришлёт HTTP API token — строку вида
1234567890:AA..., которая используется для авторизации бота на стороне Telegram.Сохранить токен в безопасном месте и не публиковать его в репозиториях и скриншотах.
Дальше этот токен будет использоваться в конфигурации Python-приложения через переменные окружения или отдельный конфигурационный файл, который не попадает в систему контроля версий.
Шаг 2. Структурируем проект на Python
На небольших проектах соблазнительно писать всё в одном файле bot.py, но даже для простого бота лучше с самого начала отделить конфигурацию, обработчики и запуск.
Пример минимальной структуры:
project_root/
├─ bot/
│ ├─ __init__.py
│ ├─ config.py
│ ├─ handlers/
│ │ ├─ __init__.py
│ │ ├─ common.py
│ │ └─ orders.py
│ └─ main.py
├─ .env
├─ requirements.txt
└─ README.md
Такой разбор по каталогам позволяет со временем добавлять новые сценарии, не превращая код в неуправляемый монолит.
Установка зависимостей
В файле requirements.txt можно указать минимум:
aiogram>=3.0.0
python-dotenv>=1.0.0
Установка через pip стандартна:
pip install -r requirements.txt
Библиотека python-dotenv используется для загрузки конфигурации (например, токена бота) из файла .env, что удобно для локальной разработки.
Конфигурация бота
Файл .env (его не стоит коммитить в репозиторий) может выглядеть так:
BOT_TOKEN=1234567890:AA... # ваш токен от BotFather
ADMIN_CHAT_ID=123456789 # ID чата или пользователя, куда слать заявки
Пример кода для загрузки этих значений в модуле config.py:
from dataclasses import dataclass
import os
from dotenv import load_dotenv
load_dotenv()
@dataclass
class Settings:
bot_token: str
admin_chat_id: int
def get_settings() -> Settings:
return Settings(
bot_token=os.environ["BOT_TOKEN"],
admin_chat_id=int(os.environ["ADMIN_CHAT_ID"]),
)
settings = get_settings()
Использование dataclass делает конфигурацию типобезопасной и удобной для дальнейшей передачи в различные части приложения.
Шаг 3. Поднимаем базовый echo-бот на aiogram 3.x
Начальная цель — убедиться, что бот вообще отвечает и корректно подключён к Telegram Bot API.
Минимальный main.py может выглядеть так:
import asyncio
import logging
import sys
from aiogram import Bot, Dispatcher, F
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.filters import CommandStart
from aiogram.types import Message
from bot.config import settings
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
dp = Dispatcher()
@dp.message(CommandStart())
async def cmd_start(message: Message) -> None:
await message.answer(
"Привет! Это бот малого бизнеса.\n"
"Используйте меню ниже, чтобы посмотреть каталог или оставить заявку."
)
@dp.message(F.text)
async def echo(message: Message) -> None:
await message.answer(f"Вы написали: {message.text}")
async def main() -> None:
bot = Bot(
token=settings.bot_token,
default=DefaultBotProperties(parse_mode=ParseMode.HTML),
)
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
Этот код создаёт диспетчер, регистрирует обработчик команды /start и простейший echo-обработчик всех текстовых сообщений. После запуска скрипта и отправки команды /start бот должен прислать приветствие, а на любые другие сообщения — повторять текст пользователя.
Такая заготовка часто используется в официальных и неофициальных «быстрых стартах» по aiogram, что облегчает диагностику проблем с сетью и токеном.
Шаг 4. Добавляем пользовательское меню и сценарий заявки
Echo-бот сам по себе не несёт пользы бизнесу, поэтому далее вводится простое меню и форма заявки.
Кнопки главного меню
В aiogram 3.x для создания клавиатур используются типы ReplyKeyboardMarkup и InlineKeyboardMarkup. Для простоты хватит обычной клавиатуры под полем ввода:
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
main_menu = ReplyKeyboardMarkup(
keyboard=[
[KeyboardButton(text="Каталог")],
[KeyboardButton(text="Оформить заявку")],
[KeyboardButton(text="Связаться с менеджером")],
],
resize_keyboard=True,
)
Теперь можно обновить обработчик /start, чтобы он прикреплял клавиатуру к сообщению:
@dp.message(CommandStart())
async def cmd_start(message: Message) -> None:
await message.answer(
"Привет! Вы в боте магазина.\n"
"Выберите действие в меню ниже.",
reply_markup=main_menu,
)
Кнопки сокращают количество «ручного» текста и помогают пользователю сразу понять, какие сценарии поддерживает бот.
Простая форма заявки через конечный автомат
Aiogram 3.x предлагает простой подход к конечным автоматам состояний, когда бот по шагам спрашивает у пользователя необходимые данные. Для бизнес-заявки разумно запросить имя, способ связи и, при необходимости, интересующий товар или услугу.
Пример упрощённого сценария в модуле handlers/orders.py:
from aiogram import Router, F
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.context import FSMContext
from aiogram.types import Message
from bot.config import settings
router = Router()
class OrderForm(StatesGroup):
name = State()
contact = State()
comment = State()
@router.message(F.text == "Оформить заявку")
async def order_start(message: Message, state: FSMContext) -> None:
await message.answer("Как вас зовут?")
await state.set_state(OrderForm.name)
@router.message(OrderForm.name)
async def order_name(message: Message, state: FSMContext) -> None:
await state.update_data(name=message.text.strip())
await message.answer("Укажите, пожалуйста, удобный способ связи (телефон или @username).")
await state.set_state(OrderForm.contact)
@router.message(OrderForm.contact)
async def order_contact(message: Message, state: FSMContext) -> None:
await state.update_data(contact=message.text.strip())
await message.answer("Опишите, что именно вас интересует (товар, услуга, время и т.п.).")
await state.set_state(OrderForm.comment)
@router.message(OrderForm.comment)
async def order_comment(message: Message, state: FSMContext) -> None:
await state.update_data(comment=message.text.strip())
data = await state.get_data()
await state.clear()
text = (
"<b>Новая заявка</b>\n"
f"Имя: {data['name']}\n"
f"Контакт: {data['contact']}\n"
f"Комментарий: {data['comment']}"
)
await message.answer("Спасибо! Заявка отправлена менеджеру.")
await message.bot.send_message(chat_id=settings.admin_chat_id, text=text)
Чтобы этот роутер заработал, его нужно подключить в main.py:
from aiogram import Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from bot.handlers import orders
dp = Dispatcher(storage=MemoryStorage())
dp.include_router(orders.router)
Памятное хранилище (MemoryStorage) достаточно для небольших ботов и первых экспериментов; в реальных продакшн-сценариях уместно использовать Redis или другую внешнюю систему для масштабирования и отказоустойчивости.
Шаг 5. Логирование и базовая наблюдаемость
Даже у простого бота важно видеть, что именно нажимают и пишут пользователи, особенно на старте проекта.
Использование стандартного модуля logging с выводом в stdout уже даёт минимальную картину происходящего. Настроенный ранее вызов logging.basicConfig(level=logging.INFO, stream=sys.stdout) позволяет видеть в логах все входящие апдейты и ошибки, если включить соответствующие сообщения в обработчиках.
На следующем этапе можно подключить сбор логов в централизованный сервис (Elasticsearch, Loki и т.п.) или хотя бы сохранять их в файлы с ротацией, но для первых запусков часто достаточно стандартного вывода в консоль или системный журнал на сервере.
Шаг 6. Развёртывание бота на сервере
Разработчики Telegram-ботов традиционно используют два режима работы: получение обновлений через webhook или опрос (getUpdates, long polling). Aiogram 3.x упрощает организацию long polling, а для небольших ботов этого вполне достаточно, если нет жёстких требований по задержкам.
Базовый вариант деплоя:
Поднять на сервере Python требуемой версии и скопировать туда проект (через Git, SCP или другой привычный способ).
Установить зависимости с помощью
pip install -r requirements.txtв виртуальном окружении.Создать на сервере файл
.envс боевым токеном и ID чата администратора.Запустить
python -m bot.mainи убедиться по логам, что бот успешно подключился и отвечает.Для постоянной работы оформить запуск через systemd, supervisord или screen/tmux, чтобы бот перезапускался при падении и не зависел от SSH-сессии.
Документация Telegram Bot API и многочисленные практические статьи подчёркивают, что long polling остаётся валидным и надёжным вариантом для большого числа use-case’ов, особенно когда нагрузка невысока.