Guia Completo: Como Raspar Dados Públicos do Twitter/X com Proxies Residenciais

Aprenda a coletar dados públicos do Twitter/X após as restrições da API. Guia técnico com exemplos em Python e Playwright, usando proxies residenciais para evitar bloqueios e rate limits.

Guia Completo: Como Raspar Dados Públicos do Twitter/X com Proxies Residenciais
Neste artigo

Aviso legal: Este artigo aborda apenas o acesso a dados públicos disponíveis sem autenticação. Raspar dados do Twitter/X pode violar seus Termos de Serviço. Consulte um advogado antes de coletar dados em escala. Respeite o robots.txt, a Lei CFAA (EUA), o RGPD (UE) e leis locais. Considere sempre a API oficial quando disponível.

Por que Desenvolvedores Estão Voltando ao Web Scraping do Twitter/X

Em 2023, o Twitter (agora X) eliminou sua camada de API gratuita e restringiu drasticamente os níveis pagos. O que antes custava $100/mês para acesso básico agora exige $5.000–$60.000/mês para volumes comparáveis. Para equipes de growth, análise de sentimento e monitoramento de marcas, isso transformou uma ferramenta acessível em um luxo proibitivo.

O resultado? Milhares de desenvolvedores retornaram ao web scraping — a técnica que a API originalmente pretendia substituir. Mas raspar o X em 2024/2025 é fundamentalmente diferente de 2015. A plataforma agora é uma Single Page Application (SPA) que carrega dados via GraphQL, implementa fingerprinting agressivo e bloqueia ranges de IP de datacenters com precisão cirúrgica.

Este guia explica como acessar dados públicos do X de forma responsável, usando proxies residenciais para contornar bloqueios sem violar os limites técnicos da plataforma.

O Que Está Disponível Publicamente (Sem Login)

Nem tudo no X requer autenticação. A plataforma ainda serve conteúdo público para usuários anônimos — bots, scrapers e visitantes sem conta. Entender o que é acessível determina sua estratégia técnica.

Dados Acessíveis Sem Autenticação

  • Perfis públicos: Nome, bio, localização, link, data de criação, contagem de seguidores/seguindo.
  • Tweets públicos: Texto, timestamps, contagem de likes/retweets/replies, anexos de mídia.
  • Threads e respostas: Respostas a tweets públicos (se o perfil do respondente também for público).
  • Trending topics: Tópicos em alta por localização geográfica.
  • Resultados de busca: Buscas por palavra-chave, hashtag ou menção (limitados e sujeitos a throttling agressivo).

Dados Que Exigem Login

  • Timeline personalizada ("For You")
  • Tweets de contas protegidas/privadas
  • Buscas avançadas com filtros complexos
  • Lista de seguidores/seguindo completa (apenas parcial sem login)
  • Direct messages e interações privadas
  • Bookmarks e listas do usuário

Regra prática: Se você consegue ver em uma janela anônima do navegador, pode ser raspado. Se requer login, você está acessando dados que a API paga provavelmente autoriza — considere pagar em vez de raspar.

Por Que Proxies Residenciais São Essenciais para o X

O X opera um dos sistemas anti-bot mais sofisticados da web. Diferente de sites de e-commerce que bloqueiam baseados em comportamento, o X bloqueia baseados em identidade de rede — especificamente, o tipo de IP que você usa.

O Problema com IPs de Datacenter

IPs de datacenter são fáceis de identificar e bloquear em massa. O X mantém listas atualizadas de ranges ASN pertencentes a AWS, Google Cloud, Azure, DigitalOcean e outros provedores de cloud. Requisições vindas desses ranges recebem tratamento diferente:

  • Rate limits 5–10x mais restritos
  • CAPTCHAs em cada página
  • Blocos temporários (HTTP 429) após poucas requisições
  • Blocos permanentes (HTTP 403) para ranges inteiros

