Retour au blog

Comment contourner la limitation de taux avec des proxies : architecture, rotation d'IP et exemples de code pour développeurs

Le rate limiting bloque votre parser ou client API ? Nous examinons comment contourner les limites de requêtes à l'aide de proxies - avec des exemples de code et des solutions architecturales.

📅12 mai 2026
```html

Le rate limiting est l'une des raisons les plus fréquentes pour lesquelles les scrapers échouent, les intégrations API se rompent et les scripts automatisés reçoivent le statut 429 Too Many Requests. Le serveur détecte trop de requêtes provenant d'une seule IP — et cesse simplement de répondre. Dans cet article, nous allons examiner comment construire correctement une infrastructure sur des proxies pour contourner les limites de requêtes sans bans ni pannes — avec de véritables exemples de code en Python et Node.js.

Qu'est-ce que le rate limiting et pourquoi les délais habituels ne fonctionnent pas

Le rate limiting (limitation de fréquence des requêtes) est un mécanisme de protection du serveur qui limite le nombre de requêtes provenant d'une seule source sur une période donnée. La source est généralement une adresse IP, mais les systèmes avancés prennent également en compte les tokens d'autorisation, User-Agent, cookies et même les modèles de comportement.

Lorsque votre script dépasse la limite, le serveur renvoie l'une des réponses suivantes :

  • 429 Too Many Requests — statut HTTP standard pour le rate limiting
  • 503 Service Unavailable — parfois utilisé à la place de 429
  • 403 Forbidden — si l'IP est déjà sur la liste noire
  • Réponse vide ou timeout — en cas de blocage agressif

La première pensée de la plupart des développeurs est d'ajouter time.sleep(1) entre les requêtes. Cela fonctionne seulement avec des limites très douces (par exemple, 60 requêtes par minute). Mais les scénarios réels sont plus complexes :

Limites réelles des plateformes populaires :

  • Twitter/X API (gratuit) : 500 000 tweets par mois, mais pas plus de 15 requêtes toutes les 15 minutes
  • Google Search : ~100 requêtes par jour depuis une IP sans autorisation
  • Wildberries, Ozon : rate limiting agressif — blocage après 30–50 requêtes par minute
  • GitHub API : 60 requêtes/heure sans token, 5000/heure avec token
  • Sites protégés par Cloudflare : peuvent bloquer après seulement 10–20 requêtes par minute

Si vous devez collecter 100 000 fiches produits d'un marketplace ou surveiller les prix en temps réel — les délais ne suffisent pas. Une autre architecture est nécessaire. Et c'est ici que les proxies deviennent une nécessité, pas une option.

Il est important de comprendre : le rate limiting est lié à l'adresse IP. Si vous avez 100 IP différentes — vous avez en fait 100 « quotas » indépendants. C'est le principe clé pour contourner les limitations via des proxies.

Comment les proxies résolvent le problème des limitations de requêtes

Le mécanisme est simple : chaque requête au serveur cible part d'une adresse IP différente. Du point de vue du serveur — ce sont des utilisateurs différents. Le quota de chacun d'eux n'est pratiquement pas consommé, donc le blocage ne se produit pas.

Considérons la différence entre le fonctionnement sans proxy et avec un pool de proxies sur un exemple concret. Supposons que le serveur autorise 10 requêtes par minute depuis une seule IP :

Scénario Requêtes par minute Blocage Temps pour 10 000 requêtes
Une IP, sans proxy 10 Oui, après 10 requêtes ~16 heures
10 proxies, rotation 100 Non ~1.7 heures
100 proxies, rotation 1000 Non ~10 minutes

En plus de l'augmentation de la bande passante, les proxies offrent encore plusieurs avantages lors de l'utilisation du rate limiting :

  • Isolation des sessions — si une IP est bannie, les autres continuent de fonctionner
  • Répartition géographique — les requêtes proviennent de différentes régions, ce qui réduit la suspicion
  • Sessions collantes — possibilité de « coller » à une IP pour des scénarios multi-étapes (authentification + action)
  • Contrôle de la charge — il est possible de doser précisément les requêtes pour chaque IP, sans dépasser la limite

Quel type de proxy choisir pour votre tâche

Tous les proxies ne sont pas également efficaces contre le rate limiting. Le choix du type dépend du site cible, du volume de requêtes et du budget. Examinons trois types principaux :

Proxies résidentiels

Ce sont des adresses IP d'utilisateurs domestiques réels. Elles ressemblent à un trafic Internet normal et sont très rarement bloquées. Les proxies résidentiels sont le choix optimal pour les sites avec une protection agressive : marketplaces (Wildberries, Ozon), réseaux sociaux, ressources protégées par Cloudflare. Le principal inconvénient est un prix plus élevé par rapport aux proxies de centre de données.

Proxies mobiles

Adresses IP des opérateurs mobiles (3G/4G/5G). Leur particularité est qu'une IP peut être utilisée par des milliers de vrais abonnés en même temps, donc bloquer une telle adresse est très indésirable pour les sites. Les proxies mobiles montrent les meilleurs résultats là où les résidentiels commencent déjà à être bloqués — par exemple, lors du scraping à haute fréquence d'Instagram ou lors de l'utilisation d'API de plateformes qui analysent le type de connexion.

Proxies de centre de données

IP rapides et bon marché provenant de centres de données. Ils conviennent parfaitement pour le scraping de sites sans protection sérieuse : API ouvertes, agrégateurs de nouvelles, bases de données publiques. Pour les tâches avec rate limiting, il en faut plus (car elles sont plus souvent sur les listes noires), mais avec une bonne rotation, elles gèrent très bien de gros volumes de requêtes. Plus de détails sur la page des proxies de centre de données.

Type de proxy Anonymat Vitesse Prix Meilleur scénario
Résidentiels Très élevé Moyenne $$ Marketplaces, réseaux sociaux, Cloudflare
Mobiles Maximale Moyenne $$$ API Instagram, scraping à haute fréquence
Centres de données Moyenne Élevée $ API ouvertes, données publiques

Stratégies de rotation d'IP : par requête, sessions collantes, round-robin

Le simple fait d'avoir des proxies ne résout pas le problème — il est important de bien les gérer. Il existe plusieurs stratégies de rotation, chacune étant adaptée à ses scénarios.

Rotation par requête (nouvelle IP pour chaque requête)

Chaque requête HTTP passe par une nouvelle adresse IP. C'est la stratégie la plus agressive pour contourner le rate limiting — le serveur n'a physiquement pas le temps d'accumuler un compteur pour une seule IP. Convient pour :

  • Scraping de fiches produits (chaque fiche est une requête distincte)
  • Collecte de données à partir de moteurs de recherche
  • Toutes les requêtes sans état, ne nécessitant pas de session

Sessions collantes (IP fixe pour la session)

Une IP est utilisée tout au long de la session (généralement 1 à 30 minutes). C'est crucial pour les scénarios nécessitant une authentification : se connecter à un compte, effectuer une action, se déconnecter. Si l'IP change entre les étapes — le serveur peut bloquer la session comme suspecte.

Round-robin avec limite de requêtes par IP

La stratégie la plus précise. Vous connaissez la limite du serveur (par exemple, 10 requêtes par minute) et répartissez les requêtes sur le pool de proxies de manière à ce que chaque IP ne dépasse jamais ce seuil. Cela nécessite la mise en œuvre d'une file d'attente tenant compte du temps de la dernière requête pour chaque IP.

Formule pour calculer le nombre de proxies nécessaires :

N proxies = (Vitesse cible de requêtes/min) ÷ (Limite du serveur/min par IP)
Exemple : besoin de 500 requêtes/min, limite du serveur — 10/min → besoin d'au moins 50 proxies. Ajoutez 20 % de réserve en cas de blocages : total de 60 proxies.

Exemples de code en Python : requests, aiohttp, Scrapy

Passons à la pratique. Voici des modèles prêts à l'emploi pour trois des outils Python les plus populaires.

1. requests + rotation de proxies manuellement

La solution la plus simple — une liste de proxies et un choix aléatoire pour chaque requête :

import requests
import random
import time

PROXIES = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    # ... ajoutez le nombre nécessaire
]

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 limité sur {proxy}, changement en cours...")
                time.sleep(1)
                continue
            return response
        except requests.RequestException as e:
            print(f"Tentative {attempt+1} échouée : {e}")
            time.sleep(2)
    return None

# Utilisation
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)} octets")

2. Pool de proxies intelligent tenant compte du rate limit

Une option plus avancée — la classe ProxyPool, qui suit le temps de dernière utilisation de chaque IP et ne dépasse pas la limite établie :

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

class ProxyPool:
    def __init__(self, proxies, rate_limit=10, window=60):
        """
        proxies : liste de chaînes de type 'http://user:pass@host:port'
        rate_limit : maximum de requêtes depuis une IP pendant une fenêtre de temps
        window : fenêtre de temps en secondes
        """
        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:
                # Nettoyer les timestamps obsolètes
                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  # Tous les proxies ont épuisé leur limite

    def fetch(self, url, **kwargs):
        proxy = self.get_available_proxy()
        if proxy is None:
            print("Tous les proxies sont limités, attente...")
            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"Requête échouée : {e}")
            return None

# Utilisation
pool = ProxyPool(
    proxies=[
        "http://user:[email protected]:8080",
        "http://user:[email protected]:8080",
    ],
    rate_limit=10,  # 10 requêtes par minute par IP
    window=60
)

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

3. aiohttp pour le scraping asynchrone

L'approche asynchrone permet d'utiliser des dizaines de proxies en parallèle sans bloquer les 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"Erreur : {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"Collecté : {sum(1 for r in results if r is not None)} pages")

4. Scrapy avec rotation via middleware

Pour Scrapy, il existe une solution prête à l'emploi — scrapy-rotating-proxies. Mais vous pouvez écrire votre propre 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 limité, proxy : {request.meta.get('proxy')}")
            # Vous pouvez ajouter la logique pour exclure le proxy problématique
        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

Exemples de code en Node.js : axios, got, Puppeteer

Node.js est un choix populaire pour l'automatisation des navigateurs et le travail avec des API. Voici des modèles prêts à l'emploi pour travailler avec des proxies.

1. axios avec rotation 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 limité, changement de proxy...`);
        await new Promise(r => setTimeout(r, 1000));
        continue;
      }
      console.error(`Tentative ${i + 1} échouée :`, error.message);
    }
  }
  return null;
}

