Eine Website kann sich ändern, ohne dass ein Besucher etwas davon bemerkt. Ein aktualisierter Kommentarzähler oder ein Tracking-Attribut verändert den HTML-Hash, während ein neues Hero-Bild das Markup weitgehend unberührt lassen kann. Keiner der beiden Fälle sagt einem Monitoring-System, ob sich ein wichtiges Element der Landingpage tatsächlich geändert hat.

Um zu messen, was Besucher sehen, haben wir einen Python-Monitor gebaut, der gerenderte Seiten mit Crawlbase aufnimmt, Screenshots mit dem Structural Similarity Index (SSIM) vergleicht und ein Vision-Modell nur dann um eine Beschreibung des Unterschieds bittet, wenn eine bildbasierte Schwelle überschritten wird. Er behält das HTML aus demselben Crawl zur Gegenprüfung, schreibt lokale Alerts und pflegt eine Baseline für jede Kombination aus URL und Gerät.

Der Code liegt in ScraperHub/visual-change-detection-with-screenshots-and-vision-models, mit einem Checkpoint pro Stufe unter steps/ und dem vollständigen Monitor unter final/, dazu Tests, Konfiguration und Beispiele für das Scheduling. Die Zahlen unten stammen aus einem kleinen Live-Lauf gegen Hacker News und Wikipedia, nicht aus einem synthetischen Benchmark.

Die Kurzfassung
  • Mit der Crawling API ein ganzseitiges JPEG aufnehmen und sofort herunterladen, zusammen mit dem HTML aus derselben Antwort; zu einem Screenshot wird das HTML nicht gespeichert.
  • Beide Screenshots auf eine gemeinsame Breite normalisieren und dann mit SSIM und dem Anteil der Änderungsfläche bewerten. Überschreitet einer der beiden Scores seine Schwelle, öffnet sich das Gate für genau einen Aufruf des Vision-Modells.
  • Den Absatz des Modells als Erklärungsvorschlag behandeln. Die Belege sind die Screenshots, die Heatmap und das gespeicherte HTML.
Ein Lauf pro URL und Gerät: aufnehmen, JPEG und HTML sichern, gegen die Baseline bewerten und das Vision-Modell nur aufrufen, wenn sich das Gate öffnet.

Warum HTML-Hashes nicht verraten, was sich visuell geändert hat

Bei zwei Desktop-Crawls von Hacker News änderte sich das HTML von 34.626 auf 34.508 Bytes und die SHA-256-Präfixe unterschieden sich: 45b9d53f52b3 gegenüber efc0c606f53b. Auch der Python-Artikel der Wikipedia änderte sich auf Markup-Ebene, von 1.309.531 auf 1.310.770 Bytes, mit unterschiedlichen Hashes. Dennoch blieb das extrahierte h1 von Wikipedia unverändert: Python (programming language).

Ein Hash beantwortet, ob zwei Bytefolgen übereinstimmen. Er kann eine rotierte Nonce nicht von einem geänderten Angebot unterscheiden und misst weder Layout noch Pixel. Umgekehrt kann sich ein Bild ändern, ohne dass sich die Struktur des HTML erkennbar ändert. Für das Monitoring von Landingpages lautet die nützliche Frage deshalb nicht Hat sich das Dokument geändert? sondern Was hat sich in der gerenderten Seite geändert, und lohnt es sich, dem nachzugehen?

Testziele waren die Startseite von Hacker News auf Desktop und Mobil sowie der Python-Artikel der Wikipedia auf Desktop. Jede Kombination aus URL und Gerät erhält eine eigene Screenshot-Baseline.

JavaScript-gerenderte Screenshots mit Crawlbase aufnehmen

Der Monitor nutzt die Crawling API mit einem JavaScript token. Jede Aufnahme verwendet screenshot=true, store=true und format=json; Scrollen und eine Wartezeit lassen nachgeladene Inhalte erscheinen, bevor der Screenshot entsteht. Der Capture-Schritt baut die Parameter als Strings auf, sodass die URL-Kodierung den Wert true sendet und nicht Pythons True:

