Zurück zum Blog

Rate Limiting umgehen mit Proxys: Architektur, IP-Rotation und Codebeispiele für Entwickler

Rate Limiting blockiert Ihren Parser oder API-Client? Wir erklären, wie man die Beschränkungen der Anfragenanzahl mit Proxys umgeht – mit Codebeispielen und architektonischen Lösungen.

📅12. Mai 2026
```html

Rate Limiting ist einer der häufigsten Gründe, warum Scraper abstürzen, API-Integrationen fehlschlagen und automatisierte Skripte den Status 429 Too Many Requests erhalten. Der Server sieht zu viele Anfragen von einer IP-Adresse und hört einfach auf zu antworten. In diesem Artikel werden wir besprechen, wie man die Infrastruktur mit Proxys richtig aufbaut, um die Anfragebeschränkungen ohne Sperren und Ausfälle zu umgehen — mit echten Codebeispielen in Python und Node.js.

Was ist Rate Limiting und warum helfen normale Verzögerungen nicht

Rate Limiting (Anfragebeschränkung) ist ein Schutzmechanismus des Servers, der die Anzahl der Anfragen von einer Quelle über einen bestimmten Zeitraum begrenzt. Die Quelle ist meist die IP-Adresse, aber fortschrittliche Systeme berücksichtigen auch Autorisierungstoken, User-Agent, Cookies und sogar Verhaltensmuster.

Wenn Ihr Skript das Limit überschreitet, gibt der Server eine der folgenden Antworten zurück:

  • 429 Too Many Requests — Standard-HTTP-Status für Rate Limiting
  • 503 Service Unavailable — wird manchmal anstelle von 429 verwendet
  • 403 Forbidden — wenn die IP bereits auf der Sperrliste steht
  • Leere Antwort oder Timeout — bei aggressiver Sperrung

Der erste Gedanke der meisten Entwickler ist, time.sleep(1) zwischen den Anfragen hinzuzufügen. Das funktioniert nur bei sehr milden Limits (z. B. 60 Anfragen pro Minute). Aber die realen Szenarien sind komplizierter:

Reale Limits beliebter Plattformen:

  • Twitter/X API (kostenlos): 500.000 Tweets pro Monat, aber nicht mehr als 15 Anfragen alle 15 Minuten
  • Google Search: ~100 Anfragen pro Tag von einer IP ohne Authentifizierung
  • Wildberries, Ozon: aggressives Rate Limiting — Sperre nach 30–50 Anfragen pro Minute
  • GitHub API: 60 Anfragen/Stunde ohne Token, 5000/Stunde mit Token
  • Cloudflare-geschützte Websites: können bereits nach 10–20 Anfragen pro Minute blockieren

Wenn Sie 100.000 Produktkarten von einem Marktplatz sammeln oder Preise in Echtzeit überwachen müssen — helfen Verzögerungen einfach nicht. Eine andere Architektur ist erforderlich. Und hier werden Proxys zur Notwendigkeit, nicht zur Option.

Es ist wichtig zu verstehen: Rate Limiting ist an die IP-Adresse gebunden. Wenn Sie 100 verschiedene IPs haben — haben Sie faktisch 100 unabhängige „Quoten“. Das ist das Schlüsselprinzip zur Umgehung von Beschränkungen über Proxys.

Wie Proxys das Problem der Anfragebeschränkungen lösen

Der Mechanismus ist einfach: Jede Anfrage an den Zielserver wird von einer anderen IP-Adresse gesendet. Aus Sicht des Servers sind das verschiedene Benutzer. Das Kontingent jedes einzelnen wird praktisch nicht verbraucht, daher tritt keine Sperrung ein.

Lassen Sie uns den Unterschied zwischen der Arbeit ohne Proxys und mit einem Pool von Proxys anhand eines konkreten Beispiels betrachten. Angenommen, der Server erlaubt 10 Anfragen pro Minute von einer IP:

Szenario Anfragen pro Minute Sperrung Zeit für 10.000 Anfragen
Eine IP, ohne Proxys 10 Ja, nach 10 Anfragen ~16 Stunden
10 Proxys, Rotation 100 Nein ~1,7 Stunden
100 Proxys, Rotation 1000 Nein ~10 Minuten

Neben der Skalierung der Bandbreite bieten Proxys noch mehrere Vorteile bei der Arbeit mit Rate Limiting:

  • Isolation von Sitzungen — wenn eine IP gesperrt wird, funktionieren die anderen weiterhin
  • Geografische Verteilung — Anfragen kommen aus verschiedenen Regionen, was die Verdächtigkeit verringert
  • Sticky Sessions — Möglichkeit, an einer IP für mehrstufige Szenarien „kleben zu bleiben“ (Authentifizierung + Aktion)
  • Lastkontrolle — Anfragen können genau auf jede IP dosiert werden, ohne das Limit zu überschreiten

Welchen Proxy-Typ für Ihre Aufgabe wählen

Nicht alle Proxys sind gleich effektiv gegen Rate Limiting. Die Wahl des Typs hängt von der Zielwebsite, dem Anfragevolumen und dem Budget ab. Lassen Sie uns drei Haupttypen betrachten:

Residential Proxys

Dies sind IP-Adressen realer Haushaltsbenutzer. Sie sehen aus wie normaler Internetverkehr und werden extrem selten blockiert. Residential Proxys sind die optimale Wahl für Websites mit aggressivem Schutz: Marktplätze (Wildberries, Ozon), soziale Netzwerke, Cloudflare-geschützte Ressourcen. Der Hauptnachteil sind die höheren Kosten im Vergleich zu Rechenzentrums-Proxys.

Mobile Proxys

IP-Adressen von Mobilfunkanbietern (3G/4G/5G). Ihre Besonderheit ist, dass eine IP von Tausenden realer Abonnenten gleichzeitig verwendet werden kann, weshalb Websites solche Adressen äußerst ungern blockieren. Mobile Proxys zeigen die besten Ergebnisse dort, wo Residential Proxys bereits blockiert werden — beispielsweise beim hochfrequenten Scraping von Instagram oder bei der Arbeit mit API-Plattformen, die den Verbindungstyp analysieren.

Rechenzentrums-Proxys

Schnelle und günstige IPs aus Server-Rechenzentren. Ideal für das Scraping von Websites ohne ernsthaften Schutz: offene APIs, Nachrichtenaggregatoren, öffentliche Datenbanken. Für Aufgaben mit Rate Limiting werden mehr benötigt (da sie häufiger auf Sperrlisten landen), aber bei richtiger Rotation bewältigen sie große Anfragevolumen hervorragend. Weitere Informationen finden Sie auf der Seite Rechenzentrums-Proxys.

Proxy-Typ Anonymität Geschwindigkeit Preis Bester Anwendungsfall
Residential Sehr hoch Mittel $$ Marktplätze, soziale Netzwerke, Cloudflare
Mobile Maximal Mittel $$$ Instagram API, hochfrequentes Scraping
Rechenzentren Mittel Hoch $ Offene APIs, öffentliche Daten

IP-Rotationsstrategien: per-request, sticky sessions, round-robin

Der bloße Besitz von Proxys löst das Problem noch nicht — wichtig ist, sie richtig zu verwalten. Es gibt mehrere Rotationsstrategien, die jeweils für ihre Szenarien geeignet sind.

Per-Request-Rotation (neue IP für jede Anfrage)

Jede HTTP-Anfrage wird über eine neue IP-Adresse gesendet. Dies ist die aggressivste Strategie zur Umgehung von Rate Limiting — der Server hat physisch keine Zeit, einen Zähler für eine IP zu akkumulieren. Geeignet für:

  • Scraping von Produktkarten (jede Karte ist eine separate Anfrage)
  • Datensammlung von Suchmaschinen
  • Alle stateless-Anfragen, die keine Sitzung erfordern

Sticky Sessions (feste IP für die Sitzung)

Eine IP wird während der gesamten Sitzung verwendet (normalerweise 1–30 Minuten). Kritisch wichtig für Szenarien, in denen eine Authentifizierung erforderlich ist: sich in ein Konto einloggen, eine Aktion ausführen, sich abmelden. Wenn die IP zwischen den Schritten wechselt — kann der Server die Sitzung als verdächtig blockieren.

Round-Robin mit Anfrage-Limit pro IP

Die genaueste Strategie. Sie kennen das Limit des Servers (z. B. 10 Anfragen pro Minute) und verteilen die Anfragen auf den Pool von Proxys, sodass jede IP dieses Limit niemals überschreitet. Erfordert die Implementierung einer Warteschlange unter Berücksichtigung der Zeit der letzten Anfrage für jede IP.

Formel zur Berechnung der benötigten Anzahl von Proxys:

N Proxys = (Zielanfragen pro Minute) ÷ (Serverlimit pro Minute pro IP)
Beispiel: 500 Anfragen/Minute benötigt, Serverlimit — 10/Minute → mindestens 50 Proxys erforderlich. Fügen Sie 20 % Puffer für den Fall von Sperrungen hinzu: insgesamt 60 Proxys.

Codebeispiele in Python: requests, aiohttp, Scrapy

Kommen wir zur Praxis. Unten finden Sie fertige Vorlagen für die drei beliebtesten Python-Tools.

1. requests + manuelle Proxy-Rotation

Die einfachste Variante — eine Liste von Proxys und eine zufällige Auswahl für jede Anfrage:

import requests
import random
import time

PROXIES = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    # ... fügen Sie die benötigte Anzahl hinzu
]

def get_random_proxy():
    proxy = random.choice(PROXIES)
    return {"http": proxy, "https": proxy}

def fetch_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        proxy = get_random_proxy()
        try:
            response = requests.get(
                url,
                proxies=proxy,
                timeout=10,
                headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
            )
            if response.status_code == 429:
                print(f"Rate limitiert bei {proxy}, wechsle...");
                time.sleep(1)
                continue
            return response
        except requests.RequestException as e:
            print(f"Versuch {attempt+1} fehlgeschlagen: {e}")
            time.sleep(2)
    return None

# Verwendung
urls = ["https://example.com/item/1", "https://example.com/item/2"]
for url in urls:
    result = fetch_with_retry(url)
    if result:
        print(f"OK: {url} — {len(result.text)} Bytes")

2. Intelligenter Proxy-Pool unter Berücksichtigung des Rate Limits

Eine fortschrittlichere Variante — die Klasse ProxyPool, die die Zeit der letzten Nutzung jeder IP verfolgt und das festgelegte Limit nicht überschreitet:

import requests
import time
from collections import defaultdict
from threading import Lock

class ProxyPool:
    def __init__(self, proxies, rate_limit=10, window=60):
        """
        proxies: Liste von Strings im Format 'http://user:pass@host:port'
        rate_limit: maximale Anfragen von einer IP innerhalb eines Zeitfensters
        window: Zeitfenster in Sekunden
        """
        self.proxies = proxies
        self.rate_limit = rate_limit
        self.window = window
        self.usage = defaultdict(list)  # proxy -> [timestamps]
        self.lock = Lock()

    def get_available_proxy(self):
        now = time.time()
        with self.lock:
            for proxy in self.proxies:
                # Veraltete Zeitstempel löschen
                self.usage[proxy] = [
                    t for t in self.usage[proxy]
                    if now - t < self.window
                ]
                if len(self.usage[proxy]) < self.rate_limit:
                    self.usage[proxy].append(now)
                    return {"http": proxy, "https": proxy}
        return None  # Alle Proxys haben ihr Limit erreicht

    def fetch(self, url, **kwargs):
        proxy = self.get_available_proxy()
        if proxy is None:
            print("Alle Proxys sind rate-limitiert, warte...");
            time.sleep(5)
            return self.fetch(url, **kwargs)
        
        try:
            response = requests.get(url, proxies=proxy, timeout=10, **kwargs)
            return response
        except requests.RequestException as e:
            print(f"Anfrage fehlgeschlagen: {e}")
            return None

# Verwendung
pool = ProxyPool(
    proxies=[
        "http://user:[email protected]:8080",
        "http://user:[email protected]:8080",
    ],
    rate_limit=10,  # 10 Anfragen pro Minute pro IP
    window=60
)

for i in range(100):
    r = pool.fetch(f"https://example.com/page/{i}")
    if r:
        print(f"Seite {i}: {r.status_code}")

3. aiohttp für asynchrones Scraping

Der asynchrone Ansatz ermöglicht die parallele Nutzung von Dutzenden Proxys, ohne die Threads zu blockieren:

import asyncio
import aiohttp
import itertools

PROXIES = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

proxy_cycle = itertools.cycle(PROXIES)

async def fetch(session, url, proxy):
    try:
        async with session.get(
            url,
            proxy=proxy,
            timeout=aiohttp.ClientTimeout(total=10)
        ) as response:
            if response.status == 429:
                await asyncio.sleep(2)
                return None
            return await response.text()
    except Exception as e:
        print(f"Fehler: {e}")
        return None

async def main(urls):
    connector = aiohttp.TCPConnector(limit=50)
    async with aiohttp.ClientSession(connector=connector) as session:
        tasks = [
            fetch(session, url, next(proxy_cycle))
            for url in urls
        ]
        results = await asyncio.gather(*tasks)
        return results

urls = [f"https://example.com/item/{i}" for i in range(200)]
results = asyncio.run(main(urls))
print(f"Gesammelt: {sum(1 for r in results if r is not None)} Seiten")

4. Scrapy mit Rotation über Middleware

Für Scrapy gibt es eine fertige Lösung — scrapy-rotating-proxies. Aber man kann auch eine eigene Middleware schreiben:

# middlewares.py
import random

class RotatingProxyMiddleware:
    def __init__(self, proxies):
        self.proxies = proxies

    @classmethod
    def from_crawler(cls, crawler):
        return cls(proxies=crawler.settings.getlist("PROXY_LIST"))

    def process_request(self, request, spider):
        proxy = random.choice(self.proxies)
        request.meta["proxy"] = proxy

    def process_response(self, request, response, spider):
        if response.status == 429:
            spider.logger.warning(f"Rate limitiert, Proxy: {request.meta.get('proxy')}")
            # Man kann Logik hinzufügen, um problematische Proxys auszuschließen
        return response

# settings.py
PROXY_LIST = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]
DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.RotatingProxyMiddleware": 350,
}
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_TARGET_CONCURRENCY = 10

Codebeispiele in Node.js: axios, got, Puppeteer

Node.js ist eine beliebte Wahl für die Automatisierung von Browsern und die Arbeit mit APIs. Hier sind fertige Muster für die Arbeit mit Proxys.

1. axios mit Proxy-Rotation

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');

const proxies = [
  'http://user:[email protected]:8080',
  'http://user:[email protected]:8080',
  'http://user:[email protected]:8080',
];

let proxyIndex = 0;

function getNextProxy() {
  const proxy = proxies[proxyIndex % proxies.length];
  proxyIndex++;
  return proxy;
}

async function fetchWithProxy(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    const proxyUrl = getNextProxy();
    const agent = new HttpsProxyAgent(proxyUrl);
    
    try {
      const response = await axios.get(url, {
        httpsAgent: agent,
        httpAgent: agent,
        timeout: 10000,
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
        },
      });
      return response.data;
    } catch (error) {
      if (error.response?.status === 429) {
        console.log(`Rate limitiert, wechsle Proxy...`);
        await new Promise(r => setTimeout(r, 1000));
        continue;
      }
      console.error(`Versuch ${i + 1} fehlgeschlagen:`, error.message);
    }
  }
  return null;
}

// Verwendung
(async () => {
  const urls = Array.from({length: 50}, (_, i) => `https://example.com/item/${i}`);
  
  const results = await Promise.allSettled(
    urls.map(url => fetchWithProxy(url))
  );
  
  const successful = results.filter(r => r.status === 'fulfilled' && r.value).length;
  console.log(`Erfolg: ${successful}/${urls.length}`);
})();

