Scraper les données publiques Instagram avec des proxies résidentiels : guide complet

Apprenez à extraire les données publiques d'Instagram à l'échelle en utilisant des proxies résidentiels, des headers réalistes et des stratégies de rotation d'IP — sans vous faire bloquer.

How to Scrape Public Instagram Data with Residential Proxies

Pourquoi scraper Instagram est un défi de taille

Si vous avez déjà tenté de scraper Instagram même modestement, vous connaissez la frustration : quelques dizaines de requêtes plus tard, votre IP est bannie, vous faites face à un captcha, ou la réponse ne contient plus aucune donnée utile. Instagram fait partie des plateformes les plus agressives en matière de protection anti-bot, et comprendre pourquoi est la première étape pour construire un pipeline de collecte fiable.

Avertissement légal et éthique : Ce guide se concentre exclusivement sur l'accès aux données publiques d'Instagram. Le non-respect des Conditions d'Utilisation d'Instagram, l'automatisation du login, ou l'accès à des données privées peut violer le CFAA (US), le RGPD (UE), et d'autres lois locales. Scrapez de manière responsable, respectez robots.txt, et privilégiez toujours l'API officielle quand elle suffit.

Instagram déploie plusieurs couches de défense simultanées :

  • Rate limiting agressif : Les requêtes anonymes sont limitées à un très faible volume par IP et par fenêtre temporelle. Dépasser ce seuil déclenche immédiatement un blocage ou un challenge CAPTCHA.
  • Login wall : De plus en plus de contenus (commentaires, stories, données détaillées des posts) exigent une session authentifiée. Tenter d'automatiser le login expose votre compte à un ban permanent.
  • Anti-bot et fingerprinting : Instagram analyse les en-têtes HTTP, le User-Agent, les TLS fingerprints (JA3/JA4), les timings de requêtes, et même les caractéristiques du client HTTP pour distinguer un navigateur réel d'un script.
  • Device fingerprinting : L'application mobile envoie des métadonnées spécifiques (modèle d'appareil, version de l'OS, identifiants publicitaires) que les requêtes basiques ne reproduisent pas.

Quelles données sont accessibles sans login ?

Avant de construire quoi que ce soit, il est crucial de savoir ce qui est réellement accessible sans authentification. Voici un tableau récapitulatif :

Type de pageAccessible sans login ?Données récupérablesLimitations
Profil publicOuiNom d'utilisateur, bio, nombre de posts/followers/following, photos de profil récentesPas de followers list, pas de stories
Pages hashtagPartiellementPosts récents associés au hashtagVolume limité, pas de tri avancé
Pages lieu (location)PartiellementPosts géolocalisés récentsDonnées très fragmentaires
Reels feedsTrès limitéQuelques Reels en page publiqueLa plupart des données nécessitent une session
CommentairesNon (sans login)Exigent une authentification
StoriesNon (sans login)Exigent une authentification
DMs / MessagesNonAccès non autorisé — ne jamais tenter

La règle d'or : si le contenu nécessite un login dans le navigateur, ne tentez pas de l'extraire par automatisation. Concentrez-vous sur les profils publics, les hashtags et les pages de localisation.

Pourquoi les proxies résidentiels sont indispensables pour Instagram

C'est ici que le choix du proxy devient critique. Instagram flagge les IPs datacenter de manière agressive. Les plages d'IPs associées aux hébergeurs (AWS, DigitalOcean, OVH, etc.) sont connues et souvent pré-bloquées. Un script utilisant un proxy datacenter sera détecté en quelques requêtes.

Comparaison des types de proxies pour Instagram

CritèreDatacenterRésidentielMobile
Détection par InstagramTrès élevéeFaibleTrès faible
Taux de succès (profils publics)10-30%85-95%95-99%
Coût par GoLe plus basMoyenLe plus élevé
VitesseRapideMoyenneVariable
Rotation d'IPAutomatique mais flaggéePar requête ou stickyNaturelle (changement de tour)
Cas d'usage recommandéAucun pour IGScraping à grande échelleComptes et sessions sensibles

Les proxies résidentiels offrent le meilleur rapport coût/efficacité pour Instagram. Chaque requête sort depuis une IP associée à un FAI réel, ce qui rend le trafic indiscernable d'un utilisateur domestique normal. La rotation par requête garantit qu'aucune IP ne dépasse le seuil de rate limiting.

Pour des scénarios nécessitant des sessions persistantes (par exemple, maintenir un cookie de session), les proxies résidentiels avec sessions sticky sont idéaux. ProxyHat supporte les deux modes via le format du nom d'utilisateur.

