---
title: "Playwright oder Selenium: Welches Werkzeug passt?"
description: "Playwright wartet von selbst auf Elemente und nimmt den Proxy pro Context; Selenium deckt mehr Sprachen und echtes Safari ab. Dieselbe Aufgabe in beiden."
url: https://proxynet.io/de/blog/playwright-vs-selenium
date: 2026-09-19
author: "Acar Diveroli"
category: "Vergleich, Web Scraping"
lang: de
---

# Playwright oder Selenium: Welches Werkzeug passt?

Sie beginnen ein neues Projekt zur Datenerhebung oder zum Testen, und die Seite wird mit JavaScript aufgebaut, also brauchen Sie einen echten Browser. Im Team schreibt jemand seit Jahren Selenium, die neue Entwicklerin schlägt Playwright vor. Beide öffnen den Browser aus dem Code heraus und klicken darin, beide sind kostenlos; genau diese Ähnlichkeit macht die Wahl schwer. Die meisten Vergleiche betrachten das Thema mit dem Blick des Testens und lassen die Punkte aus, die bei der Datenerhebung den Ausschlag geben, etwa Proxys und das Warten.

In diesem Beitrag vergleichen wir die beiden Werkzeuge auf sieben Achsen: Architektur, automatisches Warten, Proxy-Verwaltung, Sprachunterstützung, Browser-Einrichtung, Parallelität und Fehlersuche. Den Code, der dieselbe kleine Aufgabe in beiden Werkzeugen erledigt, haben wir mit Playwright 1.63, Selenium 4.49 und Chrome 153 unter Windows 11 ausgeführt; was wir dabei gesehen haben, steht in den jeweiligen Abschnitten. „Welches fällt weniger auf" ist nicht das Thema dieses Beitrags: Beide Werkzeuge öffnen einen echten Browser, und in beiden ist es Ihre Aufgabe, die Regeln der Website einzuhalten.

> **Hinweis: Kurzantwort**
>
> Playwright spricht über eine dauerhafte Verbindung mit dem Browser, wartet von selbst, bis ein Element bereit ist, und nimmt den Proxy mit Benutzername und Passwort für jeden Context einzeln; in neuen Projekten kommen Sie damit mit weniger Code ans Ziel. Selenium folgt dem W3C-WebDriver-Standard, unterstützt mehr Sprachen einschließlich Ruby sowie echtes Safari und verteilt sich mit Grid über Maschinen; wenn Sie eine laufende Selenium-Suite oder ein Team mit Java- und C#-Schwerpunkt haben, gibt es meist keinen Grund, sie zu verlassen. Die Proxy-Authentifizierung ist in Selenium nicht Teil des Standards, der praktische Weg ist die IP-Whitelist.

## Was sind Playwright und Selenium?

Selenium ist ein quelloffenes Projekt zur Browser-Automatisierung, das seit 2004 entwickelt wird. Der heute genutzte Teil ist Selenium WebDriver: Ihr Code schickt Befehle an einen Browsertreiber, und der Treiber steuert den Browser. Die Einrichtung behandelt unser Beitrag [Selenium mit Proxy](/de/blog/selenium); Treiberdownload und Authentifizierung stehen dort ausführlich.

Playwright ist eine quelloffene Bibliothek zur Browser-Automatisierung, die Microsoft 2020 veröffentlicht hat. Sie steuert die Engines Chromium, Firefox und WebKit über eine einzige API. Installation und Proxy-Einstellungen stehen in [Was ist Playwright und wie nutzt man es mit Proxy?](/de/blog/playwright-proxy); hier behandeln wir nur die Punkte, an denen es sich von Selenium unterscheidet.

Beide beantworten denselben Bedarf: Inhalte, die mit einer einfachen HTTP-Anfrage nicht kommen und erst entstehen, wenn im Browser JavaScript läuft. Ob die Seite wirklich einen Browser braucht, klären Sie mit der Prüfung aus [Statische und dynamische Seiten beim Web Scraping](/de/blog/static-vs-dynamic-pages). Steht die Information im Quelltext der Seite, ist ein einfacher HTTP-Client oder [Scrapy](/de/blog/scrapy-proxy) günstiger als beide Werkzeuge.

## Worin liegt der Architekturunterschied: WebDriver, BiDi und CDP

Fast jeder Verhaltensunterschied der beiden Werkzeuge entsteht daraus, wie sie mit dem Browser sprechen.

In Selenium nimmt ein Befehl diesen Weg:

