Retour au blog
Guides
Raluca PenciucLast updated on May 8, 202612 min read

Comment faire pivoter les proxys en Python

Comment faire pivoter les proxys en Python
En bref : ce guide explique comment gérer la rotation des proxys de bout en bout en Python : choisir le bon type de proxy, créer et valider un pool, puis effectuer une rotation séquentielle avec itertools.cycle, de manière aléatoire avec random.choice, ou de manière asynchrone avec aiohttp. Nous associons également la rotation des adresses IP à celle des User-Agents et ajoutons des tentatives de reconnexion tenant compte de l'état, afin qu'un seul proxy défaillant ne mette pas fin à votre scraping.

Si votre scraper Python a commencé à renvoyer des codes 403, 429 ou des pages vides alors qu'il fonctionnait très bien hier, vous êtes presque certainement victime d'un bridage ou d'un bannissement par adresse IP. La solution à laquelle la plupart des équipes ont recours est la rotation des proxys, et apprendre à faire tourner les proxys en Python est un passage obligé pour quiconque souhaite aller au-delà d'un simple script amateur.

La rotation des proxys en Python consiste à changer l'adresse IP sortante à chaque requête, selon un calendrier ou de manière aléatoire, afin que chaque requête semble provenir d'une machine différente. Bien exécutée, elle répartit la charge sur de nombreuses adresses IP, contourne les limites de débit par IP et rend le trafic du scraper plus difficile à identifier pour les systèmes anti-bot. Mal exécutée, avec une liste de proxys libres obsolète et une approche globale try/except, cela ne fait que transformer une adresse IP bannie en un pool d’adresses IP bannies.

Cet article est un guide pratique sur la rotation des proxys en Python. Nous choisirons des types de proxys, construirons un pool validé, enverrons une requête via Requests, puis passerons en revue trois stratégies de rotation (séquentielle, aléatoire, asynchrone). Nous associerons la rotation d’IP à la rotation d’en-têtes, ajouterons une gestion d’erreurs réelle et terminerons par une comparaison honnête entre l’achat et la création.

Qu'est-ce que la rotation de proxys et pourquoi votre scraper Python en a besoin

Un proxy cache votre véritable adresse IP derrière une adresse intermédiaire, mais un proxy statique unique reste une adresse IP qu’une cible peut limiter en débit et bannir. La rotation des proxys change l’adresse IP sortante à chaque requête ou à chaque session, de sorte que le même scraper semble provenir de nombreuses origines.

C'est important car les systèmes anti-bot s'appuient fortement sur la limitation de débit, plafonnant le nombre de requêtes par IP dans une fenêtre donnée avant de renvoyer des codes 429. La rotation au sein d'un pool sain maintient chaque IP sous ces seuils et empêche qu'un seul bannissement ne mette fin à l'ensemble de la tâche.

Choisissez le bon type de proxy avant de lancer la rotation

La rotation n'est efficace que si les adresses IP utilisées sont de bonne qualité. Choisir le mauvais type explique pourquoi des équipes passent des semaines à peaufiner leur logique face à une cible qui n'accepterait jamais leur trafic.

Type de proxy

Vitesse

Risque de blocage

Coût

Idéal pour

Centre de données

Le plus rapide

Très performant sur les sites protégés

Le moins cher

API publiques, défenses légères

Résidentiel

Moyen

Faible

Moyen-élevé

E-commerce, SERP, pages géolocalisées

Mobile (4G/5G)

Le plus lent

Le plus bas

Le plus élevé

Réseaux sociaux, API d'applications, cibles précises

FAI (résidentiel statique)

Rapide

Faible

Moyen-élevé

Sessions longues, extraction de comptes

La première décision à prendre pour la rotation des proxys en Python ne concerne pas l'algorithme, mais l'adaptation du pool à la défense.

Configurer votre environnement Python pour la rotation des proxys

Utilisez Python 3.8+ dans un virtualenv. Installez Requests et aiohttp, et conservez les proxys dans un fichier texte brut afin que le rotateur puisse les recharger à la volée.

