Загрузка данных
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": "Cgte3N8Ypeja1DYG4vPefa2lr3XZDdzjDaFjDbXMHJXVfWUslZCpVYJv55EFLnV9PfIyoxT0usuGAshtshZWkxiE60e4cbtLSdS4IsDlj-pRGtqwakjyd8GxsJI6-X1dZTU", "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%5B1791534625%2C%22web_stats_request_error%22%2C1%2C%22https%3A//stats.vk-portal.net/web-stats/p%22%2Ctrue%2C0%5D%2C%5B1791534626%2C%22entries_requests%22%2C1%2C%22audio%22%2C%22mvk%22%5D%2C%5B1791534626%2C%22entries_requests%22%2C1%2C%22audio_player_bottom%22%2C%22mvk%22%5D%2C%5B1791534633%2C%22counters_check%22%2C1%5D%2C%5B1791534880%2C%22web_stats_request_error%22%2C1%2C%22https%3A//m.vk.ru/usefull.php%22%2Ctrue%2C0%5D%2C%5B1791534880%2C%22web_stats_request_error%22%2C1%2C%22https%3A//m.vk.ru/special.php%22%2Ctrue%2C0%5D%5D%2C%22uniqueId%22%3A356816131.87341696%7D", "domain": ".vk.ru", "path": "/"},
{"name": "remixnsid", "value": "vk1.a.atCUp48xWiA2T-BTfSwb4LuTyUE38ZY_7ZSGDybbT8EwbSInkmjtcuzAYNuhPw1gdxVKwjE-RSnWR3-jhvs5phqpC2pGpPCDHKAbUOVFxV71lKwZkUBr27eeG5buqSvhuag8Ae28M-NDIvAnp0j3GjfTVVevATCqCIdmtFy3Gts0KgGCGyHfVkIH7UHxcwKG", "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_IkQyQAe1Ys2aGq_Ej0UbN6tuG1P8GnY4gdWIT6EQxFS40xK4Z0e1FF-JJtSVWP2XbhqYkhgHedtxVUZFl1GWjg", "domain": ".vk.ru", "path": "/"},
{"name": "remixuas", "value": "M2QzYjI4YjlkYmFjOTdmZWU1NjdkNWIy", "domain": ".vk.ru", "path": "/"}
]
MOBILE_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": "*/*",
"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/friends",
"X-Requested-With": "XMLHttpRequest"
}
class TruePostCleaner:
def __init__(self):
self.session = requests.Session()
self.session.headers.update(MOBILE_HEADERS)
self.user_id = 688006907
self.action_hash = "3726c060ba1f5ee010"
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("[!] Ошибка: сессия отклонена сайтом.")
return False
print(f"[+] Сессия активна! Твой ID: {self.user_id}")
return True
except Exception as e:
print(f"[!] Ошибка подключения: {e}")
return False
def fetch_current_friend_ids(self) -> set:
"""
Запрашивает актуальный список ID друзей для контрольной проверки
"""
current_ids = set()
try:
resp = self.session.get("https://m.vk.ru/friends?section=all", timeout=15)
html = resp.text
raw_ids = re.findall(r'\[\s*(\d+)\s*,\s*["\']', html)
if not raw_ids:
raw_ids = re.findall(r'/id(\d+)', html)
for s in raw_ids:
fid = int(s)
if 0 < fid < 2000000000 and fid != self.user_id:
current_ids.add(fid)
except Exception:
pass
return current_ids
def send_real_post_delete(self, target_id: int) -> tuple:
"""
Отправляет честный POST-запрос на удаление через шлюз мобильной версии
"""
url = "https://m.vk.ru/friends"
payload = {
"act": "remove",
"id": target_id,
"_hash": self.action_hash,
"_ajax": "1"
}
headers = dict(MOBILE_HEADERS)
headers["Referer"] = f"https://m.vk.ru/id{target_id}"
try:
resp = self.session.post(url, data=payload, headers=headers, timeout=15)
raw_text = resp.text.strip()
# Проверяем, вернулся ли ответ ВК с кодом успеха или редиректом
if resp.status_code == 200:
if "error" in raw_text.lower():
return False, f"Ошибка ВК: {raw_text[:70]}"
return True, raw_text[:80]
else:
return False, f"HTTP Статус {resp.status_code}"
except Exception as e:
return False, f"Сетевая ошибка: {e}"
def main():
print("=" * 60)
print(" НАСТОЯЩЕЕ POST-УДАЛЕНИЕ ДРУЗЕЙ ВКОНТАКТЕ")
print("=" * 60)
cleaner = TruePostCleaner()
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[*] Контрольный тест POST-запроса на пользователе:")
print(f" Имя: {test_name} (id{test_id})")
print(f" Отправка POST act=remove с хэшем {cleaner.action_hash}...")
ok, response_preview = cleaner.send_real_post_delete(test_id)
print(f" Сырой ответ сервера: {response_preview}")
print("[*] Проверка: остался ли id{0} в списке друзей...".format(test_id))
time.sleep(1.5)
friends_now = cleaner.fetch_current_friend_ids()
if test_id in friends_now:
print(f"\n[!] ВНИМАНИЕ: Пользователь id{test_id} ВСЁ ЕЩЁ В СПИСКЕ ДРУЗЕЙ!")
print(" Запрос не применился на сервере. Процесс остановлен.")
sys.exit(1)
print(f"\n[+] ПОДТВЕРЖДЕНО! Пользователь id{test_id} ИСЧЕЗ из списка друзей.")
print(" POST-запрос реально сработал на серверах ВКонтакте!")
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, resp_str = cleaner.send_real_post_delete(fid)
if ok:
deleted_count += 1
print(f"[{deleted_count}/{len(targets)}] Реально удален: {name} (id{fid})")
else:
print(f"[x] Ошибка: {name} (id{fid}) -> {resp_str}")
time.sleep(1.3)
print(f"\n[+] Процесс завершен! Всего удалено: {deleted_count} из {len(targets)}.")
if __name__ == "__main__":
main()
EOF