Создание своего собственного телеграм-бота является одним из увлекательных и полезных способов практического применения программирования. Я решил создать своего бота как вариант добавления нового увлекательного проекта в свой портфолио, а также для создания комфорта и удобства для пользователей, которые используют телеграм в своей повседневной жизни.
После анализа нескольких библиотек для создания телеграм-ботов, я выбрал библиотеку Telebot, которая предоставляет богатый набор инструментов для разработки функционально-насыщенных ботов.
Мой бот будет иметь функционал защиты от спама, возможность кикать пользователей с помощью команд, мутить, а также получать статистику. В этой статье подробно рассмотрим функционал моего бота и как я использовал библиотеку Telebot для его создания.
Тестировать бота мы будем с помощью моей жены.
Библиотека Telebot для телеграм ботов на Python предоставляет ряд основных функций:
TeleBot(token)
– конструктор класса, который принимает токен вашего бота.send_message(chat_id, text)
– отправляет сообщение пользователю с указаннымchatid
.sendphoto(chatid, photo)
– отправляет фотографию пользователю с указанным chatid.send_audio(chat_id, audio)
– отправляет аудио файл пользователю с указаннымchatid
.senddocument(chatid, document)
– отправляет документ пользователю с указаннымchatid
.send_video(chat_id, video)
– отправляет видео пользователю с указаннымchatid
.sendlocation(chatid, latitude, longitude)
– отправляет геопозицию пользователю с указаннымchatid
.reply_to(message, text)
– отправляет ответ на сообщение.edit_message_text(chat_id, message_id, text)
– редактирует текст сообщения.delete_message(chat_id, message_id)
– удаляет сообщение.get_updates()
– получает все обновления.get_chat_member(chat_id, user_id)
– получает информацию о пользователе в конкретном чате.get_chat(chat_id)
– получает информацию о чате.
Начнем с импорта необходимых библиотек.
import telebot # сама библиотека telebot
import time # необходим для cрока /mute и автоматического размута после срока мута
Создаем строчку для вписания токена бота, который можно получить от https://t.me/BotFather и так же создаем сам объект бота
bot = telebot.TeleBot('TOKEN') # в TOKEN мы вводим непосредственно сам полученный токен.
Затем определяем словарь для хранения статистики чата.
Далее идут обработчики команд:
команда
/start
выводит приветственное сообщение.команда
/help
выводит список доступных команд.
Словарь для хранения статистики:
stats = {}
Обработчик команды /start:
@bot.message_handler(commands=['start'])
def start(message):
bot.reply_to(message, "Привет! Я бот для управления чатом. Напиши /help, чтобы узнать, что я умею.")
Обработчик команды /help:
@bot.message_handler(commands=['help'])
def help(message):
bot.reply_to(message, "/kick - кикнуть пользователя\n/mute - замутить пользователя на определенное время\n/unmute - размутить пользователя\n/stats - показать статистику чата\n/selfstat - показать свою статистику")
Обработчик команды /kick:
В обработчике команды /kick
проверяется, было ли оно использовано в ответ на сообщение пользователя. Если да, то определяется chat_id
(идентификатор чата) и user_id
(идентификатор пользователя), на которого нужно накинуть мут. Затем проверяется статус пользователя (администратор или нет). Если пользователь является администратором, то выводится сообщение, что кикнуть его невозможно. В противном случае кик происходит с помощью метода kick_chat_member()
и выводится соответствующее сообщение.
@bot.message_handler(commands=['kick'])
def kick_user(message):
if message.reply_to_message:
chat_id = message.chat.id
user_id = message.reply_to_message.from_user.id
user_status = bot.get_chat_member(chat_id, user_id).status
if user_status == 'administrator' or user_status == 'creator':
bot.reply_to(message, "Невозможно кикнуть администратора.")
else:
bot.kick_chat_member(chat_id, user_id)
bot.reply_to(message, f"Пользователь {message.reply_to_message.from_user.username} был кикнут.")
else:
bot.reply_to(message, "Эта команда должна быть использована в ответ на сообщение пользователя, которого вы хотите кикнуть.")
Обработчик команды /mute и /unmute:
Обработчик команды /mute
ограничивает возможности отправки сообщений выбранного пользователя на определенное количество времени. Эта команда принимает аргумент - время в минутах, на которое нужно замутить (ограничить) пользователя. Если аргумент не указан, то устанавливается значение по умолчанию - 1 минута. Если аргумент был указан, то проверяется его корректность и максимальное значение (не больше 1 дня). Если время указано верно, то с помощью метода restrictchatmember()
устанавливается ограничение на отправку сообщений пользователем на заданное время. В случае успеха выводится соответствующее сообщение.
Обработчик команды /unmute
снимает мут с выбранного пользователя. При этом с помощью метода restrictchatmember()
включаются все возможности пользователя для отправки сообщений. В случае успеха также выводится соответствующее сообщение.
Оба обработчика проверяют, было ли вызвано данная команда в ответ на сообщение пользователя. Если да, то определяются chatid
(идентификатор чата) и userid
(идентификатор пользователя), на которого нужно накинуть мут. Также проверяется статус пользователя (администратор или нет). Если пользователь является администратором, то выводится сообщение, что замутить его невозможно. Если команда использована без ответа на сообщение пользователя, которого нужно замутить/размутить, то выводится соответствующее сообщение.
Обработчик команды /mute:
@bot.message_handler(commands=['mute'])
def mute_user(message):
if message.reply_to_message:
chat_id = message.chat.id
user_id = message.reply_to_message.from_user.id
user_status = bot.get_chat_member(chat_id, user_id).status
if user_status == 'administrator' or user_status == 'creator':
bot.reply_to(message, "Невозможно замутить администратора.")
else:
duration = 60 # Значение по умолчанию - 1 минута
args = message.text.split()[1:]
if args:
try:
duration = int(args[0])
except ValueError:
bot.reply_to(message, "Неправильный формат времени.")
return
if duration < 1:
bot.reply_to(message, "Время должно быть положительным числом.")
return
if duration > 1440:
bot.reply_to(message, "Максимальное время - 1 день.")
return
bot.restrict_chat_member(chat_id, user_id, until_date=time.time()+duration*60)
bot.reply_to(message, f"Пользователь {message.reply_to_message.from_user.username} замучен на {duration} минут.")
else:
bot.reply_to(message, "Эта команда должна быть использована в ответ на сообщение пользователя, которого вы хотите замутить.")
Обработчик команды /unmute:
@bot.message_handler(commands=['unmute'])
def unmute_user(message):
if message.reply_to_message:
chat_id = message.chat.id
user_id = message.reply_to_message.from_user.id
bot.restrict_chat_member(chat_id, user_id, can_send_messages=True, can_send_media_messages=True, can_send_other_messages=True, can_add_web_page_previews=True)
bot.reply_to(message, f"Пользователь {message.reply_to_message.from_user.username} размучен.")
else:
bot.reply_to(message, "Эта команда должна быть использована в ответ на сообщение пользователя, которого вы хотите размутить.")
Обработчик команды /stats:
@bot.message_handler(commands=['stats'])
def chat_stats(message):
chat_id = message.chat.id
if chat_id not in stats:
bot.reply_to(message, "Статистика чата пуста.")
else:
total_messages = stats[chat_id]['total_messages']
unique_users = len(stats[chat_id]['users'])
bot.reply_to(message, f"Статистика чата:\nВсего сообщений: {total_messages}\nУникальных пользователей: {unique_users}")
Обработчик команды /selfstat:
@bot.message_handler(commands=['selfstat'])
def user_stats(message):
chat_id = message.chat.id
user_id = message.from_user.id
username = message.from_user.username
if chat_id not in stats:
bot.reply_to(message, "Статистика чата пуста.")
else:
if user_id not in stats[chat_id]['users']:
bot.reply_to(message, "Вы еще не отправляли сообщений в этом чате.")
else:
user_messages = stats[chat_id]['users'][user_id]['messages']
total_messages = stats[chat_id]['total_messages']
percentage = round(user_messages / total_messages * 100, 2)
bot.reply_to(message, f"Статистика для пользователя @{username}:\nВсего сообщений: {user_messages}\nПроцент от общего количества сообщений: {percentage}%")
Данный код содержит два обработчика команд: /stats
и /selfstat
для вывода статистики чата и статистики конкретного пользователя соответственно.
Обработчик команды /stats:
Определяется chat_id текущего чата.
Проверяется, есть ли статистика этого чата в словаре stats.
Если статистика отсутствует, сообщается об этом.
Если статистика есть, выводится общее количество сообщений в чате и количество уникальных пользователей по мнению бота.
Обработчик команды /selfstat:
Определяется chat_id текущего чата и user_id отправителя сообщения.
Проверяется, есть ли статистика этого чата в словаре stats.
Если статистика отсутствует, сообщается об этом.
Если статистика есть, проверяется, были ли сообщения отправлены пользователем в этом чате.
Если пользователь не отправлял сообщений в чате, сообщается об этом.
Если пользователь есть в статистике, выводится количество сообщений, отправленных данным пользователем в чат и процентное соотношение этого количества к общему количеству сообщений в чате.
Делаем защиту от спама по ключевым словам:
Список запрещенных слов:
bad_words = ['анкета', 'ссылка', 'уникальное предложение']
Функция для проверки наличия запрещенных слов в сообщении:
def check_message(message):
for word in bad_words:
if word in message.text.lower():
return True
return False
Обработчик сообщений:
@bot.message_handler(func=lambda message: True)
def handle_message(message):
# проверяем сообщение на наличие запрещенных слов
if check_message(message):
# если есть хотя бы одно запрещенное слово, кикаем пользователя
bot.kick_chat_member(message.chat.id, message.from_user.id)
bot.send_message(message.chat.id, f"Пользователь {message.from_user.username} был удален из чата за использование запрещенных слов")
else:
# если запрещенных слов нет, обрабатываем сообщение дальше
print(message.text)
Сначала в переменную badwords
заносятся все запрещенные слова, которые будут использоваться для проверки сообщений.
Затем создается функция checkmessage
, которая принимает сообщение и проверяет наличие в нем любого из запрещенных слов. Если одно из запрещенных слов есть в сообщении, функция возвращает True, иначе - False.
Далее создается обработчик сообщений, который будет вызываться каждый раз, когда пользователь отправляет сообщение в чат. В нем используется лямбда-функция, которая всегда возвращает значение True
, т.е. она будет обрабатывать все сообщения.
С помощью функции checkmessage
проверяется каждое сообщение на наличие запрещенных слов. Если в сообщении есть запрещенное слово, то бот кикает пользователя, отправляет сообщение о причине кика и завершает обработку сообщения. Если запрещенных слов нет, то бот просто выводит сообщение в консоль.
И еще одна важная строчка:
bot.infinity_polling(none_stop=True)
Эта строчка запускает бота в бесконечном режиме ожидания новых сообщений от пользователей. Метод bot.infinity_polling()
является альтернативой методу bot.polling()
и запускает бота в режиме бесконечного ожидания новых сообщений. Это значит, что бот будет постоянно проверять наличие новых сообщений и обрабатывать их. Параметр none_stop=True
указывает на то, что бот будет продолжать работать даже в случае ошибок или проблем с подключением. Это важно, чтобы бот всегда был доступен для пользователей и мог обрабатывать их запросы.
Заключение
Бот, созданный в рамках данной статьи, является прекрасным примером простого, но полезного бота для управления чатом в Telegram. Кроме того, такой бот может быть использован для сбора статистических данных и аналитики сообщений в чате. Для этого можно реализовать дополнительную функцию /stats, которая будет отображать различные статистические данные, например, количество сообщений за день/неделю/месяц, наиболее активных пользователей и т.д. Для обработки и анализа данных можно использовать библиотеку Pandas, которая предоставляет мощные инструменты для работы с табличными данными и статистическим анализом.
Комментарии (6)
Jury_78
00.00.0000 00:00+3Тестируем на жене
Просится фраза: В процессе теста ни одна жена не пострадала. :)
4uku
00.00.0000 00:00Вы храните статистику в словаре, а значит в памяти. При падении или перезапуске вся статистика обнулится, поэтому можно подключить простую tinydb.
В нескольких хендлерах вы проверяете статус юзера на админа ифами, нарушаете DRY :) может вынести в отдельную функцию и использовать оператор in?
Переменная duration с параметром по умолчанию намекает на то, что это константа, как и bad_words, можно вынести отдельно.
В хендлерк mute_user сно использовать моржовый оператор, где проверка args.
Aleksjar
00.00.0000 00:00+1Как интересную опцию можно рассмотреть возможность по подозрительным словам отправлять сообщение на проверку с помощью open AI API чтобы нейросеть дала свое мнение спам ли это. Не помню сколько поддерживает запросов бесплатный тариф, но если делать так именно с подозрительными сообщения то возможно, что уложитесь во все лимиты и не будете банить за фразы типо «ребят, я тут вчера такую дурацкую анкету заполнял при отборе на позицию».
cartonworld
Просто нажал [Tab] в начале нескольких строк (редактор вместо tab добавляет два пробела), всё ок ????
Если вставить (Ctrl + V) кусок кода из IDE/github, то получается так:
badcasedaily1 Автор
Благодарю. Выяснилось, что добавления окошка "код" и форматирование выделением текста - разные вещи. Отредактировал