Voltar ao blog

Como contornar o rate limiting com proxies: arquitetura, rotação de IP e exemplos de código para desenvolvedores

O rate limiting bloqueia seu parser ou cliente API? Vamos analisar como contornar as limitações de número de requisições usando proxies - com exemplos de código e soluções arquitetônicas.

📅12 de maio de 2026
```html

Rate limiting — uma das causas mais comuns pelas quais scrapers falham, integrações de API falham e scripts automatizados recebem o status 429 Too Many Requests. O servidor vê muitos pedidos de um único IP — e simplesmente para de responder. Neste artigo, vamos discutir como construir corretamente uma infraestrutura de proxies para contornar os limites de solicitações sem bans e falhas — com exemplos reais de código em Python e Node.js.

O que é rate limiting e por que atrasos comuns não ajudam

Rate limiting (limitação de taxa de solicitações) — é um mecanismo de proteção do servidor que limita o número de solicitações de uma única fonte em um determinado período de tempo. A fonte geralmente é um endereço IP, mas sistemas mais avançados também consideram tokens de autorização, User-Agent, cookies e até padrões de comportamento.

Quando seu script excede o limite, o servidor retorna uma das seguintes respostas:

  • 429 Too Many Requests — status HTTP padrão para rate limiting
  • 503 Service Unavailable — às vezes usado em vez de 429
  • 403 Forbidden — se o IP já estiver na lista negra
  • Resposta vazia ou timeout — em caso de bloqueio agressivo

A primeira ideia da maioria dos desenvolvedores é adicionar time.sleep(1) entre as solicitações. Isso funciona apenas em limites muito suaves (por exemplo, 60 solicitações por minuto). Mas os cenários reais são mais complexos:

Limites reais de plataformas populares:

  • Twitter/X API (gratuito): 500.000 tweets por mês, mas não mais de 15 solicitações a cada 15 minutos
  • Google Search: ~100 solicitações por dia de um único IP sem autenticação
  • Wildberries, Ozon: rate limiting agressivo — bloqueio após 30–50 solicitações por minuto
  • GitHub API: 60 solicitações/hora sem token, 5000/hora com token
  • Sites protegidos pelo Cloudflare: podem bloquear após 10–20 solicitações por minuto

Se você precisa coletar 100.000 cartões de produtos de um marketplace ou monitorar preços em tempo real — atrasos simplesmente não ajudam. É necessária uma arquitetura diferente. E é aqui que os proxies se tornam uma necessidade, não uma opção.

É importante entender: rate limiting está vinculado ao endereço IP. Se você tem 100 IPs diferentes — você tem, na verdade, 100 "cotas" independentes. Este é o princípio fundamental para contornar as limitações através de proxies.

Como os proxies resolvem o problema das limitações de solicitações

O mecanismo é simples: cada solicitação ao servidor de destino é feita a partir de um endereço IP diferente. Do ponto de vista do servidor — são usuários diferentes. A cota de cada um deles praticamente não é consumida, portanto, o bloqueio não ocorre.

Vamos considerar a diferença entre trabalhar sem proxies e com um pool de proxies em um exemplo específico. Suponha que o servidor permita 10 solicitações por minuto de um único IP:

Cenário Solicitações por minuto Bloqueio Tempo para 10.000 solicitações
Um IP, sem proxies 10 Sim, após 10 solicitações ~16 horas
10 proxies, rotação 100 Não ~1.7 horas
100 proxies, rotação 1000 Não ~10 minutos

Além de escalar a largura de banda, os proxies oferecem ainda várias vantagens ao trabalhar com rate limiting:

  • Isolamento de sessões — se um IP for banido, os outros continuam funcionando
  • Distribuição geográfica — as solicitações vêm de diferentes regiões, o que reduz a suspeita
  • Sticky sessions — possibilidade de "grudar" em um IP para cenários de múltiplas etapas (autenticação + ação)
  • Controle de carga — é possível dosar com precisão as solicitações para cada IP, sem exceder o limite

Qual tipo de proxy escolher para sua tarefa

Nem todos os proxies são igualmente eficazes contra rate limiting. A escolha do tipo depende do site-alvo, do volume de solicitações e do orçamento. Vamos discutir três tipos principais:

Proxies residenciais

Estes são endereços IP de usuários residenciais reais. Eles parecem tráfego de internet comum e raramente são bloqueados. Proxies residenciais são a escolha ideal para sites com proteção agressiva: marketplaces (Wildberries, Ozon), redes sociais, recursos protegidos pelo Cloudflare. A principal desvantagem é o preço mais alto em comparação com os de data center.

Proxies móveis

Endereços IP de operadoras móveis (3G/4G/5G). Sua característica é que um IP pode ser usado por milhares de assinantes reais ao mesmo tempo, portanto, bloquear esse endereço é algo que os sites realmente não querem. Proxies móveis mostram os melhores resultados onde os residenciais já começam a ser bloqueados — por exemplo, em scraping de alta frequência do Instagram ou ao trabalhar com APIs de plataformas que analisam o tipo de conexão.

Proxies de data center

IPs rápidos e baratos de data centers. Eles são ideais para scraping de sites sem proteção séria: APIs abertas, agregadores de notícias, bancos de dados públicos. Para tarefas com rate limiting, você precisará de mais deles (pois eles são mais frequentemente incluídos em listas negras), mas com a rotação correta, eles lidam muito bem com grandes volumes de solicitações. Para mais detalhes, veja a página de proxies de data center.

Tipo de proxy Anonimato Velocidade Preço Melhor cenário
Residenciais Muito alta Média $$ Marketplaces, redes sociais, Cloudflare
Móveis Máxima Média $$$ API do Instagram, scraping de alta frequência
Data centers Média Alta $ APIs abertas, dados públicos

Estratégias de rotação de IP: per-request, sticky sessions, round-robin

O simples fato de ter proxies não resolve o problema — é importante gerenciá-los corretamente. Existem várias estratégias de rotação, cada uma adequada para seus cenários.

Rotação per-request (novo IP para cada solicitação)

Cada solicitação HTTP é feita através de um novo endereço IP. Esta é a estratégia mais agressiva para contornar rate limiting — o servidor fisicamente não consegue acumular contagem para um único IP. É adequada para:

  • Scraping de cartões de produtos (cada cartão — uma solicitação separada)
  • Coleta de dados de motores de busca
  • Qualquer solicitação sem estado que não exija sessão

Sticky sessions (IP fixo por sessão)

Um IP é usado durante toda a sessão (geralmente 1–30 minutos). É criticamente importante para cenários onde a autenticação é necessária: entrar na conta, executar uma ação, sair. Se o IP mudar entre as etapas — o servidor pode bloquear a sessão como suspeita.

Round-robin com limite de solicitações por IP

A estratégia mais precisa. Você conhece o limite do servidor (por exemplo, 10 solicitações por minuto) e distribui as solicitações pelo pool de proxies de forma que cada IP nunca exceda esse limite. Requer a implementação de uma fila considerando o tempo da última solicitação para cada IP.

Fórmula para calcular o número necessário de proxies:

N proxies = (Taxa de solicitações alvo/min) ÷ (Limite do servidor/min por IP)
Exemplo: precisa de 500 solicitações/min, limite do servidor — 10/min → precisa de pelo menos 50 proxies. Adicione 20% de reserva para o caso de bloqueios: total de 60 proxies.

Exemplos de código em Python: requests, aiohttp, Scrapy

Vamos para a prática. Abaixo estão modelos prontos para as três ferramentas Python mais populares.

1. requests + rotação de proxies manualmente

A opção mais simples — uma lista de proxies e escolha aleatória para cada solicitação:

import requests
import random
import time

PROXIES = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    # ... adicione a quantidade necessária
]

def get_random_proxy():
    proxy = random.choice(PROXIES)
    return {"http": proxy, "https": proxy}

def fetch_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        proxy = get_random_proxy()
        try:
            response = requests.get(
                url,
                proxies=proxy,
                timeout=10,
                headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
            )
            if response.status_code == 429:
                print(f"Rate limited on {proxy}, switching...")
                time.sleep(1)
                continue
            return response
        except requests.RequestException as e:
            print(f"Attempt {attempt+1} failed: {e}")
            time.sleep(2)
    return None

# Uso
urls = ["https://example.com/item/1", "https://example.com/item/2"]
for url in urls:
    result = fetch_with_retry(url)
    if result:
        print(f"OK: {url} — {len(result.text)} bytes")

2. Pool inteligente de proxies considerando rate limit

Uma opção mais avançada — a classe ProxyPool, que rastreia o tempo da última utilização de cada IP e não excede o limite estabelecido:

import requests
import time
from collections import defaultdict
from threading import Lock

class ProxyPool:
    def __init__(self, proxies, rate_limit=10, window=60):
        """
        proxies: lista de strings no formato 'http://user:pass@host:port'
        rate_limit: máximo de solicitações de um IP por janela de tempo
        window: janela de tempo em segundos
        """
        self.proxies = proxies
        self.rate_limit = rate_limit
        self.window = window
        self.usage = defaultdict(list)  # proxy -> [timestamps]
        self.lock = Lock()

    def get_available_proxy(self):
        now = time.time()
        with self.lock:
            for proxy in self.proxies:
                # Limpa timestamps antigos
                self.usage[proxy] = [
                    t for t in self.usage[proxy]
                    if now - t < self.window
                ]
                if len(self.usage[proxy]) < self.rate_limit:
                    self.usage[proxy].append(now)
                    return {"http": proxy, "https": proxy}
        return None  # Todos os proxies esgotaram o limite

    def fetch(self, url, **kwargs):
        proxy = self.get_available_proxy()
        if proxy is None:
            print("Todos os proxies estão limitados, aguardando...")
            time.sleep(5)
            return self.fetch(url, **kwargs)
        
        try:
            response = requests.get(url, proxies=proxy, timeout=10, **kwargs)
            return response
        except requests.RequestException as e:
            print(f"Solicitação falhou: {e}")
            return None

# Uso
pool = ProxyPool(
    proxies=[
        "http://user:[email protected]:8080",
        "http://user:[email protected]:8080",
    ],
    rate_limit=10,  # 10 solicitações por minuto por IP
    window=60
)

for i in range(100):
    r = pool.fetch(f"https://example.com/page/{i}")
    if r:
        print(f"Página {i}: {r.status_code}")

3. aiohttp para scraping assíncrono

A abordagem assíncrona permite usar dezenas de proxies em paralelo sem bloquear threads:

import asyncio
import aiohttp
import itertools

PROXIES = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

proxy_cycle = itertools.cycle(PROXIES)

async def fetch(session, url, proxy):
    try:
        async with session.get(
            url,
            proxy=proxy,
            timeout=aiohttp.ClientTimeout(total=10)
        ) as response:
            if response.status == 429:
                await asyncio.sleep(2)
                return None
            return await response.text()
    except Exception as e:
        print(f"Erro: {e}")
        return None

async def main(urls):
    connector = aiohttp.TCPConnector(limit=50)
    async with aiohttp.ClientSession(connector=connector) as session:
        tasks = [
            fetch(session, url, next(proxy_cycle))
            for url in urls
        ]
        results = await asyncio.gather(*tasks)
        return results

urls = [f"https://example.com/item/{i}" for i in range(200)]
results = asyncio.run(main(urls))
print(f"Coletado: {sum(1 for r in results if r is not None)} páginas")

4. Scrapy com rotação através de middleware

Para Scrapy, existe uma solução pronta — scrapy-rotating-proxies. Mas você pode escrever seu próprio middleware:

# middlewares.py
import random

class RotatingProxyMiddleware:
    def __init__(self, proxies):
        self.proxies = proxies

    @classmethod
    def from_crawler(cls, crawler):
        return cls(proxies=crawler.settings.getlist("PROXY_LIST"))

    def process_request(self, request, spider):
        proxy = random.choice(self.proxies)
        request.meta["proxy"] = proxy

    def process_response(self, request, response, spider):
        if response.status == 429:
            spider.logger.warning(f"Rate limited, proxy: {request.meta.get('proxy')}")
            # Você pode adicionar lógica para excluir o proxy problemático
        return response

# settings.py
PROXY_LIST = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]
DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.RotatingProxyMiddleware": 350,
}
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_TARGET_CONCURRENCY = 10

Exemplos de código em Node.js: axios, got, Puppeteer

Node.js — uma escolha popular para automação de navegadores e trabalho com APIs. Aqui estão padrões prontos para trabalhar com proxies.

1. axios com rotação de proxies

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');

const proxies = [
  'http://user:[email protected]:8080',
  'http://user:[email protected]:8080',
  'http://user:[email protected]:8080',
];

let proxyIndex = 0;

function getNextProxy() {
  const proxy = proxies[proxyIndex % proxies.length];
  proxyIndex++;
  return proxy;
}

async function fetchWithProxy(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    const proxyUrl = getNextProxy();
    const agent = new HttpsProxyAgent(proxyUrl);
    
    try {
      const response = await axios.get(url, {
        httpsAgent: agent,
        httpAgent: agent,
        timeout: 10000,
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
        },
      });
      return response.data;
    } catch (error) {
      if (error.response?.status === 429) {
        console.log(`Rate limited, switching proxy...`);
        await new Promise(r => setTimeout(r, 1000));
        continue;
      }
      console.error(`Attempt ${i + 1} failed:`, error.message);
    }
  }
  return null;
}

// Uso
(async () => {
  const urls = Array.from({length: 50}, (_, i) => `https://example.com/item/${i}`);
  
  const results = await Promise.allSettled(
    urls.map(url => fetchWithProxy(url))
  );
  
  const successful = results.filter(r => r.status === 'fulfilled' && r.value).length;
  console.log(`Success: ${successful}/${urls.length}`);
})();