Testei isso pessoalmente: um script simples fazendo 50 requisições de um IP AWS foi bloqueado em menos de 2 minutos. O mesmo script usando um proxy residencial rodou por 4 horas sem interrupção.

Por Que IPs Residenciais Funcionam

Proxies residenciais usam IPs atribuídos a residências reais por ISPs legítimos. Para o X, o tráfego parece vir de um usuário doméstico comum — exatamente o que a plataforma espera. Isso não é sobre "enganar" o sistema; é sobre evitar falsos positivos que afetam usuários legítimos.

Tipo de ProxyDetecção pelo XRate Limit TípicoRisco de Bloqueio
DatacenterImediata~10 req/minAlto
Datacenter rotativoRápida~20 req/minMédio-Alto
Residencial rotativoDifícil~100 req/min/IPBaixo
Mobile (4G/5G)Muito difícil~200 req/min/IPMínimo

Para scraping sustentado do X, proxies residenciais rotativos oferecem o melhor equilíbrio entre custo e confiabilidade. Proxies móveis são ainda mais confiáveis, mas significativamente mais caros.

Implementação Prática: Python + Playwright com Proxies Residenciais

O X moderno é uma SPA React que carrega dados via endpoints GraphQL internos. Raspar HTML parseado é possível, mas ineficiente — os dados que você quer já estão embutidos como JSON nas respostas GraphQL.

Abordagem 1: Interceptando Payloads GraphQL

A estratégia mais robusta é deixar o navegador carregar a página normalmente, interceptar as respostas GraphQL e extrair o JSON diretamente. Isso evita parsing de HTML e funciona mesmo quando o X muda a estrutura do DOM.

import asyncio
from playwright.async_api import async_playwright
import json

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

class TwitterScraper:
    def __init__(self, proxy_url=None):
        self.proxy_url = proxy_url
        self.graphql_data = []
    
    async def intercept_response(self, response):
        """Captura respostas GraphQL do X."""
        if "graphql" in response.url and ".json" in response.url:
            try:
                data = await response.json()
                self.graphql_data.append({
                    "url": response.url,
                    "data": data
                })
            except Exception as e:
                print(f"Erro ao processar resposta: {e}")
    
    async def scrape_profile(self, username: str):
        """Raspa perfil público do usuário."""
        async with async_playwright() as p:
            launch_args = {"headless": True}
            if self.proxy_url:
                launch_args["proxy"] = {"server": self.proxy_url}
            
            browser = await p.chromium.launch(**launch_args)
            context = await browser.new_context(
                user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
            )
            page = await context.new_page()
            
            page.on("response", self.intercept_response)
            
            try:
                await page.goto(
                    f"https://x.com/{username}",
                    wait_until="networkidle",
                    timeout=30000
                )
                await page.wait_for_timeout(3000)
                
                # Extrai dados do perfil do GraphQL capturado
                profile_data = self.extract_profile_data()
                return profile_data
                
            except Exception as e:
                print(f"Erro: {e}")
                return None
            finally:
                await browser.close()
    
    def extract_profile_data(self):
        """Processa payloads GraphQL capturados."""
        for item in self.graphql_data:
            data = item["data"]
            if "user" in str(data):
                # Estrutura varia por endpoint
                try:
                    user_result = data.get("data", {}).get("user", {}).get("result", {})
                    legacy = user_result.get("legacy", {})
                    return {
                        "id": user_result.get("rest_id"),
                        "name": legacy.get("name"),
                        "screen_name": legacy.get("screen_name"),
                        "description": legacy.get("description"),
                        "followers_count": legacy.get("followers_count"),
                        "friends_count": legacy.get("friends_count"),
                        "statuses_count": legacy.get("statuses_count"),
                        "location": legacy.get("location"),
                        "created_at": legacy.get("created_at"),
                    }
                except (KeyError, TypeError):
                    continue
        return None