// Utilisation
(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(`Succès : ${successful}/${urls.length}`);
})();

2. Puppeteer avec proxy et contournement du rate limiting

Pour les sites avec rendu JavaScript et protection Cloudflare, un navigateur headless est nécessaire :

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();
  
  // Authentification du proxy
  await page.authenticate({
    username: 'user',
    password: 'pass',
  });

  // Définir un User-Agent réaliste
  await page.setUserAgent(
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, comme Gecko) Chrome/120.0.0.0 Safari/537.36'
  );

  try {
    await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
    
    // Vérifier le rate limit
    const status = await page.evaluate(() => document.title);
    if (status.includes('429') || status.includes('Trop de demandes')) {
      console.log('Rate limité, besoin de changer de proxy');
      return null;
    }
    
    const data = await page.evaluate(() => {
      return document.querySelector('.price')?.textContent || null;
    });
    
    return data;
  } finally {
    await browser.close();
  }
}

// Rotation par tâches
(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)); // petite pause
  }
})();

Techniques avancées : en-têtes, fingerprint, contournement de Cloudflare

Changer d'IP est nécessaire, mais pas toujours suffisant. Les systèmes de protection modernes analysent des dizaines de paramètres de requête. Examinons ce qu'il faut également prendre en compte.

En-têtes HTTP : ensemble minimal obligatoire

