Si la facture des proxies augmente plus vite que le volume des données collectées, le problème réside presque toujours dans la logique de retry. Le parseur répète silencieusement les requêtes échouées plusieurs fois, gaspillant du trafic sur des timeouts et des captchas, et le développeur ne voit même pas ces dépenses dans les logs. Analysons comment calculer les pertes réelles et les réduire sans compromettre la qualité des données.
Pourquoi la logique de retry consomme du trafic
La plupart des parseurs sont écrits avec une logique de retry naïve : si la requête échoue, on la répète, et ainsi de suite jusqu'à 3-5 fois. Le problème est que chaque requête répétée n'est pas seulement une nouvelle requête HTTP, mais un cycle complet : handshake TCP, négociation TLS, chargement complet de la page (même si seul un bloc de données est nécessaire), et parfois même le rechargement d'images ou de fichiers JS, si le parseur utilise un navigateur headless au lieu d'un simple client HTTP.
Les répétitions sont particulièrement coûteuses lorsqu'on travaille avec des proxies résidentiels, où le trafic est facturé en fonction du volume, et non du nombre de requêtes. Une requête échouée sur une page produit Wildberries avec des images et des scripts peut coûter 300-500 Ko. Si le parseur fait 3 répétitions en cas de timeout, vous payez pour la même requête échouée quatre fois de suite — et cela sans garantie que la quatrième tentative sera réussie.
La deuxième raison est le retry sur des erreurs qui ne peuvent pas être corrigées par une répétition. Si le site renvoie un 403 en raison de la détection d'un bot, une requête répétée avec le même fingerprint et la même session de cookies obtiendra presque certainement la même réponse. Le parseur gaspille du trafic sur des tentatives qui ne peuvent mathématiquement pas aboutir, tant que l'adresse IP ou le fingerprint du navigateur ne change pas.
Combien de trafic est réellement consommé par les répétitions
Pour comprendre l'ampleur du problème, prenons un exemple simple. Le parseur collecte des fiches produits d'un marketplace, la taille moyenne de la réponse est de 250 Ko (HTML + JSON API + partie statique). Lors d'un fonctionnement stable sans blocages, la part des requêtes échouées reste autour de 5-8%. Mais lors d'un parsing agressif via des proxies de datacenters bon marché, ce chiffre peut grimper à 25-35%, car le fournisseur cible reconnaît rapidement le motif et commence à renvoyer des captchas ou des bans temporaires par IP.
Calculons avec des chiffres. Supposons qu'il faille collecter 100 000 fiches produits :
| Part de requêtes échouées | Répétitions par requête (en moyenne) | Trafic total | Surconsommation |
|---|---|---|---|
| 5% | 0.15 | 28.75 Go | +15% |
| 15% | 0.45 | 36.25 Go | +45% |
| 30% | 0.90 | 47.5 Go | +90% |
Comme on peut le voir, avec une part d'échecs de 30% et une stratégie de retry « répéter jusqu'à 3 fois », le trafic réel est presque doublé par rapport au minimum théorique de 25 Go. Ces 20+ Go supplémentaires représentent des pertes budgétaires directes sur les proxies, qui peuvent être réduites en révisant la logique des répétitions.
Erreurs typiques de la logique de retry des parseurs
Avant de corriger la logique de retry, il est important de reconnaître les antipatterns typiques qui se rencontrent dans 90% des parseurs faits maison :
- Retry sans distinction du code d'erreur. La répétition se déclenche pour toute situation anormale — 403, 429, 500, timeout, rupture de connexion — alors que la stratégie de traitement devrait différer pour chacune d'elles.
- Délai fixe entre les répétitions. Par exemple, 2 secondes entre les tentatives indépendamment de la première ou de la cinquième tentative — c'est soit trop agressif pour le site, soit trop lent pour de gros volumes.
- Répétition avec la même IP et la même session. Si le site a bloqué la requête par fingerprint, une répétition avec des paramètres identiques ne change pas le résultat, mais gaspille du trafic.
- Pas de limite supérieure sur les tentatives. Certains parseurs se bloquent sur des URL « mortes » et effectuent des dizaines de répétitions avant d'abandonner.
- Absence de distinction entre erreurs temporaires et permanentes. 404 (page inexistante) et 503 (serveur temporairement indisponible) nécessitent une logique différente — mais sont souvent traitées de la même manière.
Backoff exponentiel avec code en Python
Une solution simple mais efficace est le délai exponentiel avec jitter (variation aléatoire), qui réduit le nombre de répétitions inutiles et répartit la charge dans le temps. Au lieu d'une pause fixe entre les tentatives, le délai augmente de manière exponentielle, ce qui donne au site le temps de « refroidir » après un blocage, et au parseur lui-même de ne pas gaspiller du trafic sur des requêtes qui échoueront presque certainement.
import time
import random
import requests
def fetch_with_backoff(url, proxies, max_retries=4, base_delay=1.0):
retryable_codes = {429, 500, 502, 503, 504}
non_retryable_codes = {404, 410}
for attempt in range(max_retries + 1):
try:
response = requests.get(url, proxies=proxies, timeout=10)
if response.status_code == 200:
return response
if response.status_code in non_retryable_codes:
# pas de sens à répéter — la page n'existe pas physiquement
return None
if response.status_code not in retryable_codes:
return None
except (requests.exceptions.Timeout,
requests.exceptions.ConnectionError):
pass # erreur réseau temporaire — peut être répétée
if attempt == max_retries:
return None
# délai exponentiel avec jitter
delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
return None
L'idée clé de ce code est de diviser les erreurs en trois catégories : celles qui ne peuvent pas être corrigées par une répétition (404, 410), celles qui peuvent être répétées avec un délai (429, 500-504, timeouts), et tout le reste, qui est immédiatement considéré comme un échec sans dépenses pour des tentatives supplémentaires. Cette séparation réduit à elle seule le trafic inutile de 20-30% par rapport à la logique naïve de « tout répéter ».
Conseil : ajoutez le Retry-After dans le traitement —
de nombreux sites indiquent eux-mêmes combien de secondes attendre avant de répéter. Ignorer cet en-tête est
une cause fréquente de bans inutiles et de trafic.
Circuit breaker : quand faut-il s'arrêter
Le backoff exponentiel aide au niveau d'une seule requête, mais ne protège pas contre une situation où tout le domaine ou un nœud proxy spécifique est temporairement inaccessible pour des centaines d'URL consécutives. Ici, un modèle de circuit breaker est nécessaire — un « disjoncteur » qui suit la part d'erreurs sur une période donnée et interrompt temporairement les tentatives si elle dépasse un seuil, au lieu de continuer à frapper à une porte fermée.
class CircuitBreaker:
def __init__(self, failure_threshold=0.5, window_size=50, cooldown=60):
self.failure_threshold = failure_threshold
self.window_size = window_size
self.cooldown = cooldown
self.results = []
self.open_until = 0
def is_open(self):
return time.time() < self.open_until
def record(self, success: bool):
self.results.append(success)
if len(self.results) > self.window_size:
self.results.pop(0)
if len(self.results) == self.window_size:
failure_rate = 1 - sum(self.results) / self.window_size
if failure_rate > self.failure_threshold:
self.open_until = time.time() + self.cooldown
self.results.clear()
La logique est simple : si plus de la moitié des 50 dernières requêtes ont échoué, le parseur suspend les tentatives pour ce domaine ou ce proxy pendant 60 secondes. Pendant ce temps, il peut changer d'IP, réduire la fréquence des requêtes ou passer à un autre pool de proxies. Cela est particulièrement important lors du travail avec des sites cibles qui bloquent temporairement une plage d'IP après un dépassement de la fréquence des requêtes — continuer à frapper à une porte fermée signifie simplement brûler du trafic inutilement.
Rotation intelligente des proxies lors des répétitions
L'une des mesures les plus efficaces contre les retries inutiles est de ne pas répéter la requête avec la même IP qui a déjà reçu un refus. La logique est simple : si l'erreur est liée à un blocage par IP (403, 429, redirection vers un captcha), changer de proxy avant de répéter augmente radicalement les chances de succès et réduit le nombre de tentatives.
Pour le parsing de marketplaces comme Wildberries, Ozon ou Avito, une combinaison fonctionne bien : les requêtes normales passent par des proxies de datacenters — ils sont plus rapides et moins chers, et dès que le détecteur de blocage s'active plusieurs fois de suite, le parseur passe à proxies résidentiels, qui sont moins souvent filtrés par les systèmes anti-bot. Cette approche hybride réduit la consommation totale de trafic, car les IP résidentielles coûteuses ne sont utilisées que là où cela est vraiment nécessaire, et non pour toutes les requêtes consécutives.
| Type d'erreur | Stratégie de répétition | Changement d'IP nécessaire ? |
|---|---|---|
| Timeout de connexion | Backoff, 1-2 répétitions | Non |
| 403 / captcha | Rotation immédiate | Oui, absolument |
| 429 (limite de taux) | Backoff selon Retry-After | Souhaitable |
| 500-503 | Backoff, 2-3 répétitions | Non |
| 404 / 410 | Sans répétitions | — |
Pour les parseurs qui émulent le trafic mobile (par exemple, la collecte de données à partir des versions mobiles des applications de marketplaces ou de réseaux sociaux), il est judicieux d'utiliser des proxies mobiles — ils suscitent moins de soupçons auprès des systèmes de protection précisément parce que les opérateurs de télécommunications attribuent les mêmes IP à des milliers d'utilisateurs réels simultanément, et le blocage ciblé devient peu judicieux pour le site cible.
Surveillance des métriques de retry
Sans métriques, l'optimisation de la logique de retry devient une devinette. L'ensemble minimal d'indicateurs à enregistrer à chaque requête :
- Taux de retry — part des requêtes ayant nécessité au moins une répétition.
- Succès après retry — quel pourcentage de répétitions a finalement abouti (si cet indicateur est faible, les répétitions gaspillent simplement du trafic).
- Trafic pour un résultat réussi — volume total de données transférées, divisé par le nombre d'enregistrements collectés avec succès. C'est l'indicateur clé de l'efficacité.
- Répartition des erreurs par codes — aide à comprendre où se produit la principale fuite de trafic : timeouts, 403, 429 ou autre chose.
- Taux de retry par nœuds proxy spécifiques — si une IP donne un taux de retry de 80%, tandis que les autres sont à 10%, le problème est local et se résout en changeant un nœud spécifique, et non toute la logique.
Même un simple tableau dans Google Sheets ou un log en CSV avec ces cinq métriques, mis à jour toutes les heures, fournit suffisamment de données pour détecter des anomalies et ajuster la stratégie à temps — par exemple, réduire la fréquence des requêtes vers une section spécifique du site ou augmenter la part des IP résidentielles dans le pool.
Checklist d'optimisation du trafic sur retry
- Divisez les codes d'erreur en retryables et non-retryables — ne répétez pas 404/410.
- Implémentez un backoff exponentiel avec jitter au lieu d'un délai fixe.
- Respectez l'en-tête
Retry-After, si le site l'envoie. - Changez d'IP avant de répéter en cas de 403 et de soupçon de détection de bot.
- Fixez une limite stricte sur le nombre de tentatives (généralement 3-4 suffisent).
- Implémentez un circuit breaker pour les domaines et nœuds proxy avec un taux d'échec élevé.
- Enregistrez le taux de retry et le trafic pour un résultat réussi — sans métriques, l'optimisation est impossible.
- Divisez le pool de proxies : des datacenters bon marché pour les zones stables, des IP résidentielles ou mobiles pour les zones problématiques.
Conclusion
La logique de retry n'est pas un détail mineur du parseur, mais l'un des principaux facteurs influençant le coût de la collecte de données. Une stratégie naïve de « tout répéter » peut augmenter le trafic réel de 40 à 90% par rapport au minimum théorique, tandis qu'une grande partie des répétitions se termine par le même échec que la première tentative. La séparation des erreurs par type, le backoff exponentiel, le circuit breaker et la rotation intelligente des IP permettent de réduire ces pertes de plusieurs fois sans diminuer la complétude des données collectées.
Si votre parseur travaille avec des sites qui détectent agressivement les bots — marketplaces, réseaux sociaux, plateformes publicitaires — il est judicieux de combiner plusieurs types de proxies en fonction de la tâche. Pour des opérations de base, des proxies de datacenters conviennent, tandis que là où une résistance maximale aux blocages est nécessaire, des proxies résidentiels avec des adresses IP réelles d'utilisateurs ordinaires sont recommandés. Cette approche hybride, associée à une logique de retry bien pensée, permet de réduire considérablement la consommation de trafic tout en maintenant le même volume de données collectées.