Модерация: мут, бан, фильтры
Учим Цыплёнка-помощника наводить порядок в чате клана: затыкать болтунов на время, выгонять нарушителей, ловить запрещённые слова и стирать сообщения, которые ломают правила.
Модерация — это поддержание порядка в чате силами бота: он по правилам ограничивает, удаляет или выгоняет тех, кто мешает остальным, делая это мгновенно и без эмоций.
Зачем боту уметь наводить порядок
Представь чат твоего игрового клана на сорок человек. Идёт обсуждение рейда, и тут приходит чужак и начинает кидать рекламу казино каждые десять секунд. Ты — админ, но ты на тренировке, телефон в рюкзаке. Через пятнадцать минут в чате уже сотня спам-сообщений, и половина клана его покинула. Обидно.
А теперь представь, что в чате сидит Цыплёнок-помощник с правами админа. Он замечает запрещённое слово в первом же сообщении, моментально его удаляет, а болтуна затыкает на час. Чужак даже не успевает развернуться. Ты возвращаешься с тренировки — а в чате тишина и порядок, будто ничего и не было.
Вот к чему мы придём в этом уроке. Цыплёнок научится трём вещам: временно лишать человека права писать (это называется мут), полностью выгонять нарушителя из чата (бан) и автоматически ловить запрещённые слова, стирая такие сообщения. По сути, мы превращаем бота в дежурного по чату, который не спит, не отвлекается и не поддаётся на провокации.
Чужак: Залетай на лучшее казино, дарю промокод! 🎰
Бот: (молча удаляет сообщение)
Бот: @chuzhak, за рекламу — мут на 1 час. Правила в закрепе 🐥Результат: в чате бот сам убирает спам-сообщение и пишет короткое предупреждение нарушителю, заодно лишая его права писать на час. Никто из клана не успевает даже прочитать рекламу — модерация срабатывает быстрее человека.
Как это работает: бот как дежурный по классу
Помнишь дежурного по классу? Учитель выдаёт ему повязку и говорит: «Следи за порядком, можешь делать замечания и выгонять из кабинета хулиганов». Без повязки дежурный — обычный ученик, его никто не слушает. С повязкой у него появляются права.
С ботом всё точно так же. Сам по себе бот в группе — рядовой участник, он не может никого ни замутить, ни забанить. Чтобы получить «повязку», его нужно сделать администратором группы и в настройках админ-прав включить галочки «Блокировка участников» и «Удаление сообщений». Без этих прав любая твоя команда модерации просто вернёт ошибку «недостаточно прав». Это первое и главное правило урока.
Бот без админ-прав в группе ничего модерировать не может. Сначала повязка (права админа), потом обязанности (мут, бан, удаление).
Про права и события в группах мы подробно говорили в уроке Бот в группах: права и события — если подзабыл, как бот вообще попадает в чат и что он там видит, загляни туда перед тем, как читать дальше.
Три разных инструмента — не путай
У дежурного есть разные меры строгости, и важно с самого начала понимать, чем они отличаются.
| Действие | Что делает | Метод aiogram |
| Удалить сообщение | Стирает одно сообщение, человек остаётся в чате | bot.delete_message |
| Мут | Запрещает писать, но человек остаётся в чате (можно на время) | bot.restrict_chat_member |
| Бан | Полностью выкидывает из чата | bot.ban_chat_member |
Грубо говоря: удаление — это стереть с доски одну надпись, мут — заклеить человеку рот скотчем на время, а бан — вывести за дверь совсем. Разные ситуации требуют разной строгости, и хороший модератор не банит за первую же опечатку. Чаще всего эти инструменты идут в связке: сначала удаляешь нарушающее сообщение, чтобы его не видели остальные, а потом, в зависимости от тяжести, либо мутишь автора на время, либо банишь насовсем. Именно так мы и будем их сочетать в нашем фильтре чуть дальше.
Шаг 1. Мут: затыкаем болтуна через restrict_chat_member
Начнём с самой мягкой и самой частой меры — мута. Мут в Telegram — это не отдельная кнопка «замолчи», а ограничение прав участника. Мы говорим Telegram: «вот этому человеку в этом чате запрети отправлять сообщения». Делается это методом restrict_chat_member, которому передают объект ChatPermissions со списком того, что человеку можно. Если в разрешениях всё выставить в False — он не сможет писать вообще ничего. Это и есть мут.
Чтобы мут был временным (например, на час), мы добавляем параметр until_date — момент времени, когда ограничение само снимется. Удобно посчитать его как «сейчас плюс столько-то секунд».
from datetime import datetime, timedelta
from aiogram.types import Message, ChatPermissions
from aiogram.filters import Command
@dp.message(Command("mute"))
async def cmd_mute(message: Message):
# команду пишут в ответ на сообщение нарушителя
if not message.reply_to_message:
await message.answer("Ответь этой командой на сообщение того, кого мутить.")
return
target = message.reply_to_message.from_user
until = datetime.now() + timedelta(hours=1)
await bot.restrict_chat_member(
chat_id=message.chat.id,
user_id=target.id,
permissions=ChatPermissions(can_send_messages=False),
until_date=until,
)
await message.answer(f"{target.full_name} в муте на 1 час 🤐")Результат: в чате, если ответить на сообщение болтуна командой /mute, бот лишит его права писать на час и сообщит об этом. Через час Telegram сам вернёт человеку возможность писать — отдельно размучивать не нужно.
Разберём по шагам. Сначала проверяем message.reply_to_message — это сообщение, на которое ответили нашей командой. Если его нет, значит админ просто написал /mute в воздух, и непонятно, кого мутить, — вежливо просим ответить на конкретное сообщение. Если ответ есть, достаём из него автора через .from_user — это и есть нарушитель. Считаем until как «сейчас + 1 час». И зовём restrict_chat_member: указываем чат, id нарушителя, разрешения с can_send_messages=False (писать нельзя) и время, до которого мут держится.
Почему именно «в ответ на сообщение»? Потому что так не надо вручную выяснять чей-то id — Telegram сам подскажет автора того сообщения, на которое ты ответил. Это самый удобный приём для команд модерации, и мы будем использовать его и дальше.
Шаг 2. Бан: выгоняем нарушителя через ban_chat_member
Если человек пришёл откровенно вредить и мут не помогает — пора банить. Бан полностью удаляет участника из чата, и просто так он назад уже не вернётся. Метод называется ban_chat_member и в простейшем виде требует только чат и id того, кого выгоняем.
@dp.message(Command("ban"))
async def cmd_ban(message: Message):
if not message.reply_to_message:
await message.answer("Ответь этой командой на сообщение того, кого банить.")
return
target = message.reply_to_message.from_user
await bot.ban_chat_member(
chat_id=message.chat.id,
user_id=target.id,
)
await message.answer(f"{target.full_name} забанен и удалён из чата 🚪")Результат: в чате, если ответить на сообщение нарушителя командой /ban, бот выкинет его из группы и напишет об этом. Сам нарушитель обратно по старой ссылке уже не зайдёт, пока его не разбанят.
Код почти повторяет мут — та же проверка на ответ, тот же способ достать нарушителя через reply_to_message.from_user. Разница только в действии: вместо ограничения прав мы зовём ban_chat_member, который выгоняет человека целиком. Заметь, насколько похожи команды модерации между собой — освоив одну, ты почти бесплатно получаешь остальные.
Важный нюанс: бан — это не то же самое, что «удалить и забыть». Забаненный остаётся в чёрном списке чата, и если захочешь дать ему второй шанс, его придётся явно разбанить методом unban_chat_member. Поэтому баном не разбрасываются: это самая суровая мера, после неё человек чувствует себя выставленным за дверь насовсем. Хорошее правило для бота клана: бан приберегай для откровенных спамеров и тех, кто пришёл явно вредить, а с обычными участниками, которые просто перегнули палку в споре, хватает мута на пару часов — пусть остынут и вернутся.
Шаг 3. Фильтр запрещённых слов
Команды /mute и /ban — это ручной режим: ты сам реагируешь на нарушителя. Но дежурный хорош тем, что следит постоянно. Сделаем автоматический фильтр: бот будет проверять каждое входящее сообщение и, если в нём есть запрещённое слово, сразу удалять его и мутить автора.
Сначала разберём саму проверку «есть ли в тексте плохое слово» на чистом Python, без бота. Это маленькая самодостаточная задача: приводим текст к нижнему регистру и смотрим, встречается ли в нём хоть одно слово из чёрного списка.
BAD_WORDS = {"казино", "промокод", "ставки"}
def has_bad_word(text):
lowered = text.lower()
for word in BAD_WORDS:
if word in lowered:
return True
return False
print(has_bad_word("Залетай на лучшее КАЗИНО!"))
print(has_bad_word("Привет, как дела?"))
print(has_bad_word("дарю промокод друзьям"))Вывод:
True False True
Смотри, что здесь происходит. BAD_WORDS — это множество (set) запрещённых слов; множество удобно тем, что проверка «есть ли слово внутри» быстрая. Метод text.lower() переводит всё в нижний регистр, чтобы «КАЗИНО», «Казино» и «казино» считались одним и тем же — иначе хитрый спамер обошёл бы фильтр одной заглавной буквой. Дальше мы перебираем чёрный список и для каждого слова проверяем, входит ли оно в текст через in. Нашли — сразу возвращаем True; прошли весь список без находок — возвращаем False.
Теперь подключим эту проверку к боту. Сделаем хэндлер, который ловит любое текстовое сообщение в группе, прогоняет его через has_bad_word и при срабатывании удаляет сообщение и мутит автора.
from aiogram import F
from aiogram.types import Message, ChatPermissions
from datetime import datetime, timedelta
BAD_WORDS = {"казино", "промокод", "ставки"}
def has_bad_word(text: str) -> bool:
lowered = text.lower()
return any(word in lowered for word in BAD_WORDS)
@dp.message(F.text)
async def filter_messages(message: Message):
if not has_bad_word(message.text):
return # обычное сообщение — не трогаем
await message.delete()
until = datetime.now() + timedelta(hours=1)
await bot.restrict_chat_member(
chat_id=message.chat.id,
user_id=message.from_user.id,
permissions=ChatPermissions(can_send_messages=False),
until_date=until,
)
await message.answer(
f"{message.from_user.full_name}, за рекламу — мут на 1 час. Правила в закрепе 🐥"
)Результат: в чате, как только кто-то напишет сообщение со словом из чёрного списка, бот мгновенно удалит это сообщение, замутит автора на час и оставит короткое предупреждение. Обычные сообщения без запрещённых слов проходят без помех — бот их просто пропускает.
Главная новинка здесь — @dp.message(F.text). Раньше мы вешали хэндлеры на конкретные команды, а этот ловит вообще любое текстовое сообщение. Внутри мы первым делом зовём has_bad_word: если слово не найдено, делаем return и тихо отпускаем сообщение — это важно, иначе бот реагировал бы на каждую фразу в чате. Если слово найдено — message.delete() стирает сообщение, а дальше идёт уже знакомый по шагу 1 мут автора. Функция has_bad_word тут чуть короче за счёт any(...), но делает ровно то же, что и в разминке.
Частые ошибки и подводные камни
Вот грабли, на которые наступают почти все, кто впервые делает модерацию. Прочитай сейчас — сэкономишь себе нервы и пару часов отладки.
- Забыть выдать боту права админа. Самая частая. Если бот не админ группы или у него не включены «Блокировка участников» и «Удаление сообщений», то
restrict_chat_member,ban_chat_memberиdelete_messageвернут ошибку вродеTelegramBadRequest: not enough rights. Сначала повязка, потом обязанности. - Путать мут и бан. Мут (
restrict_chat_member) оставляет человека в чате, просто молчащим, — это мягкая мера. Бан (ban_chat_member) выкидывает совсем. Не банят за первую опечатку, и не удивляются, что замученный всё ещё в списке участников — так и задумано. - Команда без reply ничего не понимает. Если написать просто
/ban, не отвечая ни на чьё сообщение, у бота нетmessage.reply_to_message— он не знает, кого банить. Всегда проверяйif not message.reply_to_messageв начале и подсказывай, что командой надо отвечать на сообщение нарушителя. - Сравнивать текст без приведения регистра. Если в фильтре забыть
text.lower(), то слово «казино» поймается, а «КАЗИНО» или «Казино» проскользнут. Спамеры этим пользуются. Всегда приводи и текст, и слова чёрного списка к одному регистру. - Пытаться забанить другого админа. Telegram не даст боту замутить или забанить участника, у которого прав больше или столько же. Попытка вернёт ошибку. Это защита от того, чтобы бот случайно (или по чьей-то злой команде) не выгнал создателя чата.
Мини-практика: добавь предупреждения перед мутом
Сейчас фильтр сразу мутит за первое же запрещённое слово. Это строго. В реальных чатах часто дают пару предупреждений и только потом наказывают. Доработай Цыплёнка, чтобы он вёл счётчик предупреждений.
- Заведи словарь
warnings = {}, где ключ — id пользователя, а значение — сколько раз он уже нарушил. Подсказка:warnings[user_id] = warnings.get(user_id, 0) + 1аккуратно увеличивает счётчик, даже если пользователя там ещё не было. - В хэндлере фильтра при срабатывании сначала удаляй сообщение и увеличивай счётчик. Если предупреждений меньше трёх — просто пиши «Предупреждение N из 3, за рекламу можно получить мут».
- Когда счётчик дойдёт до трёх — вот тогда мути на час и сбрасывай счётчик обратно в ноль.
- Проверь со второго аккаунта-друга: первые два запрещённых сообщения дают предупреждение, третье — мут.
Бонус для смелых: вынеси список BAD_WORDS в базу SQLite (помнишь таблицы из модуля про данные?) и сделай команду /addbad слово для админа, которая добавляет новое запрещённое слово прямо из чата, без перезапуска бота. Так модерацию можно настраивать на лету.
Итоги и что дальше
Сегодня Цыплёнок-помощник стал настоящим дежурным по чату. Мы разобрали три инструмента модерации и чётко развели их по строгости: delete_message стирает одно сообщение, restrict_chat_member с пустыми ChatPermissions и until_date временно лишает права писать (мут), а ban_chat_member выгоняет нарушителя из чата совсем (бан). Команды /mute и /ban мы научились применять в ответ на сообщение, чтобы не возиться с id вручную. А ещё собрали автоматический фильтр на @dp.message(F.text), который проверяет каждое сообщение функцией has_bad_word и сам удаляет спам и мутит автора. И запомнили главное правило: без админ-прав в группе бот не модерирует ничего.
Теперь твой бот умеет держать порядок без твоего постоянного присутствия — это огромный шаг для группового бота. В следующих уроках раздела мы продолжим прокачивать Цыплёнка как помощника группы: научим его встречать новичков, показывать правила и собирать статистику чата, чтобы он стал не только сторожем, но и приветливым хозяином.