Разработка ботов с использованием Python
Основной подход: бот на 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-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 версию библиотеки.
Как разработать бота для социальной сети 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.
Как реализовать многошаговый диалог с пользователем с помощью 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 правильно, бот не будет отвечать.
Расширенные примеры ботов
Пример 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 для обработки изображений. Водяной знак добавляется полупрозрачным. Обработка ошибок при загрузке шрифта.