Die meisten Proxy-Rotatoren beantworten die falsche Frage. Sie beantworten "wer ist als Nächstes dran?", während die Frage, die darüber entscheidet, ob Ihre Pipeline durchläuft, lautet: "welche Route soll diesen Request tragen?" Round Robin gibt jeder Route denselben Anteil am Traffic, was nur dann richtig ist, wenn jede Route gleich gut ist. So ordentlich sind Pools nie: eine Route ist schnell, bis sie blockiert wird, eine andere ist langsam, fällt aber nie aus, eine dritte fällt schubweise aus und erholt sich wieder.

Sobald man das akzeptiert, ist Rotation kein Scheduling-Problem mehr, sondern ein Feedback-Problem. Der Rotator beobachtet, was mit jedem Request passiert, führt eine laufende Schätzung über das Verhalten jeder Route und lässt diese Schätzungen die nächste Wahl steuern. Genau das ist die Idee hinter Health Scoring: der Pool sagt Ihnen, was er tut, und die Routing-Policy hört zu.

Diese Anleitung baut genau diesen Rotator in Python. Exponentiell gewichtete Schätzer verfolgen Erfolg und Latenz, ein Circuit Breaker fängt die abrupten Ausfälle ab, für die Durchschnitte zu träge sind, und ein Benchmark misst das Ergebnis gegen einfaches Round Robin. Eine der Routen ist der Crawlbase Smart AI Proxy, der gerade deshalb dazugehört, weil er eine ganze Schicht des Problems auflöst: Sie bewerten keine einzelnen Residential-IPs mehr, sondern eine Route, die Rotation und Anti-Bot-Handling selbst übernimmt.

Kurz gefasst
  • Trennen Sie Ausführung, Healthund Auswahl. Eine Route holt die Seite, das Health-Modell bewertet, die Policy entscheidet. Jedes Teil lässt sich einzeln austauschen oder benchmarken.
  • Zwei EWMAs tragen das kontinuierliche Signal: eine für Erfolg, eine für Latenz. Aktualisieren Sie die Latenz nur bei Erfolgen, denn ein fehlgeschlagener Request sagt nichts darüber aus, wie schnell eine Route ist, wenn sie funktioniert.
  • Ein Circuit Breaker leistet das, was ein Durchschnitt nicht kann: eine Serie aufeinanderfolgender Fehler soll eine Route sofort herausnehmen, nicht allmählich.
  • Health wird multipliziert, nicht addiert: success_ewma / (1 + latency_ewma). Eine Route muss sowohl zuverlässig als auch reaktionsschnell sein, um gut zu punkten.
  • Halten Sie den Auswahl-Exponenten moderat, damit eine sich erholende Route noch gelegentlich Traffic bekommt und beweisen kann, dass sie wieder gesund ist.
  • Round Robin ist die Kontrolle, kein Strohmann. Ohne sie können Sie nicht zeigen, dass die Feedback-Schleife überhaupt etwas bewirkt hat.

Warum Rotation Health Scoring braucht

Ein Proxy-Pool ist nicht homogen, und er hält nicht still. Routen unterscheiden sich in Latenz, Zuverlässigkeit und darin, wie ein bestimmtes Ziel sie behandelt, und alle drei können sich ändern, während ein Job läuft. Sie als austauschbar zu behandeln macht die Policy blind für genau die Bedingungen, auf die es ankommt.

Ein Health-bewusster Rotator braucht drei Signale, und das sind nicht dasselbe Signal in verschiedenen Empfindlichkeiten:

  1. Liveness. Welche Routen gerade erfolgreich sind und von welchen der Traffic wegwandern soll.
  2. Latenz. Unter den funktionierenden Routen sind die reaktionsschnellen zu bevorzugen. Ein erfolgreicher Request, der neun Sekunden gedauert hat, hat Sie trotzdem neun Sekunden gekostet.
  3. Fehlerstabilität. Wiederholte Fehler sollen eine Route aus dem normalen Traffic ziehen und sie über eine kontrollierte Probe zurückkommen lassen, nicht durch sofortige Rückkehr in den Pool.

