Wenn die Rechnung für den Proxy schneller steigt als das Volumen der gesammelten Daten, liegt das Problem fast immer in der Retry-Logik. Der Parser wiederholt stillschweigend fehlgeschlagene Anfragen mehrere Male, verbraucht Datenverkehr für Timeouts und Captchas, und der Entwickler sieht diese Ausgaben nicht einmal in den Logs. Lassen Sie uns untersuchen, wie man die tatsächlichen Verluste berechnet und sie ohne Qualitätsverlust der Daten reduziert.
Warum die Retry-Logik Datenverkehr verbraucht
Die meisten Parser sind mit einer naiven Retry-Logik geschrieben: Wenn die Anfrage fehlgeschlagen ist, wird sie wiederholt, und das bis zu 3-5 Mal. Das Problem ist, dass jede wiederholte Anfrage nicht nur eine neue HTTP-Anfrage ist, sondern auch einen vollständigen Zyklus: TCP-Handshake, TLS-Verhandlung, vollständiges Laden der Seite (auch wenn nur ein Datenblock benötigt wird), und manchmal auch das erneute Laden von Bildern oder JS-Dateien, wenn der Parser einen Headless-Browser anstelle eines einfachen HTTP-Clients verwendet.
Besonders teuer sind Wiederholungen bei der Arbeit über residential Proxys, wo der Datenverkehr nach Volumen und nicht nach Anzahl der Anfragen abgerechnet wird. Eine fehlgeschlagene Anfrage an eine Produktseite von Wildberries mit Bildern und Skripten kann 300-500 KB kosten. Wenn der Parser 3 Wiederholungen bei einem Timeout macht, zahlen Sie für dieselbe fehlgeschlagene Anfrage viermal hintereinander — und das ohne Garantie, dass der vierte Versuch erfolgreich sein wird.
Ein weiterer Grund sind Wiederholungen bei Fehlern, die nicht durch einen erneuten Versuch behoben werden können. Wenn die Website 403 zurückgibt, weil ein Bot erkannt wurde, wird eine erneute Anfrage mit demselben Fingerabdruck und derselben Cookiesitzung fast sicher dieselbe Antwort erhalten. Der Parser verbraucht Datenverkehr für Versuche, die mathematisch nicht erfolgreich sein können, solange sich die IP-Adresse oder der Browser-Fingerabdruck nicht ändert.
Wie viel Datenverkehr tatsächlich für Wiederholungen aufgebracht wird
Um das Ausmaß des Problems zu verstehen, nehmen wir ein einfaches Beispiel. Der Parser sammelt Produktkarten von einem Marktplatz, die durchschnittliche Antwortgröße beträgt 250 KB (HTML + JSON API + teilweise Statische). Bei stabiler Arbeit ohne Blockierungen liegt der Anteil der fehlgeschlagenen Anfragen bei 5-8%. Aber bei aggressivem Parsen über günstige Rechenzentrums-Proxys kann dieser Wert auf 25-35% steigen, da der Zielanbieter schnell das Muster erkennt und beginnt, Captchas oder temporäre IP-Sperren zurückzugeben.
Lassen Sie uns mit Zahlen rechnen. Angenommen, wir müssen 100.000 Produktkarten sammeln:
| Anteil der fehlgeschlagenen Anfragen | Wiederholungen pro Anfrage (im Durchschnitt) | Gesamt-Datenverkehr | Überverbrauch |
|---|---|---|---|
| 5% | 0.15 | 28.75 GB | +15% |
| 15% | 0.45 | 36.25 GB | +45% |
| 30% | 0.90 | 47.5 GB | +90% |
Wie zu sehen ist, verdoppelt sich der tatsächliche Datenverkehr bei einem Fehleranteil von 30% und der Retry-Strategie „bis zu 3 Mal wiederholen“ fast im Vergleich zum theoretischen Minimum von 25 GB. Genau diese zusätzlichen 20+ GB sind direkte Budgetverluste für Proxys, die reduziert werden können, wenn die Wiederholungslogik überdacht wird.
Typische Fehler in der Retry-Logik von Parsern
Bevor Sie die Retry-Logik reparieren, sollten Sie typische Anti-Patterns erkennen, die in 90% der selbstgeschriebenen Parser vorkommen:
- Retry ohne Berücksichtigung des Fehlercodes. Die Wiederholung wird bei jeder abnormalen Situation gestartet — 403, 429, 500, Timeout, Verbindungsabbruch — obwohl die Behandlungsstrategie für diese unterschiedlich sein sollte.
- Feste Verzögerung zwischen den Wiederholungen. Zum Beispiel 2 Sekunden zwischen den Versuchen, unabhängig davon, ob es der erste oder der fünfte Versuch ist — das ist entweder zu aggressiv für die Website oder zu langsam für große Volumen.
- Wiederholung mit derselben IP und derselben Sitzung. Wenn die Website die Anfrage aufgrund des Fingerabdrucks blockiert hat, ändert eine Wiederholung mit identischen Parametern das Ergebnis nicht, sondern verbraucht Datenverkehr.
- Kein oberes Limit für Versuche. Einige Parser geraten in eine Schleife bei „toten“ URLs und machen Dutzende von Wiederholungen, bevor sie aufgeben.
- Fehlende Unterscheidung zwischen temporären und permanenten Fehlern. 404 (Seite existiert nicht) und 503 (Server vorübergehend nicht verfügbar) erfordern unterschiedliche Logik — werden aber oft gleich behandelt.
Exponential Backoff mit Python-Code
Eine einfache, aber effektive Lösung ist eine exponentielle Verzögerung mit Jitter (zufälliger Streuung), die die Anzahl der sinnlosen Wiederholungen reduziert und die Last über die Zeit verteilt. Anstelle einer festen Pause zwischen den Versuchen wächst die Verzögerung exponentiell, was der Website Zeit gibt, sich nach einer Blockierung „abzukühlen“, und dem Parser ermöglicht, keinen Datenverkehr für Anfragen zu verschwenden, die fast sicher fehlschlagen werden.
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:
# kein Sinn zu wiederholen — die Seite existiert physisch nicht
return None
if response.status_code not in retryable_codes:
return None
except (requests.exceptions.Timeout,
requests.exceptions.ConnectionError):
pass # vorübergehender Netzwerkfehler — kann wiederholt werden
if attempt == max_retries:
return None
# exponentielle Verzögerung mit Jitter
delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
return None
Die Schlüsselidee dieses Codes ist die Unterteilung der Fehler in drei Kategorien: solche, die durch Wiederholung nicht behoben werden können (404, 410), solche, die mit Verzögerung wiederholt werden können (429, 500-504, Timeouts) und alles andere, was sofort als Fehlschlag betrachtet wird ohne zusätzliche Versuche zu verschwenden. Eine solche Unterteilung allein reduziert den überflüssigen Datenverkehr um 20-30% im Vergleich zu dem naiven „alles wiederholen“.
Hinweis: Fügen Sie den Retry-After-Header in die Verarbeitung ein —
viele Websites geben selbst an, wie viele Sekunden man vor einer Wiederholung warten sollte. Das Ignorieren dieses Headers ist
eine häufige Ursache für überflüssige Sperren und Datenverkehr.
Circuit Breaker: Wann man aufhören sollte
Exponentielles Backoff hilft auf der Ebene einer einzelnen Anfrage, schützt jedoch nicht vor Situationen, in denen die gesamte Domain oder ein bestimmter Proxy-Knoten vorübergehend für Hunderte von URLs hintereinander nicht verfügbar ist. Hier ist ein Circuit Breaker-Muster erforderlich — ein "automatischer Schalter", der den Anteil der Fehler über einen bestimmten Zeitraum verfolgt und die Versuche vorübergehend stoppt, wenn dieser den Schwellenwert überschreitet, anstatt weiterhin gegen eine geschlossene Tür zu klopfen.
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()
Die Logik ist einfach: Wenn mehr als die Hälfte der letzten 50 Anfragen fehlgeschlagen sind, pausiert der Parser die Versuche für diese Domain oder diesen Proxy für 60 Sekunden. In dieser Zeit kann die IP gewechselt, die Anfragegeschwindigkeit gesenkt oder auf einen anderen Proxy-Pool umgeschaltet werden. Dies ist besonders wichtig bei der Arbeit mit Zielwebsites, die temporär den IP-Bereich nach Überschreitung der Anfragefrequenz sperren — weiterhin gegen eine geschlossene Tür zu schlagen bedeutet einfach, Datenverkehr umsonst zu verbrennen.
Intelligente Proxy-Rotation bei Wiederholungen
Eine der effektivsten Maßnahmen gegen überflüssige Wiederholungen besteht darin, die Anfrage nicht von derselben IP zu wiederholen, die bereits eine Ablehnung erhalten hat. Die Logik ist einfach: Wenn der Fehler mit einer IP-Blockierung (403, 429, Redirect zu Captcha) verbunden ist, erhöht der Wechsel des Proxys vor der Wiederholung drastisch die Erfolgsquote und senkt die Anzahl der Versuche.
Für das Parsen von Marktplätzen wie Wildberries, Ozon oder Avito funktioniert eine Kombination gut: Normale Anfragen gehen über Rechenzentrums-Proxys — sie sind schneller und günstiger, und sobald der Blockierungsdetektor mehrmals hintereinander anschlägt, wechselt der Parser zu residential Proxys, die seltener von den Anti-Bot-Systemen gefiltert werden. Dieser hybride Ansatz reduziert den gesamten Datenverbrauch, da teure residential IPs nur dort verwendet werden, wo es wirklich nötig ist, und nicht für alle Anfragen hintereinander.
| Fehlertyp | Wiederholungsstrategie | Ist ein IP-Wechsel erforderlich? |
|---|---|---|
| Verbindungs-Timeout | Backoff, 1-2 Wiederholungen | Nein |
| 403 / Captcha | Sofortige Rotation | Ja, unbedingt |
| 429 (Rate Limit) | Backoff gemäß Retry-After | Wünschenswert |
| 500-503 | Backoff, 2-3 Wiederholungen | Nein |
| 404 / 410 | Keine Wiederholungen | — |
Für Parser, die mobilen Datenverkehr emulieren (z.B. das Sammeln von Daten aus mobilen Versionen von Marktplatz- oder sozialen Netzwerk-Apps), macht es Sinn, mobile Proxys zu verwenden — sie erregen seltener den Verdacht von Schutzsystemen, weil Telekommunikationsanbieter dieselben IPs Tausenden von echten Nutzern gleichzeitig zuweisen, und punktuelle Blockierungen für die Zielwebsite unpraktisch werden.
Überwachung der Retry-Metriken
Ohne Metriken wird die Optimierung der Retry-Logik zum Rätselraten. Das minimale Set von Kennzahlen, die bei jeder Anfrage protokolliert werden sollten:
- Retry-Rate — der Anteil der Anfragen, die mindestens einen Wiederholungsversuch erforderten.
- Erfolg nach Wiederholung — welcher Prozentsatz der Wiederholungen letztendlich erfolgreich war (wenn dieser Wert niedrig ist, verbrennen Wiederholungen einfach Datenverkehr).
- Datenverkehr für ein erfolgreiches Ergebnis — das gesamte Volumen der übertragenen Daten, geteilt durch die Anzahl der erfolgreich gesammelten Datensätze. Dies ist die Schlüsselmetrik für die Effizienz.
- Verteilung der Fehler nach Codes — hilft zu verstehen, wo der Hauptdatenverlust auftritt: Timeouts, 403, 429 oder etwas anderes.
- Retry-Rate nach bestimmten Proxy-Knoten — wenn eine IP eine Retry-Rate von 80% hat und die anderen 10%, ist das Problem lokal und kann durch den Wechsel eines bestimmten Knotens gelöst werden, nicht durch die gesamte Logik.
Selbst eine einfache Tabelle in Google Sheets oder ein Log im CSV-Format mit diesen fünf Metriken, die stündlich aktualisiert wird, liefert genügend Daten, um Anomalien zu erkennen und die Strategie rechtzeitig anzupassen — z.B. die Anfragefrequenz für einen bestimmten Bereich der Website zu senken oder den Anteil der residential IPs im Pool zu erhöhen.
Checkliste zur Optimierung des Datenverkehrs bei Retry
- Unterteilen Sie die Fehlercodes in wiederholbare und nicht wiederholbare — wiederholen Sie keine 404/410.
- Implementieren Sie exponentielles Backoff mit Jitter anstelle einer festen Verzögerung.
- Respektieren Sie den
Retry-After-Header, wenn die Website ihn sendet. - Ändern Sie die IP vor einer Wiederholung bei 403 und Verdacht auf Bot-Detection.
- Setzen Sie ein strenges Limit für die Anzahl der Versuche (in der Regel sind 3-4 ausreichend).
- Implementieren Sie einen Circuit Breaker für Domains und Proxy-Knoten mit hoher Fehlerquote.
- Protokollieren Sie die Retry-Rate und den Datenverkehr für ein erfolgreiches Ergebnis — ohne Metriken ist Optimierung unmöglich.
- Trennen Sie den Proxy-Pool: günstige Rechenzentren für stabile Bereiche, residential oder mobile IPs für problematische.
Fazit
Die Retry-Logik ist kein unwichtiges Detail des Parsers, sondern einer der Hauptfaktoren, die die Kosten für die Datensammlung beeinflussen. Eine naive Strategie „alles wiederholen“ kann den tatsächlichen Datenverkehr um 40-90% im Vergleich zum theoretischen Minimum erhöhen, wobei die meisten Wiederholungen mit demselben Fehlschlag enden wie der erste Versuch. Die Unterteilung der Fehler nach Typen, exponentielles Backoff, Circuit Breaker und intelligente IP-Rotation ermöglichen es, diese Verluste erheblich zu reduzieren, ohne die Vollständigkeit der gesammelten Daten zu verringern.
Wenn Ihr Parser mit Websites arbeitet, die Bots aggressiv erkennen — Marktplätzen, sozialen Netzwerken, Werbeplattformen — sollten Sie mehrere Proxy-Typen je nach Aufgabe kombinieren. Für grundlegende Operationen eignen sich Rechenzentrums-Proxys, und dort, wo maximale Widerstandsfähigkeit gegen Blockierungen erforderlich ist, — residential Proxys mit echten IP-Adressen von normalen Nutzern. Dieser hybride Ansatz in Kombination mit einer durchdachten Retry-Logik führt zu einer spürbaren Reduzierung des Datenverbrauchs bei gleichem Volumen der gesammelten Daten.