Загрузка данных
cat << 'EOF' > clean_friends.py
import sys
import time
import json
import re
import os
import requests
COOKIES_DATA = [
{"name": "remixuacck", "value": "85dca311dce9d73521", "domain": ".vk.ru", "path": "/"},
{"name": "remixdark_color_scheme", "value": "1", "domain": ".vk.ru", "path": "/"},
{"name": "httoken", "value": "UPml6IBSupOdTjtR8mNZ7CDJH0Bb-N0esLGzqqiRx-VXuCx3cdQIwp4tWaJS0QIK1eTg2hEvQckCkMj-g6PVDbyyuB6rim7-ywQlzbVBKzDDZG9tixx4Fve5ABSGe4YKFX0", "domain": ".m.vk.ru", "path": "/"},
{"name": "remixlang", "value": "0", "domain": ".vk.ru", "path": "/"},
{"name": "remixff", "value": "10111111111101", "domain": ".vk.ru", "path": "/"},
{"name": "remixstid", "value": "960128973_9LrUKD1VN6V9WuhzlVtB8KJD2S2pzXGDoIHpShgLIsH", "domain": ".vk.ru", "path": "/"},
{"name": "remixua", "value": "17%7C621%7C86%7C677989468", "domain": ".vk.ru", "path": "/"},
{"name": "remixdt", "value": "7200", "domain": ".vk.ru", "path": "/"},
{"name": "remixmdevice", "value": "468/1037/2.3076923076923075/!!!!!!!!!!!/468", "domain": ".vk.ru", "path": "/"},
{"name": "remixstlid", "value": "9088231374865086373_c7v7GTeuJsPheSw8dTr3KEjZauNZCcWfuNw37uYtLbc", "domain": ".vk.ru", "path": "/"},
{"name": "remixcolor_scheme_mode", "value": "auto", "domain": ".vk.ru", "path": "/"},
{"name": "remixsuc", "value": "1%3A", "domain": ".vk.ru", "path": "/"},
{"name": "remixrefkey", "value": "46b62ba5d1b4d27b3a", "domain": ".vk.ru", "path": "/"},
{"name": "remixmsts", "value": "%7B%22data%22%3A%5B%5B1791560891%2C%22entries_requests%22%2C1%2C%22core_spa%22%2C%22mvk%22%5D%2C%5B1791560891%2C%22entries_requests%22%2C1%2C%22audio%22%2C%22mvk%22%5D%2C%5B1791560891%2C%22entries_requests%22%2C1%2C%22audio_player_bottom%22%2C%22mvk%22%5D%2C%5B1791560892%2C%22counters_check%22%2C1%5D%2C%5B1791560893%2C%22counters_check%22%2C1%5D%5D%2C%22uniqueId%22%3A294709293.0240143%7D", "domain": ".vk.ru", "path": "/"},
{"name": "remixnsid", "value": "vk1.a.q6PpoNhyuYE3JJqmSWsTYOjNJxeCyJDYsYfp0O8aQ4nR3S0EteEVgNcKePzlpaQmtVGNz7nsDaPTuGNcj5Mv5gf-N1lMQa9zYFJ6e_eKbIOWpI0gek2grh97jU-rynbk7wGWgyN0dApyzKyd_3Fs5PyRttZpWmvsbLAP42DIUcGSB5xyoCQiP7DzbCUootU7", "domain": "m.vk.ru", "path": "/"},
{"name": "httoken", "value": "cPLne8Hv_rs7lMMlhSk5Nush2BP11DugSoU5Q5xxq6DGRJ20IJWDjl8EZY1oDOD7LNOYJNBHUirzMHgHvsTvnRzxgwcacp2i7VdVlUoRBVBsM_DB1aQx7Rq-vPNHo3gy-0E", "domain": ".vk.ru", "path": "/"},
{"name": "remixcurr_audio", "value": "undefined", "domain": ".vk.ru", "path": "/"},
{"name": "remixdmgr", "value": "e25cacfa8eaeb542a4121715292ac9dd063768a26d15aebc7cb1cfe13c66d5ae", "domain": ".vk.ru", "path": "/"},
{"name": "remixdmgr_tmp", "value": "98790d44713e491054b0fc82cdca08eb8b0c74be713a266b4508dc0f31bcc204", "domain": ".vk.ru", "path": "/"},
{"name": "remixgp", "value": "7e2ccff978f2c6f8eb16d61aa8712618", "domain": ".vk.ru", "path": "/"},
{"name": "remixmdv", "value": "EdaHXljyjilXaPud", "domain": ".vk.ru", "path": "/"},
{"name": "remixmvk-fp", "value": "6b40bf508d27d26aa011c5920d4b2951", "domain": ".vk.ru", "path": "/"},
{"name": "remixsid", "value": "1_p_qDcaNIQbIQ0PUocdN0K9ZWuaHLofwBUSYNRFPu1MBN8XQXuAEeZk2vVKRa8BdXqOlX9gOWInY-yp-6b7RNBw", "domain": ".vk.ru", "path": "/"},
{"name": "remixuas", "value": "M2QzYjI4YjlkYmFjOTdmZWU1NjdkNWIy", "domain": ".vk.ru", "path": "/"}
]
HEADERS = {
"User-Agent": "Mozilla/5.0 (Linux; Android 14; SM-S928B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
"Origin": "https://m.vk.ru",
"Referer": "https://m.vk.ru/"
}
class VerifiedVkCleaner:
def __init__(self):
self.session = requests.Session()
self.session.headers.update(HEADERS)
self.user_id = 688006907
self.working_method = None
self.init_cookies()
def init_cookies(self):
for c in COOKIES_DATA:
val = c["value"]
for dom in [".vk.ru", "vk.ru", ".m.vk.ru", "m.vk.ru", ".vk.com", "vk.com"]:
self.session.cookies.set(c["name"], val, domain=dom, path="/")
def check_connection(self) -> bool:
print("[*] Проверка новой сессии ВКонтакте...")
try:
resp = self.session.get("https://m.vk.ru/feed", timeout=15)
if "login" in resp.url or "act=blocked" in resp.url:
print(f"[!] Ошибка: сессия не принята сайтом. Итоговый URL: {resp.url}")
return False
uid_match = re.search(r'"id"\s*:\s*(\d+)', resp.text)
if not uid_match:
uid_match = re.search(r'/id(\d+)', resp.text)
if uid_match and int(uid_match.group(1)) > 0:
self.user_id = int(uid_match.group(1))
print(f"[+] Сессия успешно подтверждена! Твой ID: {self.user_id}")
return True
except Exception as e:
print(f"[!] Ошибка сетевого подключения: {e}")
return False
def get_profile_state(self, target_id: int):
"""
Запрашивает страницу пользователя и возвращает:
(is_friend: bool, remove_url: str, hash_val: str)
"""
url = f"https://m.vk.ru/id{target_id}"
try:
resp = self.session.get(url, timeout=15)
html = resp.text
is_friend = False
if "act=remove" in html or "friends_act" in html or "У вас в друзьях" in html:
is_friend = True
remove_url = None
url_match = re.search(r'href=["\'](/friends\?act=remove[^"\']+)["\']', html)
if url_match:
remove_url = "https://m.vk.ru" + url_match.group(1).replace("&", "&")
hash_val = None
if remove_url:
h_match = re.search(r'[&?]_?hash=([a-zA-Z0-9_\-]+)', remove_url)
if h_match:
hash_val = h_match.group(1)
if not hash_val:
h_match = re.search(r'data-hash=["\']([a-zA-Z0-9_\-]+)["\']', html)
if h_match:
hash_val = h_match.group(1)
return is_friend, remove_url, hash_val
except Exception as e:
print(f"[!] Ошибка загрузки профиля id{target_id}: {e}")
return False, None, None
def test_and_find_working_method(self, target_id: int, remove_url: str, hash_val: str) -> bool:
"""
Тестирует различные варианты отправки запроса на 1-м пользователе
и проверяет результат в профиле.
"""
print(f"\n[*] Подбор рабочего метода удаления для пользователя id{target_id}...")
# Вариант 1: Прямой переход по ссылке подтверждения с отправкой формы
if remove_url:
print(" -> Попытка 1: Запрос через страницу подтверждения m.vk.ru...")
try:
page_resp = self.session.get(remove_url, timeout=15)
# Ищем форму подтверждения
form_match = re.search(r'<form[^>]+action=["\']([^"\']+)["\'][^>]*>(.*?)</form>', page_resp.text, re.DOTALL)
if form_match:
form_action = form_match.group(1)
form_body = form_match.group(2)
if not form_action.startswith("http"):
form_action = "https://m.vk.ru" + form_action
inputs = dict(re.findall(r'<input[^>]+name=["\']([^"\']+)["\'][^>]+value=["\']([^"\']*)["\']', form_body))
post_resp = self.session.post(form_action, data=inputs, timeout=15)
print(f" Ответ формы: HTTP {post_resp.status_code}")
else:
# Если формы нет, пробуем прямой POST с _ajax=1
ajax_resp = self.session.post(remove_url, data={"_ajax": "1"}, headers={"X-Requested-With": "XMLHttpRequest"}, timeout=15)
print(f" Ответ AJAX: HTTP {ajax_resp.status_code}")
except Exception as e:
print(f" Ошибка Попытки 1: {e}")
time.sleep(1.5)
is_friend, _, _ = self.get_profile_state(target_id)
if not is_friend:
print("[+] Вариант 1 СРАБОТАЛ! Пользователь удален.")
self.working_method = "direct_url_post"
return True
# Вариант 2: Стандартный POST на /friends
if hash_val:
print(" -> Попытка 2: Стандартный POST act=remove на m.vk.ru/friends...")
payload = {
"act": "remove",
"id": target_id,
"_hash": hash_val,
"_ajax": "1"
}
headers = dict(HEADERS)
headers["X-Requested-With"] = "XMLHttpRequest"
headers["Referer"] = f"https://m.vk.ru/id{target_id}"
try:
resp = self.session.post("https://m.vk.ru/friends", data=payload, headers=headers, timeout=15)
print(f" Ответ сервера: HTTP {resp.status_code} | {resp.text[:60]}")
except Exception as e:
print(f" Ошибка Попытки 2: {e}")
time.sleep(1.5)
is_friend, _, _ = self.get_profile_state(target_id)
if not is_friend:
print("[+] Вариант 2 СРАБОТАЛ! Пользователь удален.")
self.working_method = "post_friends_ajax"
return True
# Вариант 3: Десктопный шлюз vk.ru/al_friends.php
print(" -> Попытка 3: Десктопный шлюз vk.ru/al_friends.php...")
desk_payload = {
"act": "remove",
"al": 1,
"mid": target_id
}
if hash_val:
desk_payload["hash"] = hash_val
desk_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"X-Requested-With": "XMLHttpRequest",
"Origin": "https://vk.ru",
"Referer": "https://vk.ru/friends"
}
try:
resp = self.session.post("https://vk.ru/al_friends.php", data=desk_payload, headers=desk_headers, timeout=15)
print(f" Ответ vk.ru: HTTP {resp.status_code} | {resp.text[:70]}")
except Exception as e:
print(f" Ошибка Попытки 3: {e}")
time.sleep(1.5)
is_friend, _, _ = self.get_profile_state(target_id)
if not is_friend:
print("[+] Вариант 3 СРАБОТАЛ! Пользователь удален.")
self.working_method = "desktop_al_friends"
return True
return False
def delete_single(self, target_id: int, hash_val: str) -> bool:
"""
Выполняет удаление найденным рабочим методом
"""
if self.working_method == "post_friends_ajax":
payload = {
"act": "remove",
"id": target_id,
"_hash": hash_val,
"_ajax": "1"
}
headers = dict(HEADERS)
headers["X-Requested-With"] = "XMLHttpRequest"
headers["Referer"] = f"https://m.vk.ru/id{target_id}"
try:
res = self.session.post("https://m.vk.ru/friends", data=payload, headers=headers, timeout=15)
return res.status_code == 200
except Exception:
return False
elif self.working_method == "direct_url_post":
url = f"https://m.vk.ru/friends?act=remove&id={target_id}&_hash={hash_val}"
try:
res = self.session.post(url, data={"_ajax": "1"}, headers={"X-Requested-With": "XMLHttpRequest"}, timeout=15)
return res.status_code == 200
except Exception:
return False
elif self.working_method == "desktop_al_friends":
desk_payload = {"act": "remove", "al": 1, "mid": target_id, "hash": hash_val}
desk_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"X-Requested-With": "XMLHttpRequest",
"Origin": "https://vk.ru",
"Referer": "https://vk.ru/friends"
}
try:
res = self.session.post("https://vk.ru/al_friends.php", data=desk_payload, headers=desk_headers, timeout=15)
return res.status_code == 200
except Exception:
return False
return False
def main():
print("=" * 60)
print(" ГАРАНТИРОВАННАЯ ОЧИСТКА ДРУЗЕЙ ВКОНТАКТЕ")
print("=" * 60)
cleaner = VerifiedVkCleaner()
if not cleaner.check_connection():
sys.exit(1)
backup_file = "deleted_friends_backup.txt"
if not os.path.exists(backup_file):
print(f"[!] Файл {backup_file} не найден!")
sys.exit(1)
targets = []
with open(backup_file, "r", encoding="utf-8") as f:
for line in f:
match = re.search(r"vk\.(?:com|ru)/id(\d+)\s*-\s*(.*)", line.strip())
if match:
targets.append((int(match.group(1)), match.group(2).strip()))
print(f"[+] Загружено {len(targets)} пользователей из резервного списка.")
if not targets:
print("[!] Список пуст.")
sys.exit(0)
# --- ТЕСТИРОВАНИЕ НА 1-М ПОЛЬЗОВАТЕЛЕ ---
test_id, test_name = targets[0]
print(f"\n[*] Проверка текущего статуса пользователя: {test_name} (id{test_id})...")
is_friend, remove_url, hash_val = cleaner.get_profile_state(test_id)
if not is_friend:
print(f"[+] Пользователь {test_name} (id{test_id}) УЖЕ НЕ В ДРУЗЬЯХ! Берем следующего для проверки...")
# Если первый уже не в друзьях, берем второго для теста
test_id, test_name = targets[1]
is_friend, remove_url, hash_val = cleaner.get_profile_state(test_id)
print(f" Статус в друзьях: {'ДА' if is_friend else 'НЕТ'}")
print(f" Ссылка на отписку: {remove_url}")
print(f" Хэш безопасности: {hash_val}")
success = cleaner.test_and_find_working_method(test_id, remove_url, hash_val)
if not success:
print("\n" + "!" * 60)
print("[!] ВНИМАНИЕ: Ни один метод не смог удалить тестового пользователя.")
print(" ВКонтакте отклонил команды или требует ручного подтверждения.")
print("!" * 60)
sys.exit(1)
print("\n" + "=" * 60)
print(f"[+] ПРОВЕРКА ПРОЙДЕНА: Пользователь id{test_id} РЕАЛЬНО УДАЛЕН!")
print(f" Рабочий метод: {cleaner.working_method}")
print("=" * 60)
confirm = input(f"\nПродолжить удаление остальных {len(targets) - 1} пользователей? (yes/no): ").strip().lower()
if confirm != "yes":
print("[-] Остановлено пользователем.")
sys.exit(0)
print("\n[*] Запуск массового удаления...")
deleted_count = 1
for fid, name in targets[1:]:
ok = cleaner.delete_single(fid, hash_val)
if ok:
deleted_count += 1
print(f"[{deleted_count}/{len(targets)}] Удален: {name} (id{fid})")
else:
print(f"[x] Ошибка: {name} (id{fid})")
time.sleep(1.3)
print(f"\n[+] Процесс завершен! Успешно обработано: {deleted_count} из {len(targets)}.")
if __name__ == "__main__":
main()
EOF