1. Ihr Code ruft `driver.find_element(...)` auf.
2. Die Selenium-Bibliothek macht daraus eine HTTP-Anfrage aus dem W3C-WebDriver-Standard.
3. Die Anfrage geht an das Treiberprogramm des Browserherstellers: ChromeDriver für Chrome, GeckoDriver für Firefox.
4. Der Treiber wendet den Befehl auf den Browser an und schickt das Ergebnis als HTTP-Antwort zurück.

Jeder Befehl ist eine eigene Anfrage samt Antwort; der Browser kann Ihnen von sich aus nichts mitteilen. Ein Fehler in der Konsole oder eine Netzwerkanfrage im Hintergrund bleibt unsichtbar, solange Sie nicht danach fragen. Um diese Lücke zu schließen, schreibt das Selenium-Projekt gemeinsam mit den Browserherstellern den Standard [WebDriver BiDi](https://www.w3.org/TR/webdriver-bidi/): ein bidirektionales Protokoll über WebSocket. In Selenium 4 schalten Sie es mit `options.enable_bidi = True` ein; weil der Übergang noch läuft, leben in Selenium heute zwei Welten nebeneinander.

Bei Playwright verläuft der Weg anders:

1. Ihr Code ruft `page.locator(...).click()` auf.
2. Die Bibliothek für Python, Java oder .NET reicht diesen Aufruf an den im Paket enthaltenen Playwright-Treiber weiter. Der Treiber ist ein Node.js-Prozess; in der virtuellen Umgebung liegt er als `playwright/driver/node.exe`.
3. Der Treiber spricht über eine dauerhafte Verbindung mit dem Browser. In Chromium ist das das Chrome DevTools Protocol (CDP). Für Firefox und WebKit nutzt Playwright eigene, gepatchte Browser-Builds.
4. Weil die Verbindung bidirektional ist, fließen Ereignisse im Browser (Anfrage, Antwort, Konsolenmeldung, Download) in Ihren Code, ohne dass Sie danach fragen.

Diese Entscheidung hat ihren Preis. Das [Browser-Dokument von Playwright](https://playwright.dev/python/docs/browsers) sagt es deutlich: Weil es auf Patches beruht, funktioniert es nicht mit dem markengebundenen Firefox und Safari. Chrome und Edge können Sie über die Option `channel` nutzen, doch den Bedarf „Test im echten Safari" deckt ein WebKit-Build nicht ab; Selenium steuert das installierte Safari über Apples eigenen Treiber.

## Vergleichstabelle

| | Playwright | Selenium |
|---|---|---|
| Protokoll | Dauerhafte Verbindung; in Chromium CDP, in Firefox und WebKit gepatchte Builds | W3C WebDriver (HTTP), daneben das entstehende WebDriver BiDi (WebSocket) |
| Zwischenschicht | Im Paket enthaltener Playwright-Treiber | Treiber des Browserherstellers (ChromeDriver, GeckoDriver) |
| Browser | Chromium, Firefox, WebKit; mit `channel` Chrome und Edge | Chrome, Edge, Firefox, Safari |
| Offizielle Sprachen | JavaScript und TypeScript, Python, Java, .NET | Java, Python, C#, Ruby, JavaScript |
| Warten | Vor Aktionen von selbst | Sie schreiben es: `WebDriverWait` |
| Proxy-Reichweite | Pro Browser oder pro Context | Pro Browser-Sitzung |
| Proxy-Benutzername und -Passwort | Eigene Felder im `proxy`-Objekt | Kein Feld im Standard; praktischer Weg ist die IP-Whitelist |
| Anfragen mithören und blockieren | Eingebaut (`route`, `expect_response`) | Kommt mit BiDi; im klassischen WebDriver nicht vorhanden |
| Browser-Einrichtung | `playwright install`, an die Version gebundene Builds | Selenium Manager lädt den Treiber selbst und nutzt den installierten Browser |
| Parallelität | Viele Contexts in einem Browser | Ein Browser pro Aufgabe; über Maschinen hinweg Selenium Grid |
| Fehlersuche | Trace Viewer, Inspector, codegen | Bildschirmfoto, Browser-Log, Selenium IDE |

## Wie schreibt man dieselbe Aufgabe in beiden Werkzeugen?

Unsere Testseite ist `quotes.toscrape.com/js-delayed/`: eine Übungsseite, die ihre Zitate mit JavaScript und zehn Sekunden Verzögerung ausgibt. Die Aufgabe: Seite über einen Proxy öffnen, Zitate lesen, auf den Link „Next" klicken, die zweite Seite prüfen.

Mit Playwright:

```python
from playwright.sync_api import sync_playwright

URL = "https://quotes.toscrape.com/js-delayed/"
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(URL)
    quotes = page.locator("div.quote")
    print("immediately:", quotes.count())  # 0: count() wartet nicht
    quotes.first.wait_for()  # wartet, bis das erste Zitat auf der Seite steht
    for quote in quotes.all():
        text = quote.locator("span.text").inner_text()
        author = quote.locator("small.author").inner_text()
        print(author, "-", text[:50])
    page.get_by_role("link", name="Next").click()  # wartet vor dem Klick von selbst
    page.wait_for_url("**/page/2/")
    print(page.url)
    browser.close()
```

Mit Selenium:

```python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

URL = "https://quotes.toscrape.com/js-delayed/"

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
# Kein Benutzername, kein Passwort: Ihre Ausgangs-IP muss im Panel auf der IP-Whitelist stehen
options.add_argument("--proxy-server=http://pr.proxynet.io:8000")

driver = webdriver.Chrome(options=options)  # den Treiber findet Selenium Manager
try:
    driver.get(URL)
    print("immediately:", len(driver.find_elements(By.CSS_SELECTOR, "div.quote")))  # 0
    wait = WebDriverWait(driver, 15)
    quotes = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.quote")))
    for quote in quotes:
        text = quote.find_element(By.CSS_SELECTOR, "span.text").text
        author = quote.find_element(By.CSS_SELECTOR, "small.author").text
        print(author, "-", text[:50])
    wait.until(EC.element_to_be_clickable((By.PARTIAL_LINK_TEXT, "Next"))).click()
    wait.until(EC.url_contains("/page/2/"))
    print(driver.current_url)
finally:
    driver.quit()
```

Beide Skripte gaben über unsere lokalen Test-Proxys dieselben zehn Zitate aus und wechselten zu `/js-delayed/page/2/`. Die Zeilenzahl liegt nahe beieinander; der Unterschied steckt im Detail. Bei Playwright stehen die Proxy-Zugangsdaten im Code, bei Selenium nicht; der Klick ist bei Playwright eine Zeile, bei Selenium schreiben Sie die Bedingung für die Klickbarkeit von Hand. In beiden Skripten gab die Zeile „immediately" eine `0` zurück: Die Seite gilt als geladen, der Inhalt ist aber noch nicht da. Das ist das Thema des nächsten Abschnitts.

## Worin unterscheiden sich automatisches Warten und WebDriverWait?

Auf dynamischen Seiten entstehen die meisten Fehler aus dem Timing: Der Code sucht ein Element, das JavaScript noch nicht ausgegeben hat. Das [Warte-Dokument von Selenium](https://www.selenium.dev/documentation/webdriver/waits/) nennt das eine Race Condition; mal ist der Browser zuerst bereit und der Code läuft, mal ist der Code schneller und Sie bekommen einen Fehler.

In Selenium liegt die Lösung in Ihrer Hand. `driver.get()` wartet auf das `load`-Ereignis der Seite, weiß aber nichts von Inhalten, die JavaScript später einfügt. Der Standardwert des impliziten Wartens ist null; fehlt das Element, kommt der Fehler sofort zurück. Empfohlen wird das explizite Warten: `WebDriverWait` fragt die Seite ab, bis eine Bedingung zutrifft. Das Dokument gibt noch eine Warnung: Verwenden Sie beides nicht zusammen, sonst werden die Zeiten unvorhersehbar.

Playwright legt dieselbe Arbeit in die Aktion hinein. Laut [Actionability-Dokument](https://playwright.dev/python/docs/actionability) wartet ein `click()`-Aufruf, bis das Element sichtbar ist, seine Position stabil ist, es den Klick annehmen kann und aktiv ist; werden die Bedingungen nicht rechtzeitig erfüllt, wirft er einen `TimeoutError`. Auch Aufrufe, die mit einem einzelnen Element arbeiten, etwa `fill()` und `inner_text()`, warten auf das Erscheinen des Elements.

Das hat eine Grenze: Das automatische Warten gilt für Aktionen, nicht für Zählungen. Im Beispiel oben gab `quotes.count()` ohne Warten eine `0` zurück. Das API-Dokument von Playwright hält dieselbe Anmerkung für `locator.all()` fest: Es wartet nicht auf passende Elemente, sondern liefert, was in dem Moment auf der Seite steht. Wollen Sie eine Liste lesen, warten Sie zuerst mit `first.wait_for()` auf das erste Element. Der Satz „in Playwright schreibt man kein Warten" stimmt deshalb nur halb.

Der zweite Unterschied liegt beim Elementverweis. In Selenium liefert `find_element` einen Verweis auf den DOM-Knoten in seinem damaligen Zustand; zeichnet die Seite diesen Bereich neu, veraltet der Verweis und Sie bekommen eine `StaleElementReferenceException`. In Playwright ist ein `locator` eine Beschreibung, die bei jeder Nutzung neu aufgelöst wird; derselbe Fehler tritt kaum auf. Die Sprache der Selektoren bleibt in beiden Werkzeugen Ihnen überlassen: [CSS-Selektor oder XPath: Was passt zum Web Scraping?](/de/blog/css-selector-vs-xpath).

## Wie unterscheidet sich die Proxy-Verwaltung?

Die Playwright-Seite haben wir im Schwesterbeitrag beschrieben, hier die Zusammenfassung: Das `proxy`-Objekt wird an `launch()` oder `new_context()` übergeben, `username` und `password` sind eigene Felder, und in einem Browser kann jeder Context über eine andere IP hinausgehen. Ein Context isoliert Cookies, Speicher und Proxy. Weil Browser und Maschine gleich bleiben, ändert sich der [Browser-Fingerabdruck](/de/blog/browser-fingerprinting) zwischen Contexts nicht; ein Context ist ein Sitzungstrenner, kein eigenes Gerät.

In Selenium ist der Proxy eine Sitzungsfähigkeit (Capability): Er wird beim Start des Browsers übergeben und bindet alle Tabs dieses Browsers; für einen anderen Proxy schließen Sie ihn mit `driver.quit()` und öffnen einen neuen Browser. Die Authentifizierung fehlt im Standard selbst. [Die Proxy-Definition des W3C-WebDriver](https://www.w3.org/TR/webdriver2/#proxy) zählt die Schlüssel `httpProxy`, `sslProxy`, `socksProxy`, `socksVersion` und `noProxy` auf; einen Schlüssel für Benutzername oder Passwort gibt es nicht. Auch das offizielle Beispiel von Selenium zeigt nur die Form `<HOST:PORT>`. Der Standard sagt, die Serveradresse könne Zugangsdaten tragen, doch das [Proxy-Dokument von Chromium](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md#Proxy-credentials-in-manual-proxy-settings) hält fest, dass Chrome in den Proxy-Einstellungen eingebettete Zugangsdaten nicht verwendet.

Wohin das in der Praxis führt, haben wir mit einem lokalen Proxy mit Authentifizierung geprüft. Die Ergebnisse stammen aus Einzelläufen auf dieser Maschine (Selenium 4.49, Chrome 153):

| Was wir versucht haben | Was passiert ist |
|---|---|
| `--proxy-server=http://server:port`, keine Zugangsdaten | Der Proxy gab `407` zurück. `driver.get()` warf keinen Fehler; die Seite blieb leer, `driver.title` kam leer zurück |
| `--proxy-server=http://user:pass@server:port` | Chrome öffnete die Fehlerseite `ERR_NO_SUPPORTED_PROXIES`, wieder ohne Ausnahme |
| `user:pass@server:port` im `Proxy`-Objekt | Die Seite öffnete sich, doch im Proxy-Log stand keine einzige Anfrage: Der Browser verband sich direkt, mit unserer eigenen IP |
| Port ohne Authentifizierung (entspricht der IP-Whitelist) | Lief ohne Probleme |

Die dritte Zeile ist die gefährlichste: Das Skript sieht aus, als liefe es, dabei geht der Verkehr nicht über den Proxy. Ein Chrome-Argument namens `--proxy-auth`, das in älteren Beiträgen auftaucht, gibt es ebenfalls nicht. Der Aufruf `add_auth_handler` auf der BiDi-Seite von Selenium wird in der Dokumentation für die Basic-Authentifizierung der Website selbst beschrieben; für Proxys ist er kein dokumentierter Weg, und unser Versuch mit definiertem Proxy endete in einer Zeitüberschreitung beim Laden der Seite.

Deshalb empfehlen wir in Selenium die IP-Whitelist: Sie tragen die Ausgangs-IP des Servers, auf dem das Skript läuft, im Panel in die Liste ein und geben den Wert von `--proxy-server` ohne Zugangsdaten an. Der Vergleich der beiden Verfahren steht in [Proxy-Authentifizierung: User:Pass oder IP-Whitelist](/de/blog/proxy-authentication-methods), die Proxy-Syntax von SeleniumBase in [Proxy mit SeleniumBase: Anmeldung und Rotation](/de/blog/how-to-use-proxy-with-seleniumbase).

In denselben Läufen haben wir noch etwas beobachtet: Das installierte Chrome, das Selenium öffnete, verband sich neben der Zielseite auch mit den Update- und Kontodiensten von Google über den Proxy; im eigenen Chromium-Build von Playwright standen im Proxy-Log nur die Anfragen der Seite. Wenn Sie den Verkehr pro Gigabyte bezahlen, etwa bei [Residential-Proxy](https://proxynet.io/de/residential-proxy), lohnt es sich, diesen Hintergrundverkehr im Panel zu beobachten.

## Sprachunterstützung und Ökosystem

Die offiziellen Bibliotheken von Selenium gibt es für Java, Python, C#, Ruby und JavaScript. Die von Playwright für JavaScript und TypeScript, Python, Java und .NET. Sind Sie ein Ruby-Team, entscheidet sich die Sache von selbst.

Auch wenn sich die Sprachen auf dem Papier überschneiden, liegen die Schwerpunkte anders. Selenium ist ein zwanzig Jahre altes Projekt; ein großer Teil der Testteams in Unternehmen schreibt Selenium in Java oder C#, es gibt mit TestNG, JUnit, NUnit und Cucumber gebaute Suiten mit Hunderten von Szenarien, und sie neu zu schreiben kostet meist mehr, als Playwright an Bequemlichkeit bringt. Das reifste Gesicht von Playwright ist die Node.js-Seite: Der eigene Test-Runner bringt paralleles Ausführen, den Vergleich von Bildschirmfotos und die automatische Trace-Aufzeichnung mit. In Python ist das pytest-Plugin der empfohlene Weg. Datenerhebung mit C# behandeln wir in [Daten von Websites holen mit C#: HttpClient und Proxy](/de/blog/csharp-web-scraping).

Beim Scraping geht die Wahl der Sprache oft der Wahl des Werkzeugs voraus: Liegt die Strecke, die die Daten verarbeitet, in Python, taugen beide Werkzeuge; liegt sie in Node.js, wirkt Playwright natürlicher. Der Vergleich der beiden Sprachen steht in [Web Scraping: JavaScript oder Python?](/de/blog/web-scraping-javascript-vs-python).

## Browser-Einrichtung: Selenium Manager und playwright install

Ältere Selenium-Anleitungen sagen Ihnen, Sie sollten den zu Ihrer Chrome-Version passenden ChromeDriver von Hand herunterladen und seinen Pfad mit `executable_path` übergeben. Beides liegt hinter uns: In Selenium 4.49 nimmt `webdriver.Chrome()` nur die Parameter `options`, `service` und `keep_alive` an, und das Auffinden des Treibers erledigt seit Version 4.6 der mit der Bibliothek gelieferte [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager/): Er erkennt die Version des installierten Browsers, lädt den passenden Treiber herunter und legt ihn im Ordner `~/.cache/selenium` ab. In unserem Versuch lud er für das installierte Chrome 153 ohne Zusatzschritt den ChromeDriver 153 herunter. Laut Dokument kann er Chrome, Firefox und Edge auch herunterladen, wenn der Browser nicht installiert ist; das Werkzeug wird weiterhin als Beta versioniert.

Der Ansatz von Playwright ist umgekehrt: Es vertraut dem Browser auf dem System nicht. `playwright install chromium` lädt den eigenen Build herunter, und jede Playwright-Version ist an einen bestimmten Browser-Build gebunden. Aktualisieren Sie die Bibliothek und vergessen den Befehl `install`, bekommen Sie den Fehler „Executable doesn't exist"; uns ist das bei den Versuchen zu diesem Beitrag ebenfalls passiert.

Der Tausch ist dieser: Selenium fährt den Browser, den Ihre Nutzer tatsächlich verwenden und der sich selbst aktualisiert, was für Tests sinnvoll ist, aber bei einem Browser-Update kann sich das Verhalten ändern. In Playwright wird die Browserversion mit dem Code festgezurrt; wann aktualisiert wird, entscheiden Sie.

## Parallel arbeiten: Grid oder Context?

In Playwright ist die Einheit der Parallelität der Context. Ein Browserprozess öffnet sich, jede Aufgabe bekommt ihren eigenen Context und auf Wunsch ihren eigenen Proxy:

```python
import asyncio

from playwright.async_api import async_playwright

URLS = [f"https://quotes.toscrape.com/js/page/{n}/" for n in range(1, 4)]
PROXY = {"server": "http://pr.proxynet.io:8000", "username": "user", "password": "pass"}

async def scrape(browser, url):
    context = await browser.new_context(proxy=PROXY)  # isolierte Sitzung mit eigenem Proxy
    try:
        page = await context.new_page()
        await page.goto(url)
        quotes = page.locator("div.quote span.text")
        await quotes.first.wait_for()
        return url, await quotes.count()
    finally:
        await context.close()

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()  # ein einziger Browserprozess
        for url, count in await asyncio.gather(*(scrape(browser, u) for u in URLS)):
            print(url, count)
        await browser.close()

asyncio.run(main())
```

In Selenium ist die Einheit der Browser selbst. Dieselbe Aufgabe schreibt man mit einem Thread-Pool, der pro Aufgabe einen Treiber öffnet:

```python
from concurrent.futures import ThreadPoolExecutor

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

URLS = [f"https://quotes.toscrape.com/js/page/{n}/" for n in range(1, 4)]

def scrape(url):
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    options.add_argument("--proxy-server=http://pr.proxynet.io:8000")  # mit IP-Whitelist
    driver = webdriver.Chrome(options=options)  # ein Browserprozess pro Aufgabe
    try:
        driver.get(url)
        quotes = WebDriverWait(driver, 15).until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.quote span.text"))
        )
        return url, len(quotes)
    finally:
        driver.quit()

with ThreadPoolExecutor(max_workers=3) as pool:
    for url, count in pool.map(scrape, URLS):
        print(url, count)
```

Beide Skripte lieferten von drei Seiten je zehn Zitate. Der Unterschied liegt im Ressourcenverbrauch: Beim ersten öffnet sich ein Browser, beim zweiten drei Browser und drei Treiberprozesse. Bei zwanzig gleichzeitigen Sitzungen schlägt dieser Unterschied direkt auf den Speicher durch. Wann Nebenläufigkeit und Parallelität beim Scraping nützen, steht in [Concurrency und Parallelism: Was bestimmt Scraping-Tempo?](/de/blog/concurrency-vs-parallelism).

Stark ist Selenium bei der Verteilung über Maschinen. Selenium Grid leitet Befehle an Browser auf entfernten Maschinen weiter; laut offiziellem Dokument ist sein Zweck, Tests auf mehreren Maschinen parallel auszuführen. Eine Matrix „Edge unter Windows, Safari unter macOS, Firefox unter Linux" aus einer Suite laufen zu lassen, ist die Aufgabe von Grid. Playwright hat dafür keine direkte Entsprechung: Die Verteilung über Maschinen überlässt es Ihrem CI-System. Die Anbindung an Grid ist in seiner Dokumentation als experimentell gekennzeichnet und umfasst nur Chromium-basierte Browser.

## Werkzeuge zur Fehlersuche

Unter dieser Überschrift liegt Playwright deutlich vorn. Eine Aufzeichnung, die mit `context.tracing.start(screenshots=True, snapshots=True)` beginnt und mit `tracing.stop(path="trace.zip")` endet, öffnet sich mit dem Befehl `playwright show-trace trace.zip`: Die DOM-Ansicht vor und nach jeder Aktion, die Netzwerkanfragen und die Konsolenmeldungen stehen auf einer Zeitachse. Warum ein nachts gelaufener Durchlauf leer zurückkam, beantworten Sie morgens aus dieser Datei. `PWDEBUG=1` öffnet den Inspector und führt das Skript Schritt für Schritt aus, `playwright codegen` übersetzt Ihre Handlungen im Browser in Code.

In Selenium gibt es kein einzelnes gleichwertiges Werkzeug. Mit `driver.save_screenshot()` machen Sie ein Bildschirmfoto, in Chrome schalten Sie die Fähigkeit `goog:loggingPrefs` ein und lesen mit `driver.get_log("browser")` die Konsolenmeldungen; beides haben wir versucht, es funktioniert. Den Bedarf nach Aufzeichnen und Abspielen deckt die Erweiterung Selenium IDE. Das Mithören von Netzwerkanfragen kommt mit BiDi, doch für eine Aufzeichnung, die man später durchgeht, stützen Sie sich auf Reporting-Frameworks.

## Tempo: Warum wir keine Zahlen nennen

Die meisten Vergleiche im Netz tragen eine Prozentangabe der Art „Playwright ist so viel schneller"; diese Zahlen entstanden auf der Maschine und auf der Seite des jeweiligen Autors. Die Architektur weckt eine Erwartung zugunsten von Playwright: eine offene Verbindung statt einer HTTP-Anfrage pro Befehl, ein Context statt eines Browsers. Doch bei einem echten Durchlauf über einen Proxy vergeht der größte Teil der Zeit im Netz und in der Antwortzeit der Zielseite; in unserem Beispiel endeten beide Skripte im Schatten der zehn Sekunden Seitenverzögerung.

Wenn Sie messen wollen, messen Sie auf Ihrem eigenen Ziel, mit demselben Proxy und derselben Nebenläufigkeit, an einer Stichprobe von einigen Dutzend Seiten. In den meisten Projekten kommt der eigentliche Gewinn nicht aus dem Werkzeugwechsel, sondern daraus, den Browser gar nicht erst unnötig zu öffnen.

## Einsatzbereiche

- **Daten von dynamischen Seiten holen:** In einem neuen Projekt senken das Mithören von Anfragen und das Blockieren von Ressourcen in Playwright den Verkehr; der allgemeine Aufbau steht auf der Seite [Lösung zur Datenerhebung](/de/data-scraping).
- **Viele Seiten regelmäßig durchlaufen:** Warteschlange und Entdeckungslogik hängen nicht am Werkzeug; sehen Sie die Seite [Web-Crawler-Lösung](/de/web-crawler) und den Beitrag [Was ist Pagination und wie durchläuft man sie beim Scraping?](/de/blog/pagination-web-scraping).
- **Die eigene Anwendung aus verschiedenen Ländern testen:** in Playwright ein Context pro Land, in Selenium eine Sitzung pro Land; das Detail steht auf der Seite [Anwendungstest](/de/app-testing).
- **Kompatibilitätstest über Browser hinweg:** Brauchen Sie echtes Safari und eine Betriebssystem-Matrix, dann Selenium und Grid.
- **Massenhaftes Durchlaufen unabhängiger Seiten:** In beiden Werkzeugen genügt mit [Rotierender Proxy](https://proxynet.io/de/rotating-proxy) eine einzige Gateway-Adresse; die Rotation übernimmt das Gateway.

Welches Werkzeug es auch wird, der Rahmen bleibt gleich: Halten Sie sich an die Regeln aus `robots.txt` und an die Nutzungsbedingungen, nutzen Sie die offizielle API, wenn es eine gibt, und halten Sie das Anfragetempo auf einem Niveau, das die Website trägt. Das Detail steht in [Was ist robots.txt und wie liest man die Datei?](/de/blog/robots-txt).

## Häufige Fehler

- **In Selenium die Zugangsdaten in die Proxy-Adresse einbetten.** Chrome verwendet sie nicht; in unserem Versuch war das Ergebnis entweder eine Fehlerseite oder eine direkte Verbindung ohne Proxy.
- **Annehmen, die Seite sei geöffnet, weil `driver.get()` keinen Fehler warf.** Selenium gibt den Statuscode nicht heraus; prüfen Sie das erwartete Element und die Ausgangs-IP.
- **Glauben, `count()` oder `all()` würden in Playwright warten.** Sie warten nicht; zuerst `first.wait_for()`.
- **Das Warten mit `time.sleep()` lösen.** Das ist langsam und zugleich brüchig; nutzen Sie in Selenium `WebDriverWait` und in Playwright das Warten des Locators.
- **In Selenium implizites und explizites Warten mischen.** Das offizielle Dokument warnt davor: Die Zeiten werden unvorhersehbar.
- **In Selenium `driver.quit()` nicht aufrufen.** Jede nicht geschlossene Sitzung hinterlässt einen Chrome- und einen Treiberprozess; nutzen Sie `try/finally`.
- **Eine laufende Selenium-Suite nur der Mode wegen umziehen.** Die Kosten des Wechsels liegen nicht bei den Selektoren, sondern bei der Wartelogik und der Testinfrastruktur.
- **Playwright aktualisieren, die Browser aber nicht.** Jede Version will ihren eigenen Build; nehmen Sie einen Schritt `playwright install` in Ihr CI-Image auf.

## Entscheidungshilfe

| Bedarf | Empfehlung |
|---|---|
| Neu startendes Scraping-Projekt in Python oder Node.js | Playwright |
| Proxy mit Benutzername und Passwort | Playwright; in Selenium auf die IP-Whitelist wechseln |
| Dutzende unabhängige Sitzungen auf einer Maschine, pro Sitzung eine eigene IP | Playwright, Proxy pro Context |
| Laufende, gepflegte Selenium-Testsuite | Bei Selenium bleiben |
| Testteam im Unternehmen mit Java- oder C#-Schwerpunkt | Beides geht; vorhandenes Framework und Erfahrung entscheiden |
| Ruby | Selenium |
| Test in echtem Safari und auf verschiedenen Betriebssystemen | Selenium und Grid |
| Nachträgliche Fehlersuche bei nachts laufenden Jobs | Playwright, Trace Viewer |
| Netzwerkantwort lesen, Bilder und Fonts blockieren | Playwright (eingebaut) |
| Daten im Quelltext der Seite oder an einem JSON-Endpunkt | Keines von beiden: einfacher HTTP-Client oder Scrapy |

## Häufige Fragen

### Ersetzt Playwright Selenium?

In neuen Projekten ist es oft die erste Wahl, aber zu sagen, es habe Selenium ersetzt, wäre nicht richtig. Selenium ist die Referenzumsetzung eines W3C-Standards, seine Treiber schreiben die Browserhersteller, und die fehlende bidirektionale Kommunikation wird über den Standard mit WebDriver BiDi ergänzt. Beide Projekte werden aktiv weiterentwickelt.

### Ist der Wechsel von Selenium zu Playwright schwer?

Selektoren lassen sich größtenteils übernehmen; CSS und XPath funktionieren in beiden. Aufwand macht die Wartelogik: `WebDriverWait`-Blöcke fallen weg, an ihre Stelle tritt ein Locator-basierter Ablauf; auf der Testseite werden auch Page Objects, Reporting und CI-Schritte neu aufgesetzt. Ein kleines Skript zieht an einem Tag um; bei einer Suite mit Hunderten von Szenarien ist es weniger riskant, zuerst die neuen Szenarien in Playwright zu schreiben und die alten stehen zu lassen.

### Lassen sich beide im selben Projekt nutzen?

Ja, sie kommen einander nicht ins Gehege. Üblich ist, die vorhandene Selenium-Regressionssuite zu behalten und neue Arbeiten in Playwright zu schreiben. Zu beachten ist, zwei getrennte Modelle der Browser-Einrichtung gemeinsam im CI-Image zu verwalten.

### Lässt sich in Selenium überhaupt kein Proxy mit Benutzername und Passwort nutzen?

Auf dem Standardweg nicht: In der Proxy-Definition des WebDriver gibt es kein Feld für Zugangsdaten, und Chrome verwendet die in der Adresse eingebetteten Daten nicht. Pakete von Dritten, die einen lokalen Weiterleitungs-Proxy dazwischensetzen, füllen diese Lücke, bringen aber eine zusätzliche Abhängigkeit. Arbeiten Sie von einem Server mit fester IP, ist die IP-Whitelist einfacher und sicherer; das Passwort steht dann gar nicht im Code.

### Ist Selenium in Python langsamer als Playwright?

Eine allgemeine Antwort gibt es nicht. Die Architektur spricht für Playwright, doch bei einem Durchlauf über einen Proxy bestimmen meist das Netz und die Zielseite die Zeit. Übertragen Sie veröffentlichte Prozentzahlen nicht auf Ihre eigene Arbeit; messen Sie am selben Ziel, mit demselben Proxy und derselben Nebenläufigkeit, selbst.

### Verhalten sich beide im Headless-Modus anders?

Beide laufen ohne Fenster. Playwright startet standardmäßig headless und lädt dafür einen eigenen „Headless Shell"-Build herunter; um das Fenster zu sehen, schreiben Sie `launch(headless=False)`. Selenium startet standardmäßig mit Fenster und wechselt in Chrome mit dem Argument `--headless=new` in den fensterlosen Modus. Die Proxy-Einstellung ist in beiden Modi dieselbe.

## Fazit

Playwright und Selenium erledigen dieselbe Arbeit auf verschiedenen Wegen. Selenium schickt Befehle über W3C WebDriver an den Treiber des Browserherstellers; es deckt mehr Sprachen, echtes Safari und mit Grid die Verteilung über Maschinen ab und überlässt Ihnen das Warten und die Proxy-Zugangsdaten. Playwright baut eine dauerhafte Verbindung zum Browser auf; es wartet von selbst, nimmt den Proxy mit Benutzername und Passwort pro Context, hört den Netzwerkverkehr mit und erleichtert die Fehlersuche mit einer Trace-Datei. In einem neuen Scraping-Projekt bringt Playwright Sie mit weniger Code voran; haben Sie eine laufende Selenium-Suite, genügt es meist, sie über eine IP-Whitelist an den Proxy zu binden. Die Proxy-Arten, die Sie mit beiden Werkzeugen nutzen können, finden Sie in unseren [Proxy-Diensten](/de/proxy).
