# Web Unlocker API-Tutorial: Python und Node.js, Blockiert vs. Unblockiert

Funktionierender Python- und Node.js-Code für eine Web Unlocker API: dieselbe Anfrage an eine Seite, die einfache Clients blockiert, und eine, die dies nicht tut, wie man liest, was der Unlocker meldet, und ein Helfer, der nur für den Unlocker zahlt, wenn eine Blockierung erkannt wird.

Eine Web Unlocker API spielt eine HTTP-Anfrage von einer Residential-IP unter einem Browser-TLS-Fingerprint ab, versucht es erneut mit einer neuen IP und wechselt zu einem echten Browser, wenn die Seite mit einer Herausforderung antwortet. Dieses Web Unlocker API-Tutorial zeigt es in Python und Node.js, auf einer Seite, die einfache Clients blockiert, und einer, die dies nicht tut.

Jedes unten zitierte Ergebnis wurde am 29. September 2026 gemessen: dieselbe URL wurde mit einfachem curl von einem Rechenzentrum-Server in Frankfurt abgerufen, mit einfachem curl über einen Residential-Proxy mit US-Exit und über den QuantumProxies.io Web Unlocker mit US-Exit. Wo eine Seite den Unlocker nicht benötigte, sagen wir das, weil die günstigste Anfrage die ist, die ohne ihn funktioniert.

- **Zwei Wege hinein:** ein Forward-Proxy unter `unlock.quantumproxies.io:9000` für Code, der bereits das Proxy-Protokoll spricht, oder `POST /api/v1/scraper/unlock` mit Ihrem API-Schlüssel für alles andere.
- **Was Sie zurückbekommen:** den Status, die Header und den Body des Ursprungs, plus `x-qp-*` Header, die angeben, wie viele Versuche es brauchte, ob ein Browser lief und welche Art von Mauer es stoppte, falls eine.
- **Wann Sie es nicht benötigen:** Wikipedia, GitHub, docs.python.org, Hacker News und books.toscrape.com beantworteten in unserem Test einfache Anfragen. Versuchen Sie es zuerst einfach und eskalieren Sie nur bei einer erkannten Blockierung.

## Was Sie benötigen, bevor Sie beginnen