mkdir proxy_rotator && cd proxy_rotator
python -m venv .venv && source .venv/bin/activate
pip install requests aiohttp
touch app.py proxies.txt

Construisez et validez une liste de proxys fonctionnelle

Vous pouvez assembler une proxies.txt à partir de sources publiques (agrégateurs de proxys gratuits, miroirs GitHub), ou charger des identifiants provenant d’un pool payant. Dans tous les cas, attendez-vous à ce qu’une partie importante soit hors service avant même votre première requête, en particulier sur les listes gratuites où la plupart des entrées sont peut-être déjà bloquées par des cibles populaires.

Utilisez une entrée par ligne, sous la forme http://host:port ou http://user:pass@host:port, puis validez-la par rapport à un point de terminaison IP-echo :

import requests

def validate(proxy, timeout=5):
    try:
        r = requests.get("https://httpbin.io/ip",
                         proxies={"http": proxy, "https": proxy},
                         timeout=timeout)
        return r.ok and proxy.split("@")[-1].split(":")[0] in r.text
    except requests.RequestException:
        return False

with open("proxies.txt") as f:
    pool = [p.strip() for p in f if p.strip() and validate(p.strip())]

La vérification de correspondance d'IP détecte les proxys transparents qui laissent passer votre adresse réelle. Pour des vérifications plus approfondies, envoyez une requête ping vers une page cible réelle plutôt que de vous contenter de httpbin.io/ip.

Envoyer une seule requête via un proxy avec Requests

Avant de faire tourner quoi que ce soit, assurez-vous qu'un proxy fonctionne de bout en bout. Requests accepte un proxies dict sur get() ou sur un Session; la même URL fonctionne généralement pour les deux http et https .

import requests

proxy = "http://user:pass@host:port"   # auth is embedded in the URL
proxies = {"http": proxy, "https": proxy}

with requests.Session() as s:
    s.proxies.update(proxies)
    r = s.get("https://httpbin.io/ip", timeout=10)
    print(r.status_code, r.json())

Si vous préférez ne pas inclure la configuration du proxy dans le code, définissez la HTTP_PROXY et HTTPS_PROXY ; Requests les lit automatiquement. Les proxys gratuits génèrent souvent des SSLError: CERTIFICATE_VERIFY_FAILED car ils interceptent le trafic TLS. À titre de solution temporaire, vous pouvez passer verify=False, mais considérez cela comme un outil de débogage et non comme un paramètre de production, car cela désactive complètement la validation des certificats.

Comment faire tourner les proxys en Python : trois stratégies (séquentielle, aléatoire et asynchrone)

Une fois qu’une requête fonctionne, la question de la rotation des proxys en Python se résume à un compromis entre prévisibilité, discrétion et débit. Les trois modèles ci-dessous couvrent presque tous les scrapers réels.

Rotation séquentielle avec itertools.cycle

La rotation séquentielle parcourt le pool dans l'ordre et revient au début, répartissant le trafic de manière uniforme. C'est le modèle le plus facile à comprendre, car l'adresse IP suivante est toujours connue.

import itertools, requests

with open("proxies.txt") as f:
    proxies = [p.strip() for p in f if p.strip()]

pool = itertools.cycle(proxies)

for _ in range(8):
    proxy = next(pool)
    r = requests.get("https://httpbin.io/ip",
                     proxies={"http": proxy, "https": proxy},
                     timeout=10)
    print(proxy, r.status_code)

L'inconvénient est qu'un ordre déterministe constitue en soi une empreinte. Si un défenseur voit les adresses IP A, B, C, D, A, B, C, D provenant de la même empreinte de navigateur en quelques secondes, il peut signaler l'ensemble du pool. La rotation séquentielle fonctionne mieux sur des pools plus importants avec des délais plus longs par adresse IP.

Rotation aléatoire avec random.choice

La rotation aléatoire brise le schéma en choisissant un proxy arbitraire à chaque requête, ce qui rend le trafic plus difficile à corréler.

import random, requests

