Разработка ботов с использованием Python

Раздел: API и сторонние сервисы -> Разработка ботов

Основной подход: бот на aiogram

Самое распространенное решение для создания Telegram ботов на Python - библиотека aiogram. Она асинхронна, поддерживает современные возможности, такие как FSM, middleware, вебхуки. Ниже представлен минимальный пример эхо-бота.

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

API_TOKEN = 'YOUR_TOKEN_HERE'

bot = Bot(token=API_TOKEN)
dp = Dispatcher()

@dp.message(Command("start"))
async def send_welcome(message: types.Message):
    await message.answer("Привет! Я эхо-бот.")

@dp.message()
async def echo(message: types.Message):
    await message.answer(message.text)

async def main():
    await dp.start_polling(bot)

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

написание бота python (написание бота на python)

Пояснение шагов: импорт библиотек, создание экземпляров Bot и Dispatcher, регистрация хендлеров, запуск поллинга. Токен получается у BotFather.

Ключевые особенности aiogram: асинхронность (все колбэки корутины), использование фильтров (Command, Text и др.), встроенная поддержка клавиатур, inline-режимов, FSM.

Типичные проблемы: некорректный токен, отсутствие импортов, неверная версия Python (требуется 3.7+). Решение - проверить токен, обновить Python.

Как написать бота на синхронной библиотеке python-telegram-bot?

Библиотека python-telegram-bot (версии 20+ поддерживает asyncio, ранее была синхронной). Для простых ботов, не требующих высокой производительности, подходит синхронный подход. Цель: быстрый старт без асинхронности.

from telegram.ext import Updater, CommandHandler, MessageHandler, Filters

def start(update, context):
    update.message.reply_text('Привет!')

def echo(update, context):
    update.message.reply_text(update.message.text)

def main():
    updater = Updater('TOKEN', use_context=True)
    dp = updater.dispatcher
    dp.add_handler(CommandHandler('start', start))
    dp.add_handler(MessageHandler(Filters.text & ~Filters.command, echo))
    updater.start_polling()
    updater.idle()

if __name__ == '__main__':
    main()

Ошибки: не забыть добавить use_context=True. Проблемы с блокировкой при длительных операциях - требуется многопоточность. Решение: использовать asyncio версию библиотеки.

Типичные проблемы: забывают вызвать idle(), что приводит к завершению скрипта. Также конфликты при использовании разных версий библиотеки.

Как разработать бота для социальной сети VK?

Библиотека vkbottle предоставляет асинхронный интерфейс для VK API. Цель: создание ботов в ВКонтакте с поддержкой клавиатур, FSM, middleware.

from vkbottle.bot import Bot

bot = Bot('group_token')

@bot.on.message(text='Привет')
async def answer(message):
    await message.answer('И тебе привет!')

bot.run_forever()

Для работы нужен токен сообщества, полученный в настройках группы. Поддерживает LongPoll и Callback API.

Типичные ошибки: неправильный токен (не группы, а пользователя), отсутствие прав на сообщения. Решение: проверить токен и настройки группы.

Как написать бота для Discord на Python?

Библиотека discord.py (асинхронная) позволяет легко создавать ботов для Discord. Цель: взаимодействие с серверами Discord, команды, модерация.

import discord
from discord.ext import commands

intents = discord.Intents.default()
intents.message_content = True

bot = commands.Bot(command_prefix='!', intents=intents)

@bot.event
async def on_ready():
    print(f'Бот {bot.user} готов!')

@bot.command()
async def hello(ctx):
    await ctx.send('Привет!')

bot.run('TOKEN')

Важно: токен получается в Discord Developer Portal. Необходимо включить Intents.

Ошибки: не указаны intents (бот не видит сообщения). Решение: добавить необходимые intents и включить их в настройках приложения Discord.

Как реализовать многошаговый диалог с пользователем с помощью FSM?

FSM (Finite State Machine) в aiogram позволяет управлять состояниями пользователя. Цель: сбор данных, опросы, анкеты.

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

class Form(StatesGroup):
    name = State()
    age = State()
    gender = State()

@dp.message(Command("form"))
async def start_form(message: types.Message, state: FSMContext):
    await state.set_state(Form.name)
    await message.answer("Введите имя:")