- Ein QuantumProxies.io-Konto mit Web Unlocker-Bandbreite. Der Unlocker berechnet sich aus einem vorausbezahlten GB-Guthaben, getrennt für die Residential- und die Mobile-Stufe (4G/5G-Carrier-Exits).
- Für den Forward-Proxy: ein Proxy-Sub-User, der auf der [Web Unlocker-Seite des Dashboards](https://app.quantumproxies.io/unlock) erstellt wurde. Er sieht aus wie `unlock-XXXXXXXX` mit eigenem Passwort. Es ist nicht Ihr API-Schlüssel.
- Für den REST-Endpunkt: ein API-Schlüssel aus dem Dashboard, gesendet als `Authorization: Bearer`.
- Python 3.10 oder neuer mit `requests`, und für den Node.js-Teil Node 18 oder neuer mit dem `undici`-Paket.

Bewahren Sie beide Geheimnisse in Umgebungsvariablen auf. Die Beispiele lesen `QP_UNLOCK_USER`, `QP_UNLOCK_PASSWORD` und `QP_API_KEY`. Wenn das Proxy-Passwort Zeichen wie `@` oder `:` enthält, URL-kodieren Sie es mit `urllib.parse.quote`, bevor Sie es in eine Proxy-URL einfügen.

## Schritt 1: die Blockierung mit einfachen Python requests sehen

Beginnen Sie mit dem Fehler, damit Sie wissen, was Sie beheben. Das Ziel ist eine Indeed-Job-Suche. Von unserem Frankfurter Rechenzentrum-Server antwortete es mit `403` mit einer Seite mit dem Titel 'Security Check - Indeed.com'. Über einen einfachen Residential-Proxy antwortete es immer noch mit `403`, diesmal mit einem Body, der den Client aufforderte, 'JavaScript und Cookies zu aktivieren, um fortzufahren'. Eine saubere Home-IP war nicht genug.

```python
import re
import requests

URL = "https://www.indeed.com/jobs?q=data+engineer&l=Austin%2C+TX"
HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
        "(KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36"
    ),
    "Accept-Language": "en-US,en;q=0.9",
}

def title_of(html: str) -> str:
    m = re.search(r"<title[^>]*>(.*?)</title>", html, re.I | re.S)
    return m.group(1).strip() if m else ""

r = requests.get(URL, headers=HEADERS, timeout=30)
print(r.status_code, "|", title_of(r.text))
# Our datacenter run on 29 Sep 2026 saw: 403 | Security Check - Indeed.com
```

Unsere Messung verwendete curl mit einem Chrome User-Agent, nicht `requests`, und es gibt keinen Grund zu erwarten, dass `requests` besser abschneidet. Ein User-Agent-String ist ein Header. Die Anti-Bot-Schicht liest auch den TLS-Handshake und die HTTP/2-Einstellungen, und diese sagen immer noch Python, egal welchen User-Agent Sie setzen. Deshalb bringt das Austauschen von Headern selten etwas gegen Bot-Erkennung in Python requests; die Handshake-Seite wird in unserem Leitfaden zu [TLS-Fingerprinting und warum saubere IPs immer noch blockiert werden](https://quantumproxies.io/blog/tls-ja3-fingerprinting-scraping) behandelt. Ein `403` bedeutet, dass der Server die Anfrage verstanden und abgelehnt hat ([RFC 9110, Abschnitt 15.5.4](https://www.rfc-editor.org/rfc/rfc9110.html#name-403-forbidden)). Es bedeutet nicht, dass Ihre URL oder Ihre Parameter falsch sind.

## Schritt 2: derselbe Aufruf über den Forward-Proxy

Der Forward-Proxy ist die kleinste Änderung am bestehenden Code: übergeben Sie ihn als Proxy und nichts anderes bewegt sich. Das Targeting fährt im Benutzernamen mit. `-country-us` wählt das Exit-Land, `-tier-mobile` wechselt zu mobilen Exits, und `-profile-firefox` (oder chrome, safari, safariios, edge, brave, mobile) fixiert einen TLS-Fingerprint, anstatt ihn bei Wiederholungen zu rotieren.

```python
import os
import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

user = os.environ["QP_UNLOCK_USER"] + "-country-us"   # e.g. unlock-XXXXXXXX-country-us
password = os.environ["QP_UNLOCK_PASSWORD"]
PROXY = f"http://{user}:{password}@unlock.quantumproxies.io:9000"

r = requests.get(
    URL,
    headers=HEADERS,
    proxies={"http": PROXY, "https": PROXY},
    verify=False,   # or verify="qp-unlocker-ca.pem", see below
    timeout=120,
)
print(r.status_code, "|", title_of(r.text))
print("attempts:", r.headers.get("x-qp-unlocker-attempts"),
      "rendered:", r.headers.get("x-qp-unlocker-rendered"))
```

Am 29. September gab dies `200` mit der echten Ergebnisseite zurück, betitelt 'Now Hiring: 2,000 Data Engineer Jobs in Austin, TX | Indeed', beim ersten TLS-Versuch, in 2,6 Sekunden, ohne einen Browser zu starten.

Warum `verify=False`? Um eine HTTPS-Anfrage umzuschreiben, muss der Unlocker das TLS Ihres Clients beenden und sein eigenes Zertifikat für den Zielhost präsentieren. Sie haben zwei saubere Optionen. Schalten Sie die Verifizierung nur für diese Sitzung aus, wie oben, was `curl -k` tut. Oder laden Sie das Unlocker-CA einmal herunter und vertrauen Sie ihm explizit, damit die Verifizierung eingeschaltet bleibt:

```bash
curl -H "Authorization: Bearer $QP_API_KEY" \
  -o qp-unlocker-ca.pem https://app.quantumproxies.io/api/v1/scraper/unlock/ca
```

Dann übergeben Sie `verify="qp-unlocker-ca.pem"` anstelle von `False`. Die [requests advanced usage docs](https://requests.readthedocs.io/en/latest/user/advanced/) behandeln sowohl das `proxies`-Argument als auch benutzerdefinierte CA-Bundles. Wenn Sie keines davon möchten, benötigt der REST-Endpunkt unten überhaupt kein Zertifikat.

## Schritt 3: der REST-Endpunkt, kein Proxy-Protokoll

Der REST-Endpunkt läuft mit derselben Engine hinter einem normalen HTTPS-Aufruf. Sie beschreiben die Anfrage, die Sie gestellt hätten (url, method, headers, body) und erhalten die Antwort des Ursprungs als JSON zurück. Das einzige erforderliche Feld ist `url`.

```python
import os
import requests

API_KEY = os.environ["QP_API_KEY"]

resp = requests.post(
    "https://app.quantumproxies.io/api/v1/scraper/unlock",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "url": URL,
        "country": "us",
        # "tier": "mobile",        # mobile exits, billed on the mobile balance
        # "failOnBlock": True,     # HTTP 502 instead of 200 when every tier was blocked
    },
    timeout=130,
)
resp.raise_for_status()           # 402 = no unlocker GB left, 400 = bad input
data = resp.json()["payload"]

print(data["status"], "blocked:", data["blocked"])
print("attempts:", data["attempts"], "rendered:", data["rendered"],
      "escalated:", data["escalated"], "clearance:", data.get("clearance"))
if data["blocked"]:
    print("block class:", data.get("blockClass"), "vendor:", data.get("vendor"))
html = data.get("body") or ""     # text form; bodyBase64 is always present too
```

Der Antwortumschlag ist `{ type, message, payload }`. Innerhalb von `payload` erhalten Sie `status` (den Statuscode des Ursprungs), `headers`, `body` und `bodyBase64`, `finalUrl`, den Fingerprint `profile`, `attempts`, `rendered`, `escalated`, `blocked` und, wenn etwas die Anfrage stoppte, `blockClass` und `vendor`. Ein `usage`-Objekt berichtet die für den Aufruf abgebuchten Bytes.

Ein Verhalten, um das Sie herum entwerfen sollten: Standardmäßig kommt eine Anfrage, die nach jedem Versuch blockiert blieb, immer noch als HTTP 200 von der API zurück, mit `blocked: true` und der Blockseite in `body` zur Inspektion. Sie ist gekennzeichnet, nicht getarnt. Wenn Ihre Pipeline jede 200 als Erfolg behandelt, setzen Sie `failOnBlock: true` und Sie erhalten eine 502 mit denselben Diagnosen stattdessen. Andere Felder, die es wert sind, bekannt zu sein: `method` und `body` für POSTs, `render: "html"`, um in einem Browser zu starten, `waitForSelector` und `returnCookies`.

![Ein GET durch den Web Unlocker: bis zu drei TLS-Versuche mit frischen Exit-IPs und Browser-Fingerprints, ein Headless-Browser nur, wenn eine JavaScript-Herausforderung erscheint, dann entweder die echte Seite oder ein gekennzeichneter Block. Die Karte listet die x-qp-Header auf, die die Versuche, das Rendering und die Blockklasse melden.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1790701775/blog/generated/qp-unl-g1-diag1.png)
*Ein GET durch den Unlocker: zuerst TLS-Versuche, ein echter Browser nur, wenn eine JavaScript-Herausforderung erscheint, und ein gekennzeichnetes Ergebnis in jedem Fall.*

[Sehen Sie, wie der Web Unlocker blockierte Anfragen behandelt](https://quantumproxies.io/web-unlocker)

## Schritt 4: die x-qp-Header lesen und einen gemeldeten Block behandeln

Über den Forward-Proxy berichtet der Unlocker über die Antwort selbst. Dies sind die Header, die es wert sind, bei jedem Aufruf protokolliert zu werden:

| Header | Was er Ihnen sagt |
| --- | --- |
| x-qp-unlocker-attempts | Wie viele Versuche die Anfrage benötigte, Wiederholungen eingeschlossen |
| x-qp-unlocker-rendered / x-qp-unlocker-escalated | Auf 1 gesetzt, wenn ein Headless-Browser die Seite abgerufen hat / wenn die Anfrage von der TLS-Stufe aufgestiegen ist |
| x-qp-unlocker-profile | Welchen Browser-Fingerprint der zurückgegebene Versuch verwendet hat |
| x-qp-clearance | Was mit dem Browser-Clearance-Cache bei diesem Aufruf passiert ist: minted, hit oder miss |
| x-qp-session / x-qp-country | Die tatsächlich verwendete Exit-Sitzung und das Land |
| x-qp-unlocker-blocked | Nur vorhanden, wenn die Seite nach jedem Versuch immer noch blockiert war |
| x-qp-block-class / x-qp-vendor | Welche Art von Mauer es war und welcher Anti-Bot-Anbieter, wenn erkannt |

Eine Seite, die immer noch blockiert ist, kommt nie als stille 200 an. Wenn der Ursprung mit seinem eigenen Fehler (403, 429, 503) abgelehnt hat, wird dieser Status unverändert mit `x-qp-unlocker-blocked` gesetzt weitergeleitet. Wenn der Ursprung eine Herausforderungsseite mit einem 2xx servierte, verwandelt der Proxy sie in eine 502 und setzt den Code des Ursprungs in `x-qp-origin-status`. So deckt eine Überprüfung beide ab:

```python
class Blocked(Exception):
    pass

s = requests.Session()
s.proxies = {"http": PROXY, "https": PROXY}
s.verify = False  # or "qp-unlocker-ca.pem"

NEXT_STEP = {
    "js_challenge":  "a browser could not clear it; retry later in a pinned session",
    "captcha":       "interactive captcha; decide in your own code",
    "access_denied": "the site denied access; retry with a fresh session or test tier-mobile",
    "rate_limited":  "the site is rate limiting; slow down and retry later",
    "fingerprint":   "the client fingerprint was refused; retry with another profile",
    "geo":           "the content depends on location; set the country explicitly",
    "timeout":       "the target was too slow; raise x-qp-timeout or retry",
}

def unlock_get(url: str, session_id: str | None = None) -> requests.Response:
    headers = {"x-qp-session": session_id} if session_id else {}
    r = s.get(url, headers=headers, timeout=120)
    if "x-qp-unlocker-blocked" in r.headers:
        cls = r.headers.get("x-qp-block-class", "unknown")
        raise Blocked(
            f"{url}: HTTP {r.status_code}, class={cls}, "
            f"vendor={r.headers.get('x-qp-vendor')}, next: {NEXT_STEP.get(cls, 'inspect the body')}"
        )
    return r
```

## Schritt 5: die Node.js-Version (web unlocker API in JavaScript)

In Node nimmt `fetch` einen `dispatcher`. Verwenden Sie `ProxyAgent` von `undici` für den Forward-Proxy und importieren Sie `fetch` aus demselben Paket, damit die beiden Versionen übereinstimmen. Die [ProxyAgent-Dokumentation](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md) listet die hier verwendeten Optionen auf: `token` für den Proxy-Authorization-Wert und `requestTls` für die TLS-Einstellungen gegenüber dem Ziel.

```javascript
// unlock.mjs  (npm i undici)
import { readFileSync } from "node:fs";
import { fetch, ProxyAgent } from "undici";

const user = process.env.QP_UNLOCK_USER + "-country-us";
const pass = process.env.QP_UNLOCK_PASSWORD;

const dispatcher = new ProxyAgent({
  uri: "http://unlock.quantumproxies.io:9000",
  token: "Basic " + Buffer.from(user + ":" + pass).toString("base64"),
  requestTls: { rejectUnauthorized: false },
  // verified instead: requestTls: { ca: readFileSync("qp-unlocker-ca.pem") },
});

const url = "https://www.indeed.com/jobs?q=data+engineer&l=Austin%2C+TX";
const res = await fetch(url, { dispatcher, headers: { "x-qp-session": "indeed-001" } });

if (res.headers.get("x-qp-unlocker-blocked")) {
  console.error("blocked:", res.status, res.headers.get("x-qp-block-class"), res.headers.get("x-qp-vendor"));
} else {
  const html = await res.text();
  console.log(res.status, res.headers.get("x-qp-unlocker-attempts"), html.length);
}
```

Der REST-Endpunkt benötigt nichts über das in Node 18+ eingebaute `fetch` hinaus:

```javascript
const resp = await fetch("https://app.quantumproxies.io/api/v1/scraper/unlock", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.QP_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ url: "https://www.indeed.com/jobs?q=data+engineer&l=Austin%2C+TX", country: "us" }),
});
const { payload } = await resp.json();
console.log(payload.status, payload.blocked, payload.blockClass ?? "-", payload.attempts);
```

Bei axios ist das übliche Muster für HTTPS-Ziele hinter einem Proxy, einen Agenten von `https-proxy-agent` als `httpsAgent` zu übergeben und `proxy: false` zu setzen, oder den oben genannten REST-Endpunkt aufzurufen und das Proxy-Protokoll vollständig zu überspringen.

## Schritt 6: wann Sie den Unlocker nicht benötigen

Der Unlocker wird pro GB für jedes Byte abgerechnet, das er bewegt, einschließlich Wiederholungen und Browser-Seitenladevorgängen. Ihm Seiten zu senden, die eine einfache Anfrage problemlos abruft, verbrennt Guthaben für nichts. In unserem Lauf kamen diese ohne Hilfe zurück:

| Seite | Einfacher Rechenzentrum-Server | Einfacher Residential-Proxy | Web Unlocker |
| --- | --- | --- | --- |
| docs.python.org (urllib.request-Seite) | 200 | 200 | 200, 1,6 s |
| books.toscrape.com | 200 | 200 | 200, 1,9 s |
| news.ycombinator.com | 200 | 200 | 200, 4,1 s |
| en.wikipedia.org (Web scraping) | 200 | 200 | 200, 1,9 s |
| github.com (scrapy repository) | 200 | 200 | 200, 2,0 s |
| bbc.com (Technologie) | 302 Weiterleitung | 302 Weiterleitung | 200, 1,4 s |

Die BBC-Zeile ist keine Blockierung. Unser Testclient folgte keinen Weiterleitungen, und die 302 ist die Seite, die Sie zu einer anderen URL sendet. `requests` folgt standardmäßig Weiterleitungen und landet auf der Seite.

Das richtige Muster ist also zuerst einfach, Unlocker bei einer erkannten Blockierung. Die Erkennung erfordert Sorgfalt. Der Markerscan in unserem eigenen Test-Harness markierte die Wikipedia- und GitHub-Seiten als blockiert, weil ihre Bodies das Wort 'captcha' enthalten, obwohl beide die echte Seite mit einer 200 zurückgaben. Überprüfen Sie den Statuscode, den `cf-mitigated`-Header von Cloudflare und den Seitentitel, nicht den gesamten Body:

```python
from urllib.parse import urlsplit

BLOCK_STATUSES = {403, 429, 503}
BLOCK_TITLES = (
    "just a moment",                        # Cloudflare challenge
    "attention required",                   # Cloudflare block page
    "access denied",                        # Akamai and others
    "security check",
    "access to this page has been denied",  # PerimeterX
)
needs_unlocker: set[str] = set()            # domains that blocked plain requests

def looks_blocked(r: requests.Response) -> bool:
    if r.status_code in BLOCK_STATUSES:
        return True
    if r.headers.get("cf-mitigated") == "challenge":
        return True
    return any(t in title_of(r.text).lower() for t in BLOCK_TITLES)

def fetch(url: str, session_id: str | None = None) -> tuple[requests.Response, str]:
    host = urlsplit(url).hostname or ""
    if host not in needs_unlocker:
        try:
            r = requests.get(url, headers=HEADERS, timeout=20)
            if not looks_blocked(r):
                return r, "plain"
        except requests.RequestException:
            pass  # a reset or a timeout counts as a block too
        needs_unlocker.add(host)
    return unlock_get(url, session_id), "unlocker"   # from step 4; raises Blocked

for u in ("https://docs.python.org/3/library/urllib.request.html", URL):
    resp, route = fetch(u)
    print(route, resp.status_code, title_of(resp.text)[:60])
```

Der `except`-Zweig ist wichtig. Die Laptop-Kategorie von Best Buy gab unseren einfachen Clients nie eine HTTP-Antwort: Die Verbindung schlug sowohl vom Rechenzentrum-Server als auch vom Residential-Proxy fehl. Durch den Unlocker gab dieselbe URL beim ersten Versuch `200` in 6,3 Sekunden zurück. Ein Scraper, der nur Statuscodes überprüft, würde diesen nie eskalieren.

## Gemessene Ergebnisse: vier Seiten, die den Unlocker benötigten

Gemessen am 29. September 2026. Einfache Anfragen waren curl mit einem Chrome User-Agent, einmal von einem Rechenzentrum-Server in Frankfurt und einmal über einen Residential-Proxy mit US-Exit. Web Unlocker-Anfragen verwendeten die Residential-Stufe mit US-Exit. Zeiten sind Echtzeit für eine einzelne Anfrage.

| Seite | Einfacher Rechenzentrum-Server | Einfacher Residential-Proxy | Web Unlocker |
| --- | --- | --- | --- |
| Indeed (Job-Suche) | 403, 'Security Check'-Seite | 403, 'JavaScript und Cookies aktivieren, um fortzufahren' | 200, 1 Versuch, 2,6 s |
| Glassdoor (Unternehmensbewertungen) | 403, 'Security'-Seite mit Captcha | 403, 'JavaScript und Cookies aktivieren, um fortzufahren' | 200, 2 Versuche + Browser, 17,2 s |
| Walmart (Suche) | 307 Weiterleitung, keine Ergebnisseite | 307 Weiterleitung, keine Ergebnisseite | 200, 1 Versuch, 4,8 s |
| Best Buy (Laptop-Kategorie) | Verbindung fehlgeschlagen, keine Antwort | Verbindung fehlgeschlagen, keine Antwort | 200, 1 Versuch, 6,3 s |

Kurz gesagt: Indeed, Walmart und Best Buy bestanden beim ersten TLS-Versuch ohne Browser. Glassdoor benötigte den vollständigen Pfad, zwei TLS-Versuche und dann einen Headless-Browser, um die JavaScript-Herausforderung zu beantworten, weshalb es 17,2 Sekunden dauerte. Für Walmart haben wir nicht aufgezeichnet, wohin die 307 führte. Was wir sagen können, ist, dass keiner der einfachen Clients die Ergebnisseite erhielt und der Unlocker schon.

Wiederholte Anfragen an eine herausforderungs-geschützte Seite werden schneller, wenn Sie eine Sitzung fixieren. Senden Sie denselben `x-qp-session`-Wert oder behalten Sie dasselbe `-session-<id>` im Proxy-Benutzernamen, und das vom Browser erworbene Clearance-Cookie wird wiederverwendet. In einem Glassdoor-Test am 29. September 2026, mit der Sitzung im Benutzernamen fixiert und zwei separaten Verbindungen, dauerte die erste Anfrage 14,0 Sekunden durch den Browser und die zweite 1,4 Sekunden, mit `x-qp-clearance: hit`. Unser [Leitfaden zum Scraping von Indeed-Jobanzeigen](https://quantumproxies.io/blog/scrape-indeed-job-postings) behandelt, was Sie mit der Seite tun, sobald Sie sie haben.

![Die Blockprüfung nach dem Prinzip „zuerst einfach“ aus dem Tutorial: Eine looks_blocked-Funktion markiert eine Antwort anhand ihres Statuscodes 403, 429 oder 503, anhand des Headers cf-mitigated: challenge oder anhand des Titels einer Sperrseite, und erst dann wird die URL durch den Web Unlocker geschickt. Auf das Durchsuchen des gesamten Body wird verzichtet, weil es Wikipedia markiert hat.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1790750868/blog/generated/qp-unl-g1-diag2.png)
*Zuerst einfach, Unlocker bei einer erkannten Blockierung. Der Unlocker berechnet jedes Byte, das er bewegt, daher ist die günstigste Anfrage die, die ohne ihn funktioniert.*

Wenn Sie von einem 403 hierher gekommen sind, das nur außerhalb des Browsers auftritt, geht unser Erklärer zu [warum curl ein 403 erhält, wenn der Browser funktioniert](https://quantumproxies.io/blog/curl-403-but-browser-works) tiefer in die Diagnose ein. Für einen seitenweisen Blick darauf, welche Ebene Sie tatsächlich benötigen, siehe [web unlocker vs residential proxy, getestet](https://quantumproxies.io/blog/web-unlocker-vs-residential-proxy).

## Häufig gestellte Fragen

### Gibt es eine kostenlose Web Unlocker API?

Die Open-Source-Komponenten sind kostenlos: requests, curl_cffi für browserähnliches TLS und Playwright für einen echten Browser. Sie gut zu betreiben, ist die Arbeit, denn Sie benötigen auch saubere Exit-IPs und einen Browser für JavaScript-Herausforderungen. Auf QuantumProxies.io ist das Erstellen eines Kontos kostenlos, und der Unlocker-Verkehr wird pro GB von einem vorausbezahlten Guthaben abgerechnet, das Sie im Dashboard aufladen.

### Kann man Glassdoor oder Zillow mit Python scrapen?

In unserem Test am 29. September 2026 erhielten einfache Anfragen an eine Glassdoor-Bewertungsseite sowohl von einem Rechenzentrum-Server als auch über einen Residential-Proxy ein 403, und der Unlocker gab die Seite nach einer Browser-Eskalation zurück. Zillow blockierte den Rechenzentrum-Server, servierte die Seite jedoch über einen einfachen Residential-Proxy. Überprüfen Sie die Bedingungen jeder Seite, bevor Sie etwas sammeln.

### Kann Web Scraping erkannt werden?

Ja. Seiten bewerten den Netzwerktyp und die Geschichte der IP, den TLS-Handshake, die HTTP/2-Einstellungen, die Header-Reihenfolge und, auf Herausforderungsseiten, was JavaScript über den Browser berichtet. Eine einfache Python-Anfrage scheitert an mehreren dieser Punkte gleichzeitig. Deshalb hilft das Ändern nur des User-Agents selten, und warum der Unlocker die IP, den Fingerprint und, wenn nötig, den gesamten Client ändert.

### Muss ich ein Zertifikat installieren, um den Forward-Proxy zu verwenden?

Nur für HTTPS über den klassischen Forward-Proxy, da der Unlocker TLS beendet, um die Anfrage umzuschreiben. Entweder schalten Sie die Verifizierung für diese Sitzung aus (verify=False in Python, -k in curl) oder laden Sie das CA von /api/v1/scraper/unlock/ca mit Ihrem API-Schlüssel herunter und vertrauen Sie ihm. Der REST-Endpunkt benötigt überhaupt kein Zertifikat.

### Wie halte ich dieselbe IP über mehrere Anfragen hinweg?

Senden Sie denselben x-qp-session-Header-Wert bei jeder Anfrage über den Forward-Proxy, oder setzen Sie dasselbe -session-\<id> in den Proxy-Benutzernamen. Anrufe, die diese Sitzung teilen, verlassen denselben Exit, und ein vom Browser erworbenes Clearance-Cookie wird wiederverwendet. Am REST-Endpunkt übergeben Sie eine sessionId mit Rotation auf sticky gesetzt. Eine sticky-Sitzung kann von 3 bis 1.440 Minuten dauern.

Das gesamte Muster passt in einen Satz: einfach abrufen, eine Blockierung durch Status, Header und Titel erkennen, nur diese URLs durch den Unlocker senden und die x-qp-Header protokollieren, damit Sie wissen, was jede Seite Sie gekostet hat. Beginnen Sie mit der Residential-Stufe und behalten Sie die Mobile-Stufe für Ziele, die auch Residential-Bereiche ablehnen.

[Probieren Sie den Web Unlocker auf Residential-Exits aus](https://quantumproxies.io/web-unlocker/residential)