with open("proxies.txt") as f:
    proxies = [p.strip() for p in f if p.strip()]

for _ in range(8):
    proxy = random.choice(proxies)
    r = requests.get("https://httpbin.io/ip",
                     proxies={"http": proxy, "https": proxy},
                     timeout=10)
    print(proxy, r.status_code)

L'inconvénient est une utilisation inégale : un petit pool surutilisera certaines adresses IP et en laissera d'autres inactives. Pour un meilleur équilibre, effectuez un tirage sans remplacement jusqu'à épuisement du pool à l'aide de random.sample(proxies, len(proxies)) puis mélangez à nouveau. Cela permet de garder les requêtes imprévisibles tout en répartissant la charge.

Rotation asynchrone avec aiohttp et asyncio

Lorsque votre pool dépasse quelques dizaines d'adresses IP, leur validation en série devient un goulot d'étranglement. La rotation asynchrone exécute de nombreuses requêtes simultanément dans un seul thread, ce qui réduit considérablement le temps de validation et permet à un pool de travailleurs de traiter une liste de tâches sans se bloquer sur des proxys lents.

import asyncio, aiohttp

CONCURRENCY = 20
TIMEOUT = aiohttp.ClientTimeout(total=10)

async def check_proxy(session, proxy, sem):
    async with sem:
        try:
            async with session.get("https://httpbin.io/ip",
                                   proxy=proxy, timeout=TIMEOUT) as r:
                return proxy, r.status, await r.text()
        except (aiohttp.ClientError, asyncio.TimeoutError) as e:
            return proxy, None, str(e)

async def main(proxies):
    sem = asyncio.Semaphore(CONCURRENCY)
    async with aiohttp.ClientSession() as session:
        tasks = [check_proxy(session, p, sem) for p in proxies]
        return await asyncio.gather(*tasks)

with open("proxies.txt") as f:
    proxies = [p.strip() for p in f if p.strip()]
results = asyncio.run(main(proxies))

Le sémaphore limite le nombre de requêtes traitées simultanément afin de ne pas épuiser les descripteurs de fichiers ni dépasser les limites de débit de la cible. aiohttp expose un argument par requête proxy= , que la documentation avancée du client aiohttp couvre en détail, ainsi que le comportement de l'authentification et de l'environnement de confiance.

Associez la rotation des proxys à la rotation des User-Agent et des en-têtes

La rotation des adresses IP seule laisse encore apparaître une empreinte digitale. Si 200 adresses IP différentes envoient le même python-requests/2.31.0 , un système anti-bot peut les corréler instantanément.

Faites tourner les en-têtes en même temps que les proxys et conservez les cookies liés à l'identité qui les a créés :

import random

UAS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_5) AppleWebKit/605.1.15 ...",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 ...",
]
LANGS = ["en-US,en;q=0.9", "en-GB,en;q=0.8", "de-DE,de;q=0.9,en;q=0.8"]

def rotated_headers():
    return {"User-Agent": random.choice(UAS),
            "Accept-Language": random.choice(LANGS),
            "Referer": "https://www.google.com/"}

associez un User-Agent et un ensemble de cookies à un proxy pendant toute la durée d'une session logique, puis faites-les tourner ensemble lorsque vous changez d'identité.

Gestion des erreurs et vérifications de l'état des proxys de niveau production

La plupart des débutants en rotation de proxys abandonnent un proxy à la moindre erreur. Cela revient à jeter des adresses IP qui venaient juste d’être limitées en débit et à traiter un proxy défaillant de la même manière qu’une cible vous demandant de ralentir.

Considérez le code de réponse comme un signal. Conformément à la RFC 6585, le code 429 signifie un nombre trop élevé de requêtes, et non un proxy hors service : prenez du recul et réessayez avec la même adresse IP. Abandonnez en cas de code 407 ou d'erreurs de connexion répétées, et mettez en quarantaine les mauvais proxys afin de pouvoir les revérifier après un temps de pause.

import time, random
from collections import defaultdict