Scraping Instagram en Python avec proxies résidentiels rotatifs

Voici un exemple complet utilisant requests avec un pool de proxies résidentiels Instagram rotatifs, des headers réalistes et une rotation de User-Agent.

import requests
import random
import time
from fake_useragent import UserAgent

# Configuration ProxyHat — proxies résidentiels rotatifs
PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"

# Pour une session sticky (même IP pendant X minutes) :
# PROXY_URL = "http://user-country-US-session-abc123:PASSWORD@gate.proxyhat.com:8080"

proxies = {
    "http": PROXY_URL,
    "https": PROXY_URL,
}

# Rotation de User-Agents réalistes (mobile Android/iOS)
MOBILE_USER_AGENTS = [
    "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 "
    "Chrome/124.0.0.0 Mobile Safari/537.36",
    "Mozilla/5.0 (iPhone 16; iOS 17.4) AppleWebKit/605.1.15 "
    "Mobile/15E148 Safari/604.1",
    "Mozilla/5.0 (Linux; Android 14; Samsung Galaxy S24) "
    "AppleWebKit/537.36 Chrome/125.0.0.0 Mobile Safari/537.36",
]

def scrape_public_profile(username: str) -> dict:
    """Scrape les données publiques d'un profil Instagram."""
    url = f"https://www.instagram.com/{username}/"
    
    headers = {
        "User-Agent": random.choice(MOBILE_USER_AGENTS),
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept-Encoding": "gzip, deflate, br",
        "Connection": "keep-alive",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "none",
        "Sec-Fetch-User": "?1",
        "Upgrade-Insecure-Requests": "1",
    }
    
    # Délai aléatoire pour paraître humain
    time.sleep(random.uniform(2.0, 5.0))
    
    session = requests.Session()
    session.proxies = proxies
    session.headers.update(headers)
    
    # Première requête pour obtenir les cookies (csrftoken, etc.)
    resp = session.get(url, timeout=15)
    
    if resp.status_code == 429:
        print(f"Rate limited pour {username}. Attente...")
        time.sleep(60)
        return {}
    
    if resp.status_code != 200:
        print(f"Erreur {resp.status_code} pour {username}")
        return {}
    
    # Extraire les données du JSON embarqué dans le HTML
    import re, json
    match = re.search(
        r'window\._sharedData\s*=\s*({.+?})\s*;?\s*</script>',
        resp.text
    )
    if not match:
        # Essayer le nouveau format ytInitialData / __a=1
        match = re.search(
            r'"props":\{"pageTransitions":.*?"user":\s*({.+?})\s*,\s*"',
            resp.text
        )
    
    if match:
        return json.loads(match.group(1))
    
    return {"raw_html_length": len(resp.text)}

# Test
result = scrape_public_profile("nasa")
print(f"Données récupérées : {list(result.keys())}")

Points clés de cet exemple :

  • Isolation de session : Chaque profil est scrapé dans un requests.Session() distinct, garantissant que les cookies ne fuient pas entre les requêtes.
  • User-Agents mobiles : Instagram s'attend à voir du trafic mobile. Les UA de desktop sont plus suspects.
  • Délais aléatoires : Un délai de 2 à 5 secondes entre les requêtes simule un comportement humain.
  • Gestion du 429 : Le rate limiting est géré explicitement avec un backoff.

Les spécificités techniques d'Instagram : endpoints et headers

Instagram a considérablement évolué au fil des années, rendant certaines approches obsolètes et en introduisant de nouvelles complexités.

L'endpoint ?__a=1 — RIP

Pendant des années, ajouter ?__a=1 à une URL Instagram renvoyait un JSON propre contenant toutes les données de la page. Cet endpoint a été progressivement déprécié puis supprimé en 2024-2025. Il ne fonctionne plus de manière fiable. Ne comptez pas dessus.

GraphQL queries et headers requis

L'API interne d'Instagram repose sur GraphQL. Pour y accéder (même sans login), vous devez inclure des headers spécifiques :

import requests
import hashlib
import json

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

headers = {
    "User-Agent": "Mozilla/5.0 (iPhone 16; iOS 17.4) "
                 "AppleWebKit/605.1.15 Mobile/15E148 Safari/604.1",
    "x-ig-app-id": "936619743392459",  # ID de l'app web Instagram
    "x-csrftoken": "missing",  # Rempli après la première requête
    "x-requested-with": "XMLHttpRequest",
    "Accept": "*/*",
    "Accept-Language": "en-US,en;q=0.9",
    "Origin": "https://www.instagram.com",
    "Referer": "https://www.instagram.com/",
}

