Die meisten Teams, die einen Markt beobachten, einen Suchindex aufbauen oder einen Datensatz füttern, beginnen auf dieselbe Weise: Sie crawlen Daten von einer Reihe öffentlicher Webseiten und wandeln sie in saubere Datensätze um. Das Schwierige ist selten eine einzelne Seite. Es ist das Durchführen über Hunderte von Seiten, ohne dass Anfragen gedrosselt, geblockt oder still mit halb leerem HTML beantwortet werden.

Diese Anleitung zeigt, wie man einen kleinen, ausführbaren Web-Crawler in Python erstellt. Er ruft eine Startseite über die Crawling API ab, extrahiert die Links darauf, folgt denjenigen, die innerhalb des Zielbereichs bleiben, parst die gewünschten Felder auf jeder Seite, entfernt Duplikate und exportiert sauberes JSON und CSV. Die gesamte Anleitung bleibt auf einer neutralen Beispiel-Website, sodass man sie wie vorliegend ausführen und dann auf eine eigene öffentliche Quelle zeigen kann.

Crawling vs. Scraping in einem Absatz

Diese zwei Wörter werden synonym verwendet, benennen aber verschiedene Aufgaben. Crawling ist Entdeckung: von einer oder mehreren URLs starten, Links folgen und nach außen gehen, um zu besuchende Seiten zu finden. Scraping ist Extraktion: das HTML einer Seite nehmen und die spezifischen Felder herausziehen, die man interessieren, wie einen Titel, einen Preis oder ein Datum. Eine echte Pipeline tut beides. Der Crawler entscheidet, welche Seiten besucht werden, und der Scraper entscheidet, was von jeder zu behalten ist. Das Skript in dieser Anleitung ist ein Crawler mit einem auf jede besuchte Seite angehefteten Scraper.

Was Sie bauen werden

Ein einzelnes Python-Skript, das eine Start-URL nimmt, Artikel-Links durch Folgen von Links im Bereich entdeckt, jede Seite über die Crawling API abruft und einen strukturierten Datensatz pro Seite extrahiert. Das laufende Beispiel verwendet https://example.com als Platzhalter für eine öffentliche Auflistung oder einen Blog-Index. Jeder Datensatz enthält diese Felder:

  • Titel die Hauptüberschrift der Seite.
  • URL der kanonische Link, von dem der Datensatz gescrapt wurde.
  • Zusammenfassung der einleitende Absatz oder die Meta-Beschreibung.
  • Datum das Veröffentlichungs- oder Aktualisierungsdatum, wenn die Seite eines anzeigt.
  • Links die Anzahl der im Bereich entdeckten Links auf der Seite.

Warum eine einfache Anfrage oft scheitert

Die naive Version davon ist eine Schleife um einen einfachen HTTP-Client: eine URL abrufen, sie parsen, die Links in die Warteschlange einreihen, wiederholen. Das funktioniert auf einer Test-Website und bricht bei einer echten aus zwei Gründen zusammen.

Erstens Rendering. Viele moderne Seiten liefern eine dünne HTML-Hülle und laden ihren eigentlichen Inhalt im Browser über JavaScript und Ajax. Diese Hülle mit einem einfachen Client anfordern und die gewünschten Links und Felder sind noch nicht im Body, sodass der Crawler nichts entdeckt und nichts parsed. Zweitens Blockierung. Websites beobachten automatisierten Datenverkehr: Datacenter-IP-Bereiche, fehlende Browser-Header und Anfragemuster, die schneller als jeder Mensch abgefeuert werden, werden ratenbegrenzt, IP-geblockt oder mit einem CAPTCHA konfrontiert, bevor sie den Inhalt jemals erreichen.

Ein Crawler, der im großen Maßstab standhält, benötigt also zwei Dinge in jeder Anfrage: einen Browser, der die Seite rendert, und eine IP, die die Website als echten Besucher liest. Man kann das selbst aus einem Headless-Browser plus einem Pool rotierender Residential-Proxies zusammenbauen, aber diesen Stack gesund zu halten ist der Großteil der Arbeit. Die Crawling API fasst beides in einem einzigen Aufruf zusammen: Man sendet eine URL, sie rendert die Seite hinter einer vertrauenswürdigen IP und gibt fertiges HTML zum Parsen zurück.

Voraussetzungen

Ein paar Dinge müssen zuerst vorhanden sein. Keines davon dauert lange.