2. Puppeteer mit Proxys und Umgehung von Rate Limiting

Für Websites mit JavaScript-Rendering und Cloudflare-Schutz ist ein Headless-Browser erforderlich:

const puppeteer = require('puppeteer');

const proxies = [
  'proxy1.example.com:8080',
  'proxy2.example.com:8080',
];

async function scrapeWithProxy(url, proxyHost) {
  const browser = await puppeteer.launch({
    args: [
      `--proxy-server=${proxyHost}`,
      '--no-sandbox',
      '--disable-setuid-sandbox',
    ],
    headless: true,
  });

  const page = await browser.newPage();
  
  // Proxy-Authentifizierung
  await page.authenticate({
    username: 'user',
    password: 'pass',
  });

  // Setzen eines realistischen User-Agent
  await page.setUserAgent(
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
  );

  try {
    await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
    
    // Überprüfen auf Rate Limiting
    const status = await page.evaluate(() => document.title);
    if (status.includes('429') || status.includes('Too Many')) {
      console.log('Rate limitiert, muss Proxy wechseln');
      return null;
    }
    
    const data = await page.evaluate(() => {
      return document.querySelector('.price')?.textContent || null;
    });
    
    return data;
  } finally {
    await browser.close();
  }
}

// Rotation nach Aufgaben
(async () => {
  const urls = ['https://example.com/product/1', 'https://example.com/product/2'];
  
  for (let i = 0; i < urls.length; i++) {
    const proxy = proxies[i % proxies.length];
    const result = await scrapeWithProxy(urls[i], proxy);
    console.log(`${urls[i]}: ${result}`);
    await new Promise(r => setTimeout(r, 500)); // kleine Verzögerung
  }
})();