class ProxyManager:
    def __init__(self, proxies, max_fail=3, cooldown=300):
        self.live, self.dead = list(proxies), {}
        self.fails = defaultdict(int)
        self.max_fail, self.cooldown = max_fail, cooldown

    def get(self):
        self._revive()
        return random.choice(self.live) if self.live else None

    def report(self, proxy, status=None, error=None):
        if status == 429 or (status and 500 <= status < 600):
            time.sleep(min(2 ** self.fails[proxy], 30))   # keep, back off
        elif status == 407 or error:
            self.fails[proxy] += 1
            if self.fails[proxy] >= self.max_fail:
                self.live.remove(proxy)
                self.dead[proxy] = time.time() + self.cooldown

    def _revive(self):
        now = time.time()
        for p, t in list(self.dead.items()):
            if now >= t:
                self.live.append(p); self.dead.pop(p); self.fails[p] = 0

Ajustez max_fail et le délai de base en fonction de votre profil de trafic plutôt que de copier aveuglément les valeurs par défaut.

Rotation manuelle vs rotation gérée : choisir votre voie

Développer votre propre rotateur convient pour l'apprentissage et les petites tâches. À grande échelle, cela devient un deuxième produit : rotation des proxys, validateurs, tentatives de reconnexion et intervention en cas de mise à jour de la pile d'une cible.

Un proxy rotatif géré ou une API de scraping cache tout cela derrière un seul point de terminaison et facture à la requête réussie.

Signal

DIY allégé

Gestion allégée

Taille du pool

< 100 adresses IP

Plus de mille

Difficulté de la cible

Faiblement défendu

Marketplaces, SERP, réseaux sociaux

Exigences du SLA

Meilleur effort

Taux de réussite prévisible

L'intérêt d'apprendre à faire tourner les proxys en Python n'est pas de maintenir un rotateur indéfiniment ; il s'agit de savoir quand la rotation manuelle suffit et quand il faut déléguer.

Points clés

  • Adaptez le type de proxy à la cible avant d'ajuster la logique de rotation ; faire tourner des adresses IP de centres de données bon marché contre un site sécurisé est une bataille perdue d'avance.
  • Une configuration fiable de rotation de proxys en Python commence par un pool de proxys validés, et non par une liste aléatoire, et vérifie à nouveau les proxys inactifs après un délai de refroidissement, car les pools libres alternent entre des états fonctionnels et défaillants.
  • Utilisez itertools.cycle pour une distribution prévisible, random.choice pour la discrétion, et aiohttp avec asyncio pour une validation à haut débit et des récupérations simultanées.
  • Faites tourner les valeurs User-Agent et d'en-tête en même temps que les adresses IP afin de ne pas divulguer une empreinte stable derrière 200 proxys différents.
  • Construisez un rotateur sensible à l'état qui se retire en cas de 429 et 5xx, abandonne en cas de 407 ou d'erreurs de connexion répétées, et met en quarantaine les mauvais proxys au lieu de traiter chaque exception de la même manière.

FAQ

Quelle est la différence entre faire tourner les proxys moi-même et utiliser une passerelle de proxys rotatifs ou une API de scraping ?

Gérer votre propre rotateur signifie que vous contrôlez la liste de proxys, la validation, la logique de réessai et le routage géographique. Une passerelle de proxys rotatifs expose un point de terminaison unique qui sélectionne une adresse IP pour vous à chaque requête, tandis qu'une API de scraping gère également le rendu du navigateur, les CAPTCHA et le déblocage. Le « DIY » vous offre un contrôle maximal ; les passerelles et les API sacrifient une partie du contrôle au profit d'un code d'infrastructure bien plus léger.

De combien de proxys ai-je besoin dans mon pool de rotation pour une tâche de scraping classique ?

Une règle empirique utile consiste à prévoir une adresse IP valide par worker simultané, plus 5 à 10 fois plus en réserve pour absorber le taux de désabonnement, les blocages et les proxys inactifs. Les petites tâches de quelques milliers de requêtes peuvent s’exécuter sur 20 à 50 adresses IP résidentielles vérifiées ; les scrappings qui ciblent des sites hautement sécurisés ou des millions de pages nécessitent généralement des milliers d’adresses IP rotatives pour maintenir un faible taux de requêtes par IP.