Grundlegendes Python. Man sollte in der Lage sein, ein Skript zu schreiben und auszuführen sowie Pakete mit pip zu installieren. Wenn die Parse-Seite neu ist, passt der BeautifulSoup-Leitfaden gut zu diesem Tutorial.

Python 3.8 oder höher. Prüfen Sie mit python --version. Falls nicht vorhanden, installieren Sie es von python.org oder über eine Distribution wie Anaconda und stellen Sie sicher, dass Python in Ihrem PATH ist.

Ein Crawlbase-Konto und Token. Melden Sie sich an, öffnen Sie Ihr Dashboard und kopieren Sie Ihr Token von der Kontoseite. Crawlbase gibt bis zu 20.000 kostenlose Anfragen zum Start, was mehr als genug ist, um diese Anleitung durchzuarbeiten. Es gibt zwei Token-Typen: das normale Token ruft statisches HTML ab, und das JavaScript-Token rendert die Seite zuerst in einem echten Browser. Das normale Token für statische Seiten und das JavaScript-Token verwenden, wenn der Inhalt client-seitig lädt. Das Token wie ein Passwort behandeln und aus der Versionskontrolle heraushalten.

Das Projekt einrichten

Eine virtuelle Umgebung erstellen, damit Abhängigkeiten isoliert bleiben, dann die zwei Bibliotheken installieren, die der Crawler benötigt.

bash
python --version

python -m venv crawler_env
source crawler_env/bin/activate

pip install crawlbase beautifulsoup4

Unter Windows die Umgebung mit crawler_env\Scripts\activate statt der source-Zeile aktivieren. Zwei Abhängigkeiten erledigen die Arbeit: crawlbase ist der offizielle Client für die Crawling API, und beautifulsoup4 parsed das zurückgegebene HTML, sodass man Felder und Links per CSS-Selektor herausziehen kann. Sowohl json als auch csv werden mit der Standardbibliothek geliefert, sodass für den Exportschritt nichts weiter benötigt wird.

Schritt 1: Eine Seite über Crawlbase abrufen

Beginnen Sie damit, eine Seite zuverlässig abzurufen. Die CrawlingAPI-Klasse importieren, sie mit dem Token initialisieren und die Start-URL anfordern. Das Prüfen des Crawlbase-cb_status (legacy pc_status) vor dem Parsen hält Fehler laut statt still und gibt eine saubere Stelle zum Wiederholen.

python
import time
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def fetch_html(page_url, max_retries=2):
    for attempt in range(max_retries + 1):
        response = api.get(page_url)
        if response["headers"]["cb_status"] == "200":
            return response["body"].decode("utf-8")
        if attempt < max_retries:
            print(f"Retrying ({attempt + 1}/{max_retries})...")
            time.sleep(1)
    print(f"Failed: {page_url} ({response['headers']['cb_status']})")
    return None

if __name__ == "__main__":
    html = fetch_html("https://example.com")
    print(html[:500] if html else "No HTML returned")

Der fetch_html-Helfer ist das Rückgrat des gesamten Crawlers. Er sendet die URL über Crawlbase, versucht es bis zu zweimal mit einer kurzen Pause bei einem fehlgeschlagenen Abruf erneut und gibt das dekodierte HTML bei Erfolg zurück oder None, sobald er aufgibt. Führen Sie es mit python crawler.py aus und Sie sollten echtes Markup ausgedruckt sehen, was bestätigt, dass der Anfragepfad funktioniert, bevor man einen einzigen Selektor schreibt. Wenn das Ziel Inhalt client-seitig lädt, mit dem JavaScript-Token initialisieren und {"ajax_wait": "true", "page_wait": 5000} als zweites Argument an api.get übergeben, damit die API auf den dynamischen Inhalt wartet, bevor sie die Seite erfasst.

Crawlbase Crawling API

Der obige fetch_html-Helfer stützt sich auf eine Sache: Jede Anfrage kommt gerendert zurück und von einer IP, der die Website vertraut. Die Crawling API tut genau das. Sie führt die Seite in einem echten Browser aus, wenn man es braucht, rotiert serverseitig durch Residential-IPs und gibt fertiges HTML zurück, sodass man das Aufstellen einer Headless-Browser-Flotte und eines eigenen Proxy-Pools überspringt. Zunächst auf eine öffentliche Seite im kostenlosen Tarif zeigen.

Entdeckung ist nur Link-Extraktion in einer Schleife. Das HTML in BeautifulSoup laden, jedes Anker-href herausziehen und relative Pfade gegen die Seite auflösen, auf der sie gefunden wurden, sodass man immer mit absoluten URLs arbeitet.