python
# steps/02-capture/capture.py
def build_options(
    device: str,
    page_wait: int,
    scroll_interval: int,
    css_click_selector: str = "",
) -> dict[str, str]:
    """Query params for one rendered JPEG. Strings, so urlencode sends true rather than True."""
    options = {
        "screenshot": "true",
        "store": "true",
        "format": "json",
        "device": device,
        "scroll": "true",
        "scroll_interval": str(scroll_interval),
        "page_wait": str(page_wait),
    }
    selector = with_body_fallback(css_click_selector)
    if selector:
        options["css_click_selector"] = selector
    return options

In diesem Lauf fügte page_wait=2000 nach dem Laden zwei Sekunden hinzu. scroll_interval=10 ist der kleinste Wert, den die API akzeptiert, und keine Zeitgrenze: Die API macht daraus bis zu drei Scroll-Durchgänge bis zum Seitenende und wartet in jedem Durchgang bis zu 40 Sekunden, ob die Seite wächst. Eine Seite, die nie wächst, wie die Startseite von Hacker News, verbringt trotzdem etwa 43 Sekunden im Scroll-Schritt. Der optionale Parameter country wurde weggelassen, das Routing erfolgte also automatisch.

Ein css_click_selector kann vor der Aufnahme ein Banner schließen. Für das Wikipedia-Ziel sendet der Monitor .mw-cookiebanner-dismiss in der Form .mw-cookiebanner-dismiss,body, denn ohne Scrollen lässt ein nicht passender Selektor den Request mit cb_status 595 scheitern, und der Fallback ,body passt immer. Mit scroll=true, das dieser Monitor immer sendet, klickt die API stattdessen innerhalb ihrer Scroll-Schleife und überspringt ein fehlendes Element einfach. Dieser Pfad akzeptiert nur eine Selektorliste, bleiben Sie beim Scrollen also bei einem einzelnen Selektor statt einer per | verketteten Folge von Klicks.

Bei der Crawling API liefert screenshot=true standardmäßig ein ganzseitiges JPEG zurück. Mit mode=viewport, width und height wird diese ganzseitige Aufnahme auf genau diese Maße skaliert und zugeschnitten, standardmäßig ab der oberen rechten Ecke; ohne mode=viewport werden sie ignoriert. Die separate Screenshots API nimmt keine neuen Anmeldungen mehr an, deshalb bleibt diese Implementierung bei der Crawling API. Der Crawlbase Web MCP Server bietet zudem ein Tool crawl_screenshot für interaktive Aufnahmen, ein geplanter Monitor braucht aber eine eigene, wiederholbare Capture-Schleife.

Der Crawl bringt die Seite in Form, bevor das JPEG entsteht: Gerät, Scrollen, ein Banner-Klick und eine Wartezeit gehen hinein; zurück kommen eine temporäre Screenshot-URL und ihre Request-ID.

Der erste Versuch bei Hacker News lief in einen Client-Timeout von 120 Sekunden, und ein zusätzlicher Scroll-Versuch lieferte HTTP 500. Die erfolgreichen Läufe nutzten 240 Sekunden, eine Client-Einstellung, die Spielraum lässt, und keine Vorgabe, dass jede Seite vier Minuten lang rendert. Scrollen verändert auch die Kosten: Ein scrollender Request wird für die ersten 8 Sekunden als ein JavaScript-Request abgerechnet und für jede weiteren 5 Sekunden als ein weiterer, wie die Rendering-Parameter erklären. Bei rund 43 Sekunden Scrollen wird die Aufnahme einer Seite, die nie wächst, als etwa acht JavaScript-Requests abgerechnet. Scrollen Sie also nur, wenn der Inhalt, den Sie vergleichen, unterhalb des sichtbaren Bereichs nachlädt.

Sechs erfolgreiche Aufnahmen lieferten cb_status 200, doch ihre Abmessungen schwankten stark:

Aufnahme Screenshot-Größe JPEG-Bytes
Hacker News Desktop, Baseline 3840×2144 215.392
Hacker News Desktop, Vergleich 1939×1249 199.382
Hacker News Mobil, Baseline 375×1777 175.304
Hacker News Mobil, Vergleich 1080×2324 159.983
Wikipedia Desktop, Baseline 1680×1050 198.864
Wikipedia Desktop, Vergleich 2560×1080 215.711

Gerenderte Requests nutzen kein festes Browserfenster, daher kann sich die Breite einer ganzseitigen Aufnahme von Crawl zu Crawl ändern, selbst beim selben Gerät. Diese Schwankung wird zur wichtigsten Einschränkung, wenn wir unten die Bildunterschiede auswerten.