Round Robin liefert nichts davon. Es verteilt Requests gleichmäßig, egal ob eine Route gesund, langsam oder tot ist. Genau das macht es zur richtigen Kontrolle: lassen Sie beide Policies gegen dieselbe Last laufen, und der Unterschied ist der Wert des Feedbacks.

Der Aufbau des Systems

Drei Verantwortlichkeiten, bewusst getrennt. Eine Route führt einen Abruf aus und meldet ein normalisiertes Ergebnis: erfolgreich oder nicht, HTTP-Status, Dauer. Ein Health-Modell macht aus diesem Strom von Ergebnissen einen Score. Eine Policy liest die Scores und wählt die nächste Route. Weil sie getrennt sind, können Sie die Policy austauschen, ohne den Transport anzufassen, oder zwei Policies gegen identische Routen benchmarken.

Die Schleife, die das Ganze adaptiv macht. Requests laufen in den Rotator, der beim Health-Modell die Gewichte abfragt, eine Route wählt und ausführt. Das Ergebnis geht als Erfolg und Latenz zurück ins Modell, und dieser aktualisierte Zustand entscheidet über den nächsten Request. Entfernen Sie die Rückkante, und Sie haben einen Rotator, der eine gesunde Route nicht von einer toten unterscheiden kann.

Der Smart AI Proxy verdient seinen Platz in diesem Bild, weil er eine Schicht absorbiert. Er stellt einen Endpunkt bereit und übernimmt dahinter Residential-IP-Rotation und Anti-Bot-Handling, sodass Ihre Anwendung eine Route bewertet statt eine Flotte von Adressen. Ihre Policy entscheidet weiterhin, welcher Abrufpfad den Traffic verdient.

Jeder Ausschnitt unten stammt aus dem Begleit-Repository ScraperHub/smart-ai-proxy-rotation-in-python-health-scoring-at-scale, das die lauffähige Implementierung unter final/ und gestufte Checkpoints unter steps/.

Umgebung

Python 3.11 oder neuer und ein Crawlbase-Konto für die Proxy-Route. Ihr Normal Token reicht hier aus; das JavaScript Token ist nur relevant, wenn ein Ziel Rendering braucht, um Inhalte zu liefern, und das ist eine andere Frage als Routing. Beide finden Sie in den Konsoleneinstellungen.

bash
git clone https://github.com/ScraperHub/smart-ai-proxy-rotation-in-python-health-scoring-at-scale.git
cd smart-ai-proxy-rotation-in-python-health-scoring-at-scale/final

python -m venv .venv && source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -r requirements.txt

cp .env.example .env  # then set CRAWLBASE_TOKEN

Das Token gehört in die Umgebung und nicht in den Quellcode, was gewöhnliche Hygiene ist, zugleich aber die Konfigurationsgrenze zieht, auf der der nächste Abschnitt aufbaut.

Konfiguration als Vertrag

Konfiguration ist der erste Laufzeitvertrag. Der Rotator sollte den Start verweigern, wenn eine erforderliche Abhängigkeit fehlt, statt mit einer unbrauchbaren Route hochzufahren und das erst mitten in der Last zu merken.

python
def _required(name: str) -> str:
    value = os.environ.get(name)
    if not value:
        raise RuntimeError(f"Missing required environment variable: {name}")
    return value

@dataclass(frozen=True)
class Config:
    crawlbase_token: str = field(default_factory=lambda: _required("CRAWLBASE_TOKEN"))
    smart_proxy_host: str = field(default_factory=lambda: os.environ.get("SMART_PROXY_HOST", "smartproxy.crawlbase.com"))
    smart_proxy_port: int = field(default_factory=lambda: int(os.environ.get("SMART_PROXY_PORT", "8012")))
    success_decay: float = field(default_factory=lambda: float(os.environ.get("SUCCESS_DECAY", "0.3")))
    latency_decay: float = field(default_factory=lambda: float(os.environ.get("LATENCY_DECAY", "0.3")))
    breaker_threshold: int = field(default_factory=lambda: int(os.environ.get("BREAKER_THRESHOLD", "3")))
    breaker_cooldown_s: float = field(default_factory=lambda: float(os.environ.get("BREAKER_COOLDOWN_S", "15")))

