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 Limiting503 Service Unavailable— wird manchmal anstelle von 429 verwendet403 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.