Pourquoi les proxys gratuits sont-ils toujours bloqués même lorsque je les fais tourner à chaque requête ?

Les proxys gratuits sont partagés par de nombreux inconnus qui exécutent leurs propres scrapers ; par conséquent, les adresses IP sont généralement déjà sur liste noire auprès des cibles populaires avant même que vous ne les utilisiez. Ils présentent également des fuites évidentes, en envoyant des en-têtes tels que Via ou X-Forwarded-For, ne correspondant pas à l'adresse IP qu'ils prétendent utiliser, ou en violant le protocole TLS. La rotation ne peut pas corriger une adresse IP qui figure déjà sur la liste noire.

Dois-je faire tourner les proxys à chaque requête ou conserver une session persistante par site cible ?

Utilisez des sessions persistantes chaque fois que la cible lie l'état à une adresse IP, comme les pages de connexion, les processus de paiement en plusieurs étapes ou les flux riches en JavaScript qui émettent de nombreuses sous-requêtes. Changez de proxy à chaque requête lorsque vous scrapez des listes sans état, des pages de recherche ou des flux de produits. Une pratique courante consiste à utiliser une adresse IP par session logique, puis une nouvelle adresse IP pour la session suivante.

Puis-je réutiliser ce modèle de rotation avec Selenium ou Playwright à la place de Requests ?

Oui, moyennant quelques ajustements. Ces deux outils d'automatisation de navigateur acceptent les paramètres de proxy, mais vous devez généralement lancer un contexte de navigateur par proxy, car la plupart des pilotes ne vous permettent pas de changer de proxy en cours de session. Créez un pool de navigateurs, chacun lié à une adresse IP et à un User-Agent, et effectuez la rotation des navigateurs eux-mêmes plutôt que de la variable proxy au sein d'un seul navigateur.

Conclusion : de la rotation manuelle au scraping fiable

Savoir comment faire tourner les proxys en Python est une compétence fondamentale pour tout développeur qui souhaite aller au-delà d’un scraper à IP unique. Vous disposez désormais des éléments de base : choisissez le type de proxy adapté à votre cible, validez le pool avant de lui faire confiance, effectuez la rotation de manière séquentielle, aléatoire ou asynchrone en fonction de vos compromis, intégrez la rotation des User-Agent et utilisez un gestionnaire sensible à l’état afin qu’un seul 429 ne mette pas hors service une IP en bon état.

Ce qui est plus difficile, c'est de maintenir ce système en bon état de fonctionnement face à des cibles qui modifient leurs défenses sans préavis. Les listes gratuites se détériorent, les pools résidentiels doivent être rééquilibrés et les règles 429 évoluent. Si vous préférez consacrer ce temps d'ingénierie aux données plutôt qu'à l'infrastructure, l'API Scraper de WebScrapingAPI gère la rotation des proxys, le contournement des anti-bots et les tentatives de reconnexion derrière un point de terminaison unique, ce qui vous permet de conserver votre code Requests ou aiohttp code et de simplement remplacer la couche de récupération. Faites tourner les adresses IP vous-même pour l'apprentissage ou les petites tâches, et optez pour une couche gérée lorsque les coûts de maintenance dépassent les économies réalisées.

À propos de l'auteur
Raluca Penciuc, Développeur full-stack @ WebScrapingAPI
Raluca PenciucDéveloppeur full-stack

Raluca Penciuc est développeuse Full Stack chez WebScrapingAPI ; elle conçoit des robots de collecte de données, améliore les techniques de contournement et recherche des moyens fiables de réduire le risque de détection sur les sites cibles.

Commencez à créer

Prêt à faire évoluer votre système de collecte de données ?

Rejoignez plus de 2 000 entreprises qui utilisent WebScrapingAPI pour extraire des données Web à l'échelle de l'entreprise, sans aucun coût d'infrastructure.