Beachten Sie, was diese Trennung aussagt. CRAWLBASE_TOKEN ist ein Credential und erforderlich. Alles andere ist Policy: wie schnell der Erfolgsschätzer reagiert, wie schnell der Latenzschätzer reagiert, wie viele aufeinanderfolgende Fehler den Breaker öffnen und wie lange eine geöffnete Route draußen bleibt. Die eingefrorene Dataclass sorgt dafür, dass der Routing-Pfad eine feste Konfiguration liest, statt zur Laufzeit nach Umgebungsvariablen zu greifen.

Die Baseline, die es zu schlagen gilt

Eine Route ist hier alles, was eine URL abrufen und berichten kann, was passiert ist. Die Implementierung liefert zwei: eine direkte Verbindung und den Smart AI Proxy.

python
class CrawlbaseRoute(Route):
    name = "crawlbase-smart-proxy"

    def __init__(self, config: Config) -> None:
        proxy_url = (
            f"http://{config.crawlbase_token}:@"
            f"{config.smart_proxy_host}:{config.smart_proxy_port}"
        )
        self._client = httpx.Client(proxy=proxy_url, verify=False, timeout=config.request_timeout_s, follow_redirects=True)

Das Token wird als Proxy-Benutzername mit leerem Passwort übergeben, so authentifiziert der Smart AI Proxy. verify=False ist keine Abkürzung und sollte verstanden statt kopiert werden: der Proxy terminiert TLS, um eigene Header zu ergänzen, also sieht Ihr Client ein Crawlbase-Zertifikat statt dem des Ziels, und strenge Prüfung würde es ablehnen. Das ist dokumentiertes Verhalten des Endpunkts, kein Workaround für eine Fehlkonfiguration.

DirectRoute ist dieselbe Schnittstelle ohne Proxy. Gegen ein ungeschütztes Ziel ist sie oft schneller und degradiert zuerst, sobald Anti-Bot-Kontrollen auftauchen, was sie zu einer nützlichen Quelle für genau das Fehlersignal macht, das das Health-Modell verarbeiten soll.

Die Baseline-Policy ignoriert jedes dieser Signale, und zwar bewusst:

python
class NaiveRotator:
    def __init__(self, routes: list[Route]) -> None:
        self._routes = routes
        self._cycle = itertools.cycle(routes)

    def fetch(self, url: str) -> tuple[str, FetchResult]:
        route = next(self._cycle)
        return route.name, route.fetch(url)

Das ist die ganze Policy. Sie ist deterministisch und vollkommen fair, und die Fairness ist das Problem: sie bleibt bestehen, nachdem die Routen aufgehört haben, gleich gut zu sein.

Health bewerten: zwei Durchschnitte und ein Breaker

Ein exponentiell gewichteter gleitender Durchschnitt passt hier, weil er jüngere Beobachtungen stärker gewichtet und ältere allmählich vergisst. Eine Route, die vor zehn Minuten ausgefallen ist, soll nicht ewig bestraft werden; eine Route, die vor dreißig Sekunden angefangen hat auszufallen, soll schnell abfallen. Der Decay-Faktor ist der Regler dazwischen.

python
def observe(self, ok: bool, latency_s: float) -> None:
    self.samples += 1
    outcome = 1.0 if ok else 0.0
    self.success_ewma = self.success_decay * outcome + (1 - self.success_decay) * self.success_ewma
    if ok:
        self.latency_ewma_s = self.latency_decay * latency_s + (1 - self.latency_decay) * self.latency_ewma_s
        self.consecutive_failures = 0
        if self.breaker_state is BreakerState.HALF_OPEN:
            self.breaker_state = BreakerState.CLOSED
    else:
        self.consecutive_failures += 1
        if self.consecutive_failures >= self.breaker_threshold:
            self.breaker_state = BreakerState.OPEN
            self.opened_at = time.monotonic()