Fortgeschrittene Techniken: Header, Fingerprint, Umgehung von Cloudflare

Der Wechsel der IP ist eine notwendige, aber nicht immer ausreichende Bedingung. Moderne Schutzsysteme analysieren Dutzende von Anfrageparametern. Lassen Sie uns besprechen, was noch berücksichtigt werden muss.

HTTP-Header: Minimale Pflichtausstattung

Eine Anfrage ohne normale Header sieht selbst bei einem IP-Wechsel wie ein Bot aus. Fügen Sie immer hinzu:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Cache-Control": "max-age=0",
}

Verarbeitung des Retry-After-Headers

Bei der Antwort 429 gibt der Server oft an, wie lange gewartet werden muss. Die richtige Verarbeitung dieses Headers ermöglicht es, Anfragen nicht umsonst zu verschwenden:

def handle_rate_limit(response):
    if response.status_code == 429:
        retry_after = response.headers.get("Retry-After")
        if retry_after:
            wait_time = int(retry_after)
            print(f"Rate limitiert. Warte {wait_time} Sekunden...")
            time.sleep(wait_time + 1)  # +1 Sekunde Puffer
        else:
            # Exponentielle Verzögerung, wenn kein Header vorhanden ist
            time.sleep(min(2 ** attempt, 60))
        return True
    return False

