Как скрейпить Twitter/X через прокси: полное руководство 2025

После ограничений API X многие команды перешли на веб-скрейпинг. Узнайте, как собирать публичные данные Twitter с помощью residential прокси, Python и Playwright.

Как скрейпить Twitter/X через прокси: полное руководство 2025

Важное предупреждение: Эта статья посвящена доступу к публичным данным. Всегда соблюдайте Условия использования (Terms of Service) целевой платформы и применимые законы, включая CFAA в США и GDPR в ЕС. Несанкционированный доступ к защищённым данным или обход мер безопасности может быть незаконным.

В 2023 году X (ранее Twitter) радикально изменил свою API-политику. Бесплатный tier для поиска был упразднён, а стоимость доступа к данным выросла в десятки раз. Для команд, строящих мониторинг социальных сетей, аналитику настроений или трекеры трендов, это стало критическим ударом. Многие обратились к веб-скрейпингу Twitter как к альтернативе.

Но X агрессивно защищает свою платформу. Datacenter IP блокируются массово, rate limits для незалогиненных сессий — жёсткие, а архитектура SPA на GraphQL требует особого подхода. В этом руководстве мы разберём, как скрейпить Twitter через прокси эффективно и устойчиво.

Ландшафт после API-ограничений X

До 2023 года Twitter API был одним из самых открытых среди крупных соцсетей. Бесплатный tier давал до 450 запросов в 15-минутное окно для поиска — достаточно для многих use cases. Затем всё изменилось:

  • Free tier — только posting, без доступа к search или tweet lookup
  • Basic tier ($100/месяц) — 10,000 tweet reads/месяц, что ничтожно мало
  • Pro tier ($5,000/месяц) — 1M tweet reads/месяц, но с жёсткими ограничениями
  • Enterprise — индивидуальная цена, часто $42,000+/месяц

Для стартапов, исследователей и небольших команд эти цены неприемлемы. Веб-скрейпинг стал единственной альтернативой для сбора публичных данных Twitter/X.

Что изменилось технически

X перешёл на SPA-архитектуру с GraphQL backend. Данные загружаются динамически через AJAX-запросы, а не рендерятся в HTML. Это усложняет классический scraping, но открывает возможности: GraphQL responses содержат структурированный JSON с богатыми метаданными.

Какие данные X доступны публично

Не всё требует одинакового подхода. Разберём по категориям:

Доступны без авторизации

  • Профили пользователей — имя, описание, количество followers/following, дата регистрации
  • Публичные твиты — текст, медиа, engagements (likes, retweets, replies), timestamp
  • Reply threads — ответы на твиты и цепочки обсуждений
  • Trending topics — тренды по географии
  • Search results — поиск по ключевым словам и хештегам (ограниченно)

Требуют авторизации

  • Protected accounts — твиты закрытых профилей (скрейпинг незаконен)
  • DMs и notifications — приватные данные
  • Full search history — полный архивный поиск
  • Bookmarks и lists — персональные коллекции

Ключевой принцип: скрейпинг легален только для публично доступных данных. Обход paywall или login-wall для доступа к защищённому контенту нарушает ToS и может быть преследуемым.

Почему residential прокси необходимы

X применяет многоуровневую защиту от ботов:

IP-based filtering

Datacenter IP-диапазоны помечены как подозрительные. X использует базы данных вроде MaxMind для классификации IP. Запросы с DC-адресов часто получают:

  • CAPTCHA на каждом запросе
  • HTTP 429 (Too Many Requests) после нескольких запросов
  • HTTP 403 с требованием авторизации
  • Пустые responses или редирект на login

Rate limit дифференциация

X применяет разные лимиты для разных типов сессий:

Тип сессииОриентировочный лимитПоведение при превышении
Anonymous (без cookies)~50-100 запросов/час429 или CAPTCHA
With guest token~200-500 запросов/час429, token invalidation
Logged-in session~2000+ запросов/часSoft throttle, затем 429
Verified accountВысокие лимитыЗависит от репутации

Residential vs Datacenter прокси

Residential прокси используют IP-адреса реальных домашних устройств. Для X они выглядят как обычные пользователи:

  • IP из пулов ISP, не дата-центров
  • Географическое распределение соответствует реальному трафику
  • Меньше CAPTCHA и блокировок
  • Выше success rate для X/Twitter scraping

