Auf demselben Rechner hat cheerio in Node aus einem synthetischen 10-MB-HTML-Dokument Titel und hrefs extrahiert und dafür 2.927,89 ms gebraucht. selectolax, ausgeführt über CPython mit einem C-gestützten Parser, hat genau dieselbe Feldextraktion in 158 ms erledigt. Die sortierten Titeltexte und href-Hashes waren identisch. Das ist ein Vergleich des gesamten Stacks über unterschiedliche Laufzeiten hinweg, kein isoliertes Urteil über einen einzelnen Parser-Algorithmus.
Bei einer 10-KB-Seite ist der Abstand nur doppelt so groß, und das würde niemandem groß auffallen. Die eigentliche Frage ist also: Wo auf dieser Kurve liegen Ihre Seiten?
Was cheerio ist
cheerio ist der HTML-Parser für Node mit jQuery-Syntax und in diesem Ökosystem aus gutem Grund oft die Standardwahl: 30.449 GitHub-Stars, MIT-Lizenz und ein Push ins Repository am Tag vor meinem Test. Getestete Version: 1.2.0.
Offizielle Referenz: Cheerios offizielle Einführung.
import * as cheerio from "cheerio";
const $ = cheerio.load(html);
const titles = $("h3.title").map((_, e) => $(e).text()).get();
const hrefs = $("a").map((_, e) => $(e).attr("href")).get();
Wenn du jQuery schon kennst, kennst du die API im Grunde schon. Genau diese Vertrautheit ist ein Hauptgrund dafür, warum sich das Tool in seinem Ökosystem so gut durchgesetzt hat.
Unter der Haube steckt nicht ein einzelner Parser, sondern ein ganzer Stack: htmlparser2 und parse5 fürs Parsen, domhandler und domutils für den DOM-Baum, cheerio-select für Selektoren sowie undici, encoding-sniffer und weitere — elf direkte Abhängigkeiten, die sich zu 22 Paketen auf oberster Ebene und 9,0 MiB auf der Platte summieren. Diese Pakete liefern Parsing- und Encoding-Funktionen, vergrößern aber auch den Abhängigkeitsumfang. In diesem Test wurden Ausgabe und Verhalten bei fehlerhaftem Input geprüft, nicht aber die Encoding-Korrektheit oder die Trennung der beiden Parser-Backends.
Die Messung und warum sie belastbar ist
Diese Testbasis hatte bereits einen Parser-Benchmark: fünf Seitengrößen von 1 KB bis 10 MB, 50 Iterationen, drei unabhängige Durchläufe und — der entscheidende Punkt — eine Paritätsprüfung, die den extrahierten Inhalt hasht, also sortierte Titel plus sortierte hrefs, verglichen mit einem Referenzparser. Ein Parser, der still und leise Arbeit auslässt, kann keine schnellen Werte liefern.
cheerio musste vor der Auswertung zwei Hürden nehmen.
Kam die Referenz wieder dort an, wo sie vorher stand? selectolax wurde in derselben Sitzung mit denselben Fixtures erneut ausgeführt. Sein Content-Hash reproduzierte sich bei 5 von 5 Größen, und sein p50 lag zwischen 0,989× und 1,079× des veröffentlichten Werts. Das heißt: Es ist derselbe Rechner, der schon die ursprüngliche Tabelle erzeugt hat.
Lieferte cheerio dieselben bewerteten Felder? Sein Content-Hash — in Node mit identischer Regel berechnet, SHA-256 über sortierten Titeltext und sortierte hrefs — stimmte bei 5 von 5 Größen mit der Referenz überein. Das belegt Parität für diese sortierten Felder auf diesen Fixtures, nicht aber DOM-Struktur, Dokumentreihenfolge, Attribute, Textnormalisierung oder Fehlerbehandlung.
Erst dann haben die Zeiten überhaupt Aussagekraft.
| Seitengröße | selectolax | lxml | PyQuery | cheerio (Node) | cheerio vs selectolax |
|---|---|---|---|---|---|
| 1 KB | 0,0286 ms | 0,0508 | 0,0456 | 0,1147 ms | 4,0× |
| 10 KB | 0,1725 ms | 0,1802 | 0,1728 | 0,3490 ms | 2,0× |
| 100 KB | 1,4855 ms | 1,4145 | 1,4093 | 3,8399 ms | 2,6× |
| 1 MB | 14,97 ms | 15,03 | 14,96 | 59,37 ms | 4,0× |
| 10 MB | 158,10 ms | 165,25 | 162,86 | 2.927,89 ms | 18,5× |
p50 in Millisekunden, Median aus drei Durchläufen. parser-bench.json. Die drei Python-Parser liefen in einem Prozess; cheerio lief in Node 22, also an einer Laufzeitgrenze ebenso wie an einer Bibliotheksgrenze — siehe unten.
Die Tabelle ehrlich lesen

