Загрузка данных
from playwright.sync_api import sync_playwright
from urllib.parse import urlparse
import time
MAX_CANDIDATES = 300
MAX_ONLINE = 100
# Системные страницы VK, которые нам нахрен не нужны
BLACKLIST = {
"", "feed", "im", "friends", "groups", "video",
"clips", "search", "settings", "login", "join",
"photos", "audios", "apps", "market", "stories",
"notifications", "bookmarks", "support"
}
def is_profile_link(url):
try:
parsed = urlparse(url)
if parsed.netloc not in ("vk.com", "www.vk.com"):
return False
path = parsed.path.strip("/")
# Профиль должен быть одной частью:
# vk.com/id123 или vk.com/username
if not path or "/" in path:
return False
low = path.lower()
if low in BLACKLIST:
return False
# отсекаем всякую служебную хрень
bad_prefixes = (
"photo", "video", "wall", "album",
"topic", "club", "public", "event",
"app"
)
if low.startswith(bad_prefixes):
return False
return True
except:
return False
def currently_online(page):
"""
Пытаемся определить статус online по видимому интерфейсу VK.
Никакого API.
"""
try:
# aria-label / title часто используются для индикатора статуса
selectors = [
'[aria-label*="онлайн" i]',
'[title*="онлайн" i]',
'[aria-label*="online" i]',
'[title*="online" i]',
]
for selector in selectors:
if page.locator(selector).count() > 0:
return True
# Проверяем видимый текст страницы
text = page.locator("body").inner_text().lower()
lines = [
line.strip()
for line in text.splitlines()
if line.strip()
]
# Ищем именно короткую строку статуса,
# а не любое случайное слово "онлайн" на странице
for line in lines:
if line in (
"онлайн",
"online",
"в сети",
"online с мобильного"
):
return True
return False
except:
return False
with sync_playwright() as p:
# Папка сохраняет твою сессию VK
context = p.chromium.launch_persistent_context(
"vk_browser_data",
headless=False,
viewport={
"width": 1400,
"height": 900
}
)
page = context.pages[0]
print("Открываю VK...")
page.goto(
"https://vk.com/search",
wait_until="domcontentloaded",
timeout=60000
)
print()
print("=" * 60)
print("1. Войди в VK, если потребуется.")
print("2. Открой поиск -> Люди.")
print("3. Выставь:")
print(" Пол: мужской")
print(" Возраст: 50-60")
print(" Город: какой тебе нужен")
print("4. После появления результатов вернись сюда.")
print("=" * 60)
input("\nНажми ENTER, когда фильтры выставлены...")
print("\nСобираю профили...")
profiles = set()
no_new = 0
while len(profiles) < MAX_CANDIDATES and no_new < 10:
old_count = len(profiles)
links = page.locator("a[href]").evaluate_all(
"""
elements => elements.map(a => a.href)
"""
)
for link in links:
if is_profile_link(link):
profiles.add(link.split("?")[0])
if len(profiles) >= MAX_CANDIDATES:
break
print(
f"\rСобрано кандидатов: {len(profiles)}",
end="",
flush=True
)
if len(profiles) == old_count:
no_new += 1
else:
no_new = 0
# скроллим вниз
page.evaluate(
"window.scrollTo(0, document.body.scrollHeight)"
)
time.sleep(1.5)
print()
print()
print(f"Кандидатов собрано: {len(profiles)}")
print("Теперь проверяю online...")
print()
online_users = []
checker = context.new_page()
for number, profile in enumerate(profiles, 1):
if len(online_users) >= MAX_ONLINE:
break
print(
f"[{number}/{len(profiles)}] Проверяю {profile}",
end=""
)
try:
checker.goto(
profile,
wait_until="domcontentloaded",
timeout=20000
)
time.sleep(0.7)
# Если VK решил кинуть капчу
body = checker.locator("body").inner_text().lower()
if "captcha" in body or "капча" in body:
print(" -> КАПЧА")
input(
"Реши капчу вручную в браузере "
"и нажми ENTER..."
)
if currently_online(checker):
online_users.append(profile)
print(
f" -> ONLINE [{len(online_users)}]"
)
else:
print(" -> offline")
except Exception as e:
print(" -> ошибка")
time.sleep(0.5)
with open(
"vk_online_users.txt",
"w",
encoding="utf-8"
) as f:
for i, profile in enumerate(
online_users,
1
):
f.write(
f"{i}. {profile}\n"
)
print()
print("=" * 60)
print(
f"ГОТОВО. Найдено online: "
f"{len(online_users)}"
)
print(
"Ссылки сохранены в:"
)
print(
"vk_online_users.txt"
)
print("=" * 60)
input(
"\nENTER для выхода..."
)
context.close()