Mobile прокси — ещё надёжнее, но дороже. IP мобильных операторов имеют наивысший trust score.

Python + Playwright: практическая реализация

Теперь перейдём к коду. Нам нужен браузер для выполнения JavaScript и получения GraphQL responses.

Установка зависимостей

pip install playwright asyncio
playwright install chromium

Базовый скрейпер с residential прокси

import asyncio
from playwright.async_api import async_playwright
import json

PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"

async def scrape_profile(username: str):
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            proxy={"server": PROXY_URL},
            headless=True
        )
        context = await browser.new_context(
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        )
        page = await context.new_page()
        
        # Перехват GraphQL responses
        graphql_data = []
        
        async def handle_response(response):
            if "graphql" in response.url:
                try:
                    data = await response.json()
                    graphql_data.append(data)
                except:
                    pass
        
        page.on("response", handle_response)
        
        # Навигация на профиль
        url = f"https://x.com/{username}"
        await page.goto(url, wait_until="networkidle")
        
        # Ждём загрузки данных
        await page.wait_for_timeout(3000)
        
        await browser.close()
        
        return graphql_data

# Запуск
results = asyncio.run(scrape_profile("elonmusk"))
print(json.dumps(results[0], indent=2) if results else "No data captured")

Парсинг GraphQL payload

X встраивает данные в GraphQL responses. Структура зависит от endpoint:

def extract_profile_data(graphql_response: dict) -> dict:
    """Извлечение данных профиля из GraphQL response."""
    try:
        user_data = graphql_response["data"]["user"]["result"]
        return {
            "id": user_data["rest_id"],
            "username": user_data["legacy"]["screen_name"],
            "name": user_data["legacy"]["name"],
            "description": user_data["legacy"]["description"],
            "followers_count": user_data["legacy"]["followers_count"],
            "following_count": user_data["legacy"]["friends_count"],
            "tweets_count": user_data["legacy"]["statuses_count"],
            "verified": user_data["legacy"]["verified"],
            "created_at": user_data["legacy"]["created_at"],
        }
    except KeyError as e:
        print(f"Failed to parse: missing key {e}")
        return None

Ротация IP с residential пулом

Для масштабирования нужен rotating proxy pool. ProxyHat поддерживает session-based rotation:

import random
import string

def generate_session_id(length=8):
    return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length))

def get_proxy_url(country="US", session_id=None):
    """Генерация URL с ротацией через residential пул ProxyHat."""
    if session_id is None:
        session_id = generate_session_id()
    
    # Каждый новый session_id = новый IP из пула
    return f"http://user-country-{country}-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"

# Пример: ротация IP каждые 10 запросов
async def scrape_multiple_profiles(usernames: list, batch_size=10):
    results = []
    
    for i, username in enumerate(usernames):
        # Новая сессия каждые batch_size запросов
        if i % batch_size == 0:
            session_id = generate_session_id()
        
        proxy_url = get_proxy_url(country="US", session_id=session_id)
        data = await scrape_with_proxy(username, proxy_url)
        results.append(data)
        
        # Задержка между запросами
        await asyncio.sleep(random.uniform(2, 5))
    
    return results

Обработка rate limits

X использует несколько механизмов throttling:

HTTP 429 — явный rate limit

import asyncio
from playwright.async_api import Error as PlaywrightError

async def scrape_with_retry(url: str, max_retries=3, base_delay=60):
    """Скрейпинг с exponential backoff при 429."""
    for attempt in range(max_retries):
        try:
            data = await scrape_url(url)
            return data
        except Exception as e:
            if "429" in str(e) or "Too Many Requests" in str(e):
                delay = base_delay * (2 ** attempt)
                print(f"Rate limited. Waiting {delay}s before retry {attempt + 1}")
                await asyncio.sleep(delay)
                # Rotate IP на новой сессии
                continue
            else:
                raise
    
    raise Exception(f"Max retries exceeded for {url}")

Sliding window detection

X отслеживает не только мгновенную нагрузку, но и паттерны во времени. Признаки детекции:

  • Слишком регулярные интервалы между запросами
  • Одинаковые User-Agent и заголовки
  • Идентичные behavioural patterns (scroll, click)

Митигация:

import random