2. Puppeteer com proxies e contornando rate limiting

Para sites com renderização em JavaScript e proteção do Cloudflare, um navegador headless é necessário:

const puppeteer = require('puppeteer');

const proxies = [
  'proxy1.example.com:8080',
  'proxy2.example.com:8080',
];

async function scrapeWithProxy(url, proxyHost) {
  const browser = await puppeteer.launch({
    args: [
      `--proxy-server=${proxyHost}`,
      '--no-sandbox',
      '--disable-setuid-sandbox',
    ],
    headless: true,
  });

  const page = await browser.newPage();
  
  // Autenticação do proxy
  await page.authenticate({
    username: 'user',
    password: 'pass',
  });

  // Definindo um User-Agent realista
  await page.setUserAgent(
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
  );

  try {
    await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
    
    // Verificando rate limit
    const status = await page.evaluate(() => document.title);
    if (status.includes('429') || status.includes('Too Many')) {
      console.log('Rate limited, need to switch proxy');
      return null;
    }
    
    const data = await page.evaluate(() => {
      return document.querySelector('.price')?.textContent || null;
    });
    
    return data;
  } finally {
    await browser.close();
  }
}

// Rotação por tarefas
(async () => {
  const urls = ['https://example.com/product/1', 'https://example.com/product/2'];
  
  for (let i = 0; i < urls.length; i++) {
    const proxy = proxies[i % proxies.length];
    const result = await scrapeWithProxy(urls[i], proxy);
    console.log(`${urls[i]}: ${result}`);
    await new Promise(r => setTimeout(r, 500)); // pequena pausa
  }
})();