Das JPEG herunterladen, bevor seine URL abläuft

Mit format=json, dem JSON-Antwortformat, enthält die Antwort das Feld screenshot_url im JSON-Body (beim HTML-Antwortformat kommt es stattdessen als Header); die Antwortdokumentation beschreibt beides. Crawlbase dokumentiert den Link als temporär, und er enthält das Token Ihres Kontos. Laden Sie das JPEG also sofort herunter, und protokollieren oder teilen Sie die URL selbst nie.

Der Monitor speichert das JPEG sofort unter shots/{url_hash}/{device}/{timestamp}.jpg, prüft die JPEG-Signatur FF D8, schreibt zunächst in eine temporäre Datei .part und ersetzt erst dann das Ziel. Außerdem legt er das HTML derselben Antwort neben dem Bild als Datei mit der Endung .html ab, damit die Belege auf der Festplatte bleiben. Bei diesen Antworten stand die Request-ID im Query-Parameter rid der Screenshot-URL:

python
# steps/02-capture/capture.py
def rid_from_screenshot_url(url: str) -> str:
    if not url:
        return ""
    values = parse_qs(urlparse(url).query).get("rid") or []
    return values[0] if values else ""

Der erste erfolgreiche Desktop-Screenshot von Hacker News trug die rid 907337a6a19e932cabde4165, und seine URL unter /storage lieferte ein JPEG. Das ist so gewollt: Bei einem Screenshot-Request legt Cloud Storage das Bild unter der rid des Requests ab und speichert das HTML nicht, ob mit oder ohne store=true. Das Setzen von store=true behält das JPEG als gespeicherte Seite und verursacht die Speichergebühr; der Monitor ist nicht darauf angewiesen, denn er liest das lokal gespeicherte HTML.

Die Screenshots normalisieren, dann SSIM berechnen

SSIM vergleicht einander entsprechende Bildbereiche, daher brauchen beide Eingaben dieselben Abmessungen. Der Normalisierungsschritt skaliert jeden Screenshot mit Lanczos-Resampling auf 1280 Pixel Breite und beschneidet dann beide von oben auf ihre kürzere gemeinsame Höhe:

python
# steps/03-normalize/normalize.py
shared = min(fitted_before.height, fitted_after.height)
if shared < 1:
    raise ValueError("normalized height is empty")
box = (0, 0, width, shared)

Damit werden die Arrays vergleichbar, die Layouts aber nicht gleichwertig. Die mobilen Aufnahmen von Hacker News etwa werden auf ungefähr 1280×6065 und 1280×2754 skaliert. SSIM misst nur den gemeinsamen oberen Bereich, während das Höhendelta von 3.311 Pixeln separat erfasst wird. Hat sich zwischen den Aufnahmen ein responsiver Breakpoint geändert, vermischt der Score Layoutänderungen mit Inhaltsänderungen.

Der Vergleichsschritt wandelt beide Bilder in Graustufen um und berechnet structural_similarity mit data_range=255 und einem Fenster von sieben Pixeln. OpenCV berechnet die absolute Graustufendifferenz, und Pixel, die sich um mehr als 24 Intensitätsstufen unterscheiden, zählen zum Anteil der Änderungsfläche. Konturen werden zu Bounding Boxes (die zwölf größten, Boxen unter 64 Quadratpixeln werden ignoriert), und die Heatmap färbt geänderte Pixel rot ein und umrandet die Boxen. Der Vergleichslauf ergab:

Ziel SSIM Änderungsfläche Normiertes Höhendelta
Hacker News Desktop 0.7934 8.27% 110 px
Hacker News Mobil 0.5468 24.50% 3.311 px
Wikipedia Desktop 0.5694 30.99% 260 px

Ein identisches Testbild mit 80×80 Pixeln erreichte mindestens 0.99 SSIM bei null Änderungsfläche. Alle drei Live-Paare lagen deutlich weiter auseinander, doch die Zahlen allein können ein geändertes Hero nicht von einem geänderten Preisblock unterscheiden. Die Screenshots waren nicht einheitlich gerahmt, was die Schwankung der Aufnahmen zu einem Störfaktor macht.

Das Vision-Modell mit günstigen Bild-Scores absichern