async def human_like_delay():
    """Случайная задержка, имитирующая человеческое поведение."""
    # 2-8 секунд с bias к средним значениям
    delay = random.gauss(5, 1.5)
    return max(2, min(8, delay))

async def scroll_page(page):
    """Имитация скролла."""
    for _ in range(random.randint(2, 5)):
        await page.mouse.wheel(0, random.randint(300, 800))
        await asyncio.sleep(random.uniform(0.5, 1.5))

Account-level vs IP-level throttling

При использовании logged-in sessions X throttles на уровне аккаунта:

  • IP rotation не поможет — лимит привязан к account
  • Нужны multiple accounts (risk: suspension)
  • Guest tokens ротируются лучше, но имеют меньшие лимиты

Для Twitter residential proxies оптимальная стратегия — anonymous/guest sessions с частой ротацией IP.

Node.js пример для production

Для команд на JavaScript/TypeScript:

const { chromium } = require('playwright');

const PROXY_CONFIG = {
  server: 'http://gate.proxyhat.com:8080',
  username: 'user-country-US-session-abc123',
  password: 'YOUR_PASSWORD'
};

async function scrapeTweet(tweetId) {
  const browser = await chromium.launch({
    proxy: PROXY_CONFIG,
    headless: true
  });
  
  const context = await browser.newContext({
    userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
  });
  
  const page = await context.newPage();
  
  let tweetData = null;
  
  page.on('response', async (response) => {
    if (response.url().includes('TweetDetail')) {
      try {
        tweetData = await response.json();
      } catch (e) {}
    }
  });
  
  await page.goto(`https://x.com/i/status/${tweetId}`, {
    waitUntil: 'networkidle'
  });
  
  await page.waitForTimeout(3000);
  await browser.close();
  
  return tweetData;
}

// Usage
scrapeTweet('1234567890').then(console.log);

Правовые аспекты скрейпинга Twitter/X

Недавние судебные прецеденты

X активно судится со скрейперами:

  • X v. Meta (2023) — X обвинил Meta в скрейпинге для обучения AI. Иск урегулирован.
  • X v. неизвестные лица — постоянные DMCA takedown и lawsuits против tool vendors.

Однако американское право (CFAA) традиционно защищает доступ к публичным данным. Ключевой прецедент — hiQ Labs v. LinkedIn, где суд постановил, что скрейпинг публичных данных не нарушает CFAA.

ToS X — что запрещено

Условия использования X прямо запрещают:

  • Доступ к платформе без авторизации (unauthorized access)
  • Обход rate limits и других технических мер
  • Создание производных продуктов на основе данных X
  • Scraping для конкурентного анализа или AI training

Нарушение ToS ≠ автоматически незаконно, но даёт X право:

  • Заблокировать IP и аккаунты
  • Отправить cease-and-desist
  • Подать иск за breach of contract

GDPR и data protection

В EU сбор персональных данных регулируется GDPR:

  • Твиты содержат personal data их авторов
  • Сбор и хранение требует legal basis
  • Legitimate interest может применяться для research/journalism
  • Нужна privacy policy и data minimization

Когда использовать официальное API

Скрейпинг — не всегда лучший выбор:

СценарийРекомендация
Real-time monitoring (минуты)Official API + Enterprise tier
Historical data (>7 дней)Official API или data providers
High-volume (>100K tweets/день)Official API (Pro/Enterprise)
Low-volume research (<10K/день)Scraping + residential proxies
One-time data collectionScraping acceptable
Production service с SLAOfficial API

Ключевые выводы

  • API X недоступен для большинства use cases из-за ценовой политики — scraping стал необходимостью
  • Residential прокси критичны — datacenter IP блокируются агрессивно
  • GraphQL responses содержат структурированный JSON, удобнее HTML parsing
  • Rate limits требуют стратегии: IP rotation, delays, exponential backoff
  • Публичные данные — легальны для сбора, но соблюдайте ToS и GDPR
  • Production системы с высокими требованиями должны использовать официальный API

Готовы начать собирать данные X? Изучите тарифы ProxyHat для residential прокси с геотаргетингом и ротацией IP.

Для дополнительных материалов по веб-скрейпингу посетите наш блог или страницу use case веб-скрейпинг.

Готовы начать?

Доступ к более чем 50 млн резидентных IP в 148+ странах с AI-фильтрацией.

Смотреть ценыРезидентные прокси
← Вернуться в Блог