Técnicas avançadas: cabeçalhos, fingerprint, contornando Cloudflare

Mudar de IP — uma condição necessária, mas não sempre suficiente. Sistemas modernos de proteção analisam dezenas de parâmetros da solicitação. Vamos discutir o que mais precisa ser considerado.

Cabeçalhos HTTP: conjunto mínimo obrigatório

Uma solicitação sem cabeçalhos normais parece um bot mesmo com a troca de IP. Sempre adicione:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "Accept-Language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Cache-Control": "max-age=0",
}

Tratamento do cabeçalho Retry-After

Ao receber um 429, o servidor frequentemente indica quanto tempo deve-se esperar. O tratamento correto desse cabeçalho permite não desperdiçar solicitações:

def handle_rate_limit(response):
    if response.status_code == 429:
        retry_after = response.headers.get("Retry-After")
        if retry_after:
            wait_time = int(retry_after)
            print(f"Rate limited. Waiting {wait_time} seconds...")
            time.sleep(wait_time + 1)  # +1 segundo de buffer
        else:
            # Atraso exponencial se o cabeçalho não estiver presente
            time.sleep(min(2 ** attempt, 60))
        return True
    return False

TLS fingerprinting e como contorná-lo

Sistemas avançados (Cloudflare, Akamai, PerimeterX) analisam o fingerprint TLS — uma "impressão digital" única da sua conexão TLS. A biblioteca padrão requests tem um fingerprint facilmente reconhecível. Soluções:

  • curl_cffi (Python) — emula o fingerprint do Chrome/Firefox no nível TLS
  • tls-client (Go/Python) — ferramenta semelhante com suporte a diferentes perfis de navegador
  • Playwright/Puppeteer — navegador real, fingerprint ideal por padrão
