Que faire si les proxies sont constamment bannis : guide complet de diagnostic et de résolution de problèmes
Les blocages constants de proxies sont l'un des problèmes les plus courants lors du scraping, de l'automatisation et du travail avec plusieurs comptes. Dans cet article, nous analyserons pourquoi cela se produit et comment résoudre le problème de manière systématique, plutôt que de changer constamment de fournisseurs en espérant un miracle.
Pourquoi les proxies sont vraiment bannis
Avant de chercher une solution, vous devez comprendre la mécanique des blocages. Les systèmes anti-fraude modernes utilisent une protection multicouche, et le ban du proxy n'est que la conséquence, pas la cause. Comprendre comment ces systèmes fonctionnent permet de mettre en place une stratégie de contournement efficace.
Réputation IP et listes noires
Chaque adresse IP a une réputation basée sur l'historique de son utilisation. Si l'adresse a été utilisée précédemment pour le spam, les attaques DDoS ou le scraping massif, elle se retrouve dans des bases de données comme Spamhaus, SORBS ou des listes propriétaires de services spécifiques. Lorsque vous vous connectez via une telle IP, le système vous traite immédiatement avec suspicion.
Les proxies de centre de données sont particulièrement sujets à ce problème. Des sous-réseaux entiers peuvent être marqués comme « hébergement », et tout le trafic en provenance d'eux reçoit automatiquement un niveau de vérification accru. Amazon AWS, Google Cloud, DigitalOcean — leurs plages IP sont bien connues et souvent bloquées de manière préventive.
Vous pouvez vérifier la réputation d'une IP via des services comme IPQualityScore, Scamalytics ou AbuseIPDB. Si votre proxy affiche un fraud score supérieur à 75, le problème vient de là — changez de fournisseur ou de type de proxy.
Modèles de requêtes
Un humain ne fait pas 100 requêtes par seconde. Un humain ne navigue pas entre les pages avec une périodicité parfaite de 2 secondes. Un humain n'ignore pas les images, CSS et JavaScript, en ne demandant que du HTML. Les systèmes anti-fraude analysent exactement ces modèles, et tout écart par rapport au comportement « humain » augmente le risque de blocage.
Les statistiques sur le temps entre les requêtes sont particulièrement révélatrices. Si vous avez un intervalle stable — c'est un signe évident d'automatisation. Ajouter un délai aléatoire (par exemple, de 1 à 5 secondes) réduit considérablement la probabilité de détection.
Incohérence des métadonnées
Lorsque votre User-Agent indique que vous utilisez Chrome sur Windows, mais que les en-têtes HTTP révèlent les caractéristiques de Python requests — c'est un drapeau rouge. Lorsque l'adresse IP est géolocalisée en Allemagne, mais que les paramètres de langue du navigateur indiquent le russe — c'est un autre drapeau rouge. Lorsque le fuseau horaire en JavaScript ne correspond pas à la géographie de l'IP — c'est un troisième drapeau.
L'accumulation de telles incohérences amène le système à classer la connexion comme suspecte et à appliquer des mesures de protection : des captchas au blocage complet de l'IP.
Empreinte du navigateur
Les systèmes de protection modernes collectent des dizaines de paramètres du navigateur : résolution d'écran, polices installées, plugins, rendu WebGL, contexte audio et bien d'autres. L'ensemble de ces paramètres crée une « empreinte » unique qui reste constante même lors du changement d'IP.
Si vous changez de proxy mais que l'empreinte reste la même, le système comprend que c'est le même utilisateur. Et si une empreinte apparaît avec des centaines d'IP différentes en peu de temps — c'est un signe évident d'automatisation.
Diagnostic : comment comprendre la cause du blocage
Avant de modifier les paramètres au hasard, effectuez un diagnostic. Cela vous fera gagner des heures d'expérimentation et vous aidera à trouver la véritable cause du problème. Une approche systématique du diagnostic est la clé pour résoudre efficacement le problème.
Étape 1 : Vérifiez le proxy lui-même
Commencez par une vérification basique de la fonctionnalité du proxy indépendamment de votre script principal :
import requests
proxy = {
"http": "http://user:pass@proxy-server:port",
"https": "http://user:pass@proxy-server:port"
}
# Vérification de la fonctionnalité basique
try:
response = requests.get("https://httpbin.org/ip", proxies=proxy, timeout=10)
print(f"IP via proxy : {response.json()['origin']}")
except Exception as e:
print(f"Erreur de connexion : {e}")
# Vérification de la fuite d'IP réelle
response = requests.get("https://browserleaks.com/ip", proxies=proxy)
# Comparez avec votre IP réelle
Si le proxy ne fonctionne même pas sur des requêtes simples — le problème vient du proxy lui-même ou des identifiants. Vérifiez le format correct de connexion, la présence de fonds sur le compte et les limites du fournisseur.
Étape 2 : Vérifiez la réputation de l'IP
Utilisez plusieurs services pour une évaluation complète :
# Obtenez l'IP du proxy
proxy_ip = requests.get("https://api.ipify.org", proxies=proxy).text
# Vérifiez sur ces services :
# https://www.ipqualityscore.com/free-ip-lookup-proxy-vpn-test
# https://scamalytics.com/ip/{proxy_ip}
# https://www.abuseipdb.com/check/{proxy_ip}
# https://whatismyipaddress.com/ip/{proxy_ip}
print(f"Vérifiez l'IP {proxy_ip} sur les services ci-dessus")
Prêtez attention aux indicateurs suivants : fraud score (doit être inférieur à 50), type d'IP (résidentiel est mieux que centre de données), présence dans les listes noires. Si l'IP est marquée comme VPN/Proxy — de nombreux sites la traiteront avec suspicion dès le départ.
Étape 3 : Isolez le problème
Essayez le même proxy sur différents sites cibles. Si le blocage se produit partout — le problème vient du proxy ou de votre configuration. Si seulement sur un site spécifique — le problème vient de la protection de ce site ou de votre comportement sur celui-ci.
Essayez également différents proxies sur un même site. Si tous sont bloqués — le problème ne vient pas du proxy, mais de votre script, de l'empreinte ou du modèle de comportement. C'est un test critique que beaucoup oublient.
Étape 4 : Analyse des réponses du serveur
Différents types de blocages se manifestent différemment. Apprenez à les distinguer :
def analyze_response(response):
status = response.status_code
if status == 403:
print("Accès refusé — l'IP est peut-être sur liste noire")
elif status == 429:
print("Trop de requêtes — réduisez la fréquence")
elif status == 503:
print("Service indisponible — protection DDoS possible")
elif status == 407:
print("Authentification proxy requise — vérifiez les identifiants")
elif "captcha" in response.text.lower():
print("Captcha détecté — suspicion de bot")
elif "blocked" in response.text.lower():
print("Blocage explicite — changez d'IP et révisez votre approche")
elif len(response.text) < 1000:
print("Réponse suspecte courte — peut-être un leurre")
else:
print(f"Statut {status}, longueur de réponse : {len(response.text)}")
Rotation correcte : fréquence, logique, implémentation
La rotation de proxy n'est pas simplement « changer d'IP plus souvent ». Une rotation incorrecte peut faire plus de mal que son absence. Examinons différentes stratégies et quand les appliquer.
Stratégie 1 : Rotation par nombre de requêtes
L'approche la plus simple — changer d'IP après un certain nombre de requêtes. Convient pour le scraping où la session n'est pas nécessaire :
import random
class ProxyRotator:
def __init__(self, proxy_list, requests_per_proxy=50):
self.proxies = proxy_list
self.requests_per_proxy = requests_per_proxy
self.current_proxy = None
self.request_count = 0
def get_proxy(self):
if self.current_proxy is None or self.request_count >= self.requests_per_proxy:
# Ajoutez de l'aléatoire au nombre de requêtes
self.requests_per_proxy = random.randint(30, 70)
self.current_proxy = random.choice(self.proxies)
self.request_count = 0
self.request_count += 1
return self.current_proxy
# Utilisation
rotator = ProxyRotator(proxy_list)
for url in urls_to_scrape:
proxy = rotator.get_proxy()
response = requests.get(url, proxies={"http": proxy, "https": proxy})
Notez l'aléatoire dans le nombre de requêtes par proxy. Un nombre fixe (par exemple, exactement 50) est un modèle qui peut être détecté. Une plage aléatoire rend le comportement moins prévisible.
Stratégie 2 : Rotation basée sur le temps
Pour les tâches où la session est importante (par exemple, le travail avec des comptes), il est préférable de lier l'IP au temps :
import time
import random
class TimeBasedRotator:
def __init__(self, proxy_list, min_minutes=10, max_minutes=30):
self.proxies = proxy_list
self.min_seconds = min_minutes * 60
self.max_seconds = max_minutes * 60
self.current_proxy = None
self.rotation_time = 0
def get_proxy(self):
current_time = time.time()
if self.current_proxy is None or current_time >= self.rotation_time:
self.current_proxy = random.choice(self.proxies)
# Intervalle aléatoire avant la prochaine rotation
interval = random.randint(self.min_seconds, self.max_seconds)
self.rotation_time = current_time + interval
print(f"Nouveau proxy, prochaine rotation dans {interval//60} minutes")
return self.current_proxy
Stratégie 3 : Sessions collantes pour les comptes
Lorsque vous travaillez avec plusieurs comptes, il est essentiel que chaque compte utilise une IP constante. Changer d'IP pour un compte connecté — c'est un moyen sûr d'être banni :
class AccountProxyManager:
def __init__(self, proxy_pool):
self.proxy_pool = proxy_pool
self.account_proxies = {} # account_id -> proxy
self.used_proxies = set()
def get_proxy_for_account(self, account_id):
# Si un proxy est déjà assigné au compte — le retourner
if account_id in self.account_proxies:
return self.account_proxies[account_id]
# Trouvez un proxy libre
available = [p for p in self.proxy_pool if p not in self.used_proxies]
if not available:
raise Exception("Pas de proxy libre pour les nouveaux comptes")
proxy = random.choice(available)
self.account_proxies[account_id] = proxy
self.used_proxies.add(proxy)
return proxy
def release_account(self, account_id):
"""Libère le proxy lors de la suppression du compte"""
if account_id in self.account_proxies:
proxy = self.account_proxies.pop(account_id)
self.used_proxies.discard(proxy)
# Utilisation
manager = AccountProxyManager(residential_proxy_list)
for account in accounts:
proxy = manager.get_proxy_for_account(account.id)
# Toutes les actions de ce compte passent par une seule IP
Stratégie 4 : Rotation adaptative
L'approche la plus avancée — changer de proxy en réponse aux signaux du site cible :
class AdaptiveRotator:
def __init__(self, proxy_list):
self.proxies = proxy_list
self.current_proxy = random.choice(proxy_list)
self.proxy_scores = {p: 100 for p in proxy_list} # "Santé" initiale du proxy
def get_proxy(self):
return self.current_proxy
def report_result(self, success, response_code=200):
"""Appelé après chaque requête"""
if success and response_code == 200:
# Requête réussie — augmentez légèrement le score
self.proxy_scores[self.current_proxy] = min(100,
self.proxy_scores[self.current_proxy] + 1)
elif response_code == 429:
# Limite de débit — réduisez fortement et faites tourner
self.proxy_scores[self.current_proxy] -= 30
self._rotate()
elif response_code == 403:
# Ban — réinitialisez le score et faites tourner
self.proxy_scores[self.current_proxy] = 0
self._rotate()
elif response_code == 503:
# Protection possible — réduisez et faites tourner
self.proxy_scores[self.current_proxy] -= 20
self._rotate()
def _rotate(self):
# Sélectionnez le proxy avec le meilleur score
available = [(p, s) for p, s in self.proxy_scores.items() if s > 20]
if not available:
# Tous les proxies sont "morts" — réinitialisez les scores
self.proxy_scores = {p: 50 for p in self.proxies}
available = list(self.proxy_scores.items())
# Sélection pondérée par score
self.current_proxy = max(available, key=lambda x: x[1])[0]
print(f"Rotation vers proxy avec score {self.proxy_scores[self.current_proxy]}")
Empreinte du navigateur et son rôle dans les blocages
L'empreinte est l'ensemble des caractéristiques du navigateur qui permettent d'identifier l'utilisateur même sans cookies. Si vous changez de proxy mais que l'empreinte reste la même, le système de protection relie facilement toutes vos sessions.
De quoi se compose l'empreinte
L'empreinte moderne comprend des dizaines de paramètres. Voici les catégories principales :
| Catégorie | Paramètres | Poids dans l'identification |
|---|---|---|
| User-Agent | Navigateur, version, OS | Moyen |
| Écran | Résolution, profondeur de couleur, ratio de pixels | Moyen |
| Polices | Liste des polices installées | Élevé |
| WebGL | Renderer, vendor, hash de rendu | Très élevé |
| Canvas | Hash de l'image dessinée | Très élevé |
| Audio | Empreinte AudioContext | Élevé |
| Fuseau horaire | Fuseau horaire, offset | Moyen |
| Langues | navigator.languages | Moyen |
| Plugins | navigator.plugins | Faible (dans les navigateurs modernes) |
Cohérence entre l'empreinte et l'IP
Il est essentiel que l'empreinte corresponde à la géographie de l'IP. Si le proxy est en Allemagne, l'empreinte doit ressembler à celle d'un utilisateur allemand :
// Exemple d'incohérence (MAUVAIS):
// IP : Allemagne
// Fuseau horaire : America/New_York
// Langues : ["ru-RU", "ru"]
// Cela suscite des soupçons
// Empreinte cohérente (BON):
// IP : Allemagne
// Fuseau horaire : Europe/Berlin
// Langues : ["de-DE", "de", "en-US", "en"]
Outils de gestion de l'empreinte
Pour un travail sérieux, utilisez des outils spécialisés :
Playwright avec Stealth :
from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={"server": "http://proxy:port", "username": "user", "password": "pass"}
)
context = browser.new_context(
viewport={"width": 1920, "height": 1080},
locale="de-DE",
timezone_id="Europe/Berlin",
geolocation={"latitude": 52.52, "longitude": 13.405},
permissions=["geolocation"]
)
page = context.new_page()
stealth_sync(page) # Appliquez les patches stealth
page.goto("https://target-site.com")
Puppeteer avec puppeteer-extra :
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch({
args: [`--proxy-server=http://proxy:port`]
});
const page = await browser.newPage();
// Redéfinissez le fuseau horaire
await page.evaluateOnNewDocument(() => {
Object.defineProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', {
value: function() {
return { timeZone: 'Europe/Berlin' };
}
});
});
Navigateurs anti-détection
Pour travailler avec des comptes, on utilise souvent des navigateurs anti-détection (Multilogin, GoLogin, Dolphin Anty et autres). Ils permettent de créer des profils isolés avec des empreintes uniques. Chaque profil a son propre ensemble de paramètres, cookies, localStorage — un environnement complètement isolé.
L'avantage des navigateurs anti-détection est qu'ils résolvent le problème de l'empreinte « clé en main ». L'inconvénient est le coût et la complexité de l'automatisation (bien que beaucoup aient une API).
Modèles de comportement : comment ne pas ressembler à un bot
Même avec une empreinte parfaite et une IP propre, vous pouvez être banni en raison d'un comportement non humain. Les systèmes modernes analysent non seulement les paramètres techniques, mais aussi les modèles d'interaction avec le site.
Délais temporels
Un humain ne fait pas de requêtes avec un intervalle constant. Ajoutez des délais aléatoires avec une distribution normale :
import random
import time
import numpy as np
def human_delay(min_sec=1, max_sec=5, mean=2.5):
"""
Génère un délai ressemblant à celui d'un humain.
Utilise une distribution log-normale —
la plupart des délais sont courts, mais il y en a parfois de longs.
"""
delay = np.random.lognormal(mean=np.log(mean), sigma=0.5)
delay = max(min_sec, min(max_sec, delay))
return delay
def human_typing_delay():
"""Délai entre les appuis sur les touches lors de la saisie de texte"""
return random.uniform(0.05, 0.25)
# Utilisation
for url in urls:
response = requests.get(url, proxies=proxy)
process(response)
time.sleep(human_delay()) # Pause aléatoire entre les requêtes
Imitation de la navigation
Un humain ne va pas directement à la page du produit via un lien direct. Il va sur la page d'accueil, utilise la recherche, parcourt les catégories. Imitez ce chemin :
async def human_like_navigation(page, target_url):
"""Imite la navigation humaine vers la page cible"""
# 1. Allez sur la page d'accueil
await page.goto("https://example.com")
await page.wait_for_timeout(random.randint(2000, 4000))
# 2. Parfois, faites défiler la page d'accueil
if random.random() > 0.5:
await page.evaluate("window.scrollBy(0, 300)")
await page.wait_for_timeout(random.randint(1000, 2000))
# 3. Utilisez la recherche ou la navigation
if random.random() > 0.3:
search_box = await page.query_selector('input[type="search"]')
if search_box:
await search_box.type("search query", delay=100)
await page.keyboard.press("Enter")
await page.wait_for_timeout(random.randint(2000, 4000))
# 4. Allez à la page cible
await page.goto(target_url)
# 5. Faites défiler la page comme un humain
await human_scroll(page)
async def human_scroll(page):
"""Imite le défilement humain"""
scroll_height = await page.evaluate("document.body.scrollHeight")
current_position = 0
while current_position < scroll_height * 0.7: # Pas jusqu'au bout
scroll_amount = random.randint(200, 500)
await page.evaluate(f"window.scrollBy(0, {scroll_amount})")
current_position += scroll_amount
await page.wait_for_timeout(random.randint(500, 1500))
Mouvements de souris
Certains systèmes suivent les mouvements de la souris. Un mouvement rectiligne du point A au point B est un signe de bot. Un humain bouge la souris en courbe avec des micro-corrections :
import bezier
import numpy as np
def generate_human_mouse_path(start, end, num_points=50):
"""
Génère un chemin de souris ressemblant à celui d'un humain,
en utilisant des courbes de Bézier avec un léger bruit.
"""
# Points de contrôle pour la courbe de Bézier
control1 = (
start[0] + (end[0] - start[0]) * random.uniform(0.2, 0.4) + random.randint(-50, 50),
start[1] + (end[1] - start[1]) * random.uniform(0.2, 0.4) + random.randint(-50, 50)
)
control2 = (
start[0] + (end[0] - start[0]) * random.uniform(0.6, 0.8) + random.randint(-50, 50),
start[1] + (end[1] - start[1]) * random.uniform(0.6, 0.8) + random.randint(-50, 50)
)
# Créez une courbe de Bézier
nodes = np.asfortranarray([
[start[0], control1[0], control2[0], end[0]],
[start[1], control1[1], control2[1], end[1]]
])
curve = bezier.Curve(nodes, degree=3)
# Générez des points sur la courbe
points = []
for t in np.linspace(0, 1, num_points):
point = curve.evaluate(t)
# Ajoutez du micro-bruit
x = point[0][0] + random.uniform(-2, 2)
y = point[1][0] + random.uniform(-2, 2)
points.append((x, y))
return points
async def human_click(page, selector):
"""Cliquez sur un élément avec un mouvement de souris humain"""
element = await page.query_selector(selector)
box = await element.bounding_box()
# Point cible — pas le centre, mais un point aléatoire à l'intérieur de l'élément
target_x = box['x'] + random.uniform(box['width'] * 0.2, box['width'] * 0.8)
target_y = box['y'] + random.uniform(box['height'] * 0.2, box['height'] * 0.8)
# Position actuelle de la souris (ou position de départ aléatoire)
start_x = random.randint(0, 1920)
start_y = random.randint(0, 1080)
# Générez le chemin
path = generate_human_mouse_path((start_x, start_y), (target_x, target_y))
# Déplacez la souris le long du chemin
for x, y in path:
await page.mouse.move(x, y)
await page.wait_for_timeout(random.randint(5, 20))
# Petite pause avant le clic
await page.wait_for_timeout(random.randint(50, 150))
await page.mouse.click(target_x, target_y)
Chargement des ressources
Un vrai navigateur charge non seulement du HTML, mais aussi du CSS, du JavaScript, des images, des polices. Si vous utilisez requests et ne demandez que du HTML — c'est suspect. Lors de l'utilisation de navigateurs headless, ce problème est résolu automatiquement, mais lors de l'utilisation de clients HTTP, vous devez en tenir compte.
Choix du type de proxy pour votre tâche
Différents types de proxies ont des caractéristiques différentes et conviennent à différentes tâches. Un mauvais choix est une cause fréquente de blocages.
Proxies de centre de données
Les proxies de centre de données sont des adresses IP appartenant à des fournisseurs d'hébergement. Ils sont faciles à identifier par l'appartenance à AS (systèmes autonomes) de grands centres de données.
Avantages :
- Vitesse et stabilité élevées
- Coût faible
- Grands pools d'IP
Inconvénients :
- Faciles à détecter
- Souvent dans les listes noires
- Ne conviennent pas aux sites avec protection sérieuse
Conviennent pour : outils SEO, vérification de disponibilité, travail avec des API sans protection stricte, tests.
Proxies résidentiels
Les proxies résidentiels sont des adresses IP d'utilisateurs réels, fournies via des programmes partenaires ou des SDK dans les applications. Ils appartiennent à des fournisseurs d'accès Internet ordinaires (FAI).
Avantages :
- Ressemblent à des utilisateurs ordinaires
- Faible score de fraude
- Géographie large
- Difficiles à détecter
Inconvénients :
- Coût plus élevé (paiement au trafic)
- La vitesse dépend de l'utilisateur final
- Les IP peuvent « partir » (l'utilisateur a éteint l'appareil)
Conviennent pour : scraping de sites protégés, travail avec les réseaux sociaux, e-commerce, toute tâche où il est important de ne pas être détecté.
Proxies mobiles
Les proxies mobiles sont des adresses IP d'opérateurs mobiles (MTS, Beeline, Megafon et analogues dans d'autres pays). Ils ont un statut particulier en raison de la technologie CGNAT.
Avantages :
- Confiance maximale de la part des sites
- Une IP est utilisée par des milliers d'utilisateurs réels — difficile à bannir
- Idéaux pour le travail avec des comptes
- Changement d'IP à la demande (reconnexion au réseau)
Inconvénients :
- Coût le plus élevé
- Vitesse limitée
- Choix de géographies limité
Conviennent pour : multi-comptage, travail avec Instagram/Facebook/TikTok, enregistrement de comptes, toute tâche à haut risque de ban.
Tableau comparatif
| Paramètre | Centre de données | Résidentiels | Mobiles |
|---|---|---|---|
| Détectabilité | Élevée | Faible | Très faible |
| Vitesse | Élevée | Moyenne | Faible-moyenne |
| Coût | $ | $$ | $$$ |
| Pour les réseaux sociaux | Ne conviennent pas | Conviennent | Idéaux |
| Pour le scraping | Sites simples | N'importe quel site | Excessif |
Techniques avancées de contournement de protection
Lorsque les méthodes de base ne fonctionnent pas, vous devez utiliser des techniques plus complexes. Examinons plusieurs approches avancées.
Travail avec Cloudflare et protections similaires
Cloudflare, Akamai, PerimeterX — ces systèmes utilisent des défis JavaScript pour vérifier le navigateur. Une simple requête HTTP ne passera pas. Options de solution :
1. Utilisation d'un vrai navigateur :
from playwright.sync_api import sync_playwright
def bypass_cloudflare(url, proxy):
with sync_playwright() as p:
browser = p.chromium.launch(
headless=False, # Parfois, headless est détecté
proxy={"server": proxy}
)
page = browser.new_page()
page.goto(url)
# Attendez le passage de la vérification (généralement 5-10 secondes)
page.wait_for_timeout(10000)
# Vérifiez si nous avons réussi
if "challenge" not in page.url:
# Enregistrez les cookies pour les requêtes ultérieures
cookies = page.context.cookies()
return cookies
browser.close()
return None
2. Utilisation de solutions prêtes à l'emploi :
# cloudscraper — bibliothèque pour contourner Cloudflare
import cloudscraper
scraper = cloudscraper.create_scraper(
browser={
'browser': 'chrome',
'platform': 'windows',
'desktop': True
}
)
scraper.proxies = {"http": proxy, "https": proxy}
response = scraper.get("https://protected-site.com")
Résolution de captcha
Si le site affiche un captcha, il existe plusieurs approches :
Services de reconnaissance : 2Captcha, Anti-Captcha, CapMonster. Ils résolvent le captcha pour vous