JavaScript-Rendering beim Web-Scraping: wann du es brauchst und was es kostet

Wie du erkennst, ob eine Seite einen echten Browser statt eines einfachen Fetch braucht, warum Rendering überall mehr kostet, und die Credit-Multiplikatoren, August 2026.

Ein einfacher HTTP-Fetch liefert dir das HTML, das der Server geschickt hat. Zunehmend ist das nicht die Seite, die ein Besucher sieht. Die Lücke zwischen beidem ist JavaScript-Rendering, und sie ist der größte einzelne Grund, warum ein Scraper, der auf einer Website funktioniert, auf der nächsten stillschweigend versagt.

Wie erkennst du, ob eine Seite Rendering braucht?

Zwei Prüfungen, beide schnell, bevor du Scraping-Code schreibst:

View-Source mit dem DOM vergleichen. Im Browser zeigt dir View-Source (Strg+U oder Cmd+Option+U) genau das, was ein einfacher Fetch bekommen würde: das rohe HTML vom Server, bevor irgendein Skript läuft. Öffne jetzt die Dev-Tools und schau dir das Elements-Panel an, das das DOM nach der JavaScript-Ausführung zeigt. Wenn der Inhalt, den du willst, Preise, Listings, Bewertungen, im Elements-Panel vorhanden ist, aber im View-Source fehlt oder durch ein Loading-Skelett ersetzt ist, baut die Seite diesen Inhalt clientseitig auf.

Selbst abrufen, ohne Browser. Dieselbe Prüfung aus dem Code, keine Dev-Tools nötig:

import requests

resp = requests.get("https://example.com/products", timeout=30)
print(len(resp.text))
print("add-to-cart" in resp.text)  # gegen einen String tauschen, von dem du weißt, dass er im echten Inhalt steht

Wenn ein Marker-String, den du auf der Live-Seite sehen kannst, in resp.text fehlt, bekommst du mit einem einfachen Fetch den Inhalt nicht, und du brauchst etwas, das JavaScript ausführt, bevor es die Seite liest.

Ein kurzer Grund, warum das häufiger passiert als früher: Moderne Frameworks (React, Vue, Svelte und Verwandte) liefern eine fast leere HTML-Hülle aus und bauen die eigentliche Seite im Browser. Das ist eine bewusste Architekturentscheidung der Website, keine Anti-Scraping-Maßnahme, führt für dich aber trotzdem zum gleichen Ergebnis.

Warum kostet Rendering überall mehr?

Ein einfacher Fetch ist ein Socket, ein Request, eine Antwort. Rendering bedeutet, etwas nahe an einem vollständigen Browser hochzufahren: das DOM laden, Skripte ausführen, warten, bis Netzwerkaufrufe sich beruhigen, manchmal scrollen, um Lazy-Loaded-Inhalt auszulösen. Das ist echte CPU und echter Speicher pro Seite, offen gehalten für die Dauer des Renderns, nicht die Mikrosekunden, die ein statischer Fetch braucht.

Diese Kostenstruktur ist nicht spezifisch für einen bestimmten Anbieter. Jeder Anbieter, der sowohl einen statischen als auch einen gerenderten Fetch anbietet, bepreist den gerenderten höher, weil er in großem Maßstab tatsächlich teurere Infrastruktur ist: ein Pool echter Browserprozesse statt eines Connection-Pools. Wenn ein Angebot für gerendertes Scraping genauso teuer wie statisches aussieht, schau genau hin, was „gerendert” in ihren Docs bedeutet.

Was Rendering bei FastAF kostet

/scrape hat vier Preisstufen, und der Multiplikator folgt den tatsächlichen Kosten dessen, was hinter dem Request läuft:

Modus Parameter Credits
Statischer Fetch (Standard) 1
JS-Rendering dynamic=true 5
Premium-Proxys, kein Rendering premium=true 10
JS-Rendering + Premium-Proxys dynamic=true&premium=true 25

Statisch ist ein 5-facher Sprung, um Rendering hinzuzufügen, und ein 25-facher Sprung, um sowohl Rendering als auch Premium-Proxy-Routing draufzupacken. Das sind die echten Kosten der zusätzlichen Infrastruktur, kein willkürlicher Aufschlag, weshalb es sich lohnt zu prüfen, ob du Rendering überhaupt brauchst, bevor du es standardmäßig einsetzt.

Die Strategie: erst statisch versuchen, nur bei Fehlschlag eskalieren

Die meisten Scraping-Jobs mischen Seiten, die Rendering brauchen, mit solchen, die es nicht brauchen, sogar innerhalb derselben Website. Bei jedem Request dynamic=true zu bezahlen, obwohl nur manche Seiten es brauchen, ist der häufigste Weg, bei diesem Endpoint zu viel auszugeben:

import requests

API_KEY = "faf_live_..."  # dein FastAF-Key

def scrape(url, dynamic=False, premium=False, wait=None):
    params = {"url": url}
    if dynamic:
        params["dynamic"] = "true"
    if premium:
        params["premium"] = "true"
    if wait:
        params["wait"] = wait
    resp = requests.get(
        "https://api.fastaf.co/v1/scrape",
        params=params,
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=90,
    )
    resp.raise_for_status()
    return resp.text

def scrape_smart(url, marker):
    html = scrape(url)
    if marker in html:
        return html  # statisch hat gereicht, 1 Credit ausgegeben

    html = scrape(url, dynamic=True)  # eskalieren, 5 Credits ausgegeben
    return html

marker ist ein String, von dem du weißt, dass er im echten Inhalt vorkommt, ein Produkttitel, ein Preisformat, alles, was in einer Hüllen-Seite fehlen würde. Wenn der statische Fetch ihn schon hat, hast du auf dieser URL 4 Credits gespart. Wenn nicht, eskalierst du einmal, nicht auf gut Glück.

Greif separat zu premium=true: Es geht um Proxy-Qualität und das Umgehen IP-basierter Blocks, nicht um JavaScript. Eine Website kann eins von beiden, beides oder keins brauchen. wait (Millisekunden) lohnt sich, explizit bei dynamic=true-Requests zu setzen, für Seiten, die Inhalt laden, nachdem ein API-Aufruf abgeschlossen ist, statt anzunehmen, dass die Standardwartezeit reicht.

Kurz zusammengefasst

Prüf View-Source gegen das gerenderte DOM, oder ruf die Seite selbst ab, bevor du annimmst, du brauchst einen Browser. Statisch ist 1 Credit, Rendering ist 5, Premium-Proxys sind 10, beides zusammen ist 25: die Multiplikatoren existieren, weil echte Browser-Infrastruktur im Betrieb tatsächlich mehr kostet. Versuch zuerst statisch und eskalier nur bei den URLs zu dynamic=true, bei denen der Marker-Inhalt tatsächlich fehlt, dann zahlst du den Rendering-Aufschlag nur dort, wo er sich lohnt.