Une requête sans en-têtes normaux ressemble à un bot même avec un changement d'IP. Ajoutez toujours :

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, comme 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": "fr-FR,fr;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",
}

Gestion de l'en-tête Retry-After

Lors d'une réponse 429, le serveur indique souvent combien de temps il faut attendre. Une bonne gestion de cet en-tête permet de ne pas gaspiller des requêtes :

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 limité. Attente de {wait_time} secondes...")
            time.sleep(wait_time + 1)  # +1 seconde tampon
        else:
            # Délai exponentiel si l'en-tête n'est pas présent
            time.sleep(min(2 ** attempt, 60))
        return True
    return False

TLS fingerprinting et comment le contourner

Les systèmes avancés (Cloudflare, Akamai, PerimeterX) analysent le TLS fingerprint — une « empreinte » unique de votre connexion TLS. La bibliothèque standard requests a un fingerprint facilement identifiable. Solutions :

  • curl_cffi (Python) — émule le fingerprint Chrome/Firefox au niveau TLS
  • tls-client (Go/Python) — outil similaire avec support de différents profils de navigateur
  • Playwright/Puppeteer — véritable navigateur, fingerprint idéal par défaut
# 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",  # Émule Chrome 120
    proxies={"https": "http://user:[email protected]:8080"}
)
print(response.json())

Gestion des cookies et des sessions

Si le site utilise des cookies pour suivre les sessions, changer d'IP sans changer de cookies est inutile. Lors du changement de proxy, créez toujours une nouvelle session :

import requests

