Das Schwierige ist nicht das Parsen von HTML. Es ist das Erhalten einer nutzbaren Antwort von modernen Websites.
Das Sammeln von Daten von modernen Websites ist oft weniger ein Parser-Problem und mehr ein Zugriffsproblem. Ein einfacher Python-requests-Aufruf gibt einen 403-Status oder eine Blockierungsseite zurück, bevor BeautifulSoup überhaupt etwas Nützliches zu verarbeiten hat.
Die übliche Reaktion ist, Proxies hinzuzufügen, Header zu rotieren oder zu Playwright zu wechseln. Diese Ansätze funktionieren, aber sie fügen auch Infrastruktur hinzu, die der Scraper nun verwalten muss.
Bright Data's Web Unlocker API fungiert als Zugriffsschicht zwischen dem Python-Scraper und der Zielwebsite. Anstatt den Scraper direkt mit Proxy-Rotation, Anti-Bot-Verhalten, CAPTCHA-Behandlung, Rendering-Problemen und blockierten Anfragen umgehen zu lassen, sendet das Skript die Ziel-URL an Web Unlocker und erhält eine Antwort, die wie normales HTML geparst werden kann.
Web Unlocker verwaltet Proxy-Rotation, Anti-Bot-Herausforderungen und CAPTCHA-Lösung in einem einzigen API-Aufruf und gibt saubere HTML- oder JSON-Antworten zurück, die zum Parsen bereit sind.
In diesem Artikel verwende ich Web Unlocker als Fetching-Schicht für einen kleinen Python-Scraper:
- zuerst konfiguriere ich eine Web Unlocker API Zone in der Bright Data UI;
- dann zeige ich, warum rohe
requestsauf einer modernen geschützten Seite scheitern; - danach sende ich dasselbe Ziel durch Web Unlocker API;
- schließlich parse ich das zurückgegebene HTML mit BeautifulSoup und vergleiche die Ergebnisse.
Der Punkt ist nicht, Playwright überall zu ersetzen. Der Punkt ist, Browser-Automatisierung zu vermeiden, wenn der Scraper nur gerenderte HTML benötigt.
Warum Web Unlocker für dieses Problem geeignet ist
Wenn ein Scraping-Skript die Daten nicht sehen kann, lautet der übliche Rat, Playwright oder Selenium zu verwenden.
Dieser Rat ist oft richtig. Browser-Automatisierung ist das richtige Werkzeug, wenn der Workflow Klicks, Formulare, Login-Flows, Scrollen oder kontrollierte Interaktion mit einer Seite erfordert.
Aber viele Scraping-Jobs sind einfacher als das. Sie benötigen keine Browser-Steuerung. Sie brauchen nur die Seite, nachdem JavaScript fertig ist, den Inhalt zu erzeugen.
Mit Playwright besitzt die Anwendung den Browser-Lebenszyklus. Sie muss einen Browser starten oder verbinden, die Seite navigieren, auf den richtigen Zustand warten, den Inhalt sammeln und die Sitzung sauber beenden.
Mit Web Unlocker behält der Scraper eine Request-Response-Form:
Ziel-URL → Web Unlocker API → gerenderte Antwort → Parser
Web Unlocker kombiniert Website-Entsperrung, automatisches Proxy-Management und integriertes JavaScript-Rendering. Für Seiten, die JavaScript-Ausführung erfordern, kann es im Hintergrund einen Headless-Browser starten und die gerenderte Ausgabe zurückgeben.
Das macht Web Unlocker als Zwischenschicht nützlich, wenn rohe requests zu eingeschränkt, vollständige Browser-Automatisierung zu aufwändig und der Scraper nur parsebaren Inhalt durch einen HTTP-Aufruf benötigt.
Schritt 1: Web Unlocker API Zone in Bright Data UI erstellen
Bevor der Python-Scraper geschrieben wird, muss eine Web Unlocker API Zone im Bright Data Control Panel erstellt werden.
Navigiere im linken Menü zu Web Access APIs, dann klicke auf Create API. Im API-Auswahlbildschirm wähle Web Unlocker API und fahre fort.
Nach der Auswahl gib der Zone einen beschreibenden Namen. Für dieses Beispiel:
python_js_rendered_html
Ein beschreibender Name ist wichtig, wenn du später mehrere Zonen verwaltest. Der Name sollte beschreiben, wofür diese Zone ist, ohne die Einstellungen öffnen zu müssen.
Nach der Konfiguration bietet Bright Data einen Test-API-Bildschirm mit einem einsatzbereiten cURL-Befehl. Dieser zeigt die genaue Anfrageform: den Endpoint, den Authorization-Header, den Zonennamen, die Ziel-URL und das Antwortformat.
Sobald die Zone erstellt ist, öffne den Overview-Tab. Dieser Tab gibt dir die Werte für direkten API-Zugriff:
- API-Schlüssel
- Zonenname
- Einsatzbereites Anfragebeispiel
Für die geschützte Bewertungsseite in diesem Beispiel aktiviere auch Manual 'expect' elements in den Zoneneinstellungen.
Diese Einstellung ist wichtig, weil Web Unlocker warten soll, bis ein bestimmtes Element auf der gerenderten Seite erscheint, bevor die Antwort zurückgegeben wird. Ohne diese Einstellung kann die API den manuellen Expect-Parameter ablehnen:
Manual expect is not enabled for this zone
Die Option ist verfügbar unter: Configuration → Advanced settings → Custom Unlocker API → Manual 'expect' elements
Der Direct API Endpoint ist:
https://api.brightdata.com/request
Die Anfrage wird mit einem Bearer-Token authentifiziert:
Authorization: Bearer <BRIGHT_DATA_API_KEY>
Das Basis-Payload enthält den Web Unlocker Zonennamen, die Ziel-URL und das Antwortformat:
{
"zone": "deine_web_unlocker_zone",
"url": "https://ziel-url.com",
"format": "raw"
}
Ich habe format: "raw" verwendet, weil ich den Response-Body wollte und die HTML selbst mit BeautifulSoup parsen wollte. Die andere Option, format: "json", gibt direkt strukturierte Daten zurück.
Schritt 2: Zugangsdaten lokal speichern
Das Python-Skript benötigt zwei Werte aus der UI:
BRIGHT_DATA_API_KEY
BRIGHT_DATA_ZONE
Diese außerhalb des Codes als Umgebungsvariablen speichern:
export BRIGHT_DATA_API_KEY="dein_api_schluessel_hier"
export BRIGHT_DATA_ZONE="deine_web_unlocker_zone_hier"
Das hält Geheimnisse aus dem Skript heraus und macht denselben Code einfacher lokal, in CI oder in einem geplanten Worker später auszuführen.
Schritt 3: Zuerst den normalen Python-Scraper ausprobieren
Für den Smoke-Test wurde eine echte geschützte Zielseite verwendet:
https://www.g2.com/products/mongodb/reviews
Die Seite ist im Browser verfügbar, aber eine einfache Python-Anfrage erhält eine blockierte Antwort statt nützlichem Bewertungsinhalt:
import requests
from bs4 import BeautifulSoup
TARGET_URL = "https://www.g2.com/products/mongodb/reviews"
response = requests.get(
TARGET_URL,
headers={"User-Agent": "Mozilla/5.0"},
timeout=30,
)
print("status_code:", response.status_code)
print("html_length:", len(response.text))
soup = BeautifulSoup(response.text, "html.parser")
headings = [h.get_text(strip=True) for h in soup.find_all("h2")]
print("headings_count:", len(headings))
print("first_headings:", headings[:3])
Die Ausgabe bestätigt, dass die Basis-Anfrage nicht ausreicht. Rohe requests erhalten eine 403-Antwort von der G2-Bewertungsseite, so dass BeautifulSoup keinen nützlichen Inhalt zu parsen hat.
An diesem Punkt ist die Fetching-Schicht das Problem.
Schritt 4: Ziel-URL durch Web Unlocker API senden
Jetzt die gleiche G2-Bewertungsseite durch die Web Unlocker API Zone senden.
Abhängigkeiten installieren:
pip install requests beautifulsoup4
Dann einen kleinen Wrapper um den Web Unlocker API-Aufruf erstellen:
import os
import requests
from bs4 import BeautifulSoup
WEB_UNLOCKER_ENDPOINT = "https://api.brightdata.com/request"
BRIGHT_DATA_API_KEY = os.environ["BRIGHT_DATA_API_KEY"]
BRIGHT_DATA_ZONE = os.environ["BRIGHT_DATA_ZONE"]
TARGET_URL = "https://www.g2.com/products/mongodb/reviews"
def fetch_with_web_unlocker(url: str, timeout: int = 90) -> str:
payload = {
"zone": BRIGHT_DATA_ZONE,
"url": url,
"format": "raw",
"method": "GET",
"headers": {
"x-unblock-expect": "{\"text\": \"reviews\"}"
},
}
headers = {
"Authorization": f"Bearer {BRIGHT_DATA_API_KEY}",
"Content-Type": "application/json",
}
response = requests.post(
WEB_UNLOCKER_ENDPOINT,
json=payload,
headers=headers,
timeout=timeout,
)
response.raise_for_status()
return response.text
Der wichtige Punkt ist, dass der Python-Code sich nicht direkt mit einem Proxy verbindet. Er sendet eine normale HTTP-Anfrage an den Web Unlocker API-Endpoint.
Ein erfolgreicher Durchlauf gibt einen nutzbaren Seiten-Body zurück statt der blockierten Antwort von rohen requests.
Schritt 5: Strukturierte Daten aus der Web Unlocker-Antwort extrahieren
Sobald Web Unlocker einen nutzbaren Seiten-Body zurückgibt, wird der Extraktionscode wieder normales BeautifulSoup:
# Verwendet fetch_with_web_unlocker() und TARGET_URL aus Schritt 4
import json
from bs4 import BeautifulSoup
html = fetch_with_web_unlocker(TARGET_URL)
soup = BeautifulSoup(html, "html.parser")
headings = [
h.get_text(strip=True)
for h in soup.find_all("h2")
]
page_text = soup.get_text(" ", strip=True)
result = {
"url": TARGET_URL,
"html_length": len(html),
"headings_count": len(headings),
"first_headings": headings[:5],
"contains_mongodb": "mongodb" in page_text.lower(),
"contains_reviews": "reviews" in page_text.lower(),
}
print(json.dumps(result, indent=2))
Das ist der Hauptvorteil dieses Ansatzes: die Extraktionsschicht bleibt einfach. Der Parser muss nicht wissen, ob die ursprüngliche Seite geschützt, für rohe Anfragen blockiert oder schwer direkt zugänglich war. Er erhält HTML und extrahiert Daten daraus.
Die Komplexität bewegt sich aus dem Scraper heraus und in die Zugriffsschicht, genau dort wo Web Unlocker passt.
Schritt 6: Rohe Requests und Web Unlocker vergleichen
Um den Unterschied sichtbar zu machen, ein Nebeneinander-Vergleichsskript:
import os
import requests
from bs4 import BeautifulSoup
WEB_UNLOCKER_ENDPOINT = "https://api.brightdata.com/request"
BRIGHT_DATA_API_KEY = os.environ["BRIGHT_DATA_API_KEY"]
BRIGHT_DATA_ZONE = os.environ["BRIGHT_DATA_ZONE"]
TARGET_URL = "https://www.g2.com/products/mongodb/reviews"
def fetch_with_requests(url: str) -> tuple[int, str]:
response = requests.get(
url,
headers={"User-Agent": "Mozilla/5.0"},
timeout=30,
)
return response.status_code, response.text
def fetch_with_web_unlocker(url: str, timeout: int = 90) -> tuple[int, str]:
payload = {
"zone": BRIGHT_DATA_ZONE,
"url": url,
"format": "raw",
"method": "GET",
"headers": {
"x-unblock-expect": "{\"text\": \"reviews\"}"
},
}
headers = {
"Authorization": f"Bearer {BRIGHT_DATA_API_KEY}",
"Content-Type": "application/json",
}
response = requests.post(
WEB_UNLOCKER_ENDPOINT,
json=payload,
headers=headers,
timeout=timeout,
)
return response.status_code, response.text
# --- Vergleich ---
raw_status, raw_html = fetch_with_requests(TARGET_URL)
unlocker_status, unlocker_html = fetch_with_web_unlocker(TARGET_URL)
for label, status, html in [
("raw requests", raw_status, raw_html),
("web unlocker", unlocker_status, unlocker_html),
]:
soup = BeautifulSoup(html, "html.parser")
headings = [h.get_text(strip=True) for h in soup.find_all("h2")]
print(f"[{label}] status={status}, html_len={len(html)}, headings={headings[:3]}")
| Methode | Status | HTML-Länge | Gefundene Überschriften |
|---|---|---|---|
| Rohe Requests | 403 | ~2 KB | 0 |
| Web Unlocker | 200 | ~800 KB | 15+ |
Rohe requests erhalten eine blockierte 403-Antwort. Web Unlocker gibt eine 200-Antwort mit parsebaren Überschriften von derselben G2-Seite zurück — einschließlich Abschnitte wie "Value at a Glance", "Top-Rated Alternatives" und "MongoDB Integrations".
Schritt 7: Ausgabe speichern
Für einen kleinen Scraping-Job ist JSON Lines ein praktisches Ausgabeformat. Jeder Datensatz wird als separate Zeile geschrieben, was die Datei einfach zu inspizieren, anzuhängen und später zu verarbeiten macht.
import json
from pathlib import Path
from bs4 import BeautifulSoup
output_path = Path("g2_mongodb_reviews.jsonl")
unlocker_soup = BeautifulSoup(unlocker_html, "html.parser")
page_text = unlocker_soup.get_text(" ", strip=True)
unlocker_headings = [h.get_text(strip=True) for h in unlocker_soup.find_all("h2")]
record = {
"url": TARGET_URL,
"html_length": len(unlocker_html),
"headings_count": len(unlocker_headings),
"first_headings": unlocker_headings[:5],
"contains_mongodb": "mongodb" in page_text.lower(),
"contains_reviews": "reviews" in page_text.lower(),
}
with output_path.open("w", encoding="utf-8") as file:
file.write(json.dumps(record, ensure_ascii=False) + "\n")
print(f"gespeichert: {output_path}")
Was in der Praxis wirklich wichtig war
1. Die Antwort prüfen, bevor der Parser debuggt wird
Wenn ein Scraper leere Ergebnisse zurückgibt, ist der Instinkt, Selektoren zu ändern. Bevor die Parsing-Logik angefasst wird, sollte die rohe Antwort inspiziert werden. Wenn der Statuscode 403 ist oder das HTML eine Blockierungsseite ist, hilft keine Selektor-Korrektur.
2. Direkter API-Zugriff hielt den Code minimal
Der Scraper authentifizierte sich mit einem Bearer-Token bei https://api.brightdata.com/request. Keine Proxy-Zugangsdaten, kein Browser-Lebenszyklus, keine Rotationslogik. Die Integration blieb nah an einem normalen requests-Workflow.
3. Das UI-Setup war wichtig
Bright Data hat mehrere Produkte, die verschiedene Scraping-Probleme lösen. Browser API, Web Unlocker API, SERP API und Proxy-Zonen sind nicht dasselbe. Für diesen Artikel war das erforderliche Produkt Web Unlocker API unter Web Access APIs. Ich aktivierte auch Manual 'expect' elements für die Zone, weil die Anfrage x-unblock-expect verwendet. Ohne diese Einstellung kann die API den manuellen Expect-Parameter ablehnen.
4. Wissen, wann auf Browser API aufzurüsten ist
Wenn der Workflow Klicks, Formularausfüllungen oder mehrstufige Navigation erfordert, ist Browser API mit Playwright das bessere Werkzeug. Web Unlocker deckt den einfacheren Fall ab: eine URL rein, gerendertes HTML raus.
Fazit
Der Hauptwert der Bright Data Web Unlocker API liegt darin, dass sie eine bestimmte Klasse von Scraping-Aufgaben einfach hält.
Rohe requests sind immer noch ein guter Ausgangspunkt für statische Seiten. Browser API und Playwright sind immer noch die richtigen Werkzeuge, wenn ein Workflow Browser-Interaktion erfordert. Aber viele echte Scraping-Aufgaben liegen zwischen diesen beiden Enden des Spektrums.
Die Seite kann geschützt, blockiert oder schwer direkt zugänglich sein. Der Workflow benötigt möglicherweise immer noch nur eines: einen nutzbaren Seiten-Body, der mit normalen Python-Tools geparst werden kann.
Das ist die Lücke, die Web Unlocker füllt.
Der Scraper sendete eine Python-Anfrage an Web Unlocker API, erhielt eine große parseable HTML-Antwort von einer geschützten G2-Seite, extrahierte strukturierte Signale mit BeautifulSoup und speicherte das Ergebnis als JSON Lines. Der Code blieb nah am ursprünglichen requests-Workflow, während Web Unlocker die Zugriffsschicht verwaltete, die modernes Scraping normalerweise fragil macht.
Das ist der praktische Gewinn: der Scraper wird wieder zum Parser.
Versuche Web Unlocker API, wenn dein Scraper gerendertes HTML ohne Proxy-Verwaltung oder Browser-Sessions benötigt. Für interaktive Workflows mit Klicks, Logins oder Formularen verwende Browser API mit Playwright.


