Se você já tentou construir um pipeline de dados para social listening no Instagram, sabe a frustração: os primeiros requests funcionam, e minutos depois seu IP está bloqueado. O Instagram investe pesado em anti-bot, e raspar dados públicos em escala sem uma estratégia sólida de proxies e fingerprints é praticamente impossível.
Este guia mostra como raspar dados públicos do Instagram de forma estável e responsável, usando proxies residenciais rotativos, headers realistas e técnicas que respeitam os limites da plataforma.
Aviso legal: Raspar dados do Instagram pode violar os Termos de Serviço da plataforma. Este artigo aborda apenas o acesso a dados públicos, sem autenticação, em conformidade com leis aplicáveis (CFAA nos EUA, GDPR na UE, LGPD no Brasil). Sempre consulte o robots.txt, os ToS e um advogado antes de implementar scraping em produção. Nunca automatize logins.
Por que o Instagram é difícil de raspar em escala
O Instagram não é um site estático comum. Ele é uma Single Page Application (SPA) que carrega dados via APIs internas protegidas por múltiplas camadas de segurança:
- Rate limits agressivos: Requests não autenticados a partir de um único IP são limitados a poucas dezenas por hora. Exceder isso resulta em HTTP 429 ou redirecionamento para página de login.
- Login wall: Cada vez mais conteúdo requer autenticação para ser visualizado, mesmo perfis públicos em alguns casos.
- Anti-bot e device fingerprinting: O Instagram coleta fingerprints do navegador — canvas, WebGL, fontes, resolução, timezone — e os usa para identificar bots. Requests que não correspondem a um navegador real são bloqueados.
- HTTPS pinning no mobile: O app mobile faz certificate pinning, impedindo interceptação fácil das chamadas de API via MITM proxies.
- Shadow banning: IPs suspeitos não recebem erros explícitos; recebem respostas vazias ou dados incompletos, tornando o debug difícil.
Quais dados são acessíveis sem login
Nem tudo requer autenticação. O Instagram ainda expõe publicamente:
| Tipo de dado | Acessível sem login? | Notas |
|---|---|---|
| Perfil público (bio, seguidores, posts) | Sim | Limitado a ~12 posts recentes via HTML/JSON |
| Páginas de hashtag | Parcial | Top posts visíveis; recentes podem exigir login |
| Páginas de localização | Parcial | Depende da configuração de privacidade do local |
| Feeds de Reels | Limitado | Metadados básicos via embed endpoints |
| Stories | Não | Exigem autenticação |
| DMs e mensagens | Não | Requer login — nunca automatize isso |
| Comentários completos | Parcial | Alguns visíveis via embed; completos exigem login |
A regra de ouro: se o dado exige login para ser visto manualmente, não tente raspar via automação. Limite-se ao que um usuário anônimo pode ver no navegador.
Por que proxies residenciais são essenciais para o Instagram
O Instagram mantém listas atualizadas de IPs de datacenters (AWS, DigitalOcean, Hetzner, etc.). Requests vindos desses IPs são marcados como suspeitos imediatamente. A diferença de comportamento é dramática:
| Característica | Proxies Datacenter | Proxies Residenciais |
|---|---|---|
| Risco de bloqueio no Instagram | Altíssimo (90%+ em poucos requests) | Baixo com rotação adequada |
| Velocidade | Muito rápida | Moderada (latência de ISP residencial) |
| Custo | Baixo ($1-3/GB) | Médio ($5-15/GB) |
| Fingerprint de IP | ASN de datacenter — óbvio | ASN de ISP residencial — natural |
| Confiabilidade para IG | Péssima | Boa a excelente |
| Geo-targeting preciso | Limitado | País, cidade e até ISP |
Com proxies residenciais, cada request vem de um IP de um ISP real (Vivo, Claro, Comcast, Deutsche Telekom). O Instagram não consegue distinguir seu request de um usuário real navegando pelo app. Para scraping de Instagram, proxies residenciais não são luxo — são requisito.
Proxies mobile: a camada extra de realismo
Proxies mobile vão além: usam IPs de redes móveis reais (4G/5G). O Instagram confia ainda mais nesses IPs porque a maioria dos usuários acessa via mobile. Se o seu use case exige máxima confiabilidade, proxies mobile são a melhor opção — embora mais caros.
Implementação em Python: requests + proxy residencial rotativo
Vamos construir um scraper que raspa perfis públicos do Instagram usando proxies residenciais do ProxyHat com rotação por request.
1. Configuração base com headers realistas
import requests
import random
import time
from urllib.parse import quote
# ProxyHat residential proxy — rotation per request
PROXY_URL = "http://user-country-BR:PASSWORD@gate.proxyhat.com:8080"
PROXIES = {
"http": PROXY_URL,
"https": PROXY_URL,
}
# Realistic user agents (mobile-focused, since most IG traffic is mobile)
USER_AGENTS = [
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) "
"AppleWebKit/605.1.15 (KHTML, like Gecko) "
"Version/17.5 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (Linux; Android 14; Pixel 8) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/125.0.6422.113 Mobile Safari/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) "
"AppleWebKit/605.1.15 (KHTML, like Gecko) "
"CriOS/125.0.6422.80 Mobile/15E148 Safari/604.1",
]
def get_session():
"""Create an isolated session with realistic headers."""
session = requests.Session()
session.headers.update({
"User-Agent": random.choice(USER_AGENTS),
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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",
"Sec-Fetch-User": "?1",
})
session.proxies = PROXIES
return session
2. Raspando perfil público via embed endpoint
O endpoint ?__a=1 que retornava JSON limpo foi desativado para usuários não autenticados. Uma alternativa estável é usar o embed endpoint, que retorna HTML com dados estruturados:
import re
import json
def scrape_profile(username: str) -> dict:
"""Scrape public profile data using the embed endpoint."""
session = get_session()
embed_url = f"https://www.instagram.com/{username}/embed/"
try:
resp = session.get(embed_url, timeout=15)
resp.raise_for_status()
except requests.RequestException as e:
return {"error": str(e), "username": username}
html = resp.text
# Extract JSON data from the embed page script
match = re.search(
r'window\.__additionalDataLoaded\(undefined,(.+?)\);',
html
)
if not match:
# Fallback: try to find window._sharedData
match = re.search(
r'window\._sharedData\s*=\s*({.+?});',
html
)
if match:
try:
data = json.loads(match.group(1))
user_data = (
data
.get("entry_data", {})
.get("ProfilePage", [{}])[0]
.get("graphql", {})
.get("user", {})
)
return {
"username": user_data.get("username", username),
"full_name": user_data.get("full_name"),
"bio": user_data.get("biography"),
"followers": user_data.get("edge_followed_by", {}).get("count"),
"following": user_data.get("edge_follow", {}).get("count"),
"posts": user_data.get("edge_owner_to_timeline_media", {}).get("count"),
"is_private": user_data.get("is_private"),
"is_verified": user_data.get("is_verified"),
}
except (json.JSONDecodeError, KeyError, IndexError) as e:
return {"error": f"Parse error: {e}", "username": username}
return {"error": "No data found in page", "username": username}
# Usage
result = scrape_profile("nasa")
print(json.dumps(result, indent=2, ensure_ascii=False))
# Be polite — wait between requests
time.sleep(random.uniform(3, 7))
3. Rotação de sessão com sticky sessions
Para requisições que precisam manter o mesmo IP (ex: paginação), use sticky sessions do ProxyHat:
def get_sticky_session(session_id: str) -> requests.Session:
"""Create a session that keeps the same IP for its duration."""
sticky_proxy = f"http://user-session-{session_id}-country-BR:PASSWORD@gate.proxyhat.com:8080"
session = requests.Session()
session.headers.update({
"User-Agent": random.choice(USER_AGENTS),
"Accept-Language": "pt-BR,pt;q=0.9",
})
session.proxies = {
"http": sticky_proxy,
"https": sticky_proxy,
}
return session
# Use the same IP for a batch of related requests
import uuid
session_id = str(uuid.uuid4())[:8]
session = get_sticky_session(session_id)
# Multiple requests share the same exit IP
profile = scrape_profile_with_session("nasa", session)
# ... more requests using same session
# After the batch, discard the session
del session
Quirks específicos do Instagram que você precisa conhecer
O fim do ?__a=1 e a era do GraphQL
Até 2020, adicionar ?__a=1 a qualquer URL do Instagram retornava JSON limpo com todos os dados da página. Isso foi desativado para requests não autenticados. Hoje, o Instagram usa GraphQL queries internas que exigem headers específicos:
x-ig-app-id: O ID do app do Instagram (geralmente936619743392459para a versão web).x-csrftoken: Token CSRF obtido do cookiecsrftoken— só disponível após uma sessão autenticada.x-requested-with:XMLHttpRequestpara indicar chamada AJAX.
Problema: Esses headers são projetados para requests autenticados. Usá-los sem login pode funcionar temporariamente, mas quebra frequentemente e pode ser interpretado como tentativa de bypass de autenticação.
Reverse engineering da API mobile
Muitos scrapers avançados fazem reverse engineering do app mobile do Instagram para replicar suas chamadas de API. Isso envolve:
- Descompilar o APK/IPA para encontrar endpoints e chaves.
- Replicar assinaturas de request (User-Agent específico, headers customizados).
- Lidar com HTTPS pinning para capturar o tráfego.
Isso é frágil por natureza: qualquer atualização do app pode quebrar seu scraper. Além disso, replicar o comportamento do app mobile sem autenticação pode ser considerado violação de ToS. Para pipelines de produção, prefira endpoints estáveis (embed, oEmbed) e dados públicos.
HTTPS pinning
O app do Instagram faz certificate pinning, o que significa que ele só confia em certificados SSL específicos do Meta. Isso impede que você use um proxy MITM (como mitmproxy) para interceptar chamadas de API do app. Para contornar, seria necessário usar ferramentas como Frida ou Objection para desabilitar o pinning em tempo de execução — algo que vai além do escopo de scraping ético de dados públicos.
Padrões de rate limiting e gestão de fingerprints
Rate limiting responsável
Mesmo com proxies residenciais rotativos, você precisa ser gentil:
- Delay entre requests: 3–8 segundos por IP, imitando navegação humana.
- Limite por IP: No máximo 30–50 requests por IP antes de rotar.
- Limite global: Mesmo com rotação, não exceda centenas de requests por minuto ao total.
- Backoff exponencial: Se receber 429 ou respostas vazias, espere 60s+ antes de tentar novamente.
def scrape_with_backoff(username: str, max_retries: int = 3) -> dict:
"""Scrape with exponential backoff on failures."""
for attempt in range(max_retries):
session = get_session() # New session = new IP via rotation
try:
result = scrape_profile(username)
if "error" not in result:
return result
# Empty data might mean shadow ban
if result.get("error") == "No data found in page":
wait = (2 ** attempt) * 15 + random.uniform(0, 10)
print(f"Shadow ban suspected, waiting {wait:.0f}s...")
time.sleep(wait)
continue
except requests.exceptions.HTTPError as e:
if e.response is not None and e.response.status_code == 429:
wait = (2 ** attempt) * 30 + random.uniform(0, 30)
print(f"Rate limited, waiting {wait:.0f}s...")
time.sleep(wait)
continue
raise
finally:
time.sleep(random.uniform(3, 7)) # Polite delay
return {"error": "Max retries exceeded", "username": username}
Gestão de fingerprints
Além do IP, o Instagram verifica consistência entre headers, cookies e comportamento:
- Não misture User-Agents na mesma sessão. Um request com UA de iPhone seguido por UA de Android é obviamente suspeito.
- Mantenha cookies de sessão — não os descarte entre requests da mesma "navegação".
- Varie o Accept-Language de forma consistente com o geo-targeting do proxy.
- Ordem dos headers importa — navegadores enviam headers em ordem específica. O
requestsdo Python não preserva ordem por padrão; considere usarurllib3ouhttpxpara mais controle.
Exemplo em Node.js com axios
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
const PROXY_URL = 'http://user-country-BR:PASSWORD@gate.proxyhat.com:8080';
const proxyAgent = new HttpsProxyAgent(PROXY_URL);
const USER_AGENTS = [
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) '
+ 'AppleWebKit/605.1.15 (KHTML, like Gecko) '
+ 'Version/17.5 Mobile/15E148 Safari/604.1',
'Mozilla/5.0 (Linux; Android 14; Pixel 8) '
+ 'AppleWebKit/537.36 (KHTML, like Gecko) '
+ 'Chrome/125.0.6422.113 Mobile Safari/537.36',
];
async function scrapeInstagramProfile(username) {
const url = `https://www.instagram.com/${username}/embed/`;
const ua = USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];
try {
const response = await axios.get(url, {
httpsAgent: proxyAgent,
headers: {
'User-Agent': ua,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'pt-BR,pt;q=0.9',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
},
timeout: 15000,
});
// Parse embedded data from HTML
const match = response.data.match(
/window\.__additionalDataLoaded\(undefined,(.+?)\);/
);
if (match) {
const data = JSON.parse(match[1]);
const user = data?.entry_data?.ProfilePage?.[0]?.graphql?.user;
return {
username: user?.username,
full_name: user?.full_name,
bio: user?.biography,
followers: user?.edge_followed_by?.count,
posts: user?.edge_owner_to_timeline_media?.count,
};
}
return { error: 'No data found', username };
} catch (err) {
return { error: err.message, username };
}
}
// Usage with polite delay
(async () => {
const result = await scrapeInstagramProfile('nasa');
console.log(JSON.stringify(result, null, 2));
})();
Scraping ético e quando usar APIs oficiais
Scraping não é ilegal por si só, mas existem limites claros:
Princípios éticos fundamentais
- Respeite o robots.txt. O Instagram bloqueia crawling em
/robots.txt. Dados públicos acessíveis manualmente são uma área cinzenta, mas automação em escala é claramente contrária à intenção da plataforma. - Rate-limite a si mesmo. Mesmo que seu proxy suporte milhares de RPM, limite-se a velocidades humanas. Seu scraper não deve degradar a experiência de outros usuários.
- Nunca automatize logins. Criar contas fake ou automatizar login em contas reais é violação clara de ToS e pode ter consequências legais.
- Não raspe dados privados. Se um dado requer login para ser visto, não tente acessá-lo via scraping.
- Respeite GDPR/LGPD. Dados pessoais (mesmo públicos) estão sujeitos a regulamentações de privacidade. Ofereça mecanismos de opt-out.
Quando usar APIs oficiais em vez de scraping
| Cenário | Scraping | API Oficial (Meta Graph API) |
|---|---|---|
| Monitoramento de marca em tempo real | Arriscado e frágil | Ideal — webhooks estáveis |
| Análise de sentimento em escala | Possível com cuidado | Melhor — dados estruturados |
| Coleta de dados para IA/ML | Viola ToS | Requer aprovação do Meta |
| Monitoramento de concorrentes | Comum mas arriscado | Dados limitados via API |
| Pesquisa acadêmica | Área cinzenta | Meta Academic — melhor opção |
A Meta Graph API (Instagram Graph API) é a forma oficial de acessar dados de business accounts e creators. Requer um Facebook App aprovado, mas oferece dados estáveis, documentados e legais. Para qualquer pipeline de produção, avalie a API oficial antes de construir scrapers.
Se a API oficial não cobre seus dados, e o scraping é a única opção, use-o como último recurso — com proxies residenciais, rate limiting agressivo e monitoramento constante de falhas.
Key Takeaways
- Proxies residenciais são obrigatórios para scraping de Instagram — proxies datacenter são bloqueados quase instantaneamente.
- Limite-se a dados públicos acessíveis sem login. Nunca automatize autenticação.
- O endpoint
?__a=1está morto para usuários não autenticados. Use embed endpoints ou oEmbed como alternativa estável.- Headers e fingerprints importam tanto quanto o IP. Mantenha consistência entre UA, Accept-Language e geo do proxy.
- Rate-limite agressivamente — 3–8 segundos entre requests, no máximo 30–50 por IP.
- Use backoff exponencial ao encontrar 429s ou respostas vazias (shadow bans).
- Avalie a API oficial do Meta antes de construir scrapers. É mais estável, legal e sustentável a longo prazo.
Pronto para construir seu pipeline de dados do Instagram com proxies residenciais confiáveis? Confira os planos do ProxyHat e comece com um pool de IPs residenciais que o Instagram não consegue distinguir de tráfego real.