def graphql_user_query(user_id: str, csrf_token: str) -> dict:
    """Interroge l'API GraphQL d'Instagram pour un utilisateur."""
    query_hash = "d4d88dc1500312af6f9428803c346e19"  # Variable selon le type de query
    variables = json.dumps({"user_id": user_id, "include_reel": True})
    
    url = (
        f"https://www.instagram.com/graphql/query/"
        f"?query_hash={query_hash}&variables={variables}"
    )
    
    headers["x-csrftoken"] = csrf_token
    
    resp = requests.get(
        url,
        headers=headers,
        proxies={"http": PROXY_URL, "https": PROXY_URL},
        timeout=15,
    )
    
    if resp.status_code == 200:
        return resp.json()
    return {"error": resp.status_code}

Attention : Les query_hash changent régulièrement. Ils sont extraits du bundle JavaScript d'Instagram et peuvent varier à chaque déploiement. Vous devrez les mettre à jour périodiquement en inspectant le code source de la page.

HTTPS pinning et reverse engineering de l'API mobile

L'application mobile Instagram implémente du certificate pinning, rendant l'interception du trafic via un proxy MITM très difficile. Pour reverse-engineer l'API mobile :

  • Utilisez des outils comme objection ou Frida pour désactiver le SSL pinning sur un appareil rooté.
  • Capturez les endpoints et les payloads envoyés par l'app native.
  • Reproduisez ces requêtes depuis votre script avec les bons headers.

Cette approche est fragile : chaque mise à jour de l'app peut casser vos endpoints. Le scraping HTML reste plus stable à long terme, bien que moins structuré.

La transition du HTML vers l'API mobile

Instagram a progressivement déplacé le rendu côté client. Le HTML initial contient de moins en moins de données — le contenu est chargé dynamiquement via des appels API. Cela signifie que :

  • Le scraping HTML pur capture de moins en moins de données.
  • Les appels API nécessitent des tokens et headers de plus en plus complexes.
  • La combinaison des deux (HTML pour les données de base, API pour les détails) offre le meilleur compromis.

Exemple Node.js avec proxies résidentiels

Pour les équipes JavaScript, voici un équivalent utilisant axios et les proxies ProxyHat :

const axios = require('axios');
const { SocksProxyAgent } = require('socks-proxy-agent');

// Proxy résidentiel rotatif via ProxyHat
const PROXY_URL = 'http://user-country-US:PASSWORD@gate.proxyhat.com:8080';

const MOBILE_UAS = [
  'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 Chrome/124.0.0.0 Mobile Safari/537.36',
  'Mozilla/5.0 (iPhone 16; iOS 17.4) AppleWebKit/605.1.15 Mobile/15E148 Safari/604.1',
];

async function scrapeInstagramProfile(username) {
  const url = `https://www.instagram.com/${username}/`;
  
  const headers = {
    'User-Agent': MOBILE_UAS[Math.floor(Math.random() * MOBILE_UAS.length)],
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.9',
    'Accept-Encoding': 'gzip, deflate, br',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'none',
  };
  
  try {
    const response = await axios.get(url, {
      headers,
      proxy: false,
      httpsAgent: new (require('https-proxy-agent').HttpsProxyAgent)(PROXY_URL),
      timeout: 15000,
    });
    
    if (response.status === 429) {
      console.log('Rate limited — pause 60s');
      await new Promise(r => setTimeout(r, 60000));
      return null;
    }
    
    // Extraire les données du HTML
    const html = response.data;
    const match = html.match(/window\._sharedData\s*=\s*({.+?})\s*;?\s*<\/script>/);
    
    if (match) {
      return JSON.parse(match[1]);
    }
    
    return { htmlLength: html.length };
  } catch (error) {
    console.error(`Erreur pour ${username}: ${error.message}`);
    return null;
  }
}

// Exécution
scrapeInstagramProfile('nasa').then(data => console.log(data));

Stratégies de rate limiting et gestion des empreintes

Même avec les meilleurs proxies, une mauvaise stratégie de requêtage vous fera bloquer. Voici les bonnes pratiques :

1. Auto-rate-limiting

Ne poussez jamais Instagram à vous rate-limiter. Imposez vos propres limites avant le seuil de blocage :

  • Par IP : Maximum 30-50 requêtes par heure par IP résidentielle.
  • Par compte de proxy : Répartissez la charge sur plusieurs pays/villes si possible.
  • Délai minimum : 3-5 secondes entre chaque requête sur la même session.

2. Rotation des empreintes de navigateur

