---
title: "Was ist Playwright und wie nutzt man es mit Proxy?"
description: "In Playwright wird der Proxy beim Browserstart oder pro Context gesetzt. Authentifizierung, SOCKS5 und Rotation mit Beispielen in Python und Node.js."
url: https://proxynet.io/de/blog/playwright-proxy
date: 2026-09-19
author: "Acar Diveroli"
category: "Anleitungen, Web Scraping"
lang: de
---

# Was ist Playwright und wie nutzt man es mit Proxy?

Sie sammeln Daten aus einem Shop, der seine Preise per JavaScript nachlädt. Das HTML, das über Requests ankommt, ist leer, also wechseln Sie zu Playwright, und die Seite öffnet sich ohne Probleme. Wenn das Projekt wächst, muss der Traffic über einen Proxy laufen, und der erste Versuch endet mit `net::ERR_TUNNEL_CONNECTION_FAILED` oder „Browser does not support socks5 proxy authentication“. Die meisten Anleitungen behandeln Playwright als Werkzeug für Testautomatisierung, deshalb wird die Proxy-Seite oft aus Forenbeiträgen und Issue-Trackern zusammengesucht.

In diesem Beitrag definieren wir Playwright kurz, zeigen die Installation für Python und Node.js nebeneinander und gehen dann zum Proxy über: der Unterschied zwischen Proxy auf Browser-Ebene und auf Context-Ebene, Authentifizierung mit Benutzername und Passwort, das Verhalten von Chromium bei SOCKS5, die Wahl zwischen Rotating und Sticky, Traffic sparen durch das Blockieren von Bild- und Font-Anfragen, die Prüfung der IP und eine Fehlertabelle. Alle Beispiele in diesem Beitrag haben wir mit Playwright 1.63 und Chromium über einen lokalen Test-Proxy mit Authentifizierung ausgeführt.

> **Hinweis: Kurzantwort**
>
> Playwright ist eine Open-Source-Bibliothek für Browserautomatisierung, die Chromium, Firefox und WebKit aus dem Code heraus steuert. Der Proxy wird über das `proxy`-Objekt definiert, das dem Aufruf `launch()` oder dem Aufruf `new_context()` übergeben wird: `server`, `username` und `password` sind getrennte Felder. Im ersten Fall läuft der gesamte Browser über den Proxy, im zweiten nur dieser Context; so kann in einem einzigen Browser jeder Context über eine andere IP hinausgehen. Bei SOCKS5 werden Benutzername und Passwort nicht unterstützt, stattdessen wird eine IP-Whitelist verwendet.

## Was ist Playwright?

Playwright ist eine von Microsoft entwickelte Open-Source-Bibliothek für Browserautomatisierung. Sie öffnet einen echten Browser aus dem Code heraus, ruft eine Adresse auf, klickt, füllt Formulare aus und liest die Elemente der Seite. Die Engines Chromium, Firefox und WebKit werden über dieselbe API gesteuert; offizielle Versionen gibt es für Node.js, Python, Java und .NET.

Der Ausgangspunkt des Werkzeugs sind End-to-End-Tests, und die meisten Anleitungen stellen es von dieser Seite vor. Für Datenteams liegt der Wert woanders: Playwright führt eine per JavaScript erzeugte Seite in einem echten Browser aus, wartet von selbst, bis ein Element erscheint, und lässt Sie die API-Aufrufe mitlesen, die die Seite im Hintergrund macht, sowie unnötige Anfragen abbrechen. Ob eine Seite wirklich einen Browser braucht, klären Sie zuerst mit unserem Beitrag [Statische und dynamische Seiten beim Web Scraping](/de/blog/static-vs-dynamic-pages); liegen die Daten im Seitenquelltext oder hinter einem JSON-Endpunkt, ist ein Browser unnötiger Aufwand.

Die Aufgaben, die mit Playwright erledigt werden, lassen sich grob in vier Gruppen fassen:

- Daten aus dynamischen Seiten sammeln (Produktlisten, Preise, Lagerbestand, Anzahl der Bewertungen).
- Testen, wie Ihre eigene Website oder App aus verschiedenen Ländern aussieht.
- Screenshots und PDFs erzeugen.
- KI-Agenten einen Browser bedienen lassen. Die Einzelheiten zu diesem letzten Punkt stehen in unserem Beitrag über [Playwright MCP, Einrichtung und Proxy-Einstellungen](/de/blog/playwright-mcp).