TLS-Fingerprinting und wie man es umgeht

Fortgeschrittene Systeme (Cloudflare, Akamai, PerimeterX) analysieren das TLS-Fingerprinting — einen einzigartigen „Fingerabdruck“ Ihrer TLS-Verbindung. Die Standardbibliothek requests hat einen leicht erkennbaren Fingerabdruck. Lösungen:

  • curl_cffi (Python) — emuliert den Fingerabdruck von Chrome/Firefox auf TLS-Ebene
  • tls-client (Go/Python) — ähnliches Tool mit Unterstützung für verschiedene Browserprofile
  • Playwright/Puppeteer — echter Browser, idealer Fingerabdruck standardmäßig
# pip install curl-cffi
from curl_cffi import requests as cffi_requests

response = cffi_requests.get(
    "https://cloudflare-protected-site.com/api/data",
    impersonate="chrome120",  # Emuliert Chrome 120
    proxies={"https": "http://user:[email protected]:8080"}
)
print(response.json())

Verwaltung von Cookies und Sitzungen

Wenn die Website Cookies zur Verfolgung von Sitzungen verwendet, ist der Wechsel der IP ohne Wechsel der Cookies sinnlos. Erstellen Sie bei jedem Wechsel des Proxys immer eine neue Sitzung:

import requests