Les TLS fingerprints (JA3/JA4) sont un vecteur de détection majeur. La bibliothèque requests de Python a un fingerprint TLS distinct de Chrome ou Safari. Pour y remédier :

  • Utilisez tls-client ou curl_cffi pour reproduire le fingerprint TLS de Chrome.
  • Variez les suites cryptographiques et l'ordre des extensions TLS.
# Exemple avec curl_cffi pour un fingerprint TLS réaliste
from curl_cffi import requests as curl_requests

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

def scrape_with_tls_fingerprint(url: str) -> dict:
    """Utilise curl_cffi pour imiter le fingerprint TLS de Chrome."""
    response = curl_requests.get(
        url,
        impersonate="chrome124",  # Simule Chrome 124
        proxies={"http": PROXY_URL, "https": PROXY_URL},
        timeout=15,
    )
    return response.text

3. Géolocalisation cohérente

Si votre proxy sort des États-Unis, utilisez un User-Agent en anglais américain, des headers Accept-Language cohérents, et évitez de scraper des contenus géographiquement incohérents. Un utilisateur "US" scrapant massivement des profils russes est suspect.

4. Gestion des sessions sticky vs rotation par requête

ProxyHat offre les deux modes :

  • Rotation par requête (défaut) : Idéal pour le scraping massif de profils publics. Chaque requête = nouvelle IP.
  • Session sticky : Idéal pour maintenir des cookies de session ou scraper un fil de posts séquentiellement. L'IP reste la même pendant la durée de la session.
# Rotation par requête (défaut)
proxy_rotating = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"

# Session sticky — même IP pendant toute la session
proxy_sticky = "http://user-country-US-session-myjob123:PASSWORD@gate.proxyhat.com:8080"

Scraping éthique : quand s'arrêter et utiliser l'API officielle

Le scraping n'est pas un droit — c'est un accès conditionné aux règles de la plateforme. Voici les lignes rouges à ne pas franchir :

Ne jamais automatiser le login

L'automatisation de la connexion à Instagram (remplissage de formulaires, gestion de 2FA, contournement de checkpoints) viole directement les Conditions d'Utilisation et peut constituer une infraction au CFAA. Si vous avez besoin de données authentifiées, utilisez l'API officielle.

Respecter robots.txt

Instagram bloque déjà la plupart des bots via robots.txt. Vérifiez toujours https://www.instagram.com/robots.txt avant de scraper un nouvel endpoint. Les disallow sont explicites.

Se limiter aux données publiques

Les données accessibles sans compte sont les seules que vous devriez collecter. Les commentaires, les stories, les DMs et les listes de followers nécessitent un login — ne tentez pas de les extraire par contournement.

Quand utiliser l'API officielle à la place

  • Meta Graph API : Offre un accès légal aux données de pages et de comptes business Instagram. Limitée mais stable et légale.
  • Instagram Basic Display API (dépréciée) : Permettait un accès limité aux médias publics. Remplacée par d'autres endpoints.
  • Webhooks Meta : Pour le monitoring en temps réel des mentions et des commentaires sur vos propres comptes.

Si votre cas d'usage est couvert par l'API officielle, utilisez-la. Le scraping doit être le dernier recours, pas le premier choix.

Points clés à retenir

  • Les proxies résidentiels sont obligatoires pour Instagram — les IPs datacenter sont flaggées quasi immédiatement.
  • Seul le contenu public sans login est éthique et légal à scraper — profils publics, hashtags, pages de localisation.
  • L'endpoint ?__a=1 est mort — privilégiez le parsing HTML ou les requêtes GraphQL avec les bons headers.
  • Les TLS fingerprints sont un vecteur de détection critique — utilisez tls-client ou curl_cffi pour les masquer.
  • Auto-rate-limitez-vous à 30-50 requêtes/heure/IP pour éviter les blocages.
  • N'automatisez jamais le login — c'est une violation des CGU et potentiellement une infraction légale.
  • Vérifiez toujours l'API officielle avant de scraper — si elle couvre votre besoin, utilisez-la.

Construire un pipeline de web scraping fiable pour Instagram demande de la rigueur, des proxies résidentiels de qualité comme ceux de ProxyHat, et une discipline stricte en matière de rate limiting. Avec les bons outils et la bonne approche, vous pouvez collecter des données publiques de manière stable et éthique. Commencez par explorer nos localisations de proxies pour choisir les zones géographiques adaptées à votre audience cible.

Prêt à commencer ?

Accédez à plus de 50M d'IPs résidentielles dans plus de 148 pays avec filtrage IA.

Voir les tarifsProxies résidentiels
← Retour au Blog