# pip install curl-cffi
from curl_cffi import requests as cffi_requests

response = cffi_requests.get(
    "https://cloudflare-protected-site.com/api/data",
    impersonate="chrome120",  # Emulando Chrome 120
    proxies={"https": "http://user:[email protected]:8080"}
)
print(response.json())

Gerenciamento de cookies e sessões

Se o site usa cookies para rastrear sessões, mudar de IP sem mudar os cookies é inútil. Ao trocar de proxies, sempre crie uma nova sessão:

import requests

def create_fresh_session(proxy_url):
    """Cria uma nova sessão com cookies limpos para cada proxy"""
    session = requests.Session()
    session.proxies = {"http": proxy_url, "https": proxy_url}
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
    })
    # Cookies não são transferidos da sessão anterior
    return session

# Para cada novo IP — nova sessão
for proxy in proxies:
    session = create_fresh_session(proxy)
    response = session.get("https://example.com/protected-page")
    # Processa a resposta...

Erros comuns ao trabalhar com proxies e rate limiting

Mesmo com proxies configurados corretamente, os desenvolvedores frequentemente cometem os mesmos erros. Aqui estão os erros mais comuns e como evitá-los.

Checklist: o que verificar antes de iniciar o scraper

  • ☐ Cabeçalhos HTTP realistas adicionados (User-Agent, Accept, Accept-Language)
  • ☐ Ao trocar de proxy, uma nova sessão é criada (novos cookies)
  • ☐ Status 429, 503, 403 tratados com lógica de retry
  • ☐ Atraso implementado entre solicitações (pelo menos 100–500 ms)
  • ☐ Número de proxies corresponde à taxa de solicitações alvo
  • ☐ Proxies testados antes do início (health check)
  • ☐ Erros e estatísticas registrados para cada proxy
  • ☐ Timeout configurado para solicitações (não mais que 15–30 segundos)