def create_fresh_session(proxy_url):
    """Erstellt eine neue Sitzung mit sauberen Cookies für jeden Proxy"""
    session = requests.Session()
    session.proxies = {"http": proxy_url, "https": proxy_url}
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
    })
    # Cookies werden nicht aus der vorherigen Sitzung übertragen
    return session

# Für jede neue IP — neue Sitzung
for proxy in proxies:
    session = create_fresh_session(proxy)
    response = session.get("https://example.com/protected-page")
    # Antwort verarbeiten...

Typische Fehler bei der Arbeit mit Proxys und Rate Limiting

Selbst mit richtig konfigurierten Proxys treten Entwickler regelmäßig in die gleichen Fallen. Hier sind die häufigsten Fehler und wie man sie vermeidet.

Checkliste: Was vor dem Start des Scrapers überprüft werden sollte

  • ☐ Realistische HTTP-Header hinzugefügt (User-Agent, Accept, Accept-Language)
  • ☐ Bei Wechsel des Proxys wird eine neue Sitzung erstellt (neue Cookies)
  • ☐ Status 429, 503, 403 mit Retry-Logik verarbeitet
  • ☐ Verzögerung zwischen Anfragen implementiert (mindestens 100–500 ms)
  • ☐ Anzahl der Proxys entspricht der Zielanfragegeschwindigkeit
  • ☐ Funktionieren der Proxys vor dem Start überprüft (Health Check)
  • ☐ Fehler und Statistiken für jeden Proxy protokolliert
  • ☐ Timeout für Anfragen konfiguriert (nicht mehr als 15–30 Sekunden)