python
from urllib.parse import urljoin, urldefrag
from bs4 import BeautifulSoup

def extract_links(html, base_url):
    soup = BeautifulSoup(html, "html.parser")
    links = set()
    for a in soup.select("a[href]"):
        href = a["href"].strip()
        if not href or href.startswith(("mailto:", "tel:", "javascript:")):
            continue
        absolute = urljoin(base_url, href)
        absolute, _ = urldefrag(absolute)
        links.add(absolute)
    return links

Drei kleine Entscheidungen machen das robust. Die Funktion überspringt mailto:-, tel:- und javascript:-Anker, die keine echten Seiten sind. Sie verwendet urljoin, damit ein relatives href wie /articles/web-data zu einer vollständigen URL gegen die Seite wird, von der es stammt. Und sie ruft urldefrag auf, um das #section-Fragment zu entfernen, denn /page und /page#top sind dasselbe Dokument und man will nicht beide besuchen. Das Zurückgeben eines set dedupliziert die auf dieser einzelnen Seite gefundenen Links, bevor sie je die Warteschlange erreichen.

Schritt 3: Den Crawl im Bereich halten

Ungebunden folgt ein Crawler Links weg von der Zielwebsite und hört nie auf. Die Lösung ist eine Bereichsregel: Nur Links folgen, die denselben Host wie die Start-URL haben und optional unter einem Pfadpräfix sitzen, das einen interessiert. Das ist das Crawler-Äquivalent des Verbleibens im Produktbereich statt ins Hilfecenter zu wandern.

python
from urllib.parse import urlparse

def in_scope(url, root):
    root_parts = urlparse(root)
    url_parts = urlparse(url)
    if url_parts.scheme not in ("http", "https"):
        return False
    if url_parts.netloc != root_parts.netloc:
        return False
    return url_parts.path.startswith(root_parts.path)

in_scope vergleicht jede Kandidaten-URL mit der URL, von der man gestartet ist. Es lehnt alles ab, was nicht HTTP oder HTTPS ist, alles auf einem anderen Host (netloc), und alles, dessen Pfad nicht mit dem Root-Pfad beginnt. Den Root auf https://example.com/ setzen, um den gesamten Host zu crawlen, oder auf https://example.com/blog/, um innerhalb eines Abschnitts zu bleiben. Den Bereich hier einzuengen ist der wichtigste Hebel dafür, wie viel man abruft.

Schritt 4: Die Felder auf jeder Seite parsen

Entdeckung sagt, welche Seiten zu besuchen sind; Parsen entscheidet, was zu behalten ist. Einen kleinen, wohldefinierten Datensatz von jeder Seite ziehen und jeden Lookup absichern, sodass ein fehlendes Feld None zurückgibt statt den Durchlauf zum Absturz zu bringen.

python
def text_of(soup, selector):
    el = soup.select_one(selector)
    return el.get_text(strip=True) if el else None

def attr_of(soup, selector, attr):
    el = soup.select_one(selector)
    return el.get(attr) if el else None

def parse_page(html, url):
    soup = BeautifulSoup(html, "html.parser")
    summary = (
        attr_of(soup, 'meta[name="description"]', "content")
        or text_of(soup, "article p")
    )
    return {
        "url": url,
        "title": text_of(soup, "h1") or text_of(soup, "title"),
        "summary": summary,
        "date": attr_of(soup, "time[datetime]", "datetime"),
    }

Die zwei Helfer, text_of und attr_of, fragen ein einzelnes Element ab und geben seinen Text oder ein Attribut zurück, mit Rückfall auf None, wenn das Element fehlt. parse_page verwendet eine Kette von Rückfällen: es bevorzugt das meta[name="description"]-Tag für die Zusammenfassung und fällt auf den ersten article-Absatz zurück, wenn keins vorhanden ist, und nimmt das h1 für den Titel, aber verwendet das <title>-Tag, wenn kein h1 vorhanden ist. Diese Selektoren sind absichtlich generisch, damit das Skript auf der Beispiel-Website läuft. Für ein echtes Ziel die Seite in den Dev-Tools des Browsers öffnen und sie durch Selektoren ersetzen, die zum tatsächlichen Markup passen.

Schritt 5: Die Crawl-Schleife zusammenstellen