Erro 1: Uso de proxies "mortos"

Sempre verifique os proxies antes de adicioná-los ao pool e periodicamente durante a operação. Um proxy não funcional no loop — são solicitações perdidas e timeouts:

def check_proxy(proxy_url, test_url="https://httpbin.org/ip", timeout=5):
    try:
        r = requests.get(
            test_url,
            proxies={"http": proxy_url, "https": proxy_url},
            timeout=timeout
        )
        return r.status_code == 200
    except:
        return False

# Filtrando proxies funcionais antes do início
working_proxies = [p for p in PROXIES if check_proxy(p)]
print(f"Proxies funcionais: {len(working_proxies)}/{len(PROXIES)}")

Erro 2: Ignorar o tipo de protocolo

Proxies HTTP não podem proxiar tráfego HTTPS diretamente (apenas através de CONNECT). Proxies SOCKS5 funcionam no nível de transporte e suportam qualquer protocolo. Para a maioria dos sites modernos, use SOCKS5 ou proxies HTTPS:

# Proxies SOCKS5 em requests (requer pip install requests[socks])
proxies = {
    "http": "socks5://user:[email protected]:1080",
    "https": "socks5://user:[email protected]:1080",
}

# Proxies HTTPS
proxies = {
    "http": "https://user:[email protected]:8080",
    "https": "https://user:[email protected]:8080",
}

