LinkedIn через IPv6 прокси: автоматизация приглашений и защита аккаунта от бана
Содержание
- Почему LinkedIn так нервно реагирует на автоматизацию
- Что именно ловит антифрод LinkedIn
- IPv6-прокси: как это работает под капотом
- Настройка Playwright под IPv6-прокси
- Лимиты, которые нельзя превышать
- Ротация и sticky-сессии: где ломается логика
- Поведенческая маскировка: тайминги и паттерны
- Основной цикл
- Кейс: 4000 приглашений за месяц без бана
- Кейс: теневой бан после смены подсети
- Кейс: капча на каждом втором запросе
- Мониторинг здоровья аккаунта
- Итог
Почему LinkedIn так нервно реагирует на автоматизацию
LinkedIn — не Twitter и не Instagram. Здесь бан не прилетает мгновенно за один лишний запрос. Платформа строит поведенческую модель каждого аккаунта месяцами: с каких IP ты заходишь, в какое время, сколько профилей смотришь, как быстро кликаешь. Отклонение от этой модели запускает цепочку: сначала теневой лимит, потом ограничение функций, потом блокировка.
Проблема в том, что большинство скриптов для автоматизации приглашений палятся на сетевом уровне раньше, чем на поведенческом. Один резидентный IP, 300 запросов в час, одинаковые User-Agent — и ты в списке подозрительных ещё до того, как отправил первое приглашение.
IPv6 здесь даёт неочевидное преимущество. У каждого пользователя домашнего интернета обычно /64 подсеть — это 18 квинтиллионов адресов. LinkedIn видит реальных людей, которые приходят с разных адресов внутри одной подсети. Прокси-пул на IPv6 имитирует эту картину гораздо естественнее, чем ротация IPv4.
Что именно ловит антифрод LinkedIn
Разберём по слоям. Первый — сетевой. LinkedIn смотрит на ASN, репутацию подсети, географию. Датацентровые IP (AWS, Hetzner, DigitalOcean) изначально в чёрном списке. Резидентные IPv4 дорогие и их мало. IPv6 от жилых провайдеров — дешевле и выглядят органичнее, если правильно настроены.
Второй слой — TLS-фингерпринт. LinkedIn использует собственные детекторы JA3/JA4. Python requests с дефолтным OpenSSL палится моментально. curl тоже. Нужен либо curl_cffi с имперсонацией Chrome, либо реальный браузер через Playwright.
Третий слой — тайминги. Человек не отправляет приглашения с интервалом ровно 3.0 секунды. Человек не работает 24/7. Человек иногда открывает профиль, читает 40 секунд, закрывает. Всё это моделируется.
Четвёртый — контент. Текст приглашения, шаблонность сообщений, соотношение принятых/отклонённых. Если 90% твоих приглашений игнорируют — это тоже сигнал.
IPv6-прокси: как это работает под капотом
IPv6-прокси на lexic.ml — это пул адресов, каждый из которых маршрутизируется через отдельный выходной узел. При подключении ты получаешь либо отдельный адрес, либо целую /64 подсеть, из которой можешь брать произвольные IP.
Ключевой момент — sticky sessions. Если каждый запрос уходит с нового IPv6, LinkedIn видит, что один и тот же аккаунт прыгает по адресам как сумасшедший. Это красный флаг. Нужно, чтобы сессия жила минимум 10-30 минут на одном адресе, а лучше — весь рабочий день.
Вот как это выглядит в Python с ротацией по расписанию:
```python
import requests
import random
import time
from datetime import datetime
PROXY_POOL = [
"http://user:pass@[2a01:4f8:c17:1234::1]:8080",
"http://user:pass@[2a01:4f8:c17:1234::2]:8080",
"http://user:pass@[2a01:4f8:c17:1234::3]:8080",
]
class LinkedInSession:
def __init__(self):
self.proxy = None
self.rotated_at = 0
self.session = requests.Session()
def _pick_proxy(self):
self.proxy = random.choice(PROXY_POOL)
self.rotated_at = time.time()
self.session.proxies = {
"http": self.proxy,
"https": self.proxy,
}
def get(self, url, **kwargs):
if self.proxy is None or time.time() - self.rotated_at > 1800:
self._pick_proxy()
return self.session.get(url, timeout=30, **kwargs)
```
Проверить, что трафик реально идёт через IPv6, можно так:
```bash
curl -6 -x "http://user:pass@[2a01:4f8:c17:1234::1]:8080" \
https://api.ipify.org?format=json
```
Ответ должен содержать IPv6-адрес из твоего пула, а не IPv4. Если видишь IPv4 — прокси настроен на dual-stack и LinkedIn увидит именно его.
Настройка Playwright под IPv6-прокси
Голый requests не пройдёт TLS-фингерпринт LinkedIn. Нужен реальный Chromium. Playwright с прокси работает так:
```python
from playwright.sync_api import sync_playwright
import random
PROXY = {
"server": "http://[2a01:4f8:c17:1234::1]:8080",
"username": "user",
"password": "pass",
}
with sync_playwright() as p:
browser = p.chromium.launch(
headless=False,
proxy=PROXY,
args=[
"--disable-blink-features=AutomationControlled",
"--no-sandbox",
],
)
context = browser.new_context(
viewport={"width": 1440, "height": 900},
user_agent=(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/122.0.0.0 Safari/537.36"
),
locale="en-US",
timezone_id="America/New_York",
)
context.add_init_script(
"Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
)
page = context.new_page()
page.goto("https://www.linkedin.com/feed/")
browser.close()
```
Обрати внимание на `--disable-blink-features=AutomationControlled`. Без него `navigator.webdriver` равен true, и LinkedIn отдаёт капчу на первом же запросе. `add_init_script` дополнительно маскирует флаг в JS-контексте.
Лимиты, которые нельзя превышать
LinkedIn официально не публикует числа, но эмпирика за годы работы: безопасный дневной лимит для нового аккаунта — 20-30 приглашений. Для прогретого (3+ месяца активности, 500+ контактов) — 80-100. Еженедельный потолок около 200, иначе автоматический weekly invite restriction.
Просмотры профилей: до 80-100 в день для прогретого аккаунта. Сообщения: 50-80 в день. Всё это распределяется неравномерно — утром больше, вечером меньше, выходные почти ноль.
| Параметр | Новый аккаунт | Прогретый (3 мес) | Лимит риска |
|---|---|---|---|
| Приглашения/день | 20 | 80 | 150+ |
| Приглашения/неделя | 100 | 200 | 300+ |
| Просмотры/день | 40 | 100 | 200+ |
| Сообщения/день | 20 | 60 | 100+ |
| Запросов/минуту | 3 | 8 | 15+ |
Цифры — не догма. Зависит от размера сети, отрасли, возраста аккаунта. Но если ты стабильно сидишь на верхней границе — жди ограничений.
Ротация и sticky-сессии: где ломается логика
Классическая ошибка — ротация IP на каждый запрос. Скрипт работает быстро, но LinkedIn видит, что один cookie jar приходит с 50 разных IPv6 за минуту. Это физически невозможно для одного человека.
Правильная схема: одна подсеть на аккаунт, один адрес внутри подсети на сессию. Сессия живёт от логина до логаута или до 2-4 часов. Потом адрес меняется, но остаётся в той же /64. Это имитирует смену IP у домашнего провайдера — нормальное явление.
```python
import ipaddress
import random
SUBNET = ipaddress.ip_network("2a01:4f8:c17:1234::/64")
def random_ip_in_subnet(net):
network_int = int(net.network_address)
broadcast_int = int(net.broadcast_address)
return str(ipaddress.IPv6Address(random.randint(network_int + 1, broadcast_int - 1)))
print(random_ip_in_subnet(SUBNET))
```
Геолокация должна совпадать. Если аккаунт зарегистрирован в США, а IPv6 из Германии — привет, челлендж. Проверяй через `ipinfo.io` или `maxmind` перед тем, как запускать сессию.
Поведенческая маскировка: тайминги и паттерны
Даже с идеальными прокси скрипт палится на ритме. Человек не может отправлять приглашения с интервалом 3.000 секунды. Нужен рандом с человеческим распределением.
```python
import random
import time
def human_delay(base=45, jitter=30):
delay = random.gauss(base, jitter)
delay = max(5, delay)
time.sleep(delay)
def work_hours():
hour = time.localtime().tm_hour
return 9 <= hour <= 21
Основной цикл
for target in targets:
if not work_hours():
time.sleep(3600)
continue
send_invite(target)
human_delay(base=random.choice([30, 60, 120]))
```
Гауссово распределение даёт естественный разброс. Иногда 15 секунд, иногда 2 минуты. Плюс паузы на «обед» (12:00-13:00), паузы на «чтение» (открыл профиль, подождал 30-90 секунд, закрыл).
Ещё момент — порядок действий. Реальный пользователь не идёт по списку сверху вниз. Он открывает поиск, смотрит 5-10 профилей, отправляет 2-3 приглашения, потом возвращается в ленту, читает пост, лайкает. Всё это нужно воспроизводить.
Кейс: 4000 приглашений за месяц без бана
Клиент — B2B-агентство, продвигали SaaS-продукт через LinkedIn. Аккаунт: 4 года, 2800 контактов, активность 2-3 поста в неделю. Задача — 100-150 приглашений в день на несколько аккаунтов.
Первый подход на резидентных IPv4: 3 аккаунта из 5 улетели в ограничение за 9 дней. Причина — один и тот же ASN у всех, плюс одинаковые User-Agent и тайминги.
Переделали на IPv6-пул: каждому аккаунту своя /64 подсеть, свой часовой пояс в Playwright, свой набор User-Agent. Тайминги — гауссово распределение, паузы на обед и ночь. Плюс рандомизация порядка действий: 70% сессий начинались с ленты, 20% — с поиска, 10% — с уведомлений.
Результат: за 30 дней 4200 приглашений, ни одного ограничения. Acceptance rate 34% — выше среднего по отрасли. Ключевое отличие от первого подхода — не прокси сами по себе, а совокупность сетевого и поведенческого слоёв.
Кейс: теневой бан после смены подсети
Другой пример. Аккаунт работал стабильно 2 месяца на подсети `2a01:4f8:c17:1234::/64`. Провайдер решил «оптимизировать» и перевёл пул на `2a01:4f8:c17:5678::/64`. Без предупреждения, в середине дня.
Через 4 часа — теневой бан. Приглашения уходят, но не доставляются. Сообщения не читаются. Профиль в поиске не индексируется.
Причина: LinkedIn зафиксировал резкую смену ASN и подсети у аккаунта, который до этого месяц сидел на одном месте. Это выглядит как угон сессии или передача аккаунта третьему лицу.
Решение: медленная миграция. За 2 недели постепенно перевели 30% трафика на новую подсеть, потом 60%, потом 100%. Смена ASN всё равно триггерит проверку, но плавная — не блокирует. Плюс параллельно снизили активность на 50% на время миграции.
Вывод: любые инфраструктурные изменения на стороне прокси нужно мониторить и синхронизировать с активностью аккаунтов. Внезапный переезд — почти гарантированный бан.
Кейс: капча на каждом втором запросе
Аккаунт новый, 2 недели от регистрации. Скрипт на requests с дефолтным OpenSSL. IPv6-прокси нормальный, геолокация совпадает. Но капча вылезает на каждом втором запросе.
Причина — TLS-фингерпринт. JA3-хеш Python requests отличается от Chrome радикально. LinkedIn это видит и включает challenge. Плюс `Accept-Language` был `en-US,en;q=0.9` без вариаций, `Accept-Encoding` без `br` (Brotli), `Sec-Fetch-*` заголовки отсутствовали.
Перевели на Playwright + curl_cffi для лёгких запросов. Капча исчезла в течение суток. Скорость упала в 5 раз, но зато аккаунт выжил.
```python
from curl_cffi import requests
response = requests.get(
"https://www.linkedin.com/voyager/api/me",
impersonate="chrome122",
proxies={"https": "http://user:pass@[2a01:4f8:c17:1234::1]:8080"},
)
print(response.status_code)
```
`curl_cffi` с `impersonate` подделывает JA3-фингерпринт Chrome. Работает быстрее Playwright, но не покрывает JS-челленджи. Для voyager API хватает.
Мониторинг здоровья аккаунта
Автоматизация без мониторинга — лотерея. Нужно логировать каждый запрос: URL, статус, время ответа, IP, наличие капчи в ответе. Раз в час проверять ключевые эндпоинты.
Признаки надвигающегося бана: рост времени ответа на 200-400 мс, появление `X-Challenge-*` заголовков, капча чаще раза в день, приглашения перестали приниматься (acceptance rate упал до нуля), сообщения не помечаются как прочитанные.
Если видишь два и более признака — стоп на 48 часов. Снижение активности до 30% от обычной. Смена подсети на свежую. Проверка через веб-интерфейс вручную.
Итог
IPv6-прокси — не серебряная пуля. Это один слой из четырёх: сеть, TLS, поведение, контент. Прокси без правильных таймингов палится так же быстро, как тайминги без прокси. Стек должен быть согласованным.
Главное правило — не гнаться за объёмом. Аккаунт на 80 приглашений в день, который живёт годами, приносит больше, чем пять аккаунтов по 300 приглашений, которые умирают за неделю. LinkedIn считает не действия, а отклонения от нормы. Чем ближе твой скрипт к поведению живого человека — тем дольше он работает.