# Scrapy Proxy Middleware: Rotierende Proxies ohne Sperren

Scrapy unterstützt seit Version 0.8 Proxys, aber die Dokumentation erklärt nie, wie man rotiert, erneut versucht und Sperren im großen Maßstab überlebt. Hier ist die Anatomie der Middleware, der Code und die Einstellungen, die entscheiden, ob Ihr Crawl abgeschlossen wird.

Scrapy hat seit Version 0.8 eine Proxy-Middleware, also wurde die Frage 'Unterstützt Scrapy Proxys?' vor fünfzehn Jahren geklärt. Was die Dokumentation nie ganz zusammenfügt, ist das Produktionsbild: wie die eingebaute Scrapy-Proxy-Middleware tatsächlich Anmeldeinformationen verarbeitet, wann Proxys pro Anfrage im Vergleich zu global gesetzt werden sollten und wie man rotiert und sich erholt, wenn ein Ziel beginnt, Ausgänge mitten im Crawl zu sperren. Dieser Leitfaden führt durch die gesamte Kette — die eingebaute `HttpProxyMiddleware`, pro Anfrage `meta`, eine benutzerdefinierte Rotations-Middleware mit Sperrbehandlung und die Einstellungen, die entscheiden, ob ein Crawl über 100.000 Seiten abgeschlossen wird oder um 3 Uhr morgens stirbt.

## Wie die eingebaute Scrapy-Proxy-Middleware funktioniert

`scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware` ist standardmäßig mit Priorität 750 in `DOWNLOADER_MIDDLEWARES_BASE` aktiviert. Das Lesen des Quellcodes (etwa 100 Zeilen in Scrapy 2.17) verrät Ihnen alles, was Sie zum Debuggen benötigen:

- Beim Start ruft es `urllib.request.getproxies()` auf, sodass `http_proxy` / `https_proxy` Umgebungsvariablen einen Spider ohne Code konfigurieren. `no_proxy` wird nur für http- und https-Schemata berücksichtigt.
- Pro Anfrage gewinnt `request.meta['proxy']` immer über die Umgebung. Setzen Sie es auf `None`, um eine direkte Verbindung für diese Anfrage zu erzwingen.
- In der Proxy-URL eingebettete Anmeldeinformationen (`http://user:pass@host:port`) werden entfernt, Base64-codiert und als `Proxy-Authorization: Basic` Header gesendet. Die Kodierung erfolgt standardmäßig in latin-1 und ist über `HTTPPROXY_AUTH_ENCODING` konfigurierbar.
- Die Middleware dekodiert Anmeldeinformationen vor der Kodierung, daher sollten Sie Sonderzeichen wie `@` in Passwörtern URL-kodieren — sie werden korrekt durchgereicht.
- Wenn ein erneuter Versuch den Proxy ändert, verwirft die Middleware den veralteten Auth-Header, anstatt ihn an den neuen Proxy zu leaken — eine Maßnahme zur Anmeldeinformationen-Hygiene in modernem Scrapy und ein guter Grund, keine alten Versionen zu verwenden.

Praktische Konsequenz: Sie benötigen fast nie ein Drittanbieter-Proxy-Paket. Alles, was eine gültige Proxy-URL in `request.meta['proxy']` vor Priorität 750 einfügt, erhält Authentifizierung und Header-Verarbeitung kostenlos.

## Pro-Anfrage-Proxys mit Meta

Die leichteste Integration besteht darin, `meta` direkt im Spider zu setzen — nützlich, wenn nur einige Anfragen einen Proxy benötigen oder verschiedene Ziele unterschiedliche Ausgangsländer benötigen:

```python
import scrapy

class PricesSpider(scrapy.Spider):
    name = "prices"

    def start_requests(self):
        yield scrapy.Request(
            "https://example.com/product/1",
            meta={"proxy": "http://USER:PASS@residentialpremium.quantumproxies.io:8080"},
        )
```

Pro-Anfrage-Meta glänzt, wenn die Proxy-Wahl selbst datengetrieben ist: leiten Sie deutsche Produktseiten über einen auf Deutschland ausgerichteten Benutzernamen, senden Sie Bilddownloads über günstige Rechenzentrumsausgänge, während HTML über Wohnanschlüsse geht, oder eskalieren Sie eine hartnäckige URL bei ihrem zweiten Versuch auf eine stabilere Sitzung. Da Meta Wiederholungen und Weiterleitungen überlebt, folgt die Entscheidung, die Sie beim Erstellen der Anfrage treffen, dem gesamten Download-Zyklus. Das Setzen von Meta auf Tausenden von Anfragen von Hand skaliert jedoch nicht — dafür sind Downloader-Middlewares da.

## Das einfachste Produktionssetup: ein rotierendes Gateway