Nun die Teile zu einem Breadth-First-Crawler zusammenfügen. Eine Warteschlange enthält zu besuchende URLs, ein visited-Set verhindert das zweifache Abrufen derselben Seite, und eine max_pages-Obergrenze stoppt den Durchlauf, damit er nicht ewig weitergeht. Für jede abgerufene Seite parsed der Crawler einen Datensatz, zählt die Links im Bereich und reiht die neuen in die Warteschlange ein.

python
import csv
import json
import time
from collections import deque
from urllib.parse import urljoin, urldefrag, urlparse
from crawlbase import CrawlingAPI
from bs4 import BeautifulSoup

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def fetch_html(page_url, max_retries=2):
    for attempt in range(max_retries + 1):
        response = api.get(page_url)
        if response["headers"]["cb_status"] == "200":
            return response["body"].decode("utf-8")
        if attempt < max_retries:
            time.sleep(1)
    return None

def extract_links(html, base_url):
    soup = BeautifulSoup(html, "html.parser")
    links = set()
    for a in soup.select("a[href]"):
        href = a["href"].strip()
        if not href or href.startswith(("mailto:", "tel:", "javascript:")):
            continue
        absolute, _ = urldefrag(urljoin(base_url, href))
        links.add(absolute)
    return links

def in_scope(url, root):
    r, u = urlparse(root), urlparse(url)
    return (
        u.scheme in ("http", "https")
        and u.netloc == r.netloc
        and u.path.startswith(r.path)
    )

def text_of(soup, selector):
    el = soup.select_one(selector)
    return el.get_text(strip=True) if el else None

def attr_of(soup, selector, attr):
    el = soup.select_one(selector)
    return el.get(attr) if el else None

def parse_page(html, url, link_count):
    soup = BeautifulSoup(html, "html.parser")
    summary = (
        attr_of(soup, 'meta[name="description"]', "content")
        or text_of(soup, "article p")
    )
    return {
        "url": url,
        "title": text_of(soup, "h1") or text_of(soup, "title"),
        "summary": summary,
        "date": attr_of(soup, "time[datetime]", "datetime"),
        "links": link_count,
    }

def crawl(start_url, max_pages=25):
    queue = deque([start_url])
    visited = set()
    records = []
    while queue and len(visited) < max_pages:
        url = queue.popleft()
        if url in visited:
            continue
        visited.add(url)
        html = fetch_html(url)
        if not html:
            continue
        found = {l for l in extract_links(html, url) if in_scope(l, start_url)}
        records.append(parse_page(html, url, len(found)))
        for link in found:
            if link not in visited:
                queue.append(link)
        print(f"[{len(visited)}/{max_pages}] {url}")
        time.sleep(2)
    return records

Das ist ein lehrbuchmäßiger Breadth-First-Crawl. Das visited-Set ist die Deduplizierungsschutzvorrichtung auf Crawl-Ebene: Eine URL wird hinzugefügt, bevor sie abgerufen wird, sodass selbst wenn drei Seiten alle auf denselben Artikel verlinken, er genau einmal angefordert wird. max_pages begrenzt die Gesamtarbeit, der Bereichsfilter verhindert, dass die Warteschlange sich mit externen Links füllt, und der Zwei-Sekunden-Schlaf dosiert den Durchlauf, damit man den Server nicht überlastet. Die print-Zeile gibt während der Ausführung einen Live-Fortschrittshinweis.

Schritt 6: Deduplizieren und als JSON und CSV exportieren

Das visited-Set verhindert bereits, eine URL zweimal abzurufen, aber Weiterleitungen und Trailing-Slash-Varianten können immer noch zwei Datensätze erzeugen, die dieselbe Seite beschreiben. Ein abschließender Durchlauf, der auf der URL basiert, fasst diese vor dem Export zusammen.

python
def dedupe(records):
    seen = {}
    for record in records:
        seen[record["url"].rstrip("/")] = record
    return list(seen.values())

