Добавление бота в чат.
Начнём с самого начала, а именно с добавления бота в чат.
В чате с ботом открываем его профиль.
Там выбираем пункт "Добавить в группу". В открывшемся списке выбираем необходимую группу.
Бот добавлен, но он не имеет доступа к сообщениям. Он будет работать, если к нему напрямую обращаться по команде, а остальные сообщения он не будет видеть. Это не позволит ему проверять сообщения, а также не позволит работать машине состояний, если будет несколько уровней взаимодействия.
Чтобы разрешить доступ к сообщениям боту, необходимо сделать его администратором чата. Достаточно минимальных прав, либо можно на будущее выбрать необходимое. Всё зависит от требуемого функционала.
Для этого откройте управление группой и выберите пункт "Администраторы". Нажмите "Добавить администратора" и выберите в списке вашего бота.
Затем выберите необходимые права и по желанию боту можно прописать роль.
Готово. Бот добавлен в группу и может читать сообщения.
Получение идентификатора чата.
Для взаимодействия бота с чатом, разграничением функционала и корректной работы, необходимо знать ID-чата.
Есть разные способы получить идентификатор, от простого - воспользоваться другим ботом, до замороченного - вывод идентификатора в консоль при срабатывании команды.
Воспользуемся простым.
Открываем чат с ботом https://t.iss.one/userinfobot
Сразу после запуска он покажет ваш Telegram-ID, но нам необходим ID-чата.
Переходим в чат и пишем сообщение от имени чата. Затем выделяем сообщение и пересылаем его в ранее упомянутого бота.
В ответ он пришлёт идентификатор чата начинающийся со знака
Отлично. Теперь у вас есть идентификатор вашего чата.
Доработка кода бота.
Разобравшись с формальностями, перейдём к коду. Откроем файл
У нас есть
Добавим новую строчку:
Вместо
Меню для чата.
На данный момент в моём боте есть четыре команды:
-
-
-
-
Однако, в чате в первых двух командах нет необходимости. Я хочу, чтобы они были доступны только из бота и их не было видно в меню чата.
Для этого откроем файл
В теле функции
Ниже до команды
У меня на данный момент это две команды:
-
-
Ниже, под
Новая строка:
Теперь в чате будут отображаться только необходимые команды.
Ограничение существующих команд.
Теперь необходимо ограничить существующие команды от выполнения в чате. Это необходимо сделать, поскольку команду можно написать и не открывая меню и если команда там не указана, не значит, что она не может быть выполнена.
Откроем файл
Получится вот так:
Во второй функции нет необходимости в проверке, поскольку в неё не попасть без первой.
Начнём с самого начала, а именно с добавления бота в чат.
В чате с ботом открываем его профиль.
Там выбираем пункт "Добавить в группу". В открывшемся списке выбираем необходимую группу.
Бот добавлен, но он не имеет доступа к сообщениям. Он будет работать, если к нему напрямую обращаться по команде, а остальные сообщения он не будет видеть. Это не позволит ему проверять сообщения, а также не позволит работать машине состояний, если будет несколько уровней взаимодействия.
Чтобы разрешить доступ к сообщениям боту, необходимо сделать его администратором чата. Достаточно минимальных прав, либо можно на будущее выбрать необходимое. Всё зависит от требуемого функционала.
Для этого откройте управление группой и выберите пункт "Администраторы". Нажмите "Добавить администратора" и выберите в списке вашего бота.
Затем выберите необходимые права и по желанию боту можно прописать роль.
Готово. Бот добавлен в группу и может читать сообщения.
Получение идентификатора чата.
Для взаимодействия бота с чатом, разграничением функционала и корректной работы, необходимо знать ID-чата.
Есть разные способы получить идентификатор, от простого - воспользоваться другим ботом, до замороченного - вывод идентификатора в консоль при срабатывании команды.
Воспользуемся простым.
Открываем чат с ботом https://t.iss.one/userinfobot
Сразу после запуска он покажет ваш Telegram-ID, но нам необходим ID-чата.
Переходим в чат и пишем сообщение от имени чата. Затем выделяем сообщение и пересылаем его в ранее упомянутого бота.
В ответ он пришлёт идентификатор чата начинающийся со знака
-. Всё верно, Идентификаторы пользователей - целое число, а идентификаторы чатов и каналов - отрицательное.Отлично. Теперь у вас есть идентификатор вашего чата.
Доработка кода бота.
Разобравшись с формальностями, перейдём к коду. Откроем файл
settings.py.У нас есть
Dataclass Secrests в котором мы храним важные для работы бота данные, а именно токен и идентификатор администратора.Добавим новую строчку:
group_id: int = -12345
Вместо
-12345 вставляем идентификатор вашего чата.Меню для чата.
На данный момент в моём боте есть четыре команды:
-
start - Начало работы-
get_file - Получение файла с материалами-
help - Помощь по доступным командам-
about - Информация о ботеОднако, в чате в первых двух командах нет необходимости. Я хочу, чтобы они были доступны только из бота и их не было видно в меню чата.
Для этого откроем файл
commands.py.В теле функции
set_commands находится список commands, определяющий меню бота. Его мы не трогаем. Ниже до команды
await bot.set_my_commands создаём новый список commands_chat и вписываем туда, по аналогии со списком выше, команды доступные в чате.У меня на данный момент это две команды:
-
help - Помощь по доступным командам-
about - Информация о ботеНиже, под
await bot.set_my_commands добавляем ещё одну такую же строчку. Изменив первый аргумент на новый список, а во втором прописав BotCommandScopeChat(chat_id=Secrets.group_id). Так мы определяем, что меню будет доступно в конкретном чате.Новая строка:
from botlogic.settings import Secrets
await bot.set_my_commands(commands_chat, BotCommandScopeChat(chat_id=Secrets.group_id))
Теперь в чате будут отображаться только необходимые команды.
Ограничение существующих команд.
Теперь необходимо ограничить существующие команды от выполнения в чате. Это необходимо сделать, поскольку команду можно написать и не открывая меню и если команда там не указана, не значит, что она не может быть выполнена.
Откроем файл
send_file.py и в самое начало функции send_file_start добавим условие:from botlogic.settings import Secrets
if message.chat.id != Secrets.group_id:
Получится вот так:
async def send_file_start(message: Message, state: FSMContext):
if message.chat.id != Secrets.group_id:
await message.answer(views.send_file_start_msg())
await state.set_state(SendFileSteps.get_code_from_user)
Во второй функции нет необходимости в проверке, поскольку в неё не попасть без первой.
Далее откроем файл
Функция
Функция
Сперва добавим условие, как и раньше, ниже прописываем
Получается вот так:
Переходим во
Завершение.
Готово. Бот подготовлен к работе в чате. В следующем посте начнём делать самую востребованную функцию.
Всё правильно, это погода.
Файлы к посту, можно получить в боте по коду: 385736
Пост на сайте.
Поддержать канал.
simple.py и добавим такое же условие к функции start_command.Функция
about_command у меня универсальна, оставляем как есть.Функция
help_command выводит текст со списком доступных команд, следовательно, необходимо сделать две текстовые функции в файле views.py. Сперва добавим условие, как и раньше, ниже прописываем
else и повторяем команду с сообщением, изменив название функции, например, на help_chat_message.Получается вот так:
async def help_command(message: Message):
if message.chat.id != Secrets.group_id:
await message.answer(views.help_message())
else:
await message.answer(views.help_chat_message())
Переходим во
views.py и создаём функцию, возвращающую текст с новым списком команд.Завершение.
Готово. Бот подготовлен к работе в чате. В следующем посте начнём делать самую востребованную функцию.
Всё правильно, это погода.
Файлы к посту, можно получить в боте по коду: 385736
Пост на сайте.
Поддержать канал.
Внезапный ночной опрос)
В какое время вам комфортнее работать/кодить?
В какое время вам комфортнее работать/кодить?
Anonymous Poll
39%
Ночью никто не отвлекает!
17%
По утрам голова свежее =)
5%
Только днем и не раньше обеда!!
39%
Пока то, пока сё, вот уже и вечер. Самое время)
AIOgram3 13. Прогноз погоды в боте - OpenWeatherMap
Самое востребованное в чате и наверное, одно из самых простых применений бота - прогноз погоды.
Использовать будем сервис
На бесплатном тарифе нам доступно 60 запросов в минуту и 1000 в день.
Регистрация и получение API-ключа.
Начнём с регистрации и получение ключа для API. После его получения, он начинает действовать в течении "пары часов", как раз успеем написать код.
Переходим на сайт: https://home.openweathermap.org/users/sign_in
Нажимаем на "Create an Account."
Вводим ник, почту, два раза пароль и отмечаем две первые галочки. Другие три галочки не трогаем, если конечно вы не желаете получать спам. Проходим капчу и нажимаем "Create Account".
Далее нас спросят с какой мы целью тут. Я выбрал "Education/Science". И ведь не соврал 😉. Нажимаем "Save".
Далее необходимо подтвердить электронную почту.
Самое востребованное в чате и наверное, одно из самых простых применений бота - прогноз погоды.
Использовать будем сервис
OpenWeatherMap.На бесплатном тарифе нам доступно 60 запросов в минуту и 1000 в день.
Регистрация и получение API-ключа.
Начнём с регистрации и получение ключа для API. После его получения, он начинает действовать в течении "пары часов", как раз успеем написать код.
Переходим на сайт: https://home.openweathermap.org/users/sign_in
Нажимаем на "Create an Account."
Вводим ник, почту, два раза пароль и отмечаем две первые галочки. Другие три галочки не трогаем, если конечно вы не желаете получать спам. Проходим капчу и нажимаем "Create Account".
Далее нас спросят с какой мы целью тут. Я выбрал "Education/Science". И ведь не соврал 😉. Нажимаем "Save".
Далее необходимо подтвердить электронную почту.
👍1
Сверху-справа нажимаем на свой ник, в выпадающем списке выбираем пункт "My API keys". Оказываемся на странице, где уже есть один ключ. Также после подтверждения почты, ключ и сопутствующая информация придёт на почту.
Как я и упомянул ранее, он активируется не сразу, а спустя какое-то время, поэтому переходим к коду.
Добавляем ключ.
Для начала, добавим API-ключ в наши "секреты".
Откроем файл
Получение погоды.
В пакете
Создаём функцию
Код функции:
В переменную
С помощью библиотеки
Вторым аргументом передаём словарь параметров, подробнее по пунктам:
-
-
-
-
-
Далее идёт проверка, если в ответе
Иначе, возвращаем результат выполнения функции генерирующей строку с результатом.
Парсинг ответа и генерация строки с результатом.
Под функцией
Код функции:
Тут мы из ответа получаем значения в 8 переменных, затем формируем строку с результатом.
Строку и необходимые данные можно кастомизировать по желанию.
Команда получения погоды.
Теперь перейдём к созданию команды. В пакете
Создадим асинхронную функцию
В теле функции прописываем две команды:
- Отправка сообщения пользователю. В сообщении просим ввести город или отменить запрос.
- Переход на следующий шаг в машине состояний.
Код функции:
Для первой команды необходимо открыть файл
Для второй команды необходимо открыть файл
Как я и упомянул ранее, он активируется не сразу, а спустя какое-то время, поэтому переходим к коду.
Добавляем ключ.
Для начала, добавим API-ключ в наши "секреты".
Откроем файл
settings.py и добавим новую строку в классе Secrets:weather_key: str = 'ваш ключ'
Получение погоды.
В пакете
utils создадим новый файл get_weather.py.Создаём функцию
request_weather, принимающую один аргумент city.Код функции:
import requests
from botlogic.settings import Secrets
def request_weather(city):
result = requests.get("https://api.openweathermap.org/data/2.5/find",
params={
'q': city,
'type': 'like',
'units': 'metric',
'lang': 'ru',
'APPID': Secrets.weather_key,
}).json()
if result['count'] == 0:
return 0
else:
return generate_result(result, city)
В переменную
result попадает JSON с ответом от сервера. С помощью библиотеки
requests делаем GET-запрос. Первым аргументом передаём API URL.Вторым аргументом передаём словарь параметров, подробнее по пунктам:
-
q - отправляемый запрос, в нашем случае это город.-
type - тип поиска, в нашем случае ищем по совпадению.-
units - система измерения, в нашем случае метрическая.-
lang - язык.-
APPID - API-ключ.Далее идёт проверка, если в ответе
count равен нулю, то либо пользователь ошибся в названии города, либо такого города нет в базе сервиса. Возвращаем 0.Иначе, возвращаем результат выполнения функции генерирующей строку с результатом.
Парсинг ответа и генерация строки с результатом.
Под функцией
request_weather создаём новую функцию generate_result, принимающую данные из сервиса data и город city.Код функции:
def generate_result(data, city):
temp = int(data['list'][0]['main']['temp'])
feels_like = data['list'][0]['main']['feels_like']
pressure = int(data['list'][0]['main']['pressure']) * 0.75
humidity = data['list'][0]['main']['humidity']
wind_speed = int(data['list'][0]['wind']['speed'])
rain = 'не ожидается' if data['list'][0]['rain'] is None else 'ожидается'
snow = 'не ожидается' if data['list'][0]['snow'] is None else 'ожидается'
weather = data['list'][0]['weather'][0]['description']
return f'''
<b>Прогноз погоды в городе {city}</b>
Сейчас температура {temp}°C
Ощущается как {feels_like}°
⛅️{weather}⛅️
💨 Скорость ветра {wind_speed}м/с 💨
Давление {pressure} мм рт.ст.
Влажность {humidity}%
💦 Дождь {rain}
❄️ Снег {snow}
'''
Тут мы из ответа получаем значения в 8 переменных, затем формируем строку с результатом.
Строку и необходимые данные можно кастомизировать по желанию.
Команда получения погоды.
Теперь перейдём к созданию команды. В пакете
handlers создадим файл weather_fsm.py.Создадим асинхронную функцию
get_weather_command, принимающую два аргумента: message и state.В теле функции прописываем две команды:
- Отправка сообщения пользователю. В сообщении просим ввести город или отменить запрос.
- Переход на следующий шаг в машине состояний.
Код функции:
from aiogram.fsm.context import FSMContext
from aiogram.types import Message
from botlogic import views
from botlogic.utils.statesform import GetWeatherSteps
async def get_weather_command(message: Message, state: FSMContext):
await message.answer(views.enter_city())
await state.set_state(GetWeatherSteps.BY_CITY)
Для первой команды необходимо открыть файл
views.py и создать функцию enter_city, возвращающую строку с просьбой ввести город или отменить запрос.Для второй команды необходимо открыть файл
statesform.py и создать новый класс GetWeatherSteps:class GetWeatherSteps(StatesGroup):
BY_CITY = State()
👍1
Возвращаемся в файл
Код функции:
Первым делом проверяем, отменил пользователь запрос или нет.
Если запрос отменён, выводим сообщение и очищаем состояние.
Если отмены не произошло, вызываем функцию получения погоды, передав туда сообщение пользователя.
Далее снова проверка. Если вернулась сформированная строка, отвечаем пользователю сформированной строкой, затем отправляем сообщение, что задача выполнена и очищаем состояние.
Иначе, если вернулся
Готово. Осталось только зарегистрировать команды и прописать в меню.
Регистрация команды.
Откроем файл
Ниже добавим следующие строки:
Добавляем в меню.
Откройте файл
Добавьте команду в меню, по аналогии с другими:
Завершение.
Поздравляю. Теперь ваш бот умеет сообщать прогноз погоды.
Как я и говорил в начале, добавление функционала погоды, достаточно простое. Также оно служит "примером" использования бота для получения каких-либо данных по API.
Файлы к посту, можно получить в боте по коду: 603735
Пост на сайте.
Поддержать канал.
weather_fsm.py и ниже создаём вторую функцию get_by_city.Код функции:
from botlogic.utils.get_weather import request_weather
from botlogic.settings import bot
async def get_by_city(message: Message, state: FSMContext):
if message.text.lower() == 'отмена':
await message.answer(views.abort_weather())
await state.clear()
else:
result = request_weather(message.text)
if result:
await message.reply(result)
await message.answer(views.weather_request_done())
await state.clear()
else:
await bot.send_message(message.chat.id, views.weather_wrong_city())
await state.set_state(GetWeatherSteps.BY_CITY)
Первым делом проверяем, отменил пользователь запрос или нет.
Если запрос отменён, выводим сообщение и очищаем состояние.
Если отмены не произошло, вызываем функцию получения погоды, передав туда сообщение пользователя.
Далее снова проверка. Если вернулась сформированная строка, отвечаем пользователю сформированной строкой, затем отправляем сообщение, что задача выполнена и очищаем состояние.
Иначе, если вернулся
0, просим пользователя повторить попытку или отменить запрос.Готово. Осталось только зарегистрировать команды и прописать в меню.
Регистрация команды.
Откроем файл
main.py и найдем другие зарегистрированные команды.Ниже добавим следующие строки:
from botlogic.handlers import weather_fsm
from botlogic.utils.statesform import GetWeatherSteps
dp.message.register(weather_fsm.get_weather_command, Command(commands='weather'))
dp.message.register(weather_fsm.get_by_city, GetWeatherSteps.BY_CITY)
Добавляем в меню.
Откройте файл
commands.py в пакете utils.Добавьте команду в меню, по аналогии с другими:
BotCommand(
command='weather',
description='Получить прогноз погоды'
),
Завершение.
Поздравляю. Теперь ваш бот умеет сообщать прогноз погоды.
Как я и говорил в начале, добавление функционала погоды, достаточно простое. Также оно служит "примером" использования бота для получения каких-либо данных по API.
Файлы к посту, можно получить в боте по коду: 603735
Пост на сайте.
Поддержать канал.
🔥2
Состоялся релиз новой версии Python - 3.12.
Из ключевых изменений:
- Улучшена работа с f-строками.
- Улучшена поддержка многоядерных систем, за счёт определения добавления поддержки изолированных субинтерпретаторов и отдельных GIL.
- Улучшена работа с ошибками и подсказками для ошибок.
Подготовил для вас перевод ключевых изменений.
Пост на сайте.
Поддержать проект.
Из ключевых изменений:
- Улучшена работа с f-строками.
- Улучшена поддержка многоядерных систем, за счёт определения добавления поддержки изолированных субинтерпретаторов и отдельных GIL.
- Улучшена работа с ошибками и подсказками для ошибок.
Подготовил для вас перевод ключевых изменений.
Пост на сайте.
Поддержать проект.
🔥7
Правительство РФ и США сегодня проведут проверку системы оповещения населения через мобильные телефоны.
А вы уже выключили мобилку и замотали её в фольгу?
А вы уже выключили мобилку и замотали её в фольгу?
Anonymous Poll
11%
А? ЧТО? ГДЕ МОЯ ФОЛЬГА?! *надевая шапочку*😱
4%
Пойду-ка я до магаза... Ковидные запасы гречки и туалетки кончаются😬
32%
Да всё нормуль будет, чипы от привики активируют и всё🙄
54%
О чём вы вообще?😁
Статистика сайта за 3 месяца
Месяц назад я закончил выкладывать на сайт вышедшие в Telegram-канале посты. На тот момент сайту было 2 месяца.
С того времени сайт начал появляться в выдаче поисковых систем и появились переходы из них. Переходы из поиска занимают третье место по числу пользователей.
На втором месте переходы из Telegram-канала. Тут всё понятно.
Удивительно, но на первом месте стоят переходы из Dzen. Я туда дублирую посты, статистика там неважная - практически нет подписчиков, дочитываний статей очень мало, кликов из ленты и того меньше. Тем не менее это на данный момент основной источник трафика на сайт.
В сухом итоге:
- Посетители: Было 136, стало 210. Прирост 54.41%.
- Переходы из Dzen: Было 15.9%, стало 37.6%. Прирост 136.47%.
- Переходы из Telegram-канала: Было 12.2%, стало 24.2%. Прирост 98.36%.
- Переходы из поиска: Было 0%, стало 17.6%.
Я считаю, это хороший результат. Пишите в комментариях, если интересно наблюдать статистику каждый месяц.
Пост на сайте.
Поддержать канал.
Месяц назад я закончил выкладывать на сайт вышедшие в Telegram-канале посты. На тот момент сайту было 2 месяца.
С того времени сайт начал появляться в выдаче поисковых систем и появились переходы из них. Переходы из поиска занимают третье место по числу пользователей.
На втором месте переходы из Telegram-канала. Тут всё понятно.
Удивительно, но на первом месте стоят переходы из Dzen. Я туда дублирую посты, статистика там неважная - практически нет подписчиков, дочитываний статей очень мало, кликов из ленты и того меньше. Тем не менее это на данный момент основной источник трафика на сайт.
В сухом итоге:
- Посетители: Было 136, стало 210. Прирост 54.41%.
- Переходы из Dzen: Было 15.9%, стало 37.6%. Прирост 136.47%.
- Переходы из Telegram-канала: Было 12.2%, стало 24.2%. Прирост 98.36%.
- Переходы из поиска: Было 0%, стало 17.6%.
Я считаю, это хороший результат. Пишите в комментариях, если интересно наблюдать статистику каждый месяц.
Пост на сайте.
Поддержать канал.
🔥8
AIOgram3 14. Фильтруем запрещённые слова
Следующей задачей для бота является фильтрация сообщений от запрещённый слов.
Задача не самая сложная, но есть пара нюансов.
Первый - что делать с сообщением?
Сообщение другого пользователя нельзя отредактировать удалив оттуда нежелательные слова. Его можно удалить, но бывают ситуации когда пользователь пишет большое сообщение и может вставить туда какое-то ругательство и весь его труд будет потерян.
Решение будет следующим:
- Пользовательское сообщение проверяется на наличие слова в нём
- В случае нахождения, создаётся копия сообщения
- Затем из копии удаляются / заменяются на звёздочки / модифицируются слова. Тут уже зависит от того, какой результат вы хотите получить. В моём случае слова будут заменяться на звёздочки.
- Далее удаляется оригинальное сообщение и от имени бота отправляется новое, содержащее имя отправителя и отредактированное сообщение.
Следующей задачей для бота является фильтрация сообщений от запрещённый слов.
Задача не самая сложная, но есть пара нюансов.
Первый - что делать с сообщением?
Сообщение другого пользователя нельзя отредактировать удалив оттуда нежелательные слова. Его можно удалить, но бывают ситуации когда пользователь пишет большое сообщение и может вставить туда какое-то ругательство и весь его труд будет потерян.
Решение будет следующим:
- Пользовательское сообщение проверяется на наличие слова в нём
- В случае нахождения, создаётся копия сообщения
- Затем из копии удаляются / заменяются на звёздочки / модифицируются слова. Тут уже зависит от того, какой результат вы хотите получить. В моём случае слова будут заменяться на звёздочки.
- Далее удаляется оригинальное сообщение и от имени бота отправляется новое, содержащее имя отправителя и отредактированное сообщение.
Второй - сложность алгоритма и затрачиваемые ресурсы.
В используемом списке бранных слов насчитывается свыше 1000 слов.
Сообщение от пользователя очищается от пунктуации и разделяется на множество (set) слов.
При большом потоке сообщений, это может сильно увеличить нагрузку на сервер и замедлить работу бота.
Я опишу уже улучшенный вариант, к которому мы пришли с подписчиком @rusheslav после тестирования фильтра в чате, но если у вас есть комментарии или рекомендации по улучшению кода, буду рад!
Множество запрещённых слов.
Использовать будем готовый список: https://github.com/bars38/Russian_ban_words
Вы можете составить свой или найти другой.
Скачиваем файл
В корне проекта создаём директорию
Открываем файл
В этой константе создаётся множество из слов в файле.
Фильтрующая функция.
В пакете
Создаём асинхронную функцию
Код функции:
По ходу действий:
Создаём переменную
После проверки на наличие сообщения создаём переменную
Далее проходимся циклом
Если слово есть среди запрещённых, заменяем его на звёздочки в количестве длинны слова и выставляем "флаг" о наличии в тексте запрещённых слов.
Далее проверка "флага", если переменная
В противном случае бот сперва удаляет исходное сообщение. Записывает сообщение и информацию от кого в лог файл. Затем отправляет стикер по его идентификатору, после чего отправляет сообщение с исправленным текстом.
Как получить идентификатор стикера.
Для получения идентификатора стикера, достаточно отправить боту https://t.iss.one/idstickerbot стикер, идентификатор которого хотите получить.
В ответ он пришлёт идентификатор.
Готово.
Завершение
Осталось только зарегистрировать обработчик. Добавляем в файл
Готово. Теперь бот фильтрует нежелательные слова в сообщениях. Конечно это не панацея и мы все знаем, как можно исхитриться в Русском языке, но основную часть отсеивать будет. А потом просто добавляем слова.
Дополнительно: Изменение логгера.
Изначально логгер находился в файле
Вынес логгер в файл
В используемом списке бранных слов насчитывается свыше 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.iss.one/idstickerbot стикер, идентификатор которого хотите получить.
В ответ он пришлёт идентификатор.
Готово.
Завершение
Осталось только зарегистрировать обработчик. Добавляем в файл
main.py следующую строку: dp.message.register(check_message). Отсутствие второго аргумента означает, что бот будет обрабатывать все сообщения.Готово. Теперь бот фильтрует нежелательные слова в сообщениях. Конечно это не панацея и мы все знаем, как можно исхитриться в Русском языке, но основную часть отсеивать будет. А потом просто добавляем слова.
Дополнительно: Изменение логгера.
Изначально логгер находился в файле
main.py и не записывал никуда события, только отображал в терминале.Вынес логгер в файл
settings.py. Определил два обработчика, для терминала и для файла.Код нового логгера:
Файлы к посту, можно получить в боте по коду: 702209
Пост на сайте.
Поддержать канал.
# Логгер
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)
Файлы к посту, можно получить в боте по коду: 702209
Пост на сайте.
Поддержать канал.
Возрастной опрос =)
Сколько вам лет?
Сколько вам лет?
Anonymous Poll
3%
До 15
0%
От 16 до 18
13%
От 19 до 25
40%
От 26 до 35
36%
От 36 до 45
6%
От 46 до 55
1%
От 56
1%
Не скажу, я стесняшка☺️
😱5