def create_fresh_session(proxy_url):
    """Crée une nouvelle session avec des cookies propres pour chaque 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)...",
    })
    # Les cookies ne sont pas transférés de la session précédente
    return session

# Pour chaque nouvelle IP — nouvelle session
for proxy in proxies:
    session = create_fresh_session(proxy)
    response = session.get("https://example.com/protected-page")
    # Traitez la réponse...

Erreurs courantes lors de l'utilisation de proxies et du rate limiting

Même avec des proxies correctement configurés, les développeurs tombent régulièrement dans les mêmes pièges. Voici les erreurs les plus fréquentes et comment les éviter.

Checklist : que vérifier avant de lancer le scraper

  • ☐ En-têtes HTTP réalistes ajoutés (User-Agent, Accept, Accept-Language)
  • ☐ Une nouvelle session est créée lors du changement de proxy (nouveaux cookies)
  • ☐ Les statuts 429, 503, 403 sont traités avec une logique de retry
  • ☐ Un délai est implémenté entre les requêtes (au moins 100–500 ms)
  • ☐ Le nombre de proxies correspond à la vitesse cible des requêtes
  • ☐ Les proxies sont vérifiés avant le démarrage (vérification de santé)
  • ☐ Les erreurs et statistiques sont journalisées pour chaque proxy
  • ☐ Un timeout est configuré pour les requêtes (pas plus de 15–30 secondes)

Erreur 1 : Utilisation de proxies « morts »

Vérifiez toujours les proxies avant de les ajouter au pool et périodiquement pendant le fonctionnement. Un proxy non fonctionnel dans la boucle — c'est des requêtes perdues et des 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

# Filtrer les proxies fonctionnels avant le démarrage
working_proxies = [p for p in PROXIES if check_proxy(p)]
print(f"Proxies fonctionnels : {len(working_proxies)}/{len(PROXIES)}")

Erreur 2 : Ignorer le type de protocole

Les proxies HTTP ne peuvent pas proxyfier le trafic HTTPS directement (uniquement via CONNECT). Les proxies SOCKS5 fonctionnent au niveau du transport et prennent en charge tous les protocoles. Pour la plupart des sites modernes, utilisez des proxies SOCKS5 ou HTTPS :

# Proxies SOCKS5 dans requests (nécessite 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",
}

Erreur 3 : Absence de backoff exponentiel

Si après 429 vous répétez immédiatement la requête — vous aggravez la situation. La bonne stratégie est d'utiliser un délai exponentiel avec jitter (écart aléatoire) :

import random

def exponential_backoff(attempt, base=1, max_wait=60):
    """
    attempt : numéro de la tentative (commençant à 0)
    base : délai de base en secondes
    max_wait : délai maximum
    """
    wait = min(base * (2 ** attempt), max_wait)
    # Jitter ±25% pour éviter le thundering herd
    jitter = wait * 0.25 * random.uniform(-1, 1)
    return wait + jitter

# Utilisation dans la logique 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 limité. Attente de {wait:.1f}s (tentative {attempt+1})")
        time.sleep(wait)
    else:
        break

Erreur 4 : Un seul thread pour tous les proxies

Si vous avez 50 proxies, mais un seul thread d'exécution — vous utilisez au maximum 1 proxy à la fois. Utilisez ThreadPoolExecutor ou une approche asynchrone pour utiliser tout le pool en parallèle :

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)

# Utiliser tous les proxies en parallèle
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})")

Conclusion et recommandations

Le rate limiting est un problème résolvable si on l'aborde de manière systématique. Les conclusions clés de ce guide :

  • Un pool de proxies, pas un seul proxy — l'unité minimale pour un travail sérieux. Le nombre de proxies est déterminé par la formule : vitesse cible ÷ limite du serveur par IP.
  • La stratégie de rotation est importante — par requête pour les requêtes sans état, sessions collantes pour les scénarios authentifiés.
  • L'IP n'est pas le seul paramètre — les en-têtes, cookies, fingerprint TLS et modèles de comportement sont également analysés par les systèmes de protection.
  • Traitez correctement le 429 — backoff exponentiel, en-tête Retry-After, changement de proxy en cas de blocage.
  • Le type de proxy dépend de l'objectif — centres de données pour les API ouvertes, résidentiels pour les marketplaces, mobiles pour une protection maximale.

Si vous travaillez avec le scraping de marketplaces (Wildberries, Ozon), la collecte de données à partir d'API protégées ou l'automatisation à grande vitesse — nous vous recommandons de commencer par des proxies résidentiels : ils offrent un équilibre optimal entre anonymat et vitesse, et leurs adresses IP sont pratiquement jamais bloquées. Pour les tâches nécessitant une résistance maximale aux blocages à haute fréquence de requêtes, envisagez des proxies mobiles — leurs IP sont partagées par des milliers d'utilisateurs réels, rendant le blocage extrêmement indésirable pour tout site.

```