Erro 3: Falta de backoff exponencial

Se após um 429 você imediatamente repete a solicitação — você só agrava a situação. A estratégia correta é um atraso exponencial com jitter (desvio aleatório):

import random

def exponential_backoff(attempt, base=1, max_wait=60):
    """
    attempt: número da tentativa (começando em 0)
    base: atraso base em segundos
    max_wait: atraso máximo
    """
    wait = min(base * (2 ** attempt), max_wait)
    # Jitter ±25% para evitar thundering herd
    jitter = wait * 0.25 * random.uniform(-1, 1)
    return wait + jitter

# Uso na lógica de retry
for attempt in range(5):
    response = requests.get(url, proxies=proxy)
    if response.status_code == 429:
        wait = exponential_backoff(attempt)
        print(f"Rate limited. Waiting {wait:.1f}s (attempt {attempt+1})")
        time.sleep(wait)
    else:
        break

Erro 4: Um thread para todos os proxies

Se você tem 50 proxies, mas uma única thread de execução — você está usando no máximo 1 proxy ao mesmo tempo. Use ThreadPoolExecutor ou uma abordagem assíncrona para usar todo o pool em paralelo:

from concurrent.futures import ThreadPoolExecutor, as_completed

def fetch_url(args):
    url, proxy = args
    try:
        r = requests.get(url, proxies={"https": proxy}, timeout=10)
        return url, r.status_code, len(r.text)
    except Exception as e:
        return url, None, str(e)

# Usando todos os proxies em paralelo
tasks = [(url, proxies[i % len(proxies)]) for i, url in enumerate(urls)]

with ThreadPoolExecutor(max_workers=len(proxies)) as executor:
    futures = {executor.submit(fetch_url, task): task for task in tasks}
    for future in as_completed(futures):
        url, status, size = future.result()
        print(f"{url}: {status} ({size})")

Conclusão e recomendações

Rate limiting — um problema solucionável, se abordado de forma sistemática. Principais conclusões deste guia:

  • Pool de proxies, não um único proxy — a unidade mínima para trabalho sério. O número de proxies é determinado pela fórmula: taxa alvo ÷ limite do servidor por IP.
  • A estratégia de rotação é importante — per-request para solicitações sem estado, sticky sessions para cenários autenticados.
  • IP — não é o único parâmetro — cabeçalhos, cookies, fingerprint TLS e padrões de comportamento também são analisados pelos sistemas de proteção.
  • Trate 429 corretamente — backoff exponencial, cabeçalho Retry-After, troca de proxies em caso de bloqueio.
  • O tipo de proxy depende do objetivo — proxies de data center para APIs abertas, residenciais para marketplaces, móveis para máxima proteção.

Se você está trabalhando com scraping de marketplaces (Wildberries, Ozon), coleta de dados de APIs protegidas ou automação em altas velocidades — recomendamos começar com proxies residenciais: eles oferecem o equilíbrio ideal entre anonimato e velocidade, e seus endereços IP raramente entram em listas negras. Para tarefas que exigem máxima resistência a bloqueios em alta frequência de solicitações, considere proxies móveis — seus IPs são compartilhados por milhares de usuários reais, tornando o bloqueio extremamente indesejável para qualquer site.

```