← Alle Artikel

Sitzungspersistenz beim Web Scraping: Cookies Wiederverwenden fuer Schnelleres Scraping

Wenn dein Scraper fuer jede einzelne Seite einen Headless-Browser hochfaehrt, zahlst du bei jeder Anfrage den langsamsten moeglichen Weg. Einen echten Browser zu starten kostet Hunderte von Millisekunden bis zu einigen Sekunden, verbraucht Speicher und wiederholt immer wieder dieselbe Login- und Challenge-Arbeit.

Es gibt ein besseres Muster: waerme eine Sitzung einmal in einem Browser auf, erfasse die Cookies und uebergib sie fuer den Grossteil deiner Anfragen an einen schnellen HTTP-Client. Das ist Sitzungspersistenz, und es ist eine der wirkungsvollsten Optimierungen, die du an einer Scraping-Pipeline vornehmen kannst. Richtig gemacht senkt sie deine Kosten pro Anfrage um eine Groessenordnung und laesst deinen Traffic konsistenter wirken, nicht weniger.

Diese Anleitung erklaert, was eine Sitzung wirklich ist, wie man sie von einem Browser zu einem normalen HTTP-Client verschiebt, warum kurzlebige Cookies wie __cf_bm dich zum Erneuern zwingen und wie du das Ganze in der Produktion stabil haeltst.

Was eine “Sitzung” Wirklich Ist

Wenn Leute “eingeloggt bleiben” oder “die Sitzung am Leben halten” sagen, meinen sie meist die Cookies. Aber eine Sitzung ist mehr als ein Login-Token. Auf einer modernen Seite mit einer Anti-Bot-Schicht ist eine funktionierende Sitzung ein Buendel von Dingen, die konsistent bleiben muessen:

  • Authentifizierungs-Cookies. Das Token, das beweist, dass du eingeloggt bist (oft etwas wie access_token, session_id oder ein signiertes JWT in einem Cookie).
  • CSRF-Tokens. Mal in einem Cookie, mal in einem Header oder einem versteckten Formularfeld.
  • Bot-Management-Cookies. Diese vergisst man gern. Cloudflare setzt __cf_bm (ein kurzlebiges Bot-Management-Cookie, meist rund 30 Minuten gueltig) und nach einer Challenge cf_clearance. Andere Anbieter haben ihre eigenen Entsprechungen.
  • Eine konsistente Client-Identitaet. Derselbe User-Agent, dasselbe breite Header-Set, idealerweise dieselbe IP-Adresse und ein TLS-Fingerabdruck, der zu einem echten Browser passt.

Die Falle besteht darin, eine Sitzung als “nur das Login-Cookie” zu behandeln. Du kopierst das Auth-Cookie in requests, es funktioniert ein paar Minuten, dann liefert alles 403 zurueck oder leitet auf eine Challenge-Seite um. Das ist fast immer ein ablaufendes Bot-Management-Cookie oder ein TLS-Fingerabdruck-Missverhaeltnis, nicht dein sterbendes Login.

Das Hybride Muster: Im Browser Aufwaermen, Im HTTP-Client Ausfuehren

Die Kernidee ist eine Arbeitsteilung:

  1. Nutze einen echten (oder Headless-)Browser, um die Sitzung aufzubauen. Der Browser bewaeltigt JavaScript-Challenges, den Login-Ablauf und jede clientseitige Token-Erzeugung. Das ist der teure Teil, den du selten machst.
  2. Exportiere die Cookies. Zieh alle Cookies heraus, die der Browser gesammelt hat, nicht nur das Login-Cookie.
  3. Spiele mit einem schnellen HTTP-Client ab. Fuer die eigentlichen Datenseiten nutze einen leichtgewichtigen Client, der diese Cookies wiederverwendet. Kein Browser, keine JavaScript-Engine, nur HTTP.

Der Haken ist das Fingerprinting. Eine schlichte requests-Anfrage hat eine Python-TLS-Signatur, die Anti-Bot-Systeme sofort erkennen, sodass die muehsam erzeugten Cookies abgelehnt werden. Die Loesung ist ein HTTP-Client, der den TLS- und HTTP/2-Fingerabdruck eines Browsers imitiert. In Python macht curl_cffi genau das.

Schritt 1: Die Sitzung in Playwright Aufwaermen

from playwright.sync_api import sync_playwright

def warm_session(url: str) -> dict:
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context()
        page = context.new_page()

        # Lade die Seite, damit sie ihr JS ausfuehrt und ihre Cookies setzt.
        page.goto(url, wait_until="networkidle")

        # Falls es einen Login gibt, mach ihn hier, damit die Auth-Cookies gesetzt werden.
        # page.fill("#email", "..."); page.fill("#password", "...")
        # page.click("button[type=submit]"); page.wait_for_load_state("networkidle")

        cookies = context.cookies()
        user_agent = page.evaluate("() => navigator.userAgent")
        browser.close()

    # Flach zu einem name -> value Dict fuer den HTTP-Client.
    jar = {c["name"]: c["value"] for c in cookies}
    return {"cookies": jar, "user_agent": user_agent}