def save_outputs(records):
    with open("crawl_results.json", "w") as f:
        json.dump(records, f, indent=2)
    if not records:
        return
    with open("crawl_results.csv", "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=records[0].keys())
        writer.writeheader()
        writer.writerows(records)

def main():
    records = crawl("https://example.com", max_pages=25)
    records = dedupe(records)
    save_outputs(records)
    print(f"Saved {len(records)} pages")

if __name__ == "__main__":
    main()

dedupe schlüsselt jeden Datensatz auf seiner URL mit entferntem abschließendem Slash auf, sodass /article und /article/ zu einem Eintrag werden und der spätere Datensatz gewinnt. save_outputs schreibt eine JSON-Datei und ein CSV unter Verwendung der Schlüssel des ersten Datensatzes als Header, was die Daten in welcher Form auch immer das nächste Tool möchte verfügbar macht. Diese zwei Funktionen unterhalb der Crawl-Schleife aus Schritt 5 einfügen und das Skript läuft von Ende zu Ende.

Wie die Ausgabe aussieht

Das vollständige Skript mit python crawler.py ausführen und man erhält einen strukturierten Datensatz pro Seite, bereit für Analysen, eine Datenbank oder eine Tabellenkalkulation.

json
[
  {
    "url": "https://example.com/articles/web-data",
    "title": "A Practical Guide to Web Data",
    "summary": "How teams turn public pages into clean, structured records.",
    "date": "2024-09-18",
    "links": 12
  },
  {
    "url": "https://example.com/articles/crawling-basics",
    "title": "Crawling Basics",
    "summary": "Discovery, scope, and dedupe explained from first principles.",
    "date": "2024-08-02",
    "links": 9
  }
]

Das passende CSV trägt dieselben Spalten, eine Zeile pro Seite, was direkt in pandas oder jede Tabellenkalkulation zum Sortieren, Filtern oder Verbinden mit einem anderen Datensatz passt. Wenn man den Speicherschritt weiter ausbauen möchte, sind gescrapte Daten in der Cloud speichern und sie in SQL laden natürliche nächste Schritte.

Den Crawl skalieren

Das obige Skript ist absichtlich single-threaded, damit es leicht zu lesen und leicht höflich zu halten ist. Ein paar Änderungen bringen es von einer Demo zu einem Job, den man laufen lassen kann.

  • Die Obergrenze vorsichtig erhöhen. max_pages ist das Sicherheitsventil. In Schritten erhöhen und beobachten, wie viele Links im Bereich der Crawl entdeckt, bevor man sich auf einen großen Durchlauf festlegt.
  • Die Frontier persistieren. Bei langen Crawls die Warteschlange und das visited-Set auf die Festplatte schreiben, damit ein unterbrochener Durchlauf fortgesetzt wird statt von vorne anzufangen und alles neu abzurufen.
  • Für Volumen asynchron gehen. Wenn man Tausende von Seiten braucht, reiht der async Crawler Anfragen in eine Warteschlange ein und sendet die Ergebnisse per Webhook, sodass man keine Verbindungen offen hält, während Seiten rendern.

Für JavaScript-lastige Ziele, bei denen die Links selbst client-seitig laden, funktioniert dieselbe Schleife, sobald man zum JavaScript-Token und den Wait-Optionen wechselt; siehe JavaScript-Websites crawlen für die Details.

Entsperrt bleiben

Auch mit Rendering und vertrauenswürdigen IPs halten einige Gewohnheiten einen längeren Crawl gesund.

  • Anfragen dosieren. Der Zwei-Sekunden-Schlaf in der Schleife ist ein Boden, keine Decke. Für größere Jobs erweitern und vermeiden, einen Pfad so schnell zu crawlen, wie der Server antwortet.
  • Auf Rotation setzen. Ein Pool von Residential-IPs verteilt Anfragen über viele echte Nutzeradressen, sodass keine einzelne eine Ratenbegrenzung auslöst. Die Crawling API erledigt das für einen; wenn man seinen eigenen Stack aufbaut, ist das der Teil, den man richtig machen muss.
  • Statuscodes lesen. Ein Durchlauf, der anfängt, Nicht-200-cb_status-Werte zurückzugeben, signalisiert, dass die aktuelle Rate oder IP-Stufe nicht mehr ausreicht. Das als Signal zum Zurückfahren behandeln, nicht als Rauschen zum Ignorieren.

Für das vollständigere Playbook, siehe wie man Websites scrapt, ohne geblockt zu werden.

Verantwortungsvoll scrapen

Nur öffentliche Daten crawlen und die Regeln der besuchten Websites respektieren. Die Nutzungsbedingungen und robots.txt jedes Ziels lesen, bevor man beginnt, die Anfragerate vernünftig halten, damit man niemandes Server belastet, und alles hinter einem Login oder einer Bezahlschranke meiden. Wenn die gesammelten Seiten personenbezogene Daten enthalten, gelten Datenschutzgesetze wie DSGVO und CCPA für die Speicherung und Verwendung, also die Felder auf das tatsächlich Benötigte beschränken und das Ernten von Details zu identifizierbaren Personen vermeiden. Der Code in dieser Anleitung lässt den technischen Teil funktionieren; das Projekt auf der richtigen Seite dieser Linien zu halten liegt bei Ihnen.

Zusammenfassung

Wichtigste Erkenntnisse

  • Crawling und Scraping sind zwei Aufgaben. Der Crawler entdeckt, welche Seiten durch Folgen von Links zu besuchen sind; der Scraper extrahiert die Felder, die man von jeder behält.
  • Rendern und über eine vertrauenswürdige IP routen. Ein einfacher Client übersieht client-gerenderten Inhalt und wird geblockt; die Crawling API gibt fertiges HTML von einer vertrauenswürdigen IP in einem Aufruf zurück.
  • Bereich und Deduplizierung halten den Crawl vernünftig. Eine in_scope-Prüfung verhindert, dass der Durchlauf die Website verlässt, und ein visited-Set plus ein URL-basierter Durchlauf entfernen doppelte Arbeit und doppelte Datensätze.
  • Defensiv parsen. Jeden Selektor absichern, sodass ein fehlendes Feld None zurückgibt und eine ungewöhnliche Seite den Durchlauf nicht beendet.
  • Einmal exportieren, überall verwenden. Sowohl JSON als auch CSV schreiben lässt denselben Datensatz ohne Nacharbeit in pandas, eine Datenbank oder eine Tabellenkalkulation fließen.

Häufig gestellte Fragen

Was ist der Unterschied zwischen Web Crawling und Web Scraping?

Crawling ist der Entdeckungsschritt: von einer oder mehreren URLs starten und Links folgen, um besuchenswerte Seiten zu finden. Scraping ist der Extraktionsschritt: das HTML einer einzelnen Seite nehmen und spezifische Felder wie einen Titel oder ein Datum herausziehen. Die meisten echten Pipelines tun beides auf einmal, was genau das ist, was das Skript in dieser Anleitung tut: Crawlen zum Finden von Seiten und Scrapen eines Datensatzes von jeder.

Warum gibt mein Crawler leeres oder teilweises HTML zurück?

Meist weil die Seite ihren Inhalt im Browser mit JavaScript rendert, sodass das anfängliche HTML eine dünne Hülle ist und die Links und Felder noch nicht darin sind. Die Seite über die Crawling API mit dem JavaScript-Token und den ajax_wait- und page_wait-Optionen abrufen, die die Seite zuerst rendern und das fertige Markup zum Parsen zurückgeben.

Wie verhindere ich, dass der Crawler die Zielwebsite verlässt?

Eine Bereichsregel verwenden. Die in_scope-Funktion vergleicht jeden Kandidaten-Link mit dem Host und Pfad der Start-URL und lehnt alles ab, was nicht übereinstimmt. Den Root-Pfad eng setzen, zum Beispiel https://example.com/blog/, um den Crawl innerhalb eines Abschnitts statt der gesamten Domain zu halten.

Wie vermeidet der Crawler das zweifache Besuchen derselben Seite?

Zwei Schichten. Ein visited-Set zeichnet jede URL auf, bevor sie abgerufen wird, sodass eine Seite, die von vielen Stellen verlinkt wird, dennoch nur einmal angefordert wird. Nach dem Crawl fasst ein Deduplizierungsdurchlauf, der auf der URL basiert (mit normalisiertem abschließendem Slash), alle Datensätze zusammen, die immer noch dieselbe Seite beschreiben, bevor sie JSON und CSV erreichen.

Sollte ich zu JSON oder CSV exportieren?

Beides, und das nachgelagerte Tool entscheiden lassen. JSON behält die verschachtelte, typisierte Form, die Code und APIs bevorzugen, während CSV direkt in Tabellenkalkulationen und pandas passt. Die save_outputs-Funktion schreibt beides aus denselben Datensätzen, sodass man nicht auf ein Format festgelegt ist. Für mehr zu den Kompromissen, den Unterschied zwischen JSON und CSV erkunden.

Wie viele Seiten kann ich im kostenlosen Tarif crawlen?

Crawlbase gibt bis zu 20.000 kostenlose Anfragen zum Start, und man zahlt nur für erfolgreiche Anfragen. Jede vom Crawler abgerufene Seite ist eine Anfrage, sodass die max_pages-Obergrenze im Skript direkt auf den Verbrauch abbildet. Für größere oder wiederkehrende Jobs skaliert der async Crawler denselben Ansatz, ohne Verbindungen offen zu halten.

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 Datenpipelines ausliefert, statt Crawl-Infrastruktur zu pflegen. 1.000 Anfragen kostenlos, keine Karte erforderlich.

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