Die 1-KB-Zeile ist Rauschen. Über die drei Python-Parser hinweg lag die Streuung bei dieser Größe bei 77,6 %, und die Einzelwerte überlappen stark — selectolax bewegte sich über seine drei Durchläufe zwischen 0,0267 und 0,0404 ms. Bei 28 Mikrosekunden dominieren Timerauflösung und Scheduling. Ich würde bei 1 KB nichts ranken, auch cheerio nicht.
Die Mitte der Tabelle ist unspektakulär. Zwischen 10 KB und 1 MB liegen die Werte um den Faktor 2 bis 4 auseinander. Bei einem Scraper, der nur ein paar Hundert Seiten verarbeitet, wären das 45 Millisekunden pro Seite statt 15 — praktisch kaum wahrnehmbar.
Die 10-MB-Zeile ist kein Rauschen. cheerios drei Durchläufe lagen bei 2.839, 2.928 und 2.954 ms — eng beieinander und klar von den anderen Größen getrennt. Das End-to-End-Ergebnis bei 10 MB weicht deutlich vom Muster der kleineren Seiten ab. Aus fünf Messpunkten lässt sich weder die asymptotische Komplexität ableiten noch genau sagen, ob der Sprung aus der Laufzeit-, Parser-, Selektor-, Allokations- oder Garbage-Collection-Schicht kommt.
Es landet im Bereich von BeautifulSoup. Der veröffentlichte Benchmark misst vier weitere Parser auf demselben 10-MB-Fixture, und cheerios 2.927,89 ms daneben zu stellen, ist der nützlichste Vergleich in diesem Artikel:
| Parser (10 MB) | p50 |
|---|---|
| selectolax (lexbor) | 159,93 ms |
| lxml | 172,93 ms |
| parsel | 231,85 ms |
| selectolax (modest) | 247,95 ms |
| BeautifulSoup + lxml | 2.261,56 ms |
| BeautifulSoup + html.parser | 2.788,75 ms |
| cheerio | 2.927,89 ms |
Die vier Python-Zeilen stammen aus den veröffentlichten Werten in bench_parse.json; cheerios Wert stammt aus diesem Lauf. Der Referenzparser reproduzierte sich zwischen den beiden Läufen innerhalb von 0,989× bis 1,079×. Unterschiede unter etwa 8 % sollten daher als innerhalb dieser Unsicherheit betrachtet werden — cheerio gegenüber BeautifulSoups html.parser-Backend (5 % Abstand) liegt darin, cheerio gegenüber selectolax (18×) nicht.
BeautifulSoup ist die Bibliothek, zu der viele greifen, wenn sie es bequem wollen und bewusst in Kauf nehmen, dass sie langsam ist — die Bibliothek, die in jedem Python-Performance-Thread als Erstes ersetzt werden soll. Bei einem 10-MB-Dokument liegt cheerio am unteren Rand genau dieses Bereichs und nicht in dem Bereich der C-gestützten Parser, mit denen es oft in einen Topf geworfen wird.
Die Frage nach einem Ersatz auf der Node-Seite bleibt in diesem Artikel offen. Neuere Node-Alternativen wurden nicht getestet, daher kann dieses Ergebnis weder sagen, dass ein Bibliothekswechsel unmöglich ist, noch dass andere Optionen weniger etabliert wären. Es zeigt nur den gemessenen cheerio-Pfad im Vergleich zu den aufgeführten Python-Stacks.
Das ist ebenso ein Laufzeitvergleich wie ein Bibliotheksvergleich. cheerios Millisekunden hängen an Nodes JIT und Garbage Collector; die anderen entstehen dadurch, dass CPython in C-gestützte Parser hineinruft. Der Content-Hash beweist, dass dieselbe Arbeit erledigt wurde, und beide Zahlen sind genau das, was Entwickler bei der Stack-Wahl tatsächlich erleben — aber niemand sollte daraus lesen, dass „cheerios Algorithmus 18× schlechter ist als der von selectolax“. Es ist das, was auf diesem Rechner in der nativen Laufzeit der jeweiligen Bibliothek passiert ist.
Die Realität des Setups
| Bibliothek | Pakete | Speicherplatz | Lizenz | Stars | Letzter Push |
|---|---|---|---|---|---|
| cheerio | 22 (npm) | 9,0 MiB | MIT | 30.449 | 2026-08-11 |
| PyQuery | 3 (pip) | 20,1 MiB | BSD | 2.380 | 2026-07-27 |
Offizielle Referenz: cheerio-Konfigurationsdokumentation.
metadata-snapshot.json, am Tag des Schreibens abgerufen.
npm install cheerio dauerte unter zwei Sekunden und zog 9,0 MiB nach. Der Kaltimport wurde in einem separaten Konverterlauf auf demselben Rechner mit 0,056 s gemessen.
Elf direkte Abhängigkeiten sind für einen Parser viel, und das sollte man kennen, wenn man seinen Abhängigkeitsbaum prüft: htmlparser2, parse5, parse5-htmlparser2-tree-adapter, parse5-parser-stream, domhandler, domutils, dom-serializer, cheerio-select, encoding-sniffer, undici und whatwg-mimetype. Zwei vollständige Parser-Implementierungen stecken darin, weil cheerio je nach Anforderung die eine oder die andere verwenden kann.
Dreißigtausend Stars und ein Push am Tag vor dem Test sind in dieser Kategorie ein ziemlich gesundes Wartungssignal.
Speicherverbrauch und was kaputtes HTML damit macht
Speicherbedarf und Verhalten bei fehlerhaftem HTML beeinflussen Deployment und Fehlerbehandlung, deshalb werden beide hier getrennt gemessen.
Den größeren Kontext des Stresstests findest du im Vergleich von zehn Bibliotheken zu Speicherverbrauch und fehlerhaftem HTML.
Maximaler Resident Memory, gemessen mit /usr/bin/time -l, jeweils ein frischer Prozess pro Zelle — die Import-Basis ist das, was die geladene und ruhende Bibliothek kostet; die Spitzenwerte enthalten das Dokument.
| Bibliothek | Laufzeit | Import-Basis | Peak bei 226 KB | Peak bei 10 MB |
|---|---|---|---|---|
| html2text | python3.14 | 18,7 | 19,9 | 71,2 |
| pyquery | python3.14 | 30,3 | 33,9 | 172,5 |
| resiliparse | python3.14 | 20,5 | 25,1 | 225,1 |
| markdownify | python3.14 | 23,9 | 28,9 | 278,5 |
| goose3 | python3.14 | 44,1 | 52,4 | 398,5 |
| cheerio | node22 | 66,8 | 76,5 | 398,5 |
| justext | python3.14 | 30,3 | 36,6 | 431,2 |
| newspaper4k | python3.14 | 52,6 | 61,8 | 668,5 |
| trafilatura | python3.14 | 52,5 | 64,8 | 927,1 |
| turndown | node22 | 47,8 | 68,4 | 2947,1 |
memory-results.json. Python- und Node-Baselines sind nicht direkt miteinander vergleichbar; der Interpreter steckt in beiden.
cheerio hat in dieser gemischten Kontexttabelle mit 66,8 MiB die höchste Import-Basis einschließlich Node-Laufzeit und Abhängigkeiten. Der Prozess erreichte beim 10-MB-Fixture 398,5 MiB. Die anderen Zeilen enthalten Parser, Konverter und Article-Extraktoren mit unterschiedlicher Hauptaufgabe, also sollte man sie eher als Kontext zum Prozess-Footprint lesen denn als direkte Performance-Rangliste. Die turndown-Zeile in derselben Laufzeit erreichte zwar deutlich höhere Werte, sie konvertiert aber statt des hier für cheerio gemessenen Titellink-Vertrags.
Fehlerhaftes HTML. Zwölf Dokumente, die jeweils genau eine Sache kaputt machen — nicht geschlossene Tags, falsch verschachtelte Inline-Elemente, nicht gesetzte Anführungszeichen bei Attributen mit Leerzeichen, übrig gebliebene Schließ-Tags, gar kein <html>, doppelte Attribute, ein mitten im Tag abgeschnittenes Dokument, ungültige Entities, ein nicht geschlossenes <script>, eine falsche Charset-Deklaration, ein Kommentar mit Markup und 600 Verschachtelungsebenen — plus zwei korrekt geformte Kontrollfälle in passenden Größen, denn „es kam nichts zurück“ sagt nur dann etwas über Fehlerhaftigkeit aus, wenn die Bibliothek auf einem sauberen Dokument derselben Größe nicht ebenfalls schweigt.
cheerio warf bei 0 von 14 Fällen eine Ausnahme und gab bei 0 nichts zurück; es stellte auf den fehlerhaften Fixtures 11/22 bewertete Marker wieder her (malformed-results.json). Bei Parsern prüft der Scorer Heading- und Link-Sentinels über elf auswertbare fehlerhafte Dokumente; der Absatz-Sentinel wird nicht bewertet, und das nicht geschlossene <script>-Fixture ist ausgeschlossen. Ohne eine Baseline mit demselben Vertrag in diesem Abschnitt ist 11/22 kein Qualitätsranking. Die belastbare Schlussfolgerung ist, dass cheerio auf allen vierzehn fehlerhaften plus Kontroll-Eingaben ohne Ausnahme nicht-leere Ausgaben erzeugt hat und dabei die Hälfte der bewerteten Marker wiedergefunden hat.
Vor- und Nachteile
Vorteile. Vertraute jQuery-Syntax. MIT. Ein Wartungssignal mit Zeitstempel: 30.449 Stars und Repository-Aktivität am Tag vor dem Test. Zwei Parser-Backends und encoding-bezogene Pakete sind vorhanden, auch wenn Backend-Recovery und Encoding-Korrektheit hier nicht isoliert geprüft wurden. Der Hash aus sortierten Titeln plus hrefs stimmte auf jeder Fixture-Größe mit der Referenz überein.
Nachteile. Auf einem 10-MB-Dokument 18,5× langsamer als selectolax und auf 1 MB 4×. Elf direkte Abhängigkeiten, darunter zwei vollständige Parser-Implementierungen. Nur für Node. Und in der Dokumentation gibt es keinen Hinweis darauf, ab welcher Größe es nicht mehr die naheliegende Wahl ist.
Wer es nutzen sollte und wer nicht
cheerio verwenden, wenn du in Node arbeitest, die jQuery-ähnliche API wichtig ist und deine repräsentativen Seiten ungefähr in der getesteten Größenordnung bis 1 MB liegen. 1 MB ist der größte getestete Punkt vor dem deutlichen Sprung bei 10 MB; dieser Artikel legt keinen exakten Schwellenwert dazwischen fest und behauptet auch nicht, wie viel des Webs darunter liegt.
Vor dem Einsatz benchmarken, wenn du mit sehr großen HTML-Dokumenten arbeitest, etwa generierten Reports, Katalog-Dumps oder langen Listen-Seiten. XML-Sitemap-Verhalten wurde nicht getestet. Beim 10-MB-HTML-Fixture sind 2,9 Sekunden pro Dokument ein spürbarer Kostenfaktor, der sich schnell summiert.
Wenn du in Python arbeitest, sagt dieser Vergleich etwas anderes: selectolax, lxml und PyQuery liegen ab 10 KB praktisch gleichauf (innerhalb von 0,5 % bis 5,4 %, mit überlappenden Laufbereichen), also solltest du eher nach API als nach Geschwindigkeit wählen. Der interessante Wert ist der Abstand von cheerio zu allen drei, nicht die Unterschiede zwischen diesen dreien.
Wo eine Managed API hineinpasst
cheerio analysiert HTML, das du bereits besitzt. Es lädt nichts, rendert kein JavaScript und kümmert sich nicht um Anti-Bot-Schichten — und genau das ist bei vielen realen Zielen die schwierigere Hälfte der Aufgabe.
Ein Managed Service für Abruf, Rendering und Extraktion, einschließlich unseres eigenen Thunderbit, liegt auf einer anderen Verantwortungsebene. Thunderbit wurde hier nicht benchmarked. Der relevante Unterschied ist: geliefertes HTML mit Selektoren parsen versus das Einsammeln, Rendern und Extrahieren auszulagern; dieser Artikel liefert keinen Vergleich nach denselben Messgrößen für Qualität, Latenz oder Kosten.
Die faire Einordnung: Wenn du das HTML hast und deine Selektoren kennst, ist cheerio kostenlos und angenehm zu benutzen. Wenn du Seiten in großem Umfang abrufen oder lieber die Daten statt des DOMs beschreiben willst, ist das ein anderes Produkt.
Für das breitere Feld deckt unser Überblick über Web-Scraping-APIs gehostete Optionen ab, und der Open-Source-Scraper-Leitfaden die selbst gehosteten Lösungen. Wenn die extrahierten Daten später in ein Modell gehen, zeigt HTML in Python zu Markdown konvertieren, wo Informationen verloren gehen.
Thunderbit für Web-Datenextraktion testen
Sollte man cheerio verwenden?
Ja, in Node, wenn die passende API wichtig ist und die repräsentativen Dokumente im getesteten Bereich von klein bis 1 MB bleiben.
Die Vertrautheit der API und die aktuellen Wartungssignale sind legitime Auswahlkriterien. Der Benchmark beweist weder, dass ein bestimmter Support-Fall existiert, noch dass die getestete Seitenverteilung mit einem Produktionskorpus identisch ist.
Die Zahl, die man sich merken sollte, ist die für 10 MB. Irgendwo zwischen 1 MB und 10 MB hört es bei cheerio auf, den anderen zu folgen, und beginnt sich zu vervielfachen — 4× werden zu 18,5×. Wenn dein Korpus solche Dokumente enthält, benchmarke vor der Entscheidung, denn die Bibliothek selbst warnt dich davor nicht.
Thunderbit für Web-Datenextraktion testen Get Started Free
FAQs
Ist der Vergleich von cheerio mit Python-Parsern fair?
Ja, als Stack-Vergleich, nicht als Algorithmus-Vergleich. Alle vier lieferten unter der Hash-Regel auf 5 von 5 Seitengrößen identische sortierte Titeltexte und hrefs. Das beweist jedoch keine vollständige Gleichwertigkeit der Parser. cheerios Zeiten enthalten das Laufzeitverhalten von Node, die anderen das Zusammenspiel von CPython mit C-gestützten Parsern; der Vergleich beschreibt diese End-to-End-Entscheidungen.
Warum wird die 1-KB-Zeile nicht gerankt?
Weil bei 28 Mikrosekunden die Messung vom Rauschen dominiert wird. Über drei Durchläufe streuten die Python-Parser um 77,6 %, und die Einzelwerte überlappten einander. Jede Reihenfolge an dieser Größe wäre Zufall. Ab 10 KB aufwärts ist die Messung stabil genug.
Was verursacht den Sprung bei 10 MB?
Dieser Test sagt es nicht. Fest steht nur: Der Sprung ist real und kein Rauschen. cheerios drei Durchläufe lagen bei 2.839, 2.928 und 2.954 ms, klar getrennt von allem anderen, während der Abstand bei 1 MB noch 4× betrug. Um die Ursache zu isolieren, müsste man cheerios Parser-Backends separat profilieren; das lag außerhalb des Umfangs.
Wie viele Abhängigkeiten hat es wirklich?
Elf direkte, 22 auf oberster Ebene nach der Auflösung, 9,0 MiB auf der Platte. Zwei davon sind komplette Parser-Implementierungen — htmlparser2 und parse5 — weil cheerio je nach Bedarf beide einsetzen kann. Das ist der Preis dafür, sowohl fehlertolerantes als auch spezifikationsnahes Parsing abzudecken, und wichtig für Audits von Abhängigkeitsbäumen.
Was wurde hier nicht getestet?
Getestet wurden die Spitzenwerte des Prozessspeichers auf einem 226-KB- und einem 10-MB-Dokument sowie ein Vierzehn-Eingaben-Set aus fehlerhaften und Kontrollfällen, bei dem cheerio bei keinem Eingabefall eine Ausnahme geworfen, bei allen nicht-leere Ausgaben erzeugt und 11/22 bewertete Marker wiedergefunden hat. Nicht getestet wurden Streaming über parse5-parser-stream, Encoding-Korrektheit, backend-spezifische Fehlerbehandlung, die genaue Position des Leistungssprungs zwischen 1 und 10 MB, XML-Parsing oder neuere Node-Alternativen.


