← все статьи
~/blog/telegram-bot-python-2024.md
15 ноября 2024 г.·12 мин

Как написать Telegram-бота на Python в 2024 году — полное руководство

Пошаговое руководство по созданию production-ready Telegram-бота с использованием Aiogram 3, PostgreSQL и деплоем на VPS. От нуля до рабочего продукта.

PythonTelegramAiogramPostgreSQLDocker

Как написать Telegram-бота на Python в 2024 году

Telegram-боты — один из самых быстрых способов автоматизировать бизнес-процессы или создать полноценный продукт. В этой статье я расскажу, как с нуля построить production-ready бота с базой данных, правильной архитектурой и деплоем.

Архитектура Telegram-бота на Aiogram 3

Что мы построим

  • Бот на Aiogram 3 (async, современный API)
  • PostgreSQL как хранилище данных
  • Конфигурация через .env
  • Docker для деплоя
  • FSM (конечный автомат состояний) для многошаговых сценариев

Почему Aiogram 3, а не python-telegram-bot

Aiogram 3 — де-факто стандарт для серьёзных ботов на Python:

  • Полностью асинхронный (asyncio)
  • Роутеры и мидлвары как в FastAPI
  • Удобный FSM для диалогов
  • Активная поддержка и хорошая документация

Установка и структура проекта

pip install aiogram==3.* sqlalchemy asyncpg python-dotenv

Структура проекта:

bot/
├── handlers/
│   ├── __init__.py
│   ├── common.py      # /start, /help
│   └── user.py        # пользовательские сценарии
├── middlewares/
│   └── database.py    # инжект сессии в хэндлеры
├── models/
│   └── user.py        # SQLAlchemy модели
├── keyboards/
│   └── reply.py
├── config.py
└── main.py

Конфигурация

# config.py
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    BOT_TOKEN: str
    DATABASE_URL: str
    ADMIN_ID: int

    class Config:
        env_file = ".env"

settings = Settings()

Основной файл

# main.py
import asyncio
from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from handlers import common, user
from config import settings

async def main():
    bot = Bot(token=settings.BOT_TOKEN)
    dp = Dispatcher(storage=MemoryStorage())

    dp.include_router(common.router)
    dp.include_router(user.router)

    await dp.start_polling(bot)

if __name__ == "__main__":
    asyncio.run(main())

Хэндлер /start

# handlers/common.py
from aiogram import Router
from aiogram.filters import CommandStart
from aiogram.types import Message

router = Router()

@router.message(CommandStart())
async def cmd_start(message: Message):
    await message.answer(
        f"Привет, {message.from_user.first_name}! 👋\n\n"
        "Я помогу тебе автоматизировать твои задачи."
    )

FSM — многошаговые диалоги

from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup

class OrderForm(StatesGroup):
    waiting_name    = State()
    waiting_phone   = State()
    waiting_comment = State()

@router.message(Command("order"))
async def start_order(message: Message, state: FSMContext):
    await state.set_state(OrderForm.waiting_name)
    await message.answer("Как вас зовут?")

@router.message(OrderForm.waiting_name)
async def got_name(message: Message, state: FSMContext):
    await state.update_data(name=message.text)
    await state.set_state(OrderForm.waiting_phone)
    await message.answer("Укажите номер телефона:")

Работа с базой данных

# models/user.py
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import BigInteger, String, DateTime, func

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"

    id:         Mapped[int]    = mapped_column(BigInteger, primary_key=True)
    username:   Mapped[str | None] = mapped_column(String(64))
    first_name: Mapped[str]    = mapped_column(String(128))
    created_at: Mapped[DateTime] = mapped_column(server_default=func.now())

Dockerfile

FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .
CMD ["python", "main.py"]
# docker-compose.yml
services:
  bot:
    build: .
    env_file: .env
    depends_on: [db]
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    env_file: .env
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Деплой на VPS

git clone your-repo && cd bot
cp .env.example .env  # заполнить токены
docker compose up -d

Итог

Правильно выстроенный Telegram-бот — это не просто скрипт с if '/start'. Это полноценное приложение с роутерами, мидлварами, базой данных и CI/CD. Aiogram 3 даёт для этого все инструменты.

Если нужна помощь с разработкой бота — напишите мне.

// нужна помощь с проектом?

Разрабатываю бэкенды, боты, автоматизации и AI-инструменты.

написать →