Beachte, dass du auch den User-Agent erfasst. Der HTTP-Client muss denselben senden, sonst wirkt die Sitzung inkonsistent.

Schritt 2: Mit curl_cffi Abspielen

from curl_cffi import requests as cffi

def fetch_with_session(url: str, session: dict) -> str:
    resp = cffi.get(
        url,
        cookies=session["cookies"],
        headers={"User-Agent": session["user_agent"]},
        impersonate="chrome",  # den TLS/HTTP2-Fingerabdruck eines echten Chrome nachahmen
        timeout=30,
    )
    resp.raise_for_status()
    return resp.text

Jetzt kannst du Hunderte solcher Aufrufe pro aufgewaermter Sitzung abfeuern. Jeder ist eine normale HTTP-Anfrage mit einem Fingerabdruck auf Browser-Niveau und einem vollstaendigen Cookie-Glas. Kein Browser-Overhead pro Seite.

Warum Du Erneuern Musst: Das Problem der Kurzlebigen Cookies

Hier fallen die meisten naiven Implementierungen auseinander. Manche Cookies sind langlebig (ein Login-Token kann Tage halten), aber die Bot-Management-Cookies sind bewusst kurzlebig. Cloudflares __cf_bm ist das klassische Beispiel: Es ist so ausgelegt, dass es in etwa 30 Minuten ablaeuft, damit eine erfasste Sitzung nicht ewig abgespielt werden kann.

Eine Sitzung ist also keine einmalige Erfassung. Sie ist etwas Lebendiges, das du nachfuellen musst. Die langlebigen Cookies (dein Login) bleiben gueltig; die kurzlebigen muessen neu gepraegt werden. Das saubere Modell lautet:

  • Bewahre die langlebigen Cookies (Auth) im Langzeitspeicher auf.
  • Oeffne regelmaessig erneut einen Browser mit diesen bereits injizierten langlebigen Cookies, lass die Seite dir frische kurzlebige Cookies aushaendigen und schiebe das aktualisierte Glas zurueck an deinen schnellen Client.

Die langlebigen Cookies vor der Navigation in einen frischen Browser-Kontext zu injizieren bedeutet, dass du jedes Mal den vollstaendigen Login ueberspringst. Du zahlst nur den billigen Schritt “neu laden und frische Tokens sammeln”.

def refresh_session(url: str, durable_cookies: list[dict]) -> dict:
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context()
        context.add_cookies(durable_cookies)  # die langlebigen Auth-Cookies injizieren
        page = context.new_page()
        page.goto(url, wait_until="networkidle")  # die Seite praegt frische kurzlebige Cookies
        cookies = context.cookies()
        browser.close()
    return {c["name"]: c["value"] for c in cookies}

Fuehre das mit einem Timer aus, der bequem kuerzer ist als die kuerzeste Cookie-Lebensdauer. Wenn __cf_bm etwa 30 Minuten haelt, haelt dich ein Erneuern alle 10 bis 15 Minuten sicher innerhalb des Fensters.

Eine Abgelaufene Sitzung Erkennen

Verlass dich nicht nur auf die Uhr. Seiten aendern TTLs, und eine Sitzung kann frueh sterben. Fuege eine billige Gesundheitspruefung hinzu, damit dein Client weiss, wann er ein Erneuern ausloesen soll, statt still Muell zu scrapen.

Signale, dass eine Sitzung abgelaufen ist:

  • Ein 403 oder 429, wo du zuvor 200 bekamst.
  • Eine Weiterleitung zu /login, /challenge oder einer Cloudflare-Zwischenseite.
  • Eine 200-Antwort, deren Body die Challenge-Seite ist, nicht deine Daten (ein HTTP-200-Soft-Block).
  • Dein erwarteter CSS-Selektor oder JSON-Schluessel fehlt ploetzlich.
def looks_blocked(resp) -> bool:
    if resp.status_code in (401, 403, 429):
        return True
    body = resp.text.lower()
    markers = ["just a moment", "verify you are human", "cf-challenge", "enable javascript"]
    return any(m in body for m in markers)

Wenn looks_blocked ausloest, stelle die URL zurueck in die Warteschlange, loese ein Erneuern aus und versuche es erneut. Behandle eine einzelne Ablauf-Erkennung als Ausloeser, nicht als Fehler.

Produktionsdetails, die Wirklich Zaehlen