@dp.message(Form.name)
async def process_name(message: types.Message, state: FSMContext):
    await state.update_data(name=message.text)
    await state.set_state(Form.age)
    await message.answer("Введите возраст:")

@dp.message(Form.age)
async def process_age(message: types.Message, state: FSMContext):
    await state.update_data(age=int(message.text))
    await state.set_state(Form.gender)
    await message.answer("Введите пол (м/ж):")

@dp.message(Form.gender)
async def process_gender(message: types.Message, state: FSMContext):
    data = await state.update_data(gender=message.text)
    await state.clear()
    await message.answer(f"Спасибо! Ваше имя: {data['name']}, возраст: {data['age']}, пол: {data['gender']}")

Валидация ввода: нужно добавить проверку возраста (число) и пола (один из символов).

Типичные проблемы: неправильные данные вызывают исключение, состояние не очищается. Решение: обработка исключений, использование фильтров.

Как настроить бота на вебхуки вместо поллинга?

В aiogram вебхуки настраиваются с помощью aiohttp. Цель: повышение производительности, работа с собственным сервером.

from aiohttp import web

async def on_startup(app):
    await bot.set_webhook(f'https://example.com/webhook')

async def webhook_handler(request):
    update = types.Update(**(await request.json()))
    await dp.feed_update(bot, update)
    return web.Response()

async def main():
    app = web.Application()
    app.router.add_post('/webhook', webhook_handler)
    app.on_startup.append(on_startup)
    await web.run_app(app, host='0.0.0.0', port=8443)