Fehler 1: Verwendung von „toten“ Proxys

Überprüfen Sie immer die Proxys, bevor Sie sie in den Pool aufnehmen, und regelmäßig während des Betriebs. Ein nicht funktionierender Proxy in der Schleife bedeutet verlorene Anfragen und Timeouts:

def check_proxy(proxy_url, test_url="https://httpbin.org/ip", timeout=5):
    try:
        r = requests.get(
            test_url,
            proxies={"http": proxy_url, "https": proxy_url},
            timeout=timeout
        )
        return r.status_code == 200
    except:
        return False

# Funktionierende Proxys vor dem Start filtern
working_proxies = [p for p in PROXIES if check_proxy(p)]
print(f"Funktionierende Proxys: {len(working_proxies)}/{len(PROXIES)}")

Fehler 2: Ignorieren des Protokoltyps

HTTP-Proxys können HTTPS-Verkehr nicht direkt proxysieren (nur über CONNECT). SOCKS5-Proxys arbeiten auf Transportebene und unterstützen alle Protokolle. Verwenden Sie für die meisten modernen Websites SOCKS5 oder HTTPS-Proxys:

# SOCKS5-Proxy in requests (erfordert pip install requests[socks])
proxies = {
    "http": "socks5://user:[email protected]:1080",
    "https": "socks5://user:[email protected]:1080",
}

# HTTPS-Proxy
proxies = {
    "http": "https://user:[email protected]:8080",
    "https": "https://user:[email protected]:8080",
}