Ein paar Dinge trennen eine Demo von einer Pipeline, die wochenlang laeuft:

  • Halte die IP konsistent mit der, auf der die Cookies gepraegt wurden. Anti-Bot-Systeme binden Sitzungen locker an das Netzwerk, in dem sie erstellt wurden. Wenn du eine Sitzung auf einer IP aufwaermst und sie von einer voellig anderen abspielst, provozierst du eine Challenge. Wo du Proxys nutzt, halte eine Sitzung fuer ihre Lebensdauer an einen stabilen Ausgang gebunden.
  • Gleiche das gesamte Header-Profil ab, nicht nur den User-Agent. Header-Reihenfolge, Accept-Language, die Sec-Ch-Ua-Hinweise und Accept-Encoding sollten wie der Browser aussehen, mit dem du aufgewaermt hast. Das impersonate von curl_cffi erledigt das meiste davon fuer dich.
  • Ueberlaste nicht eine einzelne Sitzung. Eine einzelne Browser-Sitzung, die Tausende Anfragen pro Minute abfeuert, ist selbst ein Verraeter. Verteile die Last auf mehrere aufgewaermte Sitzungen und rotiere zwischen ihnen.
  • Persistiere Cookies auf die Festplatte oder in eine kleine Datenbank. Wenn dein Prozess neu startet, willst du nicht jeden Login wiederholen. Speichere die langlebigen Cookies, lade sie neu und erneuere.
  • Rotiere Identitaeten, wenn du mehrere Konten fuehrst. Halte die langlebigen Cookies jedes Kontos getrennt und waehle pro Charge eines zufaellig aus. Das verteilt jegliche Rate-Limits pro Konto, aendert aber nichts an der zugrunde liegenden Reputation deiner IP.

Dieser letzte Punkt verdient Ehrlichkeit. Sitzungswiederverwendung loest Geschwindigkeit und Throttling pro Konto. Sie repariert keine schlechte IP. Wenn deine Ausgangsadressen bereits markiert sind, rettet dich keine Cookie-Hygiene, und genau da verdient sich eine verwaltete Entsperr-Schicht ihren Platz.

Haeufig Gestellte Fragen

Brauche ich noch einen Browser, wenn ich Sitzungspersistenz nutze? Ja, aber selten. Der Browser baut die Sitzung auf und erneuert sie; der schnelle HTTP-Client erledigt den Grossteil des Abrufs. Du gehst von einem Browser-Start pro Seite zu einem alle 10 bis 30 Minuten ueber.

Warum funktioniert mein kopiertes Cookie im Browser, aber nicht in requests? Fast immer ein Fingerabdruck-Missverhaeltnis. Blankes requests hat eine Python-TLS-Signatur, die Anti-Bot-Systeme sofort erkennen. Nutze curl_cffi mit impersonate oder einen anderen Client, der einen Browser-Fingerabdruck nachahmt, und sende denselben User-Agent.

Was ist das __cf_bm-Cookie und warum laeuft es staendig ab? __cf_bm ist Cloudflares Bot-Management-Cookie. Es ist absichtlich kurzlebig (etwa 30 Minuten), damit erfasste Sitzungen nicht unbegrenzt abgespielt werden koennen. Erneuere deine Sitzung innerhalb dieses Fensters.

Kann ich eine Sitzung ueber viele Maschinen teilen? Kannst du, aber halte sie hinter derselben oder einer aehnlichen Ausgangs-IP und ueberschreite keine vernuenftigen Anfrageraten. Eine Sitzung gleichzeitig ueber viele IPs zu verteilen ist ein haeufiger Weg, sie zu entwerten.

Zum Abschluss

Bei Sitzungspersistenz geht es vor allem darum, zu respektieren, wie Sitzungen wirklich funktionieren: ein Buendel aus langlebigen und kurzlebigen Cookies, gebunden an eine konsistente Client-Identitaet und ein Netzwerk. Waerme einmal in einem Browser auf, spiele mit einem Client mit abgeglichenem Fingerabdruck ab, erneuere vor Ablauf der kurzlebigen Cookies und achte auf Soft-Blocks, um rechtzeitig neu aufzuwaermen.

Wenn du die Browser-Flotte, den Cookie-Erneuerer und die Proxy-Rotation lieber nicht selbst betreiben willst, ist genau das, was ScrapeUnblocker hinter einem einzigen API-Aufruf erledigt: Es verwaltet die Sitzung, den Fingerabdruck und die Entsperrung, sodass du einfach eine URL anfragst und die Seite zurueckbekommst. Du kannst die Entwicklerdokumentation lesen, um zu sehen, wie es in eine bestehende Pipeline passt. So oder so bleibt das Prinzip gleich: erledige die teure Arbeit einmal und verwende sie wieder.

ScrapeUnblocker kostenlos testen

Über 95 % Erfolgsquote · ab 0,55 € pro 1.000 Aufrufe · 500 kostenlose Anfragen bei der Registrierung.

Kostenlos testen → Preise ansehen