Die architektonischen Unterschiede zu Selenium und die Frage, welches Werkzeug zu welchem Projekt passt, behandeln wir in einem eigenen Beitrag: [Playwright und Selenium im Vergleich](/de/blog/playwright-vs-selenium).

## Wie wird Playwright installiert?

Die Installation besteht aus zwei Schritten: zuerst die Bibliothek, dann die Browser-Binärdateien. Playwright verwendet nicht das auf dem System installierte Chrome, sondern Browser, die es selbst herunterlädt und auf eine Version festlegt. Der Fehler „Bibliothek installiert, aber Browser nicht gefunden“ entsteht, wenn der zweite Schritt ausgelassen wird.

Legen Sie auf der Python-Seite eine virtuelle Umgebung an und installieren Sie die Bibliothek. Die offizielle [Dokumentation der Python-Bibliothek](https://playwright.dev/python/docs/library) nennt dieselben Schritte auch für poetry und uv.

```bash
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install playwright
playwright install chromium
```

Auf der Node.js-Seite:

```bash
npm init -y
npm install playwright
npx playwright install chromium
```

Wenn Sie dem Befehl `install` keinen Browsernamen mitgeben, werden alle drei Engines heruntergeladen. Für Scraping-Aufgaben reicht in der Regel Chromium allein. Wenn Sie Tests schreiben wollen, werden für Python das Paket `pytest-playwright` und für Node.js `@playwright/test` empfohlen; für die Datenerfassung genügt die schlanke Bibliotheksinstallation oben.

In Python gibt es zwei APIs: `sync_api` und `async_api`. In Skripten, die Seiten nacheinander öffnen, ist die synchrone Variante besser lesbar. Wenn Sie mehrere Seiten gleichzeitig verarbeiten, nutzen Sie die auf `asyncio` basierende Variante; das vollständige Beispiel am Ende des Beitrags ist so geschrieben.

## Wie wird ein Proxy in Playwright definiert?

Der [Abschnitt HTTP Proxy in der Netzwerk-Dokumentation von Playwright](https://playwright.dev/python/docs/network#http-proxy) beschreibt zwei Ebenen: Der Proxy wird entweder für den gesamten Browser oder für jeden Context einzeln angegeben. In beiden Fällen wird dasselbe Objekt verwendet:

| Feld | Pflicht? | Bedeutung |
|---|---|---|
| `server` | Ja | `http://pr.proxynet.io:8000` oder `socks5://host:port`. Ohne Schema gilt die Angabe als HTTP Proxy |
| `username` | Nein | Benutzername für die Authentifizierung am HTTP Proxy |
| `password` | Nein | Passwort für die Authentifizierung am HTTP Proxy |
| `bypass` | Nein | Domains, die nicht über den Proxy laufen, durch Komma getrennt (`.beispiel.de, api.ihrefirma.de`) |

In Python sieht die Definition auf Browser-Ebene so aus:

```python
from playwright.sync_api import sync_playwright

PROXY = {
    "server": "http://pr.proxynet.io:8000",
    "username": "user",
    "password": "pass",
}

with sync_playwright() as p:
    browser = p.chromium.launch(proxy=PROXY)
    page = browser.new_page()
    page.goto("https://httpbin.org/ip")
    print(page.inner_text("body"))  # Ausgangs-IP des Proxys
    browser.close()
```

Das Gegenstück in Node.js:

```js
import { chromium } from "playwright";

const browser = await chromium.launch({
  proxy: {
    server: "http://pr.proxynet.io:8000",
    username: "user",
    password: "pass",
  },
});
const page = await browser.newPage();
await page.goto("https://httpbin.org/ip");
console.log(await page.innerText("body")); // Ausgangs-IP des Proxys
await browser.close();
```

Zu beachten ist, wo die Zugangsdaten stehen. Aus Gewohnheit von cURL oder Requests `http://user:pass@pr.proxynet.io:8000` zu schreiben, funktioniert hier nicht: Playwright übernimmt aus dem Wert `server` nur Schema, Host und Port und gibt Benutzername und Passwort aus der Adresse nicht an den Browser weiter. Zugangsdaten gehören immer in die Felder `username` und `password`. Das hat einen Nebeneffekt: Enthält das Passwort Zeichen wie `@` oder `:`, müssen Sie sich nicht mit URL-Kodierung befassen. Die allgemeine Logik der beiden Verfahren erklärt unser Beitrag [Proxy-Authentifizierung: User:Pass oder IP-Whitelist](/de/blog/proxy-authentication-methods).

## Worin unterscheiden sich Proxy auf Browser-Ebene und auf Context-Ebene?

Ein Context ist in Playwright eine von den anderen isolierte Browsersitzung: mit eigenen Cookies, eigenem Cache und eigenem lokalen Speicher. Er ähnelt einem Inkognito-Fenster, aber in einem einzigen Browserprozess können Dutzende davon gleichzeitig geöffnet sein, und das Öffnen kostet deutlich weniger als der Start eines neuen Browsers.

Wenn Sie den Proxy nicht an `launch()`, sondern an `new_context()` übergeben, gilt die Einstellung nur für diesen Context:

```python
from playwright.sync_api import sync_playwright

PROXIES = [
    {"server": "http://pr.proxynet.io:8000", "username": "user", "password": "pass"},
    {"server": "http://pr.proxynet.io:8001", "username": "user", "password": "pass"},
]

with sync_playwright() as p:
    browser = p.chromium.launch()  # der Browser wird einmal gestartet, ohne Proxy
    for proxy in PROXIES:
        context = browser.new_context(proxy=proxy)  # jeder Context mit eigenem Proxy
        page = context.new_page()
        page.goto("https://httpbin.org/ip")
        print(proxy["server"], page.inner_text("body"))
        context.close()  # Cookies und Cache werden zusammen mit dem Context gelöscht
    browser.close()
```

Als wir dieses Beispiel mit zwei getrennten lokalen Proxys ausführten, landete die Anfrage jedes Contexts im Log seines eigenen Proxys; ein dritter Context ohne Proxy verband sich direkt. In älteren Anleitungen heißt es, unter Windows müsse man für Chromium einen Platzhalter-Proxy wie `http://per-context` in den Aufruf `launch()` schreiben. Das war eine Einschränkung älterer Playwright-Versionen und wurde [im August 2024 aus dem Code entfernt](https://github.com/microsoft/playwright/pull/31724); auch die aktuelle Dokumentation enthält keinen solchen Hinweis mehr. Mit Playwright 1.63 unter Windows 11 lief das Beispiel ohne Platzhalter.

| | Browser-Ebene (`launch`) | Context-Ebene (`new_context`) |
|---|---|---|
| Geltungsbereich | Alle Contexts und Seiten | Nur dieser Context |
| Verschiedene IPs in einem Browser | Nein | Ja, eigener Proxy pro Context |
| Proxy wechseln | Browser schließen und neu starten | Context schließen und einen neuen öffnen |
| Cookies und Sitzung | Contexts bleiben trotzdem getrennt | Werden zusammen mit dem Proxy isoliert |
| Geeignet für | Skripte und Tests, denen ein Ausgangspunkt genügt | Viele unabhängige Sitzungen, Ländervergleiche |

Die praktische Regel lautet: eine Sitzung, ein Context, eine IP. Innerhalb desselben Contexts lässt sich der Proxy nicht wechseln, und das ist gut so; eine Sitzung, deren Cookies gleich bleiben, während sich die IP ändert, ist aus Sicht der Zielseite ein widersprüchlicher Besucher.

## Funktioniert Playwright mit einem SOCKS5 Proxy?

Ja, aber ohne Benutzername und Passwort. Wenn Sie in `server` eine Adresse mit dem Schema `socks5://` angeben und `username` hinzufügen, meldet Playwright diesen Fehler, ohne den Browser überhaupt zu starten:

```text
BrowserType.launch: Browser does not support socks5 proxy authentication
```

Dieselbe Prüfung gilt für `new_context()`. Der Grund ist Chromium selbst: [Die Proxy-Dokumentation von Chromium](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md#SOCKSv5-proxy-scheme) hält ausdrücklich fest, dass für SOCKSv5 kein Authentifizierungsverfahren unterstützt wird. Wir haben das am Tag des Schreibens mit einem lokalen SOCKS5-Server ausprobiert. Das einzige Verfahren, das Chromium in seiner Handshake-Nachricht anbot, war `0x00`, also „keine Authentifizierung“; das Verfahren mit Benutzername und Passwort (`0x02`) aus [RFC 1929](https://www.rfc-editor.org/rfc/rfc1929) stand nicht auf der Liste. Auch die Zugangsdaten in die Adresse einzubetten (`socks5://user:pass@...`) änderte nichts: Playwright verwarf diesen Teil, und weil der Server eine Authentifizierung verlangte, wurde die Verbindung mit `net::ERR_SOCKS_CONNECTION_FAILED` geschlossen. Bei einem SOCKS5-Server ohne Authentifizierung öffnete sich die Seite ohne Probleme.

Die Lösung besteht darin, sich nicht mit einem Passwort, sondern mit der eigenen IP-Adresse auszuweisen. Sie tragen die Ausgangs-IP des Servers, auf dem das Skript läuft, im Proxy-Dashboard in die IP-Whitelist ein und geben nur das Feld `server` an:

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    # Kein Benutzername, kein Passwort: Ihre Ausgangs-IP muss im Dashboard auf der IP-Whitelist stehen
    browser = p.chromium.launch(proxy={"server": "socks5://pr.proxynet.io:1080"})
    page = browser.new_page()
    page.goto("https://httpbin.org/ip")
    print(page.inner_text("body"))
    browser.close()
```

In unseren Testprotokollen schickte Chromium dem SOCKS5-Server keinen IP-Wert, sondern den Domainnamen; die DNS-Auflösung findet also auf der Proxy-Seite statt, und die von cURL bekannte Unterscheidung `socks5h://` ist hier nicht nötig. Zum Öffnen von Seiten reicht meistens ein HTTP Proxy, weil HTTPS-Traffic ohnehin durch einen `CONNECT`-Tunnel läuft. Wann SOCKS5 die bessere Wahl ist, erklären wir in [SOCKS und HTTP Proxy im Vergleich: was wählen?](/de/blog/socks-vs-http-proxy); die Produktseite dazu ist [SOCKS5-Proxy](https://proxynet.io/de/socks5-proxy).

## Rotating oder Sticky: was für welche Aufgabe?

Ein Browser verhält sich anders als ein Skript, das eine einzelne HTTP-Anfrage sendet. Beim Laden einer Seite werden für das Hauptdokument, Skripte, Stylesheets, Bilder und API-Aufrufe getrennte Verbindungen zu verschiedenen Domains geöffnet. An einem Gateway, das bei jeder Verbindung die Ausgangs-IP wechselt, können diese Verbindungen über verschiedene IPs hinausgehen. Beim Crawlen voneinander unabhängiger Seiten ist das kein Problem. In Abläufen mit Login, Warenkorb oder mehrstufigem Formular kann ein IP-Wechsel mitten in der Sitzung jedoch dazu führen, dass die Website die Sitzung beendet.

- **Unabhängige Seiten** (Produktliste, Kategorie, Suchergebnis): [Rotierender Proxy](https://proxynet.io/de/rotating-proxy) passt hier. Die Rotation übernimmt das Gateway, Sie führen im Code keine Proxy-Liste. Wie Rotation funktioniert, steht in unserem Beitrag über [IP-Rotation](/de/blog/ip-rotation-explained).
- **Abläufe, die eine Sitzung brauchen** (Login mit dem eigenen Konto, mehrstufige Vorgänge): Mit [Sticky-Proxy](https://proxynet.io/de/sticky-proxy) bleibt dieselbe IP für die Lebensdauer des Contexts erhalten. Die Angaben zur Sticky Sitzung entnehmen Sie dem Dashboard und tragen sie im Feld `proxy` des Contexts ein.
- **Inhalte, die je nach Land abweichen**: Sie öffnen für jedes Land einen eigenen Context und geben ihm den Ausgangspunkt dieses Landes; ein Browser, direkter Vergleich nebeneinander.

Ein Proxy pro Context ist für sich genommen schon ein Rotationsschema: Wenn Sie den Context schließen und einen neuen öffnen, werden Cookies und IP gemeinsam erneuert.

## Wie lässt sich Traffic durch das Blockieren von Bildern und Fonts senken?

[Residential-Proxy](https://proxynet.io/de/residential-proxy) wird pro GB abgerechnet, und ein Browser lädt alles herunter, was ein schlichter HTTP-Client nicht lädt: Produktbilder, Webfonts, Videos. Wenn Sie Preis und Titel brauchen, hat es keinen Sinn, für diese Bytes zu zahlen. Der `route`-Mechanismus von Playwright fängt eine Anfrage ab, bevor sie ins Netz geht; Sie können sie nach Ressourcentyp abbrechen.

```python
from playwright.sync_api import sync_playwright

BLOCKED = {"image", "media", "font"}

def filter_resources(route):
    if route.request.resource_type in BLOCKED:
        route.abort()
    else:
        route.continue_()

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": "http://pr.proxynet.io:8000",
        "username": "user",
        "password": "pass",
    })
    page = browser.new_page()
    page.route("**/*", filter_resources)
    page.goto("https://books.toscrape.com/")
    print(page.locator("article.product_pod h3 a").first.get_attribute("title"))
    browser.close()
```

Wie groß die Ersparnis ist, hängt von der Seite ab; eine allgemeine Prozentzahl wäre irreführend. Um sie für Ihr eigenes Ziel zu messen, öffnen Sie dieselbe Seite mit und ohne Filter und vergleichen den Traffic-Zähler im Proxy-Dashboard. Zwei Warnungen: Das Blockieren von Stylesheets (`stylesheet`) und Skripten (`script`) kann verhindern, dass die Seite ihren Inhalt aufbaut; beschränken Sie die Liste deshalb auf Bilder, Medien und Fonts. Diese Technik dient dem Sparen von Traffic, sie wird nicht eingesetzt, um die Schutzskripte einer Website herauszufiltern.

Die größere Ersparnis steckt oft in dem Traffic, den der Browser mitliest. Dynamische Seiten holen ihre Daten meist von einem JSON-Endpunkt, und Playwright lässt Sie diese Antwort direkt lesen:

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": "http://pr.proxynet.io:8000",
        "username": "user",
        "password": "pass",
    })
    page = browser.new_page()
    with page.expect_response("**/api/quotes?page=1") as info:
        page.goto("https://quotes.toscrape.com/scroll")
    data = info.value.json()
    for quote in data["quotes"][:3]:
        print(quote["author"]["name"], "-", quote["text"][:60])
    browser.close()
```

Statt HTML mit Selektoren zu zerlegen, erhalten Sie strukturierte Daten. Verlangt der Endpunkt keine Anmeldung, können Sie im nächsten Schritt ganz auf den Browser verzichten und diese Adresse mit einem schlichten HTTP-Client aufrufen.

## Wie prüft man, ob der Proxy funktioniert?

Drei Prüfungen genügen:

1. Öffnen Sie `https://httpbin.org/ip` mit Playwright und vergleichen Sie die zurückgegebene IP mit Ihrer eigenen. Weicht sie ab, läuft der Traffic über den Proxy.
2. Öffnen Sie dieselbe Adresse mit einem Context ohne Proxy. Sind beide Ergebnisse gleich, wurde das `proxy`-Objekt dem falschen Aufruf übergeben oder die Domain steht auf der `bypass`-Liste.
3. Wenn Sie ein Land ansteuern, prüfen Sie den Standort der IP in einem Geolokalisierungsdienst. Warum Datenbanken voneinander abweichen, erklären wir in [IP-Standort falsch? Was eine IP-Adresse wirklich verrät](/de/blog/ip-geolocation-accuracy).

Den Proxy unabhängig von Playwright zu testen, zeigt, ob das Problem im Code oder im Netz liegt. Die Tests für die Kommandozeile stehen in [Funktioniert mein Proxy? So testen Sie einen Proxy](/de/blog/how-to-test-a-proxy).

## Vollständiges Beispiel: parallele Contexts, Wiederholungen und Ressourcen-Blocking

Das folgende Skript crawlt sechs per JavaScript erzeugte Seiten. Es hält höchstens drei Contexts gleichzeitig offen, verwendet bei jedem Versuch einen frischen Context und eine frische Proxy-Verbindung, blockiert Bilder und Fonts und wiederholt vorübergehende Fehler mit exponentieller Wartezeit plus Zufallsanteil. Bei Fehlern, die zeigen, dass der Proxy gar nicht erreichbar ist, wiederholt es nicht, denn diese Lage behebt nicht das Warten, sondern die Konfiguration.

```python
import asyncio
import random

from playwright.async_api import Error, async_playwright

PROXY = {
    "server": "http://pr.proxynet.io:8000",
    "username": "user",
    "password": "pass",
}
URLS = [f"https://quotes.toscrape.com/js/page/{n}/" for n in range(1, 7)]
BLOCKED = {"image", "media", "font"}
CONCURRENCY = 3  # Anzahl gleichzeitig offener Contexts
ATTEMPTS = 3
# Fehler, an denen eine Wiederholung nichts ändert: zuerst die Konfiguration korrigieren
FATAL = ("ERR_PROXY_CONNECTION_FAILED", "ERR_TUNNEL_CONNECTION_FAILED", "ERR_SOCKS_CONNECTION_FAILED")

async def filter_resources(route):
    if route.request.resource_type in BLOCKED:
        await route.abort()
    else:
        await route.continue_()

async def scrape(browser, url, limit):
    async with limit:
        for attempt in range(ATTEMPTS):
            context = await browser.new_context(proxy=PROXY)  # frische Sitzung bei jedem Versuch
            try:
                page = await context.new_page()
                await page.route("**/*", filter_resources)
                response = await page.goto(url, timeout=30_000)
                if response is None or response.status >= 400:
                    raise Error(f"HTTP {response.status if response else 'keine Antwort'}")
                quotes = page.locator("div.quote span.text")
                await quotes.first.wait_for(timeout=10_000)  # warten, bis JavaScript den Inhalt erzeugt hat
                return url, await quotes.all_inner_texts()
            except Error as exc:  # TimeoutError leitet sich ebenfalls von Error ab
                if any(code in str(exc) for code in FATAL):
                    raise
                if attempt == ATTEMPTS - 1:
                    raise
                await asyncio.sleep(2**attempt + random.random())
            finally:
                await context.close()

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        limit = asyncio.Semaphore(CONCURRENCY)
        results = await asyncio.gather(
            *(scrape(browser, url, limit) for url in URLS), return_exceptions=True
        )
        await browser.close()
    for url, result in zip(URLS, results):
        if isinstance(result, Exception):
            print(url, "FEHLER:", str(result).splitlines()[0])
        else:
            print(url, len(result[1]), "Zitate")

asyncio.run(main())
```

Auf unserem lokalen Test-Proxy kamen alle sechs Seiten mit je zehn Zitaten zurück; als wir den Proxy-Port absichtlich falsch schrieben, stoppte das Skript ohne Wiederholung mit `ERR_PROXY_CONNECTION_FAILED`. Für den echten Einsatz ergänzen Sie zwei Dinge. Die Wiederholungslogik, die bei `429` und `503` den Header `Retry-After` beachtet, übernehmen Sie aus dem Beispiel in [HTTP-Statuscodes beim Web Scraping: 403, 407, 429, 503](/de/blog/http-status-codes-web-scraping); wir wiederholen sie hier nicht. Richten Sie außerdem die Parallelität am Arbeitsspeicher aus: Jeder Context und jede Seite belegt Speicher, starten Sie `CONCURRENCY` deshalb niedrig und erhöhen Sie den Wert, während Sie Ihren Server beobachten. Die Einzelheiten zu Wartestrategien (warum man auf ein Element statt auf `networkidle` wartet) stehen im oben genannten Beitrag über statische und dynamische Seiten.

## Fehlertabelle: ERR_PROXY_CONNECTION_FAILED, ERR_TUNNEL_CONNECTION_FAILED, 407

Jede der folgenden Zeilen haben wir auf dem lokalen Test-Proxy absichtlich herbeigeführt.

| Was Sie sehen | Was es bedeutet | Was zu tun ist |
|---|---|---|
| `net::ERR_PROXY_CONNECTION_FAILED` | Zum Proxy-Server kam keine TCP-Verbindung zustande: Adresse oder Port falsch, oder eine Firewall sperrt ausgehenden Traffic | Wert von `server` und Port prüfen, dieselbe Adresse mit cURL testen |
| `net::ERR_TUNNEL_CONNECTION_FAILED` | Der Proxy wurde erreicht, aber auf die `CONNECT`-Anfrage kam eine andere Antwort als `200`: Authentifizierung abgelehnt (`407`) oder der Proxy erreichte das Ziel nicht (`502`) | Zuerst die Zugangsdaten, dann die Zieladresse prüfen |
| Zeitüberschreitung bei `goto` auf einer HTTPS-Adresse, `407` im Proxy-Log | Benutzername oder Passwort falsch oder gar nicht angegeben. In unserem Versuch meldete das Ereignis `requestfailed` den Fehler `ERR_TUNNEL_CONNECTION_FAILED`, aber `goto` wartete bis zur Zeitüberschreitung, statt einen Fehler auszulösen | Den echten Fehler mit `page.on("requestfailed")` sichtbar machen, die Felder `username` und `password` korrigieren |
| Antwortcode `407` auf einer HTTP-Adresse (unverschlüsselt) | Gleiche Ursache; ohne Tunnel kommt die Antwort des Proxys als Seitenantwort an | `response.status` prüfen, Zugangsdaten korrigieren |
| `Browser does not support socks5 proxy authentication` | Zusammen mit einer `socks5://`-Adresse wurde `username` angegeben | Zugangsdaten entfernen und IP-Whitelist nutzen oder auf HTTP Proxy wechseln |
| `net::ERR_SOCKS_CONNECTION_FAILED` | Der SOCKS5-Server verlangt eine Authentifizierung oder Ihre IP steht nicht auf der Whitelist | Ihre Ausgangs-IP im Dashboard in die Liste eintragen |
| Die Seite öffnet sich, aber die IP ist Ihre eigene | Das `proxy`-Objekt wurde gar nicht angewendet oder die Domain steht auf der `bypass`-Liste | Prüfen, ob das Objekt an `launch` oder `new_context` übergeben wurde |

Die dritte Zeile kostet am meisten Zeit: Das Skript meldet keinen Fehler, es wartet nur dreißig Sekunden und läuft in die Zeitüberschreitung, und das Problem wird der langsamen Zielseite zugeschrieben. Während der Entwicklung verkürzen diese zwei Zeilen die Diagnose:

```python
page.on("requestfailed", lambda r: print("FEHLGESCHLAGEN:", r.url, r.failure))
page.on("response", lambda r: print(r.status, r.url) if r.status >= 400 else None)
```

Die allgemeine Bedeutung des Codes `407` und sein Erscheinungsbild in anderen Bibliotheken finden Sie in unserem Beitrag über HTTP-Statuscodes; für Fehler der Art „Proxyserver antwortet nicht“ außerhalb der Browserautomatisierung lesen Sie unseren Beitrag über [Proxy-Fehler und die Meldung „Proxyserver antwortet nicht“](/de/blog/proxy-server-not-responding).

## Einsatzbereiche

- **Dynamische Shop- und Katalogseiten:** per JavaScript geladene Preis- und Bestandsdaten. Den allgemeinen Aufbau zeigt unsere Seite zur [Data-Scraping-Lösung](/de/data-scraping).
- **Regelmäßiges Crawlen vieler Seiten:** Seitenerkennung und Warteschlangenverwaltung stehen auf der Seite zur [Web-Crawler-Lösung](/de/web-crawler); Muster für die Seitennummerierung in unserem Beitrag über [Pagination beim Web Scraping](/de/blog/pagination-web-scraping).
- **Ihre App aus verschiedenen Ländern testen:** ein Context pro Land, jeweils mit dem Ausgangspunkt dieses Landes. Einzelheiten auf der Seite [App-Tests](/de/app-testing).
- **Preisbeobachtung bei Wettbewerbern:** ein täglicher Crawl mit Ressourcen-Blocking, der Ratenlimits einhält. Die geschäftliche Seite behandelt unser Beitrag über [Preisbeobachtung der Konkurrenz im E-Commerce](/de/blog/competitor-price-tracking).

Bei jeder Aufgabe gilt derselbe Rahmen: Halten Sie die Regeln der `robots.txt` und die Nutzungsbedingungen der Website ein, ziehen Sie eine offizielle API vor, wenn es eine gibt, und halten Sie Ihre Anfragerate auf einem Niveau, das die Website verkraftet. Wie man eine `robots.txt` liest, steht in [Was ist robots.txt und wie liest man die Datei?](/de/blog/robots-txt).

## Häufige Fehler

- **Zugangsdaten in die `server`-Adresse einbetten.** Playwright ignoriert diesen Teil; das Ergebnis ist `407` oder eine Zeitüberschreitung.
- **Benutzername und Passwort mit SOCKS5 versuchen.** Chromium unterstützt das nicht; nutzen Sie eine IP-Whitelist oder einen HTTP Proxy.
- **Für jede Seite einen neuen Browser starten.** Der Browser wird einmal gestartet, Isolation und Proxy-Wechsel laufen über Contexts.
- **Einen Ablauf mit Sitzung über ein rotierendes Gateway schicken.** Die Verbindungen gehen über verschiedene IPs hinaus, die Sitzung bricht ab. Nutzen Sie Sticky.
- **Contexts nicht schließen.** Jeder offene Context hält Speicher; schließen Sie ihn im `finally`-Block.
- **Skripte und Stylesheets blockieren.** Die Seite kann ihren Inhalt nicht aufbauen, Ihr Selektor liefert nichts.
- **Eine Zeitüberschreitung bei `goto` der Zielseite zuschreiben.** Sehen Sie zuerst auf das Ereignis `requestfailed` und auf die Proxy-Zugangsdaten.
- **Eine `200`-Antwort akzeptieren, ohne den Inhalt anzusehen.** Prüfen Sie, ob das erwartete Element auf der Seite steht; auch Verifizierungsseiten können `200` liefern.

## Entscheidungshilfe

| Bedarf | Empfehlung |
|---|---|
| Skript oder Test, dem ein Ausgangspunkt genügt | `launch(proxy=...)`, HTTP Proxy |
| Mehrere unabhängige Sitzungen in einem Browser | `new_context(proxy=...)`, eigener Proxy pro Context |
| Massenhaftes Crawlen unabhängiger Seiten | Rotating Proxy, eine einzige Gateway-Adresse |
| Mehrstufiger Ablauf mit Login | Sticky Proxy, ein Context eine IP |
| SOCKS5 ist Pflicht | IP-Whitelist, ohne `username` und `password` |
| Nach GB abgerechneter Traffic | Bild-, Medien- und Font-Anfragen mit `route` blockieren; wenn möglich die JSON-Antwort lesen |
| Daten im Seitenquelltext oder hinter einem JSON-Endpunkt | Schlichter HTTP-Client statt Playwright |
| Einen KI-Agenten den Browser bedienen lassen | Playwright MCP |

## Häufige Fragen

### Ist Playwright kostenlos?

Ja. Es ist ein Open-Source-Projekt unter der Lizenz Apache 2.0; für die Bibliothek und die heruntergeladenen Browser-Binärdateien fallen keine Kosten an. Kosten entstehen durch die Serverressourcen, die die Browser verbrauchen, und durch den genutzten Proxy-Traffic.

### Sollte man Playwright mit Python oder mit Node.js nutzen?

Proxy-Einstellung und Browserverhalten sind in beiden Sprachen gleich, weil beide mit demselben Treiber sprechen. Entscheiden sollte die Sprache Ihres Teams und Ihrer Datenverarbeitung. Einen Vergleich der beiden Sprachen aus Scraping-Sicht finden Sie in [Web Scraping: JavaScript oder Python?](/de/blog/web-scraping-javascript-vs-python).

### Kann ich für jede Seite einen eigenen Proxy verwenden?

Der Proxy hängt am Context, nicht an der Seite. Wenn Sie für jede Seite eine eigene IP wollen, öffnen Sie jede Seite in ihrem eigenen Context. Mit einem rotierenden Gateway ist auch das nicht nötig; die Rotation übernimmt das Gateway.

### Funktioniert die SOCKS5-Authentifizierung mit Firefox oder WebKit?

Wird zusammen mit einer `socks5://`-Adresse ein Benutzername angegeben, meldet Playwright den Fehler in seinem eigenen Validierungsschritt, noch bevor der Browser startet, und diese Prüfung unterscheidet nicht nach Browsertyp. Wir haben es nur mit Chromium ausprobiert; gehen Sie auch bei den anderen Engines von der IP-Whitelist aus.

### Verhält sich der Proxy im Headless-Modus anders?

Nein. Das `proxy`-Objekt wird mit und ohne Fenster auf dieselbe Weise angewendet. Wenn Sie das Problem mit eigenen Augen sehen wollen, öffnen Sie das Fenster mit `launch(headless=False)` und führen dasselbe Skript aus.

### Lässt ein Proxy Verifizierungsseiten verschwinden?

Nein. Ein Proxy ändert nur, über welche IP die Anfrage hinausgeht; Anfragerate, Browsersignale und die Konsistenz der Sitzung bleiben gleich. Warum diese Seiten erscheinen, erklären wir in [Puppeteer und CAPTCHA: warum, und wie seltener?](/de/blog/puppeteer-captcha); das dort Gesagte gilt auch für Playwright. Erweiterungen zum Umgehen der Erkennung empfehlen wir nicht: Der dauerhafte Weg sind eine vernünftige Rate, eine konsistente Sitzung und, wo vorhanden, eine offizielle API.

## Fazit

In Playwright ist der Proxy ein einzelnes Objekt: `server`, `username`, `password`. Übergeben Sie es an `launch()`, geht der gesamte Browser über den Proxy hinaus; übergeben Sie es an `new_context()`, nur diese Sitzung. Der zweite Weg bedeutet eine eigene IP pro Context in einem einzigen Browser. Zugangsdaten werden nicht in die Adresse geschrieben, bei SOCKS5 tritt die IP-Whitelist an die Stelle des Passworts, Abläufe mit Sitzung bekommen Sticky, unabhängige Seiten Rotating. Wenn Sie Traffic pro GB bezahlen, blockieren Sie Bilder und Fonts; wenn Sie Zeitüberschreitungen sehen, prüfen Sie zuerst das Ereignis `requestfailed`. Die zu Ihrer Aufgabe passenden Proxy-Typen finden Sie bei [unseren Proxy-Diensten](/de/proxy).