Требуется HTTPS сертификат (Let's Encrypt или self-signed). Ошибка: если не настроить webhook правильно, бот не будет отвечать.

Проблемы: неправильный URL, порт заблокирован, отсутствие SSL. Решение: проверить настройки сервера, использовать сертификат.

Расширенные примеры ботов

Пример 1: Бот с инлайн-клавиатурой и запросом внешнего API

Этот бот по команде /fact отправляет случайный факт с использованием API (uselessfacts.jsph.pl). Клавиатура позволяет получить новый факт без ввода команды.

Пример
import asyncio
import aiohttp
from aiogram import Bot, Dispatcher, types
from aiogram.filters import Command
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup

API_TOKEN = 'YOUR_TOKEN'
bot = Bot(token=API_TOKEN)
dp = Dispatcher()

async def get_fact():
    async with aiohttp.ClientSession() as session:
        async with session.get('https://uselessfacts.jsph.pl/random.json?language=en') as resp:
            data = await resp.json()
            return data['text']

@dp.message(Command("fact"))
async def send_fact(message: types.Message):
    fact = await get_fact()
    keyboard = InlineKeyboardMarkup(
        inline_keyboard=[[InlineKeyboardButton(text='Ещё факт', callback_data='new_fact')]]
    )
    await message.answer(fact, reply_markup=keyboard)

@dp.callback_query(lambda c: c.data == 'new_fact')
async def new_fact(callback: types.CallbackQuery):
    fact = await get_fact()
    keyboard = InlineKeyboardMarkup(
        inline_keyboard=[[InlineKeyboardButton(text='Ещё факт', callback_data='new_fact')]]
    )
    await callback.message.edit_text(fact, reply_markup=keyboard)
    await callback.answer()

async def main():
    await dp.start_polling(bot)

if __name__ == '__main__':
    asyncio.run(main())
Пользователь отправляет /fact
Бот: Did you know that a group of flamingos is called a 'flamboyance'? (с кнопкой 'Ещё факт')
При нажатии на кнопку бот заменяет сообщение новым фактом.

Пояснение: используется aiohttp для асинхронного запроса, InlineKeyboardMarkup для кнопок. CallbackQuery обрабатывается отдельным хендлером.

Пример 2: Бот с FSM и сохранением данных в SQLite

Бот собирает заказ пиццы: выбирает размер, топпинги, адрес доставки. Данные сохраняются в базу SQLite.

Пример
import sqlite3
from aiogram import Bot, Dispatcher, types
from aiogram.filters import Command
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.context import FSMContext
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton

API_TOKEN = 'YOUR_TOKEN'
bot = Bot(token=API_TOKEN)
dp = Dispatcher()

# Инициализация БД
conn = sqlite3.connect('orders.db')
cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS orders (
    user_id INTEGER,
    size TEXT,
    toppings TEXT,
    address TEXT
)''')
conn.commit()

class Order(StatesGroup):
    size = State()
    toppings = State()
    address = State()

size_kb = ReplyKeyboardMarkup(
    keyboard=[[KeyboardButton(text='Маленькая'), KeyboardButton(text='Большая')]],
    resize_keyboard=True
)

@dp.message(Command("order"))
async def start_order(message: types.Message, state: FSMContext):
    await state.set_state(Order.size)
    await message.answer("Выберите размер пиццы:", reply_markup=size_kb)

@dp.message(Order.size)
async def process_size(message: types.Message, state: FSMContext):
    if message.text not in ['Маленькая', 'Большая']:
        await message.answer("Пожалуйста, используйте кнопки")
        return
    await state.update_data(size=message.text)
    await state.set_state(Order.toppings)
    await message.answer("Какие топпинги? (введите через запятую)", reply_markup=types.ReplyKeyboardRemove())

@dp.message(Order.toppings)
async def process_toppings(message: types.Message, state: FSMContext):
    await state.update_data(toppings=message.text)
    await state.set_state(Order.address)
    await message.answer("Введите адрес доставки:")

@dp.message(Order.address)
async def process_address(message: types.Message, state: FSMContext):
    data = await state.update_data(address=message.text)
    # Сохранение в БД
    cursor.execute('INSERT INTO orders (user_id, size, toppings, address) VALUES (?, ?, ?, ?)',
                   (message.from_user.id, data['size'], data['toppings'], data['address']))
    conn.commit()
    await state.clear()
    await message.answer("Заказ принят! Спасибо.")

async def main():
    await dp.start_polling(bot)

if __name__ == '__main__':
    asyncio.run(main())
Пользователь вводит /order
Бот: Выберите размер пиццы: (кнопки Маленькая/Большая)
Пользователь: Большая
Бот: Какие топпинги? (введите через запятую)
Пользователь: сыр, грибы, оливки
Бот: Введите адрес доставки:
Пользователь: ул. Ленина, д.10
Бот: Заказ принят! Спасибо.

Пояснение: SQLite используется для хранения заказов. ReplyKeyboardMarkup для выбора размера. Валидация входа на каждом шаге.

Пример 3: Бот для загрузки изображений с наложением водяного знака

Бот принимает изображение, накладывает водяной знак (текст) и возвращает обратно.

Пример
import asyncio
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
from aiogram import Bot, Dispatcher, types
from aiogram.filters import Command

API_TOKEN = 'YOUR_TOKEN'
bot = Bot(token=API_TOKEN)
dp = Dispatcher()

async def add_watermark(image_bytes: bytes, text: str) -> bytes:
    image = Image.open(BytesIO(image_bytes))
    draw = ImageDraw.Draw(image)
    try:
        font = ImageFont.truetype("arial.ttf", 36)
    except:
        font = ImageFont.load_default()
    # Позиция водяного знака - правый нижний угол
    width, height = image.size
    text_width, text_height = draw.textsize(text, font)
    x = width - text_width - 10
    y = height - text_height - 10
    draw.text((x, y), text, fill=(255, 255, 255, 128), font=font)
    output = BytesIO()
    image.save(output, format='PNG')
    output.seek(0)
    return output.read()

@dp.message(Command("watermark"))
async def start_watermark(message: types.Message):
    await message.answer("Отправьте изображение, и я добавлю водяной знак.")

@dp.message(content_types=['photo'])
async def handle_photo(message: types.Message):
    # Получаем фото в максимальном разрешении
    photo = message.photo[-1]
    file_info = await bot.get_file(photo.file_id)
    downloaded_file = await bot.download_file(file_info.file_path)
    watermarked = await add_watermark(downloaded_file.read(), "@your_bot")
    await message.reply_photo(types.BufferedInputFile(watermarked, filename="watermarked.png"),
                              caption="Изображение с водяным знаком")

async def main():
    await dp.start_polling(bot)

if __name__ == '__main__':
    asyncio.run(main())
Пользователь отправляет фото
Бот: (возвращает то же фото с текстом "@your_bot" в правом нижнем углу)

Пояснение: используются библиотеки Pillow для обработки изображений. Водяной знак добавляется полупрозрачным. Обработка ошибок при загрузке шрифта.

Написание бота на Python - comments

En
написание бота python (python)