Mit [rotierenden Proxys](https://quantumproxies.io/rotating-proxies) hinter einem einzigen Gateway-Endpunkt erfolgt die Rotation serverseitig: jede Anfrage über dieselbe URL verlässt über eine andere IP in einem 90M+ Wohnanschlusspool, der über 200+ Länder spannt. Ihre Middleware schrumpft auf drei Zeilen, und es gibt keine Liste, die überprüft, bereinigt oder aktualisiert werden muss:

```python
# middlewares.py
class RotatingGatewayMiddleware:
    PROXY = "http://USER:PASS@residentialpremium.quantumproxies.io:8080"

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

# settings.py
DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.RotatingGatewayMiddleware": 350,
}
```

Priorität 350 ist wichtig: Ihre Middleware muss vor der eingebauten bei 750 laufen, damit `HttpProxyMiddleware` die Anmeldeinformationen noch in den Auth-Header umwandeln kann. Diese Paarung — Gateway-Rotation plus Scrapy's Standard-Wiederholungsmechanismus — bietet die höchste Zuverlässigkeit pro Codezeile, da jeder erneute Versuch automatisch über eine frische Ausgangs-IP erfolgt.

![Eine Scrapy-Anfrage durchläuft die Downloader-Middleware-Kette: Der Spider gibt sie per yield aus, Ihre Middleware mit Priorität 350 setzt meta'proxy' auf das Gateway, die eingebaute HttpProxyMiddleware bei 750 wandelt die Anmeldedaten in einen Proxy-Authorization-Header um, und der Downloader geht über das rotierende Gateway hinaus; Wiederholungen erhalten eine neue IP.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335142/blog/generated/qp-b9-002-diag1.png)
*Ihre Middleware muss nur meta['proxy'] setzen; die eingebaute bei Priorität 750 verarbeitet Anmeldeinformationen, und Wiederholungen treten mit einer neuen IP erneut in die Kette ein.*

## Eine benutzerdefinierte rotierende Proxy-Middleware mit Sperrbehandlung

Wenn Sie Ihre eigene Proxy-Liste betreiben — statische ISP-Adressen oder einen gemischten Pool — ist das klassische Muster (popularisiert durch das scrapy-proxies-Paket, das `RETRY_TIMES = 10` empfahl, weil kostenlose Listen-Proxys so oft versagen): wählen Sie zufällig pro Anfrage, entfernen Sie bei Sperrsignalen, stellen Sie die Anfrage erneut in die Warteschlange:

```python
import random

class ProxyListMiddleware:
    BAN_CODES = {403, 429}

    def __init__(self, proxies):
        self.proxies = list(proxies)

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

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

    def process_response(self, request, response, spider):
        if response.status in self.BAN_CODES:
            bad = request.meta.get("proxy")
            if bad in self.proxies and len(self.proxies) > 1:
                self.proxies.remove(bad)
                spider.logger.warning("Evicted %s (%d left)", bad, len(self.proxies))
            return request.replace(dont_filter=True)  # re-queue on a new proxy
        return response
```

Beachten Sie alles, was diese Middleware tun muss, was ein Gateway kostenlos erledigt: Pool-Gesundheit verfolgen, verbrannte IPs entfernen, Anfragen erneut in die Warteschlange stellen. Es schrumpft auch unter Beschuss — ein Pool von 20 statischen IPs kann in Minuten auf einem aggressiven Ziel verdampfen. Das breitere Anti-Sperrspielbuch (Tempo, Header, Sitzungsdisziplin) finden Sie in unserer [IP-Sperrvermeidungs-Checkliste](https://quantumproxies.io/blog/avoid-ip-ban-web-scraping).

## Scrapy-Einstellungen, die das Ergebnis bestimmen

Middleware platziert den Proxy; Einstellungen entscheiden, ob der Crawl sich verhält. Diese sind am wichtigsten:

```python
# settings.py — a sane baseline for proxied crawls
RETRY_TIMES = 5
RETRY_HTTP_CODES = [429, 403, 500, 502, 503, 504, 408]

CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 8
DOWNLOAD_TIMEOUT = 30

AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_TARGET_CONCURRENCY = 4.0
```

- **RETRY_HTTP_CODES** — fügen Sie 429 und 403 hinzu, damit weiche Sperren einen erneuten Versuch auslösen (und, mit Rotation, eine neue IP) anstelle eines fehlgeschlagenen Elements.
- **RETRY_TIMES** — 3-5 ist richtig für einen Qualitäts-Pool; 10 zu benötigen ist ein Zeichen dafür, dass der Pool selbst ungesund ist.
- **CONCURRENT_REQUESTS_PER_DOMAIN** — der echte Höflichkeitsregler. Rotation verteilt die Last über IPs, aber das Ziel sieht immer noch das Gesamtvolumen.
- **DOWNLOAD_TIMEOUT** — die Standard-180 Sekunden lassen einen langsamen Ausgang einen Konkurrenz-Slot für drei Minuten besetzen. 30 ist ausreichend.
- **AUTOTHROTTLE** — passt das Tempo an die beobachtete Latenz an; passt gut zu Rotation bei zielgerichteten Zielen. Immer noch in 429s ertrinken? Unser [Rate-Limit-Leitfaden](https://quantumproxies.io/blog/fix-429-too-many-requests-scraping) behandelt Konkurrenzbudgets ausführlich.

![Zwei Rotations-Setups für Scrapy nebeneinander: eine DIY-Proxyliste, die schrumpft, wenn gesperrte IPs entfernt und Anfragen erneut eingereiht werden, und ein rotierendes Gateway, also ein einziger Endpunkt, der serverseitig rotiert. Die Karte: Eine Liste bedeutet Health-Checks und Aussortieren, 20 statische IPs können in Minuten verpuffen, ein Gateway setzt jede Wiederholung auf eine frische IP.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335142/blog/generated/qp-b9-002-diag2.png)
*Eine DIY-Liste bedeutet Gesundheitschecks, Ausweisungslogik und veraltete IPs. Ein Gateway ist ein Endpunkt, der serverseitig rotiert — Wiederholungen landen standardmäßig auf frischen IPs.*

## Sperrerkennung jenseits von Statuscodes

Fortschrittliche Ziele senden keine ehrlichen 403s. Sie liefern 200s, die eine CAPTCHA-Seite, ein leeres Produktgitter oder eine reduzierte Vorlage enthalten. Robuste Spider überprüfen den Inhalt, nicht nur den Status — suchen Sie nach einem Element, das nur auf der echten Seite existiert, und stellen Sie es erneut in die Warteschlange, wenn es fehlt. Wenn Seiten strukturell leer zurückkommen, selbst durch gute Proxys, wird der Inhalt wahrscheinlich clientseitig gerendert; siehe [warum Scraper leere Seiten erhalten](https://quantumproxies.io/blog/scraper-returns-empty-page-javascript). Und wenn eine Domain plain HTTP unabhängig von der IP besiegt, übergeben Sie diese Domain an eine [Scraper API](https://quantumproxies.io/scraper-api), die JavaScript rendert und sauberes HTML oder Markdown zurückgibt — Scrapy konsumiert es wie jede andere Antwort, und Sie behalten Ihre Pipeline.

```python
def parse(self, response):
    if not response.css("div.product-grid"):
        # 200 OK but the real content is missing: soft ban or JS wall
        yield response.request.replace(dont_filter=True)
        return
    for product in response.css("div.product-grid article"):
        yield {"name": product.css("h2::text").get()}
```

## Häufig gestellte Fragen

### Unterstützt Scrapy Proxys von Haus aus?

Ja. `HttpProxyMiddleware` wird mit Priorität 750 aktiviert geliefert: es liest `http_proxy` / `https_proxy` Umgebungsvariablen und berücksichtigt `request.meta['proxy']` pro Anfrage, einschließlich `user:pass@` Anmeldeinformationen, die es in einen Proxy-Authorization-Header umwandelt. Sie schreiben nur Code, um zu entscheiden, welcher Proxy jede Anfrage erhält.

### Wie setze ich einen Proxy für eine einzelne Anfrage in Scrapy?

Übergeben Sie ihn im Meta der Anfrage: `scrapy.Request(url, meta={'proxy': 'http://user:pass@host:port'})`. Meta überschreibt immer umgebungsweite Proxys, und das Setzen des Werts auf `None` zwingt diese eine Anfrage, direkt zu gehen — nützlich, um in einem Spider sowohl proxied als auch unproxied Traffic zu mischen.

### Wie rotiere ich Proxys in Scrapy?

Entweder schreiben Sie eine Downloader-Middleware, die pro Anfrage einen Proxy aus einer Liste auswählt und gesperrte entfernt, oder Sie richten jede Anfrage an einen rotierenden Gateway-Endpunkt, der serverseitig eine frische Ausgangs-IP zuweist. Der Gateway-Ansatz benötigt eine dreizeilige Middleware, keine Gesundheitschecks, und verwandelt jeden Scrapy-Wiederholungsversuch kostenlos in eine Rotation.

### Warum gibt mein Scrapy-Proxy 407 zurück?

Der Proxy hat die Authentifizierung abgelehnt. Überprüfen Sie, ob Anmeldeinformationen in der Proxy-URL im Meta enthalten sind, dass Sonderzeichen URL-kodiert sind und dass Ihre Server-IP auf der Whitelist steht, wenn Ihr Plan IP-Auth verwendet. Wenn Anmeldeinformationen nicht-ASCII-Zeichen enthalten, setzen Sie `HTTPPROXY_AUTH_ENCODING`, um mit Ihrem Anbieter übereinzustimmen.

Das Muster, das Sie sich merken sollten: setzen Sie `meta['proxy']` früh, lassen Sie die eingebaute Middleware bei 750 die Authentifizierung durchführen, fügen Sie 429 und 403 zu Ihren Wiederholungscodes hinzu und bevorzugen Sie serverseitige Rotation gegenüber Listenpflege. Wenn Teile Ihres Crawls JavaScript benötigen, wägen Sie die [Kosten von Headless-Browsern gegenüber HTTP-Anfragen](https://quantumproxies.io/blog/headless-browser-vs-http-requests-cost) ab, bevor Sie einen verwenden — die meisten Scrapy-Projekte benötigen bessere IPs, nicht einen Browser.

[Rotierende Proxys in Ihr Scrapy-Projekt integrieren](https://quantumproxies.io/rotating-proxies)
