IPv6-прокси для парсинга реального времени: как обойти rate limit в Twitter/X
Содержание
- Как работает блокировка
- Архитектура парсера с IPv6-ротацией
- Диапазон IPv6 адресов от прокси-провайдера
- Получение guest-токена
- Rate limit на уровне приложения
- Кейс: парсинг трендов в реальном времени
- Кейс: мониторинг аккаунтов
- Обработка данных
- Настройка прокси-пула
- !/bin/bash
- Обработка ошибок
- Сравнение подходов
- Проблемы IPv6-ротации
- Оптимизация для реального времени
- Итоги
Rate limit в Twitter/X — это боль. Особенно когда парсишь стрим в реальном времени. Официальный API режет по 150 запросов в час на бесплатном тарифе, а платный стоит как крыло самолёта. Поэтому народ уходит в неофициальные методы: GraphQL-эндпоинты, внутренние API мобильного приложения, публичные данные через guest-токены.
Но и тут подстава. Twitter банит по IP. Не сразу, а после N-го количества запросов. Сначала 429, потом 403, потом временный блок на 12 часов. Один IP живёт 15-40 минут активного парсинга. Выход — ротация IPv6-адресов. У провайдеров вроде lexic.ml пулы на тысячи адресов, и каждый запрос можно отправлять с нового.
Как работает блокировка
Твиттер использует многоуровневую защиту. Первый уровень — rate limit по IP. Второй — поведенческий анализ: скорость запросов, паттерны переходов, заголовки. Третий — fingerprint браузера, но это уже для веб-интерфейса.
Для API-запросов критичен именно IP. Внутренний эндпоинт `https://api.twitter.com/graphql` принимает запросы с guest-токеном, который живёт около 15 минут. Если с одного IP за это время ушло больше 200-300 запросов — бан.
Цифры из практики:
- 1 IP = 200-300 запросов до бана
- Guest-токен = 15 минут жизни
- Полный бан IP = от 2 до 24 часов
- 429 Too Many Requests = подождать 15-60 секунд
Архитектура парсера с IPv6-ротацией
Схема простая: каждый запрос идёт с нового IPv6-адреса. Для этого нужен прокси-пул, который выдаёт адреса из подсети /64 или /48. На каждый запрос — новый адрес. Тогда даже 10 000 запросов не вызовут бана, потому что каждый выглядит как отдельный пользователь.
Проблема: IPv6-адреса у прокси могут повторяться. Поэтому нужна логика, которая отслеживает использованные адреса и не даёт их повторно в течение N минут.
```python
import requests
import random
def get_proxy():
Диапазон IPv6 адресов от прокси-провайдера
base = "2001:db8:85a3::"
suffix = f"{random.randint(0, 65535):x}"
return f"[{base}{suffix}]"
def fetch_tweet(url):
proxy = get_proxy()
headers = {
"authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs",
"x-guest-token": get_guest_token(),
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
response = requests.get(
url,
proxies={"https": f"http://{proxy}:8080"},
headers=headers,
timeout=10
)
return response.json()
```
Получение guest-токена
Без токена GraphQL API не отдаст данные. Токен получается через `POST /i/api/1.1/guest/activate.json`. Обычно он привязан к IP, но с IPv6-ротацией это не проблема — токен можно получить с того же адреса, который будет использоваться для запроса.
```bash
curl -X POST 'https://api.twitter.com/i/api/1.1/guest/activate.json' \
-H 'authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs' \
-H 'user-agent: Mozilla/5.0' \
-H 'content-type: application/json' \
-d '{}'
```
Ответ — JSON с полем `guest_token`. Он валиден 15 минут. Для парсинга в реальном времени нужно обновлять его каждые 10-12 минут, чтобы не получить 403 на середине сессии.
Rate limit на уровне приложения
Даже с ротацией IP нельзя долбить API без пауз. Твиттер анализирует не только IP, но и общую нагрузку. Если с одного аккаунта (или без аккаунта) идёт 1000 запросов в минуту — это подозрительно.
Оптимальные задержки:
- 1 запрос в 2-3 секунды — безопасно
- 3-5 запросов в секунду — рискованно, но работает с ротацией
- 10+ запросов в секунду — бан аккаунта, а не только IP
Для реального времени нужен компромисс. Если парсишь твиты по ключевым словам — 1-2 запроса в секунду достаточно. Если собираешь полный профиль пользователя — лучше с задержкой 5 секунд между запросами.
Кейс: парсинг трендов в реальном времени
Задача: собирать топ-100 трендов каждые 5 минут. Один запрос к `https://api.twitter.com/1.1/trends/place.json?id=1` отдаёт все тренды. Но если делать это с одного IP — через час будет 429.
Решение: пул из 50 IPv6-адресов, на каждый запрос — новый. Проверка трендов каждые 5 минут = 288 запросов в сутки. С ротацией это вообще без нагрузки. Но если добавить сбор твитов по каждому тренду — тут уже тысячи запросов.
Проблема: твиты по трендам собираются через `search/tweets` или GraphQL. Каждый запрос возвращает 20-100 твитов. Для 100 трендов — минимум 100 запросов за цикл. Вот тут и нужна ротация.
Кейс: мониторинг аккаунтов
Пример: нужно отслеживать 500 аккаунтов, проверять новые твиты каждые 30 секунд. Это 1000 запросов в минуту. С одного IP — бан через 20 секунд.
С IPv6-пулом из 1000 адресов — 1 запрос с каждого адреса в минуту. Нагрузка распределена, поведенческий анализ не срабатывает. Каждый аккаунт выглядит как отдельный пользователь.
```python
import asyncio
import aiohttp
ACCOUNTS = ["user1", "user2", "user3"]
async def check_account(session, username, proxy):
url = f"https://api.twitter.com/graphql?variables=%7B%22screen_name%22%3A%22{username}%22%7D"
async with session.get(url, proxy=proxy) as resp:
data = await resp.json()
Обработка данных
return data
async def main():
async with aiohttp.ClientSession() as session:
tasks = []
for username in ACCOUNTS:
proxy = f"http://[2001:db8:85a3::{random.randint(0, 65535):x}]:8080"
tasks.append(check_account(session, username, proxy))
results = await asyncio.gather(*tasks)
```
Настройка прокси-пула
Провайдеры IPv6-прокси обычно дают доступ к подсети. Например, lexic.ml выдаёт доступ к /64 — это 18 квинтиллионов адресов. Но не все адреса рабочие. Часть заблокирована самим Twitter, часть не маршрутизируется.
Нужна проверка: перед началом работы прогнать 100-200 адресов через тестовый запрос. Те, что вернули 200 — в пул. Остальные — в чёрный список.
```bash
!/bin/bash
for i in \$(seq 1 100); do
ip="2001:db8:85a3::\$(printf '%x' \$i)"
code=\$(curl -s -o /dev/null -w "%{http_code}" \
--proxy "http://[\$ip]:8080" \
--connect-timeout 5 \
https://api.twitter.com/1.1/help/configuration.json)
if [ "\$code" = "200" ]; then
echo "\$ip" >> good_ips.txt
fi
done
```
Обработка ошибок
При парсинге в реальном времени ошибки неизбежны. 429, 403, 500, таймауты. Если не обрабатывать — потеряешь данные или получишь бан.
Схема обработки:
- 429 — подождать 30-60 секунд, сменить IP
- 403 — IP в бане, убрать из пула на 2 часа
- 500 — серверная ошибка, повторить через 5 секунд
- Таймаут — сменить IP, повторить с новым guest-токеном
```python
def fetch_with_retry(url, max_retries=5):
for attempt in range(max_retries):
proxy = get_proxy()
try:
response = requests.get(url, proxies={"https": f"http://{proxy}:8080"}, timeout=10)
if response.status_code == 200:
return response.json()
elif response.status_code == 429:
time.sleep(30)
elif response.status_code == 403:
blacklist_ip(proxy)
time.sleep(5)
else:
time.sleep(2)
except requests.exceptions.Timeout:
time.sleep(5)
raise Exception("Max retries exceeded")
```
Сравнение подходов
| Метод | Запросов/час | Бан IP | Стоимость |
|-------|-------------|--------|-----------|
| Один IP | 200-300 | Через 30 мин | 0 |
| Официальный API | 150 | Нет, но лимит | \$100/мес |
| IPv6-ротация | 5000+ | Редко | \$10-30/мес |
| Пул датацентровых IPv4 | 1000-2000 | Через 2-3 часа | \$50-100/мес |
IPv6-прокси выигрывают по цене и количеству адресов. Но есть нюанс: не все сервисы поддерживают IPv6. Твиттер — поддерживает, но не все эндпоинты отвечают по IPv6. Часть запросов может уходить по IPv4, тогда ротация не работает.
Проблемы IPv6-ротации
Первая — нестабильность адресов. Провайдер может выдать адрес, который уже забанен. Поэтому нужен постоянный мониторинг пула.
Вторая — скорость. IPv6-прокси часто медленнее IPv4. Дополнительная задержка 100-300 мс на запрос. Для парсинга в реальном времени это критично, если нужно быстро реагировать на новые твиты.
Третья — поведенческий анализ. Твиттер смотрит не только IP, но и User-Agent, заголовки, тайминги. Если все запросы идут с одинаковыми заголовками — это палево. Нужно рандомизировать UA, Accept-Language, порядок заголовков.
Оптимизация для реального времени
Для стриминга твитов по ключевым словам лучше использовать WebSocket-эндпоинт Твиттера. Он отдаёт твиты в реальном времени без необходимости дёргать API. Но и там есть rate limit — 1% от общего потока.
С IPv6-ротацией можно открыть несколько WebSocket-соединений с разных адресов. Каждое соединение получает свой кусок потока. Объединяешь — получаешь полную картину.
```python
import websockets
import asyncio
async def stream_tweets(keyword, proxy_ip):
uri = "wss://stream.twitter.com/1.1/statuses/filter.json"
headers = {
"Authorization": "Bearer TOKEN",
"Host": "stream.twitter.com"
}
async with websockets.connect(uri, extra_headers=headers, proxy=f"http://[{proxy_ip}]:8080") as ws:
await ws.send(f'{{"track":"{keyword}"}}')
while True:
tweet = await ws.recv()
process_tweet(tweet)
```
Итоги
IPv6-ротация решает проблему rate limit, но не отменяет необходимость продуманной архитектуры. Нужно:
1. Тестировать пул адресов перед стартом
2. Обрабатывать ошибки и баны
3. Рандомизировать заголовки
4. Следить за скоростью запросов
5. Обновлять guest-токены
Если всё сделать правильно — можно парсить тысячи твитов в минуту без банов. Если налажать — получишь временный блок на все адреса подсети. Проверяй каждый шаг, и тогда парсинг в реальном времени будет стабильным.