Ein Vision-Modell muss nicht jede Aufnahme lesen. Der Monitor entscheidet zuerst, ob die SSIM-Differenz oder der Anteil der Änderungsfläche groß genug für eine Untersuchung ist, und das Gate ist bewusst klein gehalten:

python
# steps/05-gate/gate.py
def crosses(ssim: float, changed_area: float, ssim_delta: float, area_delta: float) -> bool:
    return (1.0 - ssim) >= ssim_delta or changed_area >= area_delta

Die Beispielkonfiguration, final/targets.example.toml, setzt ssim_delta=0.04 und area_delta=0.03. Jede der beiden Bedingungen öffnet das Gate: eine strukturelle Differenz von mindestens 0.04 oder geänderte Pixel auf mindestens 3% der verglichenen Fläche. Das sind Startschwellen aus der Implementierung und ihren Tests, keine Schwellen, die über viele ruhige Produktionsläufe validiert wurden.

Zwei günstige, deterministische Scores entscheiden, ob überhaupt ein Modellaufruf stattfindet. Es genügt, wenn einer davon seine Schwelle überschreitet.

Jedes Live-Paar überschritt beide Schwellen, was nicht heißt, dass sich jede Seite bedeutsam geändert hat. Auch ein Karussell, eine rotierende Anzeige, eine Uhr oder ein Sprung in der Aufnahmebreite können das Gate öffnen. Kalibrieren Sie die Schwellen in Produktion an wiederholten Aufnahmen unter stabilen Bedingungen, und maskieren Sie bekannte dynamische Bereiche, wo es möglich ist.

Crawlbase Crawling API

Rendern Sie eine Seite in einem echten Browser und erhalten Sie einen ganzseitigen Screenshot samt HTML aus demselben Crawl zurück, bereit zum Diffen. Fehlgeschlagene Requests werden nicht berechnet. Starten Sie mit bis zu 5.000 kostenlosen Requests, ohne Karte.

Ein Vision-Modell fragen, was sich geändert hat, und seine Antwort prüfen

Öffnet sich das Gate, schickt der Erklärungsschritt den früheren und den späteren Screenshot an gpt-4o. Jedes Bild wird auf eine maximale Kantenlänge von 1280 Pixeln verkleinert und als JPEG mit Qualität 70 neu kodiert; die Übermittlung erfolgt mit detail="low". Der Prompt verlangt einen sachlichen Absatz, der sich auf sichtbare Unterschiede beschränkt, sowie ein Label: pricing, hero, banner oder other.

Der Verifikationslauf nutzte --max-vision-calls 1, sodass nur der Desktop-Vergleich von Hacker News kommentiert wurde; die mobilen und die Wikipedia-Paare lieferten trotzdem Scores und Alerts. Das Modell lieferte das Label other, doch sein Absatz erwähnte Story-Titel und ein YC-Batch-Jahr, die in keinem der beiden Screenshots zu sehen waren. Diesen Fehlermodus sieht man besser früh: Eine plausible Erklärung ist nicht unbedingt eine getreue Beschreibung der Pixel.

Der Parser musste außerdem mit LABEL: other umgehen, das am Ende eines Satzes angehängt war statt in einer eigenen Zeile zu stehen. Nach dem Parsen behält der Alert den Absatz des Modells unverändert bei, nur ohne das Label. SSIM, die Heatmap und die rohen Screenshots bleiben die primären Belege; der Absatz ist eine zu prüfende Interpretation, kein verifiziertes Änderungsprotokoll.

Lautet das Label pricing, hero oder banner, kann der Monitor unterstützenden Text aus dem HTML extrahieren, das bei derselben Aufnahme gespeichert wurde:

python
# steps/08-monitor/monitor.py
if vision and needs_html(label):
    extracted = storage_fn(
        token,
        shot.rid,
        target.extract_selector,
        label,
        timeout=settings.timeout,
        html_path=shot.html_path,
    )

