<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Полный гайд по разработке бота на Aiogram | Как создать бота в ТГ]]></title><description><![CDATA[<p dir="auto">Так ну что ж, давайте без какого либо вступления сразу в бой <img
      src="https://forum.exlends.com/assets/plugins/nodebb-plugin-emoji/emoji/android/1f601.png?v=a9b928d4b2f"
      class="not-responsive emoji emoji-android emoji--grin"
      style="height: 23px; width: auto; vertical-align: middle;"
      title=":grin:"
      alt="😁"
    /><br />
Будем создавать простого бота на Aiogram, а также хранить пользователей в Sqlite для сбора id.</p>
<p dir="auto">Нам понадобятся следующие библиотеки:</p>
<ul>
<li>aiogram (документация тут - <a href="https://aiogram.dev" target="_blank" rel="noopener noreferrer">https://aiogram.dev</a>)</li>
<li>dotenv</li>
<li>os</li>
<li>aiosqlite</li>
<li>asyncio</li>
</ul>
<p dir="auto">И так архитектура у нас будет такая:<br />
<code>bot.py</code><br />
<code>config.py</code><br />
<code>commands.py</code><br />
<code>sqlite_db.py</code><br />
<code>.env</code></p>
<p dir="auto">Начнем с файла <code>bot.py</code>:</p>
<blockquote>
<p dir="auto">Ах, да не забудьте установить все библиотеки через <code>pip install aiogram dotenv aiosqlite asyncio</code>, <code>os</code> - уже встроен в python.</p>
</blockquote>
<p dir="auto">Если кому в падлу читать тут, я выложил готовый код на GitHub:</p>
<p dir="auto"><div class="card col-md-9 col-lg-6 position-relative link-preview p-0">



<a href="https://github.com/KirillJsx/defaultbot" title="GitHub - KirillJsx/defaultbot: Default telegram bot + db Sqlite">
<img src="https://opengraph.githubassets.com/b0ac957b34d7d2f3d3fcb19a5169ea590737e13eb6a8869dfe96a6ea96c43b2f/KirillJsx/defaultbot" class="card-img-top not-responsive" style="max-height: 15rem;" alt="Link Preview Image" />
</a>



<div class="card-body">
<h5 class="card-title">
<a class="text-decoration-none" href="https://github.com/KirillJsx/defaultbot">
GitHub - KirillJsx/defaultbot: Default telegram bot + db Sqlite
</a>
</h5>
<p class="card-text line-clamp-3">Default telegram bot + db Sqlite. Contribute to KirillJsx/defaultbot development by creating an account on GitHub.</p>
</div>
<a href="https://github.com/KirillJsx/defaultbot" class="card-footer text-body-secondary small d-flex gap-2 align-items-center lh-2">



<img src="https://github.githubassets.com/favicons/favicon.svg" alt="favicon" class="not-responsive overflow-hiddden" style="max-width: 21px; max-height: 21px;" />



<p class="d-inline-block text-truncate mb-0">GitHub <span class="text-secondary">(github.com)</span></p>
</a>
</div></p>
<p dir="auto">Файл: <code>bot.py</code></p>
<pre><code class="language-python">import asyncio
import logging

from aiogram import Bot, Dispatcher, Router, types
from aiogram.filters import Command

from sqlite_db import SqliteUserDataManager

# Создаем экземпляр базы данных
data = SqliteUserDataManager()

# Тут импортируем все команды, нам понадобится только старт

from commands import (
    start_command,
    allusers_command
)

# Также добавим логирование что бы видеть ошибки
# Настройка логирования
logging.basicConfig(
    format=&quot;%(asctime)s - %(name)s - %(levelname)s - %(message)s&quot;, level=logging.INFO
)
logger = logging.getLogger(__name__)

# Импорт конфигурации
from config import TOKEN

# Создаем основной роутер
main_router = Router()


# Регистрируем роутер для вызова команды /start
@main_router.message(Command(&quot;start&quot;))
async def handle_start(message: types.Message):
    await start_command(message, data)

@main_router.message(Command(&quot;users&quot;))
async def handle_users(message: types.Message):
    await allusers_command(message, data)


async def main():
    # Инициализация бота
    global bot
    bot = Bot(TOKEN)
    dp = Dispatcher()

    # Регистрируем роутер
    dp.include_router(main_router)

    # Запуск бота
    logger.info(&quot;🤖 Бот запущен&quot;)
    await bot.delete_webhook(drop_pending_updates=True)
    await dp.start_polling(bot)


if __name__ == &quot;__main__&quot;:
    asyncio.run(main())
</code></pre>
<p dir="auto">Я оставил комментарии в коде, надеюсь всем будет понятно что куда и к чему.</p>
<p dir="auto">После того как мы заполним <code>bot.py</code> приступаем к написанию кода для хранения базы данных:<br />
Файл: <code>sqlite_db.py</code></p>
<pre><code class="language-python">import asyncio
import aiosqlite
from pathlib import Path

# Создаем класс нашей БД с методами
class SqliteUserDataManager:
    def __init__(self, db_file=&quot;users.db&quot;):
        self.db_file = Path(db_file)
        self.lock = asyncio.Lock()
        self.initialized = False


    # Этот код представляет собой асинхронный метод _ensure_db_exists, который проверяет и при необходимости создает базу данных SQLite с таблицей users.
    async def _ensure_db_exists(self):
        if self.initialized:
            return
            
        # Использование асинхронного блокировщика для предотвращения race condition (состояния гонки), когда несколько потоков/корутин могут попытаться инициализировать базу одновременно
        async with self.lock:
            if self.initialized:  # Дважды проверьте блокировку
                return
            
            # Подключение к SQLite базе данных с использованием асинхронной библиотеки aiosqlite.
            async with aiosqlite.connect(self.db_file) as db:
                await db.execute('''
                    CREATE TABLE IF NOT EXISTS users (
                        user_id INTEGER PRIMARY KEY,
                        username TEXT,
                        subscribed BOOLEAN DEFAULT 1,
                        created_at REAL
                    )
                ''')
                await db.commit()
            self.initialized = True
        
    # Этот код представляет собой асинхронный метод add_user, который добавляет пользователя в базу данных SQLite.
    async def add_user(self, user_id, username=None):
        await self._ensure_db_exists()
        async with self.lock:
            async with aiosqlite.connect(self.db_file) as db:
                await db.execute(
                    '''
                    INSERT OR IGNORE INTO users (user_id, username, created_at)
                    VALUES (?, ?, ?)
                    ''',
                    (user_id, username, asyncio.get_event_loop().time())
                )
                # Обновляем имя пользователя, если оно изменилось
                if username is not None:
                    await db.execute(
                        &quot;UPDATE users SET username = ? WHERE user_id = ?&quot;,
                        (username, user_id)
                    )
                await db.commit()
    
    # Этот код представляет собой асинхронный метод get_user, который получает информацию о пользователе из базы данных SQLite по его ID.
    async def get_all_users(self):
        await self._ensure_db_exists()
        async with self.lock:
            async with aiosqlite.connect(self.db_file) as db:
                cursor = await db.execute(&quot;SELECT * FROM users&quot;)
                rows = await cursor.fetchall()
                return {
                    row[0]: {
                        &quot;username&quot;: row[1],
                        &quot;subscribed&quot;: bool(row[2]),
                        &quot;created_at&quot;: row[3]
                    } for row in rows
                }
</code></pre>
<p dir="auto">После написание методов для <code>Sqlite</code> переходим к <code>commands.py</code>:</p>
<pre><code class="language-python"># Импортируем настройки ID админа из нашего файла config.py
from config import ADMIN_ID

# Простая команда которая отдает приветствие при выполнении /start в самом боте
async def start_command(message, data):
    user = message.from_user
    await data.add_user(user.id, user.username)
    await message.answer(&quot;Прииииивеееееет!&quot;,)

# Команда для получения списка всех пользователей, но только для админа
async def allusers_command(message, data):
    user_id = message.from_user.id
    admin_id = int(ADMIN_ID)

    if user_id != admin_id:
        await message.answer(&quot;❌ У вас нет прав для выполнения этой команды.&quot;)
        return

    try:
        users = await data.get_all_users()
        count = len(users)
        await message.answer(f&quot;Количество пользователей: {count}&quot;)
    except Exception as e:
        await message.answer(&quot;Ошибка при получении списка пользователей.&quot;)
        print(f&quot;[ERROR] {e}&quot;)
</code></pre>
<p dir="auto">Ну и конечно же не забываем о файле: <code>config.py</code></p>
<pre><code class="language-python">import os
from dotenv import load_dotenv
load_dotenv()

TOKEN = os.getenv(&quot;TOKEN&quot;)
ADMIN_ID = os.getenv(&quot;ADMIN_ID&quot;)
</code></pre>
<p dir="auto">На этом все! Запускайте своих ботов и тестируйте.<br />
Если будут вопросы пишите в комментариях на форуме.</p>
<p dir="auto"><img src="/assets/uploads/files/1750922246557-defbot.png" alt="defbot.png" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto">Кстати не забудь подписаться на мой ТГ канал и еще оставлю ссылку на своего бота для скачивания клипов из ТикТока <img
      src="https://forum.exlends.com/assets/plugins/nodebb-plugin-emoji/emoji/android/1f60a.png?v=a9b928d4b2f"
      class="not-responsive emoji emoji-android emoji--blush"
      style="height: 23px; width: auto; vertical-align: middle;"
      title=":blush:"
      alt="😊"
    /></p>
<p dir="auto"><div class="card col-md-9 col-lg-6 position-relative link-preview p-0">



<a href="https://t.me/kirilljsx" title="Кирилл Дворянинов">
<img src="https://cdn4.telesco.pe/file/RMdbVU4mjOhDlcUFINTmWaU05XsoZRywWUAFkVb7dsYbdZ_l7uXfe7NwxTmJTLQnBtY6gb76tSjU-__57vJYYFBMVDZSey7bxU7slkEAvwB0Jujg_obOYIsYXWtflHihBmJ-tboFbp9Ss0MvDaj1y01ih1U0tsLPrMyMJGYqW3sCALj_S0wSdtCIrOZ3CZI7dT3NOyeygXw4RvSZWOTvoA-j2MN76G9zyn12uA8BqNA3Ea1C3Fs1Iv0I_uok98NQQUigGhjQyx_fWc8X6R-kvYja4ujUCMNDBULV-R-N3AffPdaFdCH0YgB9QKe_cZcrR-S4FmcYhCDo_uZ6yVzQMA.jpg" class="card-img-top not-responsive" style="max-height: 15rem;" alt="Link Preview Image" />
</a>



<div class="card-body">
<h5 class="card-title">
<a class="text-decoration-none" href="https://t.me/kirilljsx">
Кирилл Дворянинов
</a>
</h5>
<p class="card-text line-clamp-3">Обо всем и не о чем сразу  👨🏻‍💻	ИТ форум - forum.exlends.com</p>
</div>
<a href="https://t.me/kirilljsx" class="card-footer text-body-secondary small d-flex gap-2 align-items-center lh-2">



<img src="https://telegram.org/img/website_icon.svg?4" alt="favicon" class="not-responsive overflow-hiddden" style="max-width: 21px; max-height: 21px;" />









<p class="d-inline-block text-truncate mb-0">Telegram <span class="text-secondary">(t.me)</span></p>
</a>
</div></p>
<p dir="auto">Сам бот:</p>
<p dir="auto"><div class="card col-md-9 col-lg-6 position-relative link-preview p-0">



<a href="https://telegram.me/vkclipssavebot" title="Скачать видео ВК Клипы | ТикТок">
<img src="https://cdn4.telesco.pe/file/EFKCMUMa0o2I7FCyQyJIFL4Tl0diJZaHSbVaU21xqTevjAYP--wskEYqzYsHSY3PMbqC4bRa8DMqm8MtgAC_ykielNgWrgDmknDsCaF0kgHqBrbLOYAm8PLSSF1DzBV-ooz5AVuGjxa2TxJCabV6KsWLCbJacAsvW_8xr6VElk9Oaqep0Tp-JbIxFU7wo_euovAZXK_UNiQRM6L8KXpLKT_b68QkOVrhxxFxpmpzGbVDcBm4zcpMURPvN26lamR0najXCjKIQu-drSemeGIZxxGkdCcj39VrB7istYupEbRaDSsKF0whwyPv6DqmtWitvtgGYxLxVjBZqps3jSL20A.jpg" class="card-img-top not-responsive" style="max-height: 15rem;" alt="Link Preview Image" />
</a>



<div class="card-body">
<h5 class="card-title">
<a class="text-decoration-none" href="https://telegram.me/vkclipssavebot">
Скачать видео ВК Клипы | ТикТок
</a>
</h5>
<p class="card-text line-clamp-3">🤖 Умею скачивать видео из VK Clips, TikTok, Yappy. Интеграция: https://telega.in/tg_bots/vkclipssavebot/card</p>
</div>
<a href="https://telegram.me/vkclipssavebot" class="card-footer text-body-secondary small d-flex gap-2 align-items-center lh-2">



<img src="https://telegram.org/img/website_icon.svg?4" alt="favicon" class="not-responsive overflow-hiddden" style="max-width: 21px; max-height: 21px;" />









<p class="d-inline-block text-truncate mb-0">Telegram <span class="text-secondary">(telegram.me)</span></p>
</a>
</div></p>
]]></description><link>https://forum.exlends.com/topic/159/polnyj-gajd-po-razrabotke-bota-na-aiogram-kak-sozdat-bota-v-tg</link><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 00:07:39 GMT</lastBuildDate><atom:link href="https://forum.exlends.com/topic/159.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 26 Jun 2025 07:19:41 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Полный гайд по разработке бота на Aiogram | Как создать бота в ТГ on Mon, 30 Jun 2025 15:16:26 GMT]]></title><description><![CDATA[<p dir="auto">Дополню статью, как в sqlite выводить список id пользователей, а точнее файл.</p>
<p dir="auto">Вот отдельная команда, аналогично как и другим</p>
<pre><code class="language-python">async def ids_command(message, bot, user_db):
    user_id = message.from_user.id
    admin_id = int(os.getenv("ADMIN_ID"))

    if user_id != admin_id:
        await bot.reply_to(message, "❌ У вас нет прав для выполнения этой команды.")
        return

    try:
        # Получение списка ID
        ids = await user_db.get_all_ids()
        
        if not ids:
            await bot.reply_to(message, "ℹ️ Нет пользователей в базе данных.")
            return
            
        # Определяем тип БД для названия файла
        db_type = "SQLite" if isinstance(user_db, SqliteUserDataManager) else "JSON"
        filename = f"user_ids_{db_type.lower()}.txt"
        
        # Создаем временный файл
        with open(filename, "w") as f:
            for user_id in ids:
                f.write(f"{user_id}\n")  # Каждый ID на новой строке
        
        # Отправляем файл через FSInputFile
        document = FSInputFile(path=filename)
        await bot.send_document(
            chat_id=message.chat.id,
            document=document,
            caption=f"📋 Список ID пользователей ({db_type})"
        )
        
        # Удаляем временный файл
        os.remove(filename)
        
    except Exception as e:
        logger.error(f"Ошибка при получении ID: {e}")
        await bot.reply_to(message, f"❌ Ошибка: {str(e)}")
</code></pre>
<p dir="auto">И не забудьте добавить метод в файле <code>sqlite_db.py</code></p>
<pre><code class="language-python">async def get_all_ids(self):
        await self._ensure_db_exists()
        async with self.lock:
            async with aiosqlite.connect(self.db_file) as db:
                cursor = await db.execute("SELECT user_id FROM users")
                rows = await cursor.fetchall()
                return [row[0] for row in rows]
</code></pre>
<p dir="auto">И в самом <code>bot.py</code>:</p>
<pre><code class="language-python">@main_router.message(Command("ids"))
async def handle_ids(message: types.Message):
    await ids_command(message, bot, user_db)
</code></pre>
<p dir="auto">А вот как выводится файл:<br />
<img src="/assets/uploads/files/1751296552338-%D1%81%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA-%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0-2025-06-30-%D0%B2-18.15.47.png" alt="Снимок экрана 2025-06-30 в 18.15.47.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">В основном это необходимо для рассылки пользователям уведомлений или рекламных интеграций.</p>
]]></description><link>https://forum.exlends.com/post/343</link><guid isPermaLink="true">https://forum.exlends.com/post/343</guid><dc:creator><![CDATA[kirilljsx]]></dc:creator><pubDate>Mon, 30 Jun 2025 15:16:26 GMT</pubDate></item></channel></rss>