Zwei Entscheidungen darin sind bewusst getroffen. Die Latenz wird nur bei Erfolg aktualisiert, denn die Dauer eines fehlgeschlagenen Requests beschreibt den Fehler, nicht die Reaktionsschnelligkeit der Route im Normalbetrieb; sie einzurechnen würde eine schnell scheiternde Route schnell aussehen lassen. Und die Stabilität übernimmt der Breaker statt des Durchschnitts, weil aufeinanderfolgende Fehler eine andere Art von Evidenz sind als ein driftender Mittelwert und eine schärfere Antwort verdienen.

Die beiden Schätzer fallen dann in eine einzige Zahl zusammen:

python
def value(self) -> float:
    if self.breaker_state is BreakerState.OPEN:
        return 0.0
    latency_term = 1.0 / (1.0 + self.latency_ewma_s)
    return self.success_ewma * latency_term

Multiplikation statt Addition ist hier die Designentscheidung, und sie kodiert eine Konjunktion: eine Route muss zuverlässig und reaktionsschnell sein, um gut zu punkten. Addiert man die Terme, sammelt eine schnelle Route, die meistens scheitert, aus ihrer Latenzhälfte immer noch einen respektablen Score. Multipliziert man sie, zieht eine Erfolgsrate nahe null den gesamten Wert nahe null, egal wie schnell die Fehlschläge sind. Ein offener Breaker kürzt hart auf genau 0.0ab, was den Ausschluss explizit macht statt emergent.

Die Schleife, ein Request nach dem anderen

Jeder Request durchläuft dieselben vier Schritte: die zulässigen Routen bestimmen, eine nach Health auswählen, ausführen, das Ergebnis zurückspeisen.

Ein Request, sieben Nachrichten. Der Rotator fragt das Health-Modell, welche Routen zulässig sind und was sie wert sind, zieht eine nach Gewicht, setzt den GET ab und reicht das Ergebnis an das Modell zurück, bevor er an den Aufrufer zurückkehrt. Der Aufruf observe ist der einzige Schritt, der künftiges Verhalten verändert.
python
def fetch(self, url: str) -> tuple[str, FetchResult]:
    candidates = self._eligible() or self._scored
    chosen = self._select(candidates)
    result = chosen.route.fetch(url)
    chosen.health.observe(result.ok, result.latency_s)
    return chosen.route.name, result

Die Auswahl gewichtet jede zulässige Route mit ihrer Health hoch einem Exponenten, gamma. Bei null ist die Wahl gleichverteilt; wird er größer, konzentriert sich der Traffic auf die bestbewerteten Routen. Halten Sie ihn moderat. Ein großer Exponent erzeugt einen Rotator, der sich fest auf die Route festlegt, die zufällig zuerst gut aussah, und dann keine Möglichkeit mehr hat zu bemerken, dass eine herabgestufte Route sich erholt hat, weil er ihr nie etwas schickt.

Der Fallback in der ersten Zeile zählt mehr, als er aussieht: wenn der Breaker bei allem offen ist, ist _eligible() leer, und der Rotator fällt auf die vollständige bewertete Menge zurück, statt eine Ausnahme zu werfen. Ein Pool, der komplett ungesund ist, sollte immer noch die am wenigsten schlechte Option versuchen.

Was der Benchmark tatsächlich zeigt

bash
python src/main.py benchmark 20

Policy comparison:
policy              requests    success rate    mean latency
round-robin               20          100.0%          1.589s
health-weighted           20          100.0%          0.289s

Lesen Sie das genau, denn die Schlagzeilenzahl ist der uninteressanteste Teil davon. Gegen ein ungeschütztes Ziel wie example.com sind beide Routen erfolgreich, die Erfolgsraten also identisch, und der gesamte Unterschied landet in der Latenz. Round Robin schickt weiterhin die Hälfte seines Traffics über die langsamere Route, denn das bedeutet Fairness. Die Health-gewichtete Policy merkt es und hört auf.

Derselbe Pool, zwei Policies. Round Robin hält eine feste Gleichverteilung, egal was die Routen tun. Health-gewichtet startet gleichverteilt, verschiebt sich, sobald die Schätzer auseinanderlaufen, und behält einen schmalen Anteil auf der schwächeren Route, damit eine Erholung überhaupt erkennbar bleibt. Dieser Explorationsanteil ist der Teil, den man zuerst löscht und am meisten vermisst.