Fehler 3: Fehlende exponentielle Backoff

Wenn Sie nach 429 sofort die Anfrage wiederholen — verschärfen Sie nur die Situation. Die richtige Strategie ist eine exponentielle Verzögerung mit Jitter (zufälliger Abweichung):

import random

def exponential_backoff(attempt, base=1, max_wait=60):
    """
    attempt: Versuchszahl (beginnend bei 0)
    base: Basisverzögerung in Sekunden
    max_wait: maximale Verzögerung
    """
    wait = min(base * (2 ** attempt), max_wait)
    # Jitter ±25% zur Vermeidung von Thundering Herd
    jitter = wait * 0.25 * random.uniform(-1, 1)
    return wait + jitter

# Verwendung in der Retry-Logik
for attempt in range(5):
    response = requests.get(url, proxies=proxy)
    if response.status_code == 429:
        wait = exponential_backoff(attempt)
        print(f"Rate limitiert. Warte {wait:.1f}s (Versuch {attempt+1})")
        time.sleep(wait)
    else:
        break

Fehler 4: Ein Thread für alle Proxys

Wenn Sie 50 Proxys haben, aber nur einen Ausführungs-Thread — verwenden Sie maximal 1 Proxy gleichzeitig. Verwenden Sie ThreadPoolExecutor oder einen asynchronen Ansatz, um den gesamten Pool parallel zu nutzen:

from concurrent.futures import ThreadPoolExecutor, as_completed

def fetch_url(args):
    url, proxy = args
    try:
        r = requests.get(url, proxies={"https": proxy}, timeout=10)
        return url, r.status_code, len(r.text)
    except Exception as e:
        return url, None, str(e)

# Alle Proxys parallel verwenden
tasks = [(url, proxies[i % len(proxies)]) for i, url in enumerate(urls)]

with ThreadPoolExecutor(max_workers=len(proxies)) as executor:
    futures = {executor.submit(fetch_url, task): task for task in tasks}
    for future in as_completed(futures):
        url, status, size = future.result()
        print(f"{url}: {status} ({size})")

Fazit und Empfehlungen

Rate Limiting ist ein lösbares Problem, wenn man es systematisch angeht. Die wichtigsten Erkenntnisse aus diesem Leitfaden:

  • Proxy-Pool, nicht ein Proxy — die minimale Einheit für ernsthafte Arbeit. Die Anzahl der Proxys wird nach der Formel bestimmt: Zielgeschwindigkeit ÷ Serverlimit pro IP.
  • Die Rotationsstrategie ist wichtig — per-request für stateless-Anfragen, sticky sessions für autorisierte Szenarien.
  • IP ist nicht der einzige Parameter — Header, Cookies, TLS-Fingerprinting und Verhaltensmuster werden ebenfalls von Schutzsystemen analysiert.
  • Verarbeiten Sie 429 korrekt — exponentielles Backoff, Retry-After-Header, Wechsel des Proxys bei Sperrung.
  • Der Proxy-Typ hängt vom Ziel ab — Rechenzentrums-Proxys für offene APIs, Residential Proxys für Marktplätze, Mobile Proxys für maximalen Schutz.

Wenn Sie mit dem Scraping von Marktplätzen (Wildberries, Ozon), der Datensammlung von geschützten APIs oder der Automatisierung mit hohen Geschwindigkeiten arbeiten — empfehlen wir, mit Residential Proxys zu beginnen: Sie bieten das optimale Gleichgewicht zwischen Anonymität und Geschwindigkeit, und ihre IP-Adressen landen praktisch nie auf Sperrlisten. Für Aufgaben, bei denen maximale Widerstandsfähigkeit gegen Sperrungen bei hoher Anfragefrequenz erforderlich ist, sollten Sie Mobile Proxys in Betracht ziehen — ihre IPs werden von Tausenden realer Benutzer geteilt, was eine Sperrung für jede Website äußerst unerwünscht macht.

```