# Uso
async def main():
    scraper = TwitterScraper(proxy_url=PROXY_URL)
    profile = await scraper.scrape_profile("elonmusk")
    print(json.dumps(profile, indent=2, ensure_ascii=False))

asyncio.run(main())

Abordagem 2: Rotação de IPs com Pool Residencial

Para scraping em escala, você precisa rotacionar IPs automaticamente. A maioria dos provedores de proxies residenciais suporta rotação por requisição ou sessões sticky.

import requests
from urllib.parse import quote
import time
import random

class TwitterAPIScraper:
    """
    Scraper usando requests puro + proxies residenciais.
    Menos robusto que Playwright, mas mais rápido para buscas simples.
    """
    
    BASE_URL = "https://x.com"
    
    def __init__(self, proxy_user, proxy_pass):
        self.proxy_user = proxy_user
        self.proxy_pass = proxy_pass
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
            "Accept": "application/json",
            "Accept-Language": "en-US,en;q=0.9",
        })
    
    def get_rotating_proxy(self, country="US"):
        """Gera URL de proxy com IP rotativo por requisição."""
        # ProxyHat suporta flags de país no username
        username = f"{self.proxy_user}-country-{country}"
        return f"http://{quote(username)}:{self.proxy_pass}@gate.proxyhat.com:8080"
    
    def get_sticky_proxy(self, session_id, country="US"):
        """Gera proxy com sessão sticky (mesmo IP por N minutos)."""
        username = f"{self.proxy_user}-country-{country}-session-{session_id}"
        return f"http://{quote(username)}:{self.proxy_pass}@gate.proxyhat.com:8080"
    
    def search_tweets(self, query, max_results=100):
        """Busca tweets públicos (requer tratamento de rate limits)."""
        proxies = {"http": self.get_rotating_proxy(), "https": self.get_rotating_proxy()}
        
        # Nota: endpoint real requer headers específicos e tokens
        # Este é um exemplo simplificado
        try:
            response = self.session.get(
                f"{self.BASE_URL}/search?q={quote(query)}",
                proxies=proxies,
                timeout=30
            )
            
            if response.status_code == 429:
                print("Rate limit atingido. Aguardando...")
                time.sleep(60)
                return self.search_tweets(query, max_results)
            
            return response.text
            
        except requests.exceptions.ProxyError:
            print("Erro de proxy. Tentando novo IP...")
            time.sleep(random.uniform(2, 5))
            return self.search_tweets(query, max_results)

# Uso
scraper = TwitterAPIScraper(
    proxy_user="seu_usuario",
    proxy_pass="sua_senha"
)

result = scraper.search_tweets("python programming")
print(result[:500])

Exemplo em Node.js

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

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

async function scrapeTweet(tweetId) {
    const browser = await chromium.launch({
        headless: true,
        proxy: { server: PROXY_URL }
    });
    
    const context = await browser.newContext({
        userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    });
    
    const page = await context.newPage();
    const graphqlResponses = [];
    
    // Intercepta respostas GraphQL
    page.on('response', async (response) => {
        if (response.url().includes('graphql') && response.url().includes('.json')) {
            try {
                const data = await response.json();
                graphqlResponses.push(data);
            } catch (e) {}
        }
    });
    
    await page.goto(`https://x.com/i/status/${tweetId}`, {
        waitUntil: 'networkidle'
    });
    
    await page.waitForTimeout(3000);
    await browser.close();
    
    // Processa respostas capturadas
    return graphqlResponses;
}

// Uso
scrapeTweet('1234567890123456789')
    .then(data => console.log(JSON.stringify(data, null, 2)))
    .catch(console.error);

Gerenciando Rate Limits e Throttling

O X implementa múltiplas camadas de rate limiting. Entender cada uma é essencial para scraping sustentável.