Trotz des Namens storage_fn liest die Standardimplementierung _extract_saved die Datei html_path lokal ein. Ein konfigurierter Selektor (ein Tag, #id oder .class) kann ein Element herausziehen, etwa Wikipedias unverändertes h1; ohne Selektor sucht die Preisextraktion nach einem Währungsbetrag, bevor sie auf den Titel zurückfällt. Das liefert Kontext, beweist mit einer einfachen Extraktion aber nicht, dass das Modell die Änderung richtig erkannt hat. In diesem Lauf war das einzige Label other, also lief der HTML-Zweig nicht.

Alerts speichern, Baselines rotieren und den Monitor planen

Jede Überschreitung erzeugt einen JSON-Alert mit URL, Gerät, SSIM, Anteil der Änderungsfläche, rid, Heatmap-Pfad, Label und einer gegebenenfalls generierten Erklärung. Die PNG-Heatmap bleibt auf der Festplatte. Ist SLACK_WEBHOOK_URL gesetzt, postet der Notifier eine Textzusammenfassung; das PNG lädt er nicht hoch.

Der Test erzeugte drei JSON-Alerts, einen pro Vergleich, bei nicht gesetztem Slack-Webhook. Der Baseline-Lauf dauerte 173 Sekunden und der Vergleichslauf 391 Sekunden. SQLite verzeichnete sechs Läufe: drei initiale Baselines und drei Vergleiche. Nur der Desktop-Vergleich hatte ein vom Modell erzeugtes Label samt Absatz.

Der SQLite-Baseline-Manager, final/baselines.py, legt eine Baseline pro URL und Gerät in der Tabelle baselines ab; runs und alerts führen die Historie. Mit rotate_after_n=5, also nach fünf Vergleichen (ruhige eingeschlossen), wird der neueste Screenshot zur Baseline. Wird ein Alert mit --ack <id> bestätigt, rotiert die Baseline sofort auf den Screenshot dieses Alerts, sodass eine geprüfte Änderung zur neuen Referenz wird.

Die Baseline wandert nur gewollt: nach einem bestätigten Alert oder nach der konfigurierten Zahl verglichener Läufe.

Zum Ausprobieren klonen Sie das Repository, installieren die Python-Abhängigkeiten, kopieren final/.env.example nach final/.env und setzen CRAWLBASE_JS_TOKEN. Setzen Sie OPENAI_API_KEY für Modellbeschreibungen, und lassen Sie SLACK_WEBHOOK_URL leer, wenn Sie nur lokale Alerts möchten. Im Root des Repositorys:

bash
python -m pip install -r requirements.txt
python -m pytest final
python final/monitor.py --once

Planen Sie ihn per cron ein und starten Sie den Monitor mit --once statt mit einem dauerhaft laufenden Prozess. Pfade in targets.example.toml werden relativ zu dieser Datei aufgelöst.

Was der Live-Lauf lehrt

Die Pipeline nahm sechs Screenshots auf, erzeugte drei Vergleiche samt Heatmaps, ließ einen einzigen Vision-Request durch das Gate und schrieb drei lokale Alerts. Sie hat außerdem zwei Probleme offengelegt, die man beheben sollte, bevor man denselben Workflow für Wettbewerber-Monitoring oder visuelle Regressionstests einsetzt.

Erstens: erst das Aufnahmerechteck fixieren, dann die Schwellen abstimmen. Gerätelabels allein liefern keine stabilen Screenshot-Breiten, weil das Render-Fenster variiert. mode=viewport mit festen Werten für width und height liefert feste Ausgabemaße, doch die Seite wird weiterhin mit der Fensterbreite des Renderers gelayoutet. Prüfen Sie daher das Layout über wiederholte Aufnahmen hinweg, und vergleichen Sie beim Full-Page-Monitoring zusätzlich Breite, Skalierung und Inhaltshöhe. Halten Sie Wartezeiten, Locale und Banner-Verhalten konsistent, und vergleichen Sie gegebenenfalls ausgewählte Bereiche, wenn die ganze Seite fremde dynamische Inhalte enthält.

Zweitens: KI-Kommentare als Erklärungsvorschlag behandeln. Der einzige Vision-Call beschrieb Details, die sich in den Screenshots nicht bestätigen ließen. Wenn ein Alert wichtig ist, prüfen Sie das Vorher-Nachher-Paar und die Heatmap, und gleichen Sie Text- oder Preisänderungen mit dem gespeicherten HTML ab. Übernehmen Sie einen generierten Absatz nicht direkt in ein verbindliches Audit-Protokoll.

Mit diesen Kontrollen trägt der Workflow das Monitoring von Wettbewerber-Landingpages, visuelle Regressionstests nach einem Deployment und Vergleiche derselben Landingpage über Länder hinweg, mithilfe des optionalen Parameters country von Crawlbase für das Routing. Jeder Anwendungsfall profitiert von einer eigenen stabilen Baseline und auf die Seite kalibrierten Schwellen.

Fazit

Ein nützlicher visueller Monitor trennt Aufnahme, Messung und Interpretation. Crawlbase liefert gerenderte Screenshots ohne eigene lokale Browserflotte; SSIM und Änderungsfläche entscheiden, welche Aufnahmen Aufmerksamkeit verdienen; ein Vision-Modell ergänzt eine lesbare Erklärung; und gespeichertes HTML, Heatmaps und Request-IDs halten jeden Alert nachprüfbar.

Das Experiment zeigt, dass die Pipeline funktioniert, nicht, dass ihre ersten Schwellen produktionsreif sind. Erst eine konsistente Aufnahmegeometrie und belegte Erklärungen machen aus Screenshot-Unterschieden eine verwertbare Änderungserkennung. Die vollständige Python-Implementierung steht zur Anpassung bereit: Legen Sie ein Crawlbase-Konto an und lassen Sie die Screenshot-Stufe gegen Ihre eigenen öffentlichen Seiten laufen; die Crawlbase-Preise nennen die Kosten für Aufnahme und Rendering.

Häufig gestellte Fragen (FAQs)

Worin unterscheidet sich visuelle Änderungserkennung vom Vergleich von HTML-Hashes?

Ein HTML-Hash meldet jeden Unterschied im Markup auf Byte-Ebene, auch unsichtbare. Visuelle Erkennung vergleicht gerenderte Screenshots und deckt so Änderungen an Layout, Bildern und Darstellung auf. Die Kombination aus beidem verbindet einen sichtbaren Unterschied mit dem Inhalt dahinter.

Kann Crawlbase JavaScript-lastige Landingpages aufnehmen?

Ja. Die Crawling API rendert Seiten in einem Browser, wenn Sie den JavaScript token verwenden (oder den Normal token mit javascript=true), und page_wait, Scrollen und Klick-Steuerung bereiten dynamische Inhalte vor, bevor screenshot=true die Seite aufnimmt.

Ist ein niedrigerer SSIM-Score immer ein Beleg für eine wichtige Änderung der Seite?

Nein. SSIM misst die strukturelle Ähnlichkeit zwischen ausgerichteten Bild-Arrays. Unterschiedliche Viewport-Breiten, responsive Layouts, rotierende Inhalte und andere Schwankungen der Aufnahme können den Score senken, auch wenn sich Angebot oder Botschaft nicht geändert haben.

Wie lassen sich Fehlalarme beim Screenshot-Monitoring reduzieren?

Halten Sie Gerät und Aufnahmemaße stabil, vereinheitlichen Sie die Wartezeiten beim Rendering, schließen Sie flüchtige Overlays jedes Mal auf dieselbe Weise, und schließen Sie dynamische Bereiche aus, wo es praktikabel ist. Leiten Sie Schwellen aus mehreren ruhigen Aufnahmen jedes Ziels ab, statt sich auf einen universellen Score zu verlassen.

Warum steht eine SSIM-Schwelle vor dem Vision-Modell?

Ein Bildvergleich ist im Vergleich zu einem Modellaufruf günstig und deterministisch. Das Gate überspringt Routineaufnahmen, die die Schwellen nicht überschreiten, senkt so den Modellverbrauch und lässt das Modell trotzdem potenziell bedeutsame Änderungen erklären. Eine Überschreitung garantiert nicht, dass die Änderung relevant ist.

Wie automatisiere ich Alerts und aktualisiere die Baseline?

Führen Sie python final/monitor.py --once per cron oder mit einem anderen Scheduler aus. Der Monitor speichert lokale JSON-Alerts, postet optional Zusammenfassungen in Slack und hält seine Baseline in SQLite. Die Baseline rotiert nach der konfigurierten Zahl von Vergleichen oder sofort, wenn ein Alert bestätigt wird.

Jetzt loslegen

Crawlen Sie jede Website im großen Maßstab, ohne gegen die Infrastruktur zu kämpfen.

Crawlbase übernimmt Proxys, Fingerprints und CAPTCHAs, damit Ihr Team Daten-Pipelines liefert, statt Crawl-Infrastruktur zu warten. Bis zu 5.000 Requests kostenlos, keine Karte erforderlich.

Self-Service · Kein Verkaufsgespräch erforderlich · Enterprise-Crawl-Volumen verfügbar