Кружки Иванова — это отдельный вид искусства. Вот только тех, кто способен подобное повторить, единицы. Оно и понятно, ведь спамить в каждый отдельный чат ручками — тот еще адище.
Впрочем, о тех, кто все же делает это вручную, не хочется даже и говорить… С другой стороны, у них ведь не было нашего бота, который возьмет на себя всю рутину и сделает твой спам кружками таким же весомым, как у Е. Ю.
Какие задачи решает бот для рассылки кружков по чатам
Внезапно, но основная задача, которую решает бот для рассылки кружков по чатам, — рассылка кружков по чатам. Собственно говоря, с технической точки зрения он больше никаких задач и не решает (ну, кроме обеспечения скрытности действий при привязке чата к боту, но говорить об одной-единственной функции как о фиче для решения задач — как будто бы не совсем уместно).
Как бы там ни было, путем обеспечения реализации своей основной задачи бот также может способствовать решению следующих задач:
Прокачка личного бренда — если мелькать лицом в каждом чате, тебя неизбежно запомнят.
Оперативное распространение инфоповода — на удивление, кто-то все эти кружки смотрит (но это не точно).
Нативная реклама — здесь все зависит от фантазии. Самое банальное — просто надеть мерч рекла и задвигать что-то свое по сабжу чата.
Повышение активности в чате — будучи элементом интерактива, кружки могут повысить вовлеченность в обсуждение.
Сведение активности в чате на ноль — а могут и убить любой актив. В особенности если спамить ими каждый день или вообще — после каждого «не кружка». Сотни мертвых аффилиат-чатов, где, кроме кружков Е. Ю., ничего нет — лучшее тому подтверждение.
А вообще, все упирается лишь в фантазию. Лопатой, знаете ли, тоже не только копать можно.
Принцип работы бота для рассылки кружков по чатам
Алгоритмически бот реализован на user-api. Банально потому, что в противном случае кружки будет рассылать не ваш профиль, а профиль бота с припиской «бот». А оно вам надо? Да и в чужой чат бота не добавишь. А пользовательский профиль — хоть тыщу раз. Сама логика же реализована следующим образом:
- Бот постоянно слушает эфир, игнорируя любые сообщения, кроме исходящих от аккаунта, к которому он подвязан.
- Игнорирует ввод команд в любом месте, кроме «Избранного».
- При вводе команды /add — добавляет чат в список.
- При вводе команды /del — удаляет чат из списка.
- При вводе команды /clear — очищает список.
- При вводе команды /list — выводит список списков.
- В случае если синтаксис или условия выполнения вводимой команды не соблюдены — оповещает юзера об этом, уточняя, что нужно сделать, чтоб все работало.
- В случае отсутствия указания списка в синтаксисе команды — производит текущую манипуляцию со списком default.
- В случае отсутствия указания ID чата, но при наличии пересланного от имени этого чата сообщения в сообщения с вводимой командой, — автоматически его подставляет.
- При вводе команды /go делает рассылку выбранного кружка.
- При вводе сообщений (не путать с командой) «йоу!» в ЛЮБОМ чате — автоматически добавляет этот в список default (сделано для добавления тех чатов, где от имени чата ничего не пишется).
- При вводе сообщений (не путать с командой) «йоу2» в ЛЮБОМ чате — создает сообщение с id этого чата в «Избранном» (сделано для обеспечения возможности разделения чатов, где от имени чата ничего не пишется, по разным спискам).
* Триггерные фразы «йоу!» и «йоу2» рекомендуется заменить. Мы специально оставили их нарочито неорганичными, чтобы потенциальные пользователи бота заменяли стандартный вариант, а не спамили одинаковыми сообщениями (хотя если начнется массовое йоу2, то автор кнш покекает…) и не палились друг перед другом.
Пошаговая инструкция, как сделать бот для рассылки кружков по чатам
Данный бот полностью реализован через user_api, поэтому вместо привычного BotFather у нас здесь авторизация через веб-версию Телеги для разрабов. Собственно:
- Открываем веб-версию.
- Находим и жамкаем по «API development tools», заполняем анкету.
- Копипастим куда-то api_id и api_hash.
Затем нам нужен сервер. Гайд, как развернуть собственный, вот здесь. Но в целом подойдет любой, который поддерживает Python. Также сервер нужно настроить, для этого вводим в его консоли:
pip install telethon
Далее
1. В корневой директории сервера создаем bot.py
2. Открываем его текстовым редактором и вводим:
import json
import os
from telethon import TelegramClient, events
api_id = ВАШ АПИ ИД
api_hash = 'ВАШ АПИ ХЭШ'
phone_number = 'ВАШ ТЕЛЕФОН'
DATA_FILE = "chats.json"
YO_WORD_ADD = "йоу!"
YO_WORD_SHOW = "йоу2"
if os.path.exists(DATA_FILE):
with open(DATA_FILE, "r", encoding="utf-8") as f:
chat_lists = json.load(f)
else:
chat_lists = {"default": []}
client = TelegramClient("circle_forwarder", api_id, api_hash)
def save_data():
with open(DATA_FILE, "w", encoding="utf-8") as f:
json.dump(chat_lists, f, ensure_ascii=False, indent=2)
async def resolve_chat(ref):
try:
entity = await client.get_entity(ref)
return entity
except Exception as e:
print(f"Ошибка при получении entity {ref}: {e}")
return None
@client.on(events.NewMessage)
async def handler(event):
text = (event.text or "").strip()
me = await client.get_me()
if event.sender_id != me.id:
return
if text == YO_WORD_ADD:
chat = await event.get_chat()
if chat.id not in chat_lists["default"]:
chat_lists["default"].append(chat.id)
save_data()
await client.send_message("me", f"✅ Чат {getattr(chat,'title',chat.id)} автоматически добавлен в default")
return
elif text == YO_WORD_SHOW:
chat = await event.get_chat()
await client.send_message("me", f"Чат: {getattr(chat,'title',chat.id)}, id:")
await client.send_message("me", f"{chat.id}")
return
if text.startswith("/add"):
parts = text.split(maxsplit=2)
list_name = "default"
if len(parts) == 3:
list_name = parts[2].strip()
if list_name not in chat_lists:
chat_lists[list_name] = []
chat_id = None
if event.is_reply:
reply = await event.get_reply_message()
if reply.forward and reply.forward.chat:
chat_id = reply.forward.chat.id
else:
try:
chat_id = int(reply.text.strip())
except:
await client.send_message("me", "Неверный формат. Ответьте на репост или на сообщение с ID")
return
else:
if len(parts) >= 2:
ref = parts[1].strip()
try:
entity = await resolve_chat(ref)
chat_id = entity.id if entity else int(ref)
except:
await client.send_message("me", "Неверный формат id/username")
return
else:
await client.send_message("me", "Используй: /add <id|username> [список] или ответом на репост/сообщение с id")
return
if chat_id not in chat_lists[list_name]:
chat_lists[list_name].append(chat_id)
save_data()
await client.send_message("me", f"✅ Добавлен чат в список '{list_name}': {chat_id}")
else:
await client.send_message("me", f"Этот чат уже есть в списке '{list_name}'")
elif text == "/list":
if not chat_lists:
await client.send_message("me", "Списки пусты ❌")
return
msg = "📋 Текущие списки:\n\n"
for lst, chats in chat_lists.items():
msg += f"🔹 {lst}:\n"
if chats:
for cid in chats:
try:
entity = await client.get_entity(cid)
title = getattr(entity, 'title', getattr(entity, 'first_name', str(cid)))
msg += f" • {title} (id: {cid})\n"
except:
msg += f" • {cid}\n"
else:
msg += " (пусто)\n"
await client.send_message("me", msg)
elif text.startswith("/clear"):
parts = text.split(maxsplit=1)
if len(parts) == 2:
list_name = parts[1].strip()
if list_name in chat_lists:
chat_lists[list_name] = []
save_data()
await client.send_message("me", f"🧹 Список '{list_name}' очищен")
else:
await client.send_message("me", "Такого списка нет")
else:
await client.send_message("me", "Используй: /clear <имя_списка>")
elif text.startswith("/del"):
parts = text.split(maxsplit=2)
list_name = parts[2].strip() if len(parts) == 3 else "default"
if list_name not in chat_lists:
await client.send_message("me", "Такого списка нет")
return
chat_id = None
if event.is_reply:
reply = await event.get_reply_message()
if reply.forward and reply.forward.chat:
chat_id = reply.forward.chat.id
else:
try:
chat_id = int(reply.text.strip())
except:
await client.send_message("me", "Ответьте на репост или сообщение с id")
return
else:
if len(parts) >= 2:
ref = parts[1].strip()
try:
entity = await resolve_chat(ref)
chat_id = entity.id if entity else int(ref)
except:
await client.send_message("me", "Неверный формат id/username")
return
else:
await client.send_message("me", "Используй: /del <id|username> [список] или ответом на репост/сообщение с id")
return
if chat_id in chat_lists[list_name]:
chat_lists[list_name].remove(chat_id)
save_data()
await client.send_message("me", f"❌ Удалён {chat_id} из списка {list_name}")
else:
await client.send_message("me", "Такого чата нет в списке")
elif text.startswith("/go") and event.is_reply:
parts = text.split(maxsplit=1)
list_name = parts[1].strip() if len(parts) == 2 else "default"
if list_name not in chat_lists or not chat_lists[list_name]:
await client.send_message("me", f"Список '{list_name}' пуст ❌")
return
reply_msg = await event.get_reply_message()
if reply_msg.video_note:
for cid in chat_lists[list_name]:
try:
await client.send_file(cid, file=reply_msg.video_note, caption=reply_msg.text or "")
print(f"Отправлено в {cid}")
except Exception as e:
print(f"Ошибка при отправке в {cid}: {e}")
await client.send_message("me", f"✅ Кружок разослан в список '{list_name}'")
else:
await client.send_message("me", "Это не кружок 🤔")
print("Запуск...")
client.start()
client.run_until_disconnected()
3. Заменяем ВАШ АПИ ИД, ВАШ АПИ ХЭШ, и ВАШ ТЕЛЕФОН на свои.
4. Опционально заменяем фразы йоу! и йоу2 на свои фразы. На работу бота не влияет, но настоятельно советуем так сделать.
5. Сохраняем.
6. Вводим в консоль python bot.py.
7. Проверяем работоспособность.
Демонстрация работы
Подводя итоги
Как видите, спамить кружками, как Иванов, не так уж и сложно. И для этого даже не нужно марать руки. Всего-то и нужно было быть подписанным на нашу Телегу, чтобы вовремя заметить анонс этой статьи. С чем мы вас и поздравляем!