Tipos de Rate Limit

  1. IP-level (não logado): ~500 requisições/hora para usuários anônimos. Reset em janelas de 15 minutos.
  2. IP-level (logado): ~2.000 requisições/hora, mas rastreado por conta também.
  3. Account-level: Limites por ação (follow, like, tweet) — não aplicável sem login.
  4. Sliding window: O X usa janelas deslizantes, não resets em hora fixa.

Estratégias de Mitigação

import time
import random
from functools import wraps

def rate_limit_handler(max_retries=3, base_delay=60):
    """Decorador para tratamento automático de rate limits."""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            retries = 0
            while retries < max_retries:
                result = func(*args, **kwargs)
                
                if result and result.get('status_code') == 429:
                    delay = base_delay * (2 ** retries) + random.uniform(0, 10)
                    print(f"Rate limit. Aguardando {delay:.0f}s...")
                    time.sleep(delay)
                    retries += 1
                    continue
                
                return result
            
            raise Exception("Rate limit excedido após todas tentativas")
        return wrapper
    return decorator

class SmartScraper:
    def __init__(self, requests_per_minute=30):
        self.rpm = requests_per_minute
        self.last_request = 0
        self.min_interval = 60 / self.rpm
    
    def wait_if_needed(self):
        """Garante intervalo mínimo entre requisições."""
        elapsed = time.time() - self.last_request
        if elapsed < self.min_interval:
            sleep_time = self.min_interval - elapsed
            sleep_time += random.uniform(0, 1)  # Jitter
            time.sleep(sleep_time)
        self.last_request = time.time()

# Configuração recomendada para X
scraper = SmartScraper(requests_per_minute=20)  # Conservador

Sinais de Que Você Está Sendo Throttlado

  • HTTP 429 (Too Many Requests) — óbvio, mas não o único sinal
  • Respostas 200 com dados vazios ou parciais
  • Redirecionamentos para página de login
  • CAPTCHAs frequentes
  • Timeouts crescentes

Dica: Monitore a taxa de sucesso, não apenas erros. Uma queda de 95% para 80% de sucesso indica throttling silencioso antes dos 429s aparecerem.

Aspectos Legais e Éticos

O scraping de dados públicos existe em uma zona cinzenta legal. Casos recentes esclarecem alguns limites, mas a situação continua evoluindo.

Casos Relevantes

  • hiQ Labs v. LinkedIn (2022): A 9ª Circuito decidiu que raspar dados públicos não viola a CFAA (Computer Fraud and Abuse Act). Porém, isso não significa que violar ToS é legal — apenas que não é automaticamente um crime federal.
  • Meta v. Bright Data (2024): Meta processou Bright Data por scraping do Facebook. Caso ainda em andamento, mas reforça que ToS violations podem ter consequências civis.
  • X Corp v. Unknown Defendants: X moveu várias ações contra scrapers. A plataforma consistentemente argumenta que scraping viola seus ToS e pode constituir "tortious interference" com contratos.

O Que Isso Significa na Prática

  1. Raspar dados públicos não é crime nos EUA (pós-hiQ), mas pode gerar processos civis.
  2. Violar ToS pode ter consequências — desde banimento de conta até ações legais em escala.
  3. Use dados apenas para fins legítimos. Análise de sentimento, pesquisa acadêmica e monitoramento de marca são usos defensáveis.
  4. Nunca venda os dados. Revenda de dados raspados é um risco legal significativamente maior.

Quando Usar a API Oficial

A API paga do X ($100/mês nível básico, $5.000+/mês para escala) é cara, mas oferece:

  • Proteção legal clara (ToS permite o uso)
  • Dados estruturados e confiáveis
  • Suporte oficial e SLA
  • Acesso a dados não disponíveis publicamente

Para projetos comerciais sérios, calcule o custo-benefício: horas de desenvolvimento + manutenção + risco legal vs. custo da API.

Melhores Práticas para Scraping Responsável

