AIOgram3 14. Фильтруем запрещённые слова
В этом посте сделаем так, чтобы бот фильтровал нежелательные слова в сообщениях пользователей. А так же, расскажу как получить идентификатор стикера в Telegram и об изменениях в логгере.
Дополнительные материалы
Для скачивания материалов необходимо войти или зарегистрироваться
Файлы также можно получить в Telegram-боте по коду: 702209
Реклама
Следующей задачей для бота является фильтрация сообщений от запрещённый слов.
Задача не самая сложная, но есть пара нюансов.
Первый - что делать с сообщением?
Сообщение другого пользователя нельзя отредактировать удалив оттуда нежелательные слова. Его можно удалить, но бывают ситуации когда пользователь пишет большое сообщение и может вставить туда какое-то ругательство и весь его труд будет потерян.
Решение будет следующим:
- Пользовательское сообщение проверяется на наличие слова в нём
- В случае нахождения, создаётся копия сообщения
- Затем из копии удаляются / заменяются на звёздочки / модифицируются слова. Тут уже зависит от того, какой результат вы хотите получить. В моём случае слова будут заменяться на звёздочки.
- Далее удаляется оригинальное сообщение и от имени бота отправляется новое, содержащее имя отправителя и отредактированное сообщение.
Второй - сложность алгоритма и затрачиваемые ресурсы.
В используемом списке бранных слов насчитывается свыше 1000 слов.
Сообщение от пользователя очищается от пунктуации и разделяется на множество (set) слов.
При большом потоке сообщений, это может сильно увеличить нагрузку на сервер и замедлить работу бота.
Я опишу уже улучшенный вариант, к которому мы пришли с подписчиком @rusheslav после тестирования фильтра в чате, но если у вас есть комментарии или рекомендации по улучшению кода, буду рад!
Множество запрещённых слов.
Использовать будем готовый список: https://github.com/bars38/Russian_ban_words
Вы можете составить свой или найти другой.
Скачиваем файл words.txt
. Для большей наглядности, я его переименовал в ban_words.txt
.
В корне проекта создаём директорию res
и помещаем туда файл.
Открываем файл settings.py
и в начале, после импортов создаём константу BAN_WORDS
.
В этой константе создаётся множество из слов в файле.
BAN_WORDS = set(line.strip() for line in open('res/ban_words.txt'))
Фильтрующая функция.
В пакете handlers
создадим новый файл filter_words.py
.
Создаём асинхронную функцию check_message
, принимающую message
.
Код функции:
import string
from aiogram.types import Message
from botlogic import views
from botlogic.settings import BAN_WORDS, logger
async def check_message(message: Message):
contains_ban_word = False
if message.text:
message_words = set(message.text.translate(str.maketrans('', '', string.punctuation)).split())
filtered_message = message.text
for word in message_words:
if word.lower() in BAN_WORDS:
filtered_message = filtered_message.replace(word, "*" * len(word))
contains_ban_word = True
if contains_ban_word:
await message.delete()
logger.info(f"Удалено сообщение от пользователя {message.from_user.username}: {message.text}")
await message.answer_sticker('CAACAgIAAxkBAAEKbW1lGVW1I6zFVLyovwo2rSgIt1l35QADJQACYp0ISWYMy8-mubjIMAQ')
await message.answer(views.filtered_message(message.from_user.username, filtered_message))
По ходу действий:
Создаём переменную contains_ban_word
. Это "флаг", по умолчанию считаем, что в сообщении нет запрещённых слов.
После проверки на наличие сообщения создаём переменную message_words
, в которой создаём множество очищенных от пунктуации слов. Множество не позволяет хранить в себе два одинаковых объекта, тем самым в переменной будут только уникальные слова. И переменную filtered_message
, в которую помещаем копию сообщения.
Далее проходимся циклом for
по множеству слов из сообщения.
Если слово есть среди запрещённых, заменяем его на звёздочки в количестве длинны слова и выставляем "флаг" о наличии в тексте запрещённых слов.
Далее проверка "флага", если переменная contains_ban_word
по-прежнему в изначальном состоянии False
, то бот ничего не делает.
В противном случае бот сперва удаляет исходное сообщение. Записывает сообщение и информацию от кого в лог файл.
Затем отправляет стикер по его идентификатору.
После чего отправляет сообщение с исправленным текстом.
Как получить идентификатор стикера.
Для получения идентификатора стикера, достаточно отправить боту https://t.me/idstickerbot стикер, идентификатор которого хотите получить.
В ответ он пришлёт идентификатор.
Готово.
Завершение.
Осталось только зарегистрировать обработчик. Добавляем в файл main.py
следующую строку: dp.message.register(check_message)
. Отсутствие второго аргумента означает, что бот будет обрабатывать все сообщения.
Готово. Теперь бот фильтрует нежелательные слова в сообщениях. Конечно это не панацея и мы все знаем, как можно исхитриться в Русском языке, но основную часть отсеивать будет. А потом просто добавляем слова.
Пост на сайте.
Поддержать канал.
Дополнительно: Изменение логгера.
Изначально логгер находился в файле main.py
и не записывал никуда события, только отображал в терминале.
Вынес логгер в файл settings.py
. Определил два обработчика, для терминала и для файла.
Код нового логгера:
# Логгер
logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter(
"%(asctime)s - [%(levelname)s] - %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s")
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(formatter)
file_handler = logging.FileHandler("logs.txt")
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter)
logger.addHandler(console_handler)
logger.addHandler(file_handler)
Все статьи