Die absoluten Latenzen schwanken zwischen Läufen und Zielen und sind nicht die Aussage. Die Aussage betrifft das Verhalten: eine Policy reagiert auf Evidenz, die andere kann es nicht. Richten Sie denselben Benchmark auf ein geschütztes Ziel, und derselbe Mechanismus äußert sich stattdessen in der Erfolgsrate: die Erfolgs-EWMA der direkten Route fällt, ihre aufeinanderfolgenden Fehler lösen den Breaker aus, und der Traffic wandert ab, während Round Robin weiter Requests an eine Route schickt, die sie ablehnt.

Crawlbase Smart AI Proxy

Ein Endpunkt vor rotierenden Residential-IPs, mit Anti-Bot-Handling stromaufwärts, sodass Ihr Rotator eine Route bewertet statt eine Flotte von Adressen zu verwalten. Richten Sie einen HTTP-Client darauf und lassen Sie Ihre Routing-Policy dort, wo sie hingehört. Kostenlos starten mit bis zu 5.000 Anfragen, ohne Karte.

Der Weg in den Produktivbetrieb

Der Benchmark läuft in einem Prozess und synchron, weil das die Regelschleife lesbar macht. Vier Dinge ändern sich, wenn das nicht mehr gilt.

Der Health-Zustand muss geteilt werden. Im Speicher hat jeder Worker seine eigene Meinung über den Pool, also kann ein Prozess eine Route für kaputt halten, während ein anderer sie munter weiter benutzt, und der Breaker öffnet nirgends konsistent. Erfolgs-EWMA, Latenz-EWMA, Breaker-Zustand und Fehlerzähler in etwas wie Redis zu verschieben, unter einem einheitlichen Schlüssel pro Route, macht aus dem Signal etwas Gemeinsames statt Folklore pro Prozess.

Updates müssen nebenläufigkeitssicher sein. Reale Lasten beobachten Ergebnisse parallel, und jedes Feld in observe ist ein Read-Modify-Write. Ohne Synchronisation oder atomare Operationen können zwei gleichzeitige Fehler denselben Zähler lesen und dasselbe Inkrement zurückschreiben, sodass aus einer Schwelle von drei still eine Schwelle von fünf wird.

Die Decay-Faktoren brauchen Abstimmung auf Ihren Traffic. 0.3 ist ein vertretbarer Ausgangspunkt, keine Antwort. Höhere Werte jagen den jüngsten Beobachtungen nach und reagieren schneller, um den Preis, auf einen kurzen Ausreißer überzureagieren. Niedrigere Werte sind ruhiger und bemerken eine echte Veränderung später. Welchen Fehler Sie bevorzugen, hängt davon ab, wie verrauscht Ihre Ziele sind.

Health ist vielleicht nicht Ihr einziges Ziel. Routen unterscheiden sich in Kosten wie in Qualität, und die schnellste Route ist nicht automatisch die, die jeden Request tragen soll. Erweitert man den Skalar um einen Kostenterm, kann die Policy Zuverlässigkeit und Latenz gegen Ausgaben abwägen, statt eine Dimension zu optimieren und sich über die Rechnung zu wundern.

Eine Grenze liegt außerhalb des Modells: richten Sie das nur auf Ziele, auf die Sie zugreifen dürfen, und respektieren Sie deren Bedingungen, Ratenerwartungen und Einschränkungen. Der Benchmark verwendet example.com gerade deshalb, weil es ein kontrolliertes Ziel ist, das nichts davon einfordert.

Das Wichtigste

Ein Rotator wird in dem Moment nützlich, in dem die Auswahl von beobachtetem Verhalten getrieben wird statt von der Position in einer Liste. Drei Mechanismen leisten die Arbeit: eine EWMA über den Erfolg für jüngste Zuverlässigkeit, eine EWMA über die Latenz für Reaktionsschnelligkeit und ein Circuit Breaker für die abrupten Fehler, die ein Durchschnitt verschleift. Die Multiplikation der ersten beiden hält eine Route auf beiden Achsen ehrlich; der Breaker übernimmt den Fall, in dem allmählich das falsche Tempo ist.

