Ein Scraper zieht Felder von einer einzelnen Seite, deren URL Sie bereits kennen. Ein Crawler ist das Programm, das diese URLs erst findet: Es startet von einer Seed-Seite, folgt den darin entdeckten Links und macht weiter, bis es den Teil einer Site abgedeckt hat, der Sie interessiert. Wenn Sie einen Dokumentationsbaum kartieren, alle Produktseiten unter einer Kategorie sammeln oder einen Suchindex füttern möchten, brauchen Sie die zweite Art von Programm.
Dieser Leitfaden zeigt Ihnen, wie Sie einen Web-Crawler in Java von Grund auf erstellen. Sie verwenden den modernen HttpClient (Java 11+) zum Abrufen von Seiten, Jsoup zum Parsen und Herausziehen von Links sowie eine Frontier-Queue mit einem besuchten Set, um einen Breadth-First-Crawl zu steuern. Wir fügen die Steuerelemente hinzu, die einen Spielzeug-Crawler von etwas unterscheiden, das Sie tatsächlich ausführen können: ein Tiefenlimit, eine Same-Domain-Einschränkung und Höflichkeitsverzögerungen. Dann behandeln wir den Teil, auf den jeder echte Crawl trifft, JavaScript-Rendering und IP-Blockierungen, und wie man damit umgeht, ohne den Crawler neu zu schreiben.
Crawler vs. Scraper: Was ist tatsächlich anders
Die beiden Wörter werden austauschbar verwendet, aber die Programme haben unterschiedliche Formen. Ein Scraper nimmt eine bekannte URL, ruft sie einmal ab und extrahiert Daten. Ein Crawler nimmt eine Seed-URL, ruft sie ab, extrahiert die Links und fügt die neuen einer Queue von noch zu besuchenden Seiten hinzu. Er wiederholt diese Schleife, sodass die Menge der besuchten Seiten wächst, während er läuft. Extraktion ist immer noch Teil der Aufgabe, aber das definierende Merkmal ist Link-Entdeckung und -Traversierung.
Dieser Unterschied treibt jede Designentscheidung unten. Da ein Crawler seine eigene Arbeit entdeckt, benötigt er eine Queue (die Frontier) für ausstehende URLs, ein Set zur Erinnerung, was er bereits gesehen hat, damit er nicht ewig in einer Schleife hängt, und Grenzen, damit er nicht ins gesamte Internet wandert. Diese drei richtig hinzubekommen, und der Rest ist Abrufen und Parsen.
Was Sie erstellen werden
Eine einzige ausführbare Java-Klasse, die eine Seed-URL nimmt und innerhalb einer Domain nach außen crawlt. Sie führt eine Breadth-First-Traversierung durch, hört bei einer konfigurierbaren Tiefe auf, überspringt bereits besuchte Seiten und pausiert höflich zwischen Anfragen. Für jede Seite gibt sie die URL und den Titel aus, was Sie gegen jede beliebige Extraktion austauschen können.
- Frontier-Queue eine FIFO-Queue von URLs, die abgerufen werden sollen, zusammen mit der Tiefe, bei der jede gefunden wurde.
-
Besuchtes Set ein
Setvon bereits verarbeiteten URLs, damit der Crawler dieselbe Seite nie zweimal abruft. - Tiefenlimit eine harte Obergrenze dafür, wie viele Link-Hops vom Seed aus der Crawler folgen wird.
- Same-Domain-Guard eine Prüfung, die den Crawl auf dem Host hält, von dem Sie gestartet haben.
- Höflichkeitsverzögerung eine Pause zwischen Anfragen, damit Sie das Ziel nicht überlasten.
Voraussetzungen
Sie benötigen einige Dinge, bevor Sie Code schreiben, und keines davon dauert lange.
Java 11 oder neuer. Der Crawler verwendet die java.net.http.HttpClient-API, die in Java 11 eingeführt wurde, also bestätigen Sie Ihre Version mit java -version. Jede JDK 11+-Distribution funktioniert.
Jsoup. Jsoup ist die Standard-Java-Bibliothek zum Parsen von HTML und zum Auswählen von Elementen mit CSS-Selektoren. Mit Maven fügen Sie die folgende Abhängigkeit hinzu; mit Gradle oder einem einfachen Classpath ziehen Sie das entsprechende Jar.
<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.17.2</version> </dependency>
Grundlegendes Java. Sie sollten vertraut damit sein, eine Klasse zu kompilieren und auszuführen und einen Stack Trace zu lesen. Hier werden keine Frameworks jenseits des JDK und Jsoup verwendet.
Schritt 1: Eine Seite mit HttpClient abrufen
Beginnen Sie mit dem kleinsten nützlichen Teil: einer Methode, die eine URL nimmt und das HTML als String zurückgibt. Die HttpClient-API verwendet ein Builder-Muster, unterstützt standardmäßig HTTP/2 und bietet einen synchronen send-Aufruf, der blockiert, bis die Antwort eintrifft. Ein Anfrage-Timeout verhindert, dass ein langsamer oder toter Host den gesamten Crawl zum Hängen bringt.
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; private static final HttpClient CLIENT = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .followRedirects(HttpClient.Redirect.NORMAL) .build(); static String fetch(String url) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .timeout(Duration.ofSeconds(20)) .header("User-Agent", "MyJavaCrawler/1.0") .GET() .build(); HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 200) { return response.body(); } System.out.println("Skipping " + url + " -> " + response.statusCode()); return null; }
Der einzelne statische Client ist beabsichtigt: HttpClient ist unveränderlich und thread-sicher, also erstellen Sie einen und verwenden ihn für jede Anfrage, anstatt einen pro Abruf zu bauen. Einen User-Agent zu setzen ist guter Stil und oft erforderlich, und den Statuscode vor dem Zurückgeben des Bodys zu überprüfen hält Fehler sichtbar, anstatt leeres HTML in den Parser zu speisen.
Schritt 2: Links mit Jsoup parsen
Das Abrufen gibt Ihnen einen HTML-String. Zum Crawlen brauchen Sie die darin enthaltenen Links. Jsoup parst das HTML in ein Dokument und lässt Sie Elemente mit CSS-Selektoren auswählen. Der Selektor a[href] greift jeden Anker mit einem href, und Jsoupsches absUrl löst relative Links wie /about in absolute URLs relativ zur Seite auf, auf der sie gefunden wurden, was genau das ist, was die Frontier braucht.
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.util.ArrayList; import java.util.List; static List<String> extractLinks(String html, String baseUrl) { List<String> links = new ArrayList<>(); Document doc = Jsoup.parse(html, baseUrl); System.out.println("Title: " + doc.title()); Elements anchors = doc.select("a[href]"); for (Element a : anchors) { String absolute = a.absUrl("href"); if (!absolute.isBlank()) { links.add(absolute); } } return links; }
baseUrl an Jsoup.parse zu übergeben ist das, was absUrl zum Funktionieren bringt; ohne es lösen sich relative hrefs in nichts auf. Dasselbe Dokument ist der Ort, an dem Sie Ihre echte Extraktion durchführen würden, mit Selektoren wie doc.select("h1") oder doc.select(".price"). Hier geben wir den Titel aus, damit Sie den Crawl von Seite zu Seite beobachten können. Wenn Sie einen tieferen Blick auf das Auswählen und Extrahieren von Feldern in Java werfen möchten, behandelt der Leitfaden zum Web Scraping mit Java die Parse-Seite im Detail.
Schritt 3: Den Crawl mit einer Frontier und einem besuchten Set steuern
Jetzt der Kern. Breadth-First-Crawling bedeutet, dass Sie Seiten in Wellen besuchen: zuerst den Seed, dann alles einen Hop entfernt, dann zwei Hops, und so weiter. Eine FIFO-Queue gibt Ihnen diese Ordnung kostenlos. Jeder Queue-Eintrag paart eine URL mit der Tiefe, bei der sie entdeckt wurde, sodass Sie wissen, wann Sie aufhören sollen, ihren Kindern zu folgen. Ein HashSet von besuchten URLs verhindert Zyklen, und eine Same-Domain-Prüfung hält den Crawl auf einem Host begrenzt.
import java.net.URI; import java.util.ArrayDeque; import java.util.HashSet; import java.util.Queue; import java.util.Set; static class Task { final String url; final int depth; Task(String url, int depth) { this.url = url; this.depth = depth; } } static boolean sameHost(String url, String host) { try { return host.equalsIgnoreCase(URI.create(url).getHost()); } catch (Exception e) { return false; } } static void crawl(String seed, int maxDepth, long delayMs) throws Exception { String host = URI.create(seed).getHost(); Queue<Task> frontier = new ArrayDeque<>(); Set<String> visited = new HashSet<>(); frontier.add(new Task(seed, 0)); visited.add(seed); while (!frontier.isEmpty()) { Task task = frontier.poll(); System.out.println("[" + task.depth + "] " + task.url); String html = fetch(task.url); if (html == null || task.depth >= maxDepth) continue; for (String link : extractLinks(html, task.url)) { if (sameHost(link, host) && visited.add(link)) { frontier.add(new Task(link, task.depth + 1)); } } Thread.sleep(delayMs); } }
Einige Details tragen ihr Gewicht. visited.add(link) gibt false zurück, wenn die URL bereits vorhanden war, sodass ein einzelner Aufruf sowohl die Mitgliedschaft prüft als auch die URL aufzeichnet, weshalb die Guard sameHost(link, host) && visited.add(link) lautet. Die Tiefenprüfung erfolgt nach dem Abruf, aber vor dem Einreihen von Kindern, sodass Seiten bei maxDepth immer noch abgerufen und geparst werden, aber keine neuen Links beitragen. Und Thread.sleep(delayMs) ist die Höflichkeitspause: Sie ist der Unterschied zwischen einem Crawler, den eine Site toleriert, und einem, den sie blockiert.
Schritt 4: Ein vollständiger, ausführbarer Crawler
Verbinden Sie die Teile in einer Klasse mit einer main-Methode. Kompilieren Sie sie mit Jsoup im Classpath und führen Sie sie gegen eine Seed-URL, eine Tiefe und eine Verzögerung aus.
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import java.util.*; public class WebCrawler { private static final HttpClient CLIENT = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .followRedirects(HttpClient.Redirect.NORMAL) .build(); record Task(String url, int depth) {} static String fetch(String url) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .timeout(Duration.ofSeconds(20)) .header("User-Agent", "MyJavaCrawler/1.0") .GET() .build(); HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); return response.statusCode() == 200 ? response.body() : null; } static List<String> extractLinks(String html, String baseUrl) { List<String> links = new ArrayList<>(); Document doc = Jsoup.parse(html, baseUrl); System.out.println(" Title: " + doc.title()); Elements anchors = doc.select("a[href]"); for (Element a : anchors) { String absolute = a.absUrl("href"); if (!absolute.isBlank()) links.add(absolute); } return links; } static boolean sameHost(String url, String host) { try { return host.equalsIgnoreCase(URI.create(url).getHost()); } catch (Exception e) { return false; } } static void crawl(String seed, int maxDepth, long delayMs) throws Exception { String host = URI.create(seed).getHost(); Queue<Task> frontier = new ArrayDeque<>(); Set<String> visited = new HashSet<>(); frontier.add(new Task(seed, 0)); visited.add(seed); while (!frontier.isEmpty()) { Task task = frontier.poll(); System.out.println("[" + task.depth() + "] " + task.url()); String html = fetch(task.url()); if (html == null || task.depth() >= maxDepth) continue; for (String link : extractLinks(html, task.url())) { if (sameHost(link, host) && visited.add(link)) { frontier.add(new Task(link, task.depth() + 1)); } } Thread.sleep(delayMs); } } public static void main(String[] args) throws Exception { crawl("https://books.toscrape.com/", 2, 1000); } }
Das ist ein funktionierender Breadth-First-Crawler in deutlich unter 100 Zeilen. Er verwendet einen Java-record für das Aufgabenpaar, ruft mit einem wiederverwendeten Client ab, parst mit Jsoup, bleibt auf einem Host, dedupliziert mit einem Set, hält bei Tiefe 2 an und wartet eine Sekunde zwischen Anfragen. Zeigen Sie ihn zuerst auf eine Sandbox wie books.toscrape.com, dann tauschen Sie Ihren eigenen Seed und Ihre Extraktion ein.
Bevor Sie eine Site crawlen, die Ihnen nicht gehört, lesen Sie ihre robots.txt und Nutzungsbedingungen und behandeln Sie sie als Grenze. Befolgen Sie Crawl-Delay-Direktiven, überspringen Sie nicht erlaubte Pfade und halten Sie Ihre Anfragerate niedrig genug, damit Sie den Server nicht belasten. Ein höflicher Crawler, der zurückgeht, ist einer, der weiter funktioniert; ein aggressiver wird blockiert und kann echten Schaden anrichten.
Wo ein selbst gebauter Crawler an eine Wand stößt
Der obige Crawler ist korrekt, und auf einer statischen, wohlverhaltenen Site läuft er gut. Zwei Dinge brechen ihn im modernen Web, und beide sind häufig genug, dass Sie ihnen schnell begegnen werden.
JavaScript-Rendering. Ihr Abruf gibt das rohe HTML zurück, das der Server sendet. Viele Sites bauen ihren Inhalt im Browser mit React, Angular oder Vue, sodass dieses rohe HTML eine nahezu leere Shell ist. Jsoup parst genau das, was es erhält, und kann kein JavaScript ausführen, sodass auf diesen Seiten a[href] wenige oder gar keine Links findet und der Crawl beim Seed stirbt. Sie würden einen Headless-Browser benötigen, um die Seite zuerst zu rendern. Das Crawlen von Sites, die auf clientseitigem Rendering angewiesen sind, ist ein eigenes Thema, das im Leitfaden zu JavaScript-lastige Websites crawlen behandelt wird.
IP-Blockierungen. Ein Crawler macht viele Anfragen von einer Adresse in einem kurzen Zeitfenster, was genau das Muster ist, nach dem Anti-Bot-Systeme suchen. Datacenter-IPs werden herausgefordert, rate-limitiert oder gesperrt, und sobald Ihre Adresse markiert ist, stockt der Crawl unabhängig davon, wie höflich Ihre Verzögerung ist. Anfragen über einen Pool von Residential-IPs zu verteilen vermeidet die Einzeladress-Signatur, aber das Aufbauen und Pflegen dieses Pools ist der größte Teil der Arbeit. Das umfassendere Playbook findet sich in wie man Websites ohne Blockierung scrapt.
Die Skalierungswende: serverseitiges Rendern und Rotieren
Sie können beide Probleme lösen, ohne den Crawler zu verkomplizieren. Anstatt die Ziel-URL direkt abzurufen, leiten Sie den Abruf durch einen API-Endpunkt, der die Seite in einem echten Browser rendert und sie von einer rotierenden Residential-IP bedient, und Ihnen dann fertiges HTML übergibt. Ihre Crawler-Logik, die Frontier, das besuchte Set, das Tiefenlimit, der Same-Domain-Guard, bleibt genau gleich. Nur die fetch-Methode ändert sich.
Die Crawling API ist ein einfaches HTTP GET: Sie übergeben Ihren Token und die Ziel-URL als Query-Parameter, fügen ein Flag hinzu, um JavaScript-Rendering anzufordern, und lesen den Response-Body. Da es nur ein GET ist, fügt es sich direkt in den bereits geschriebenen HttpClient-Code ein.
import java.net.URLEncoder; import java.nio.charset.StandardCharsets; private static final String TOKEN = "YOUR_CRAWLBASE_JS_TOKEN"; static String fetch(String url) throws Exception { String target = URLEncoder.encode(url, StandardCharsets.UTF_8); String endpoint = "https://api.crawlbase.com/?token=" + TOKEN + "&page_wait=3000&url=" + target; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(endpoint)) .timeout(Duration.ofSeconds(90)) .GET() .build(); HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); return response.statusCode() == 200 ? response.body() : null; }
Zwei Änderungen tragen die Last. Die Ziel-URL wird mit URLEncoder kodiert, bevor sie in den Query-String geht, weil Crawlbase erfordert, dass die innere URL kodiert ist, damit seine eigenen Parameter sauber geparst werden. Und page_wait=3000 weist die API an, drei Sekunden nach dem Laden auf spät renderenden Inhalt zu warten, bevor das HTML erfasst wird, was eine JavaScript-Shell in die vollständig gebaute Seite verwandelt, die Ihr Parser benötigt. Das JS-Token ermöglicht Rendering; die Rotation erfolgt serverseitig, sodass die Adresse, die das Ziel sieht, eine echte Residential-IP ist, nicht die Ihres Crawlers. Ein längeres Client-Timeout berücksichtigt, dass der Render-Schritt länger dauert als ein reiner Abruf.
Halten Sie Ihren Java-Crawler einfach und lassen Sie Rendering und IP-Rotation serverseitig stattfinden. Die Crawling API nimmt einen Token und eine Ziel-URL über ein einfaches GET, führt die Seite in einem echten Browser aus, rotiert durch Residential-IPs und gibt fertiges HTML zurück, sodass Ihre Frontier, Ihr besuchtes Set und Ihr Parser sich nie ändern. Verbinden Sie es in die fetch-Methode und crawlen Sie JavaScript-lastige Sites, ohne selbst eine Headless-Flotte oder einen Proxy-Pool zu betreiben.
Den Crawler für echte Läufe härten
Eine Handvoll Ergänzungen bewegen die Demo in Richtung Produktion. Keine davon ändert die Kernschleife; sie lassen sie Kontakt mit unordentlichen Sites überleben.
-
URLs vor der Deduplizierung normalisieren. Entfernen Sie Fragmente (
#section) und abschließende Schrägstriche, sodass/pageund/page#topals eine URL zählen. Ohne dies bläht sich Ihr besuchtes Set auf und Sie rufen denselben Inhalt erneut ab. -
Nicht-HTML-Links filtern. Überspringen Sie hrefs, die auf
.pdf,.jpg,.zipund Ähnliches enden, bevor Sie sie in die Queue aufnehmen, damit der Crawler nicht versucht, Binärdaten als HTML zu parsen. - Die Gesamtseitenzahl deckeln. Tiefe begrenzt die Breadth-First-Reichweite, aber eine breite Site kann immer noch Tausende von Seiten in die Queue stellen. Ein harter Grenzwert für die besuchte Größe ist ein einfaches Sicherheitsventil.
- Fehler pro Seite behandeln. Wickeln Sie jeden Abruf-und-Parse-Vorgang in einen try/catch ein, damit eine fehlerhafte URL protokolliert wird und weitergeht, anstatt den gesamten Crawl zu beenden.
- Die Frontier persistieren. Für lange Crawls sichern Sie die Queue und das besuchte Set in einer Datei oder Datenbank, damit ein Absturz keinen Fortschritt verliert und Sie fortsetzen können.
Wenn Sie echte Parallelität möchten, erweitert sich dieselbe Struktur auf einen Thread-Pool: Tauschen Sie das HashSet gegen ein ConcurrentHashMap.newKeySet() und die ArrayDeque gegen eine ConcurrentLinkedQueue, dann lassen Sie mehrere Worker-Threads von der Frontier ziehen. Halten Sie die Höflichkeitsverzögerung pro Host aufrecht, damit Parallelität nicht zu einer Flut wird. Für Workloads, bei denen Sie viele URLs übermitteln und Ergebnisse beim Fertigstellen statt beim Blockieren auf jede einzelne sammeln, verwaltet der asynchrone Crawler die Warteschlangen und Callbacks für Sie.
Wichtigste Erkenntnisse
- Ein Crawler entdeckt seine eigenen URLs. Die definierenden Teile sind eine Frontier-Queue, ein besuchtes Set und Grenzen, nicht die Extraktion.
-
HttpClient plus Jsoup ist der Kernstack. Javas
HttpClientruft ab, Jsoup parst HTML und löst Links mitabsUrlauf. -
Breadth-First braucht drei Guards. Eine FIFO-Frontier mit Tiefe, ein
HashSetbesuchter URLs und eine Same-Domain-Prüfung halten den Crawl begrenzt und schleifenfrei. -
Seien Sie höflich. Verzögern Sie zwischen Anfragen, setzen Sie einen echten
User-Agentund respektieren Sierobots.txtund Nutzungsbedingungen. - JS-Rendering und IP-Blockierungen sind der Punkt, wo DIY scheitert. Das Routing des Abrufs durch die Crawling API verarbeitet beides serverseitig und lässt die Crawler-Logik unberührt.
Häufig gestellte Fragen
Was ist der Unterschied zwischen einem Web-Crawler und einem Web-Scraper?
Ein Scraper extrahiert Daten von URLs, die Sie bereits haben. Ein Crawler beginnt von einer Seed-URL, folgt den gefundenen Links und entdeckt neue Seiten, während er läuft, sodass die Menge der besuchten Seiten im Laufe der Zeit wächst. Extraktion ist immer noch Teil des Crawling, aber die definierenden Merkmale sind Link-Entdeckung und -Traversierung, weshalb ein Crawler eine Frontier-Queue und ein besuchtes Set braucht, die ein einzelner Scraper nicht braucht.
Sollte ich HttpClient oder Jsoup verwenden, um Seiten in Java abzurufen?
Verwenden Sie beide für das, was jeder am besten kann. Javas HttpClient gibt Ihnen feine Kontrolle über die Anfrage: Timeouts, Header, Redirect-Richtlinie und synchrone oder asynchrone Sends. Jsoup ist für das Parsen des zurückgegebenen HTML und das Auswählen von Elementen mit CSS-Selektoren gebaut. Jsoup kann selbst abrufen, aber das Kombinieren eines dedizierten HTTP-Clients mit Jsoup als Parser hält die beiden Anliegen getrennt und ist leichter zu erweitern, beispielsweise für das spätere Routing von Abrufen durch eine API.
Wie verhindere ich, dass mein Crawler ewig in einer Schleife hängt?
Halten Sie ein Set von URLs, die Sie bereits in die Queue aufgenommen haben, und überprüfen Sie es, bevor Sie einen neuen Link hinzufügen. Im Beispiel gibt visited.add(link) false zurück, wenn die URL bereits vorhanden ist, sodass ein einzelner Aufruf sowohl die Mitgliedschaft testet als auch die URL aufzeichnet. Kombiniert mit einem Tiefenlimit und einem Same-Domain-Guard verhindert das Zyklen und stoppt den Crawl daran, über das gesamte Web zu wandern.
Warum gibt mein Java-Crawler leere oder fehlende Links zurück?
Die wahrscheinlichste Ursache ist JavaScript-Rendering. Ihr Abruf gibt das rohe HTML zurück, das der Server sendet, und viele Sites bauen ihren Inhalt im Browser mit Frameworks wie React oder Angular, sodass dieses rohe HTML eine nahezu leere Shell mit wenigen oder gar keinen Ankern ist. Jsoup kann kein JavaScript ausführen, also findet es nichts, dem es folgen könnte. Rendern Sie die Seite zuerst mit einem Headless-Browser, oder leiten Sie den Abruf durch die Crawling API mit aktiviertem Rendering, damit das HTML vollständig gebaut ist, bevor Sie es parsen.
Wie vermeide ich das Geblocktwerden beim Crawlen?
Taktieren Sie Ihre Anfragen mit einer Verzögerung, setzen Sie einen ehrlichen User-Agent, respektieren Sie robots.txt und Crawl-Delay-Direktiven und halten Sie das pro-Host-Volumen vernünftig. Das schwierigere Problem ist IP-Reputation: Viele Anfragen von einer Datacenter-Adresse werden schnell markiert. Das Verteilen von Anfragen über rotierende Residential-IPs vermeidet diese Signatur. Die Crawling API verarbeitet die Rotation für Sie; wenn Sie Ihren eigenen Stack bauen, ist das der Teil, in den Sie investieren sollten.
Kann ich einen Java-Crawler parallel laufen lassen?
Ja. Die Breadth-First-Struktur erweitert sich auf mehrere Threads: Ersetzen Sie das HashSet durch ConcurrentHashMap.newKeySet() und die ArrayDeque durch eine thread-sichere Queue wie ConcurrentLinkedQueue, dann lassen Sie mehrere Worker von der Frontier ziehen. Halten Sie eine Höflichkeitsverzögerung pro Host aufrecht, damit Parallelität nicht zu einer Flut wird, und erwägen Sie den asynchronen Crawler für Fire-and-Collect-Workloads, bei denen Sie viele URLs übermitteln und Ergebnisse beim Fertigstellen sammeln.
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.