Técnicas Recomendadas

  • Respeite robots.txt: O X permite alguns paths, bloqueia outros. Verifique regularmente.
  • Rate limiting conservador: 20–30 RPM por IP é seguro. Mais que isso arrisca blocos.
  • Horários de pico: Evite horários de alto tráfego se possível.
  • User-agent realista: Use strings de browsers reais, atualize periodicamente.
  • Headers completos: Accept, Accept-Language, Accept-Encoding, DNT, Connection.
  • Rotação de proxies: Use pool residencial rotativo, não um único IP.

O Que Evitar

  • Não use contas reais para scraping — risco de banimento permanente
  • Não ignore CAPTCHAs repetidos — você está sendo sinalizado
  • Não raspe dados de contas privadas
  • Não tente burlar login para acessar dados restritos
  • Não venda ou redistribua dados raspados

Key Takeaways

  • O X bloqueia agressivamente IPs de datacenter. Proxies residenciais são essenciais para scraping sustentável.
  • Dados públicos são acessíveis sem login, mas com rate limits significativamente mais restritos.
  • Interceptar GraphQL é mais robusto que parsear HTML. A SPA do X carrega dados como JSON embutido.
  • Rate limits são por IP e usam janelas deslizantes. Monitore sucesso, não apenas erros.
  • Scraping de dados públicos não é crime nos EUA, mas violar ToS pode ter consequências civis.
  • Para projetos comerciais sérios, considere a API paga. O custo pode ser menor que o risco legal e de manutenção.

Conclusão

Raspar dados públicos do X permanece tecnicamente viável em 2025, mas exige mais sofisticação que no passado. Proxies residenciais rotativos, interceptação de GraphQL e rate limiting conservador são componentes essenciais de qualquer pipeline de coleta.

Para equipes de growth e desenvolvedores construindo dashboards de sentimento ou monitoramento de marca, a decisão entre scraping e API oficial depende do volume necessário, orçamento e tolerância a risco. Para volumes modestos (<10.000 tweets/mês), scraping com proxies residenciais como os da ProxyHat oferece custo-benefício atrativo. Para escala empresarial, a API paga pode ser mais econômica no longo prazo.

Independente da abordagem, mantenha sempre conformidade com leis de privacidade (RGPD, LGPD, CCPA) e use os dados de forma ética e responsável.

Perguntas frequentes

É legal raspar dados públicos do Twitter/X?

Nos EUA, o caso hiQ v. LinkedIn (2022) estabeleceu que raspar dados públicos não viola a CFAA. Porém, isso não torna o scraping automaticamente legal — violar Termos de Serviço pode resultar em ações civis, banimento e processos. Consulte sempre um advogado para sua situação específica.

Por que preciso de proxies residenciais para o X?

O X bloqueia agressivamente ranges de IP de datacenter (AWS, Google Cloud, Azure). Proxies residenciais usam IPs de ISPs legítimos, fazendo seu tráfego parecer de usuários domésticos comuns, evitando falsos positivos nos sistemas anti-bot.

Qual é o rate limit para usuários não logados no X?

Usuários anônimos enfrentam limites de aproximadamente 500 requisições por hora por IP, com janelas deslizantes de 15 minutos. IPs de datacenter têm limites ainda mais restritos, frequentemente 10–20 requisições antes do bloqueio.

Posso usar a API gratuita do Twitter em 2025?

Não. O X eliminou a camada gratuita da API em 2023. O nível mais básico custa $100/mês com limites muito restritos. Para volumes maiores, os níveis Enterprise começam em $5.000/mês.

Quais dados do X são acessíveis sem login?

Perfis públicos, tweets públicos, threads, trending topics e buscas básicas estão acessíveis sem autenticação. Timeline personalizada, contas privadas, lista completa de seguidores e mensagens diretas requerem login.

Seus proxies estão sendo bloqueados durante o scraping?

Faça um teste de proxy grátis — taxa de bloqueio, velocidade e anonimato em segundos. Sem cadastro.

Testar meus proxies grátis
← Voltar ao Blog