Round Robin bleibt im Bild als die Kontrolle, die die Verbesserung messbar macht. Und der Smart AI Proxy fügt sich als Route ein statt als Verantwortung, indem er IP-Rotation und Anti-Bot-Handling absorbiert, damit die Policy darüber eine Routing-Entscheidung bleiben kann.

Auswählen, ausführen, beobachten, aktualisieren, erneut auswählen. Alles andere in diesem Beitrag ist ein Detail darüber, wie gut jeder Schritt erledigt wird.

Häufig gestellte Fragen (FAQ)

Warum sollte ich Routen selbst bewerten, wenn der Smart AI Proxy schon rotiert?

Sie arbeiten auf unterschiedlichen Ebenen. Der Smart AI Proxy rotiert IPs innerhalb seines eigenen Pools, Ihre Anwendung muss also keine einzelnen Adressen modellieren. Ihr Rotator bewertet Routen: eine direkte Verbindung gegen eine über Proxy, einen regionalen Endpunkt gegen einen anderen, einen günstigen Pfad gegen einen teuren. Das ist eine Entscheidung, die nur Ihre Anwendung treffen kann, weil sie weiß, wofür der Traffic da ist. Das Modell in diesem Beitrag ist bewusst allgemein gehalten, damit es auf jede Menge von Routen passt, die Sie tatsächlich betreiben.

Welchen Decay-Faktor sollte ich verwenden?

Beginnen Sie bei 0.3 für beide. Jede neue Beobachtung steuert 30% des aktualisierten Schätzers bei, der vorherige Schätzwert trägt die restlichen 70%. Erhöhen Sie ihn, wenn Ihre Ziele ihr Verhalten schnell ändern und die Policy es früher bemerken soll; senken Sie ihn, wenn die Messungen verrauscht sind und eine einzelne langsame Antwort nicht gleich Traffic verschieben soll.

Wann hilft der Circuit Breaker mehr als die Erfolgs-EWMA allein?

Wenn der Ausfall plötzlich kommt. Die EWMA ist konstruktionsbedingt ein Glätter, eine Route, die komplett stirbt, braucht also mehrere Beobachtungen, bis sie niedrig genug bewertet wird, um eine Rolle zu spielen, und jede dieser Beobachtungen ist ein verschwendeter Request. Der Breaker knüpft stattdessen an aufeinanderfolgende Fehler an und zieht die Route sofort heraus, dann bietet er nach der Abkühlzeit eine kontrollierte Half-Open-Probe an, statt zu warten, bis der Durchschnitt wieder nach oben driftet. Die beiden ergänzen sich: der Durchschnitt kümmert sich um Degradation, der Breaker um den Zusammenbruch.

Brauche ich dafür das JavaScript Token?

Nein. Das Normal Token genügt für die hier verwendete Smart-AI-Proxy-Route. Das JavaScript Token gibt es für Ziele, die erst gerendert werden müssen, bevor überhaupt Inhalt zurückkommt, und das ist eine Frage über das Ziel, nicht über das Routing. Die Rotationslogik ist in beiden Fällen dieselbe.

Kann dasselbe Modell mehr als zwei Optionen routen?

Ja, und dann ist es sogar nützlicher. Weder das Health-Modell noch die Auswahl-Policy setzen zwei Routen voraus: beide arbeiten über eine Liste. Zwei Routen machen den Benchmark nur leicht lesbar. Regionale Endpunkte oder einen zweiten Anbieter zu ergänzen heißt, die Routenliste zu erweitern, und die gewichtete Auswahl verteilt über alles, was da ist.

Jetzt loslegen

Crawlen Sie jede Website im großen Maßstab, ohne gegen die Infrastruktur zu kämpfen.

Crawlbase übernimmt Proxys, Fingerprints und CAPTCHAs, damit Ihr Team Datenpipelines ausliefert, statt Crawl-Infrastruktur zu pflegen. 1.000 Anfragen kostenlos, keine Karte erforderlich.

Self-Service · Kein Verkaufsgespräch erforderlich · Enterprise-Crawl-Volumen verfügbar