cheerio had 2,9 seconden nodig op een pagina van 10 MB in Node

Laatst bijgewerkt op August 19, 2026
cheerio had 2,9 seconden nodig op een pagina van 10 MB in Node
AI-samenvatting
Op één machine heeft cheerio in Node titels en hrefs uit een synthetisch HTML-document van 10 MB geparseerd en uitgelezen in 2.927,89 ms. selectolax, draaiend via CPython met een parser op C-basis, voltooide dezelfde veldextractie in 158 ms. De gesorteerde titeltekst en href-hashes kwamen overeen. Dit is een end-to-end vergelijking van stacks en runtimes, niet een geïsoleerd oordeel over een parseralgoritme. Op een pagina van 10 KB is het verschil 2×, en dat merkt niemand. De echte vraag is dus waar jouw pagina’s op die curve zitten. Gebruik cheerio als je in Node werkt, de jQuery-achtige API belangrijk vindt en je representatieve pagina’s lijken op de geteste groottes tot 1 MB.

Op één machine parseerde en extraheerde cheerio in Node uit een synthetisch HTML-document van 10 MB de titels en hrefs in 2.927,89 ms. selectolax, draaiend via CPython met een parser op C-basis, rondde exact dezelfde veldextractie af in 158 ms. De gesorteerde titels en de hashes van de hrefs kwamen overeen. Dit is een end-to-end vergelijking van complete stacks over runtimes heen, niet een geïsoleerd oordeel over een parser-algoritme.

Op een pagina van 10 KB is het verschil 2×, en dat merkt niemand. De echte vraag is dus waar jouw pagina’s op die curve zitten.

Wat cheerio is

cheerio is de HTML-parser met jQuery-syntaxis voor Node, en is in dat ecosysteem om goede redenen vaak het standaardantwoord: 30.449 GitHub-stars, MIT-licentie, en zelfs nog een commit de dag voordat ik deze test draaide. Geteste versie: 1.2.0.

Officiële referentie: Cheerio's officiële introductie.

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();

Als je ooit met jQuery hebt gewerkt, ken je de API al. Juist die vertrouwdheid verklaart voor een groot deel waarom het in zijn eigen ecosysteem heeft gewonnen.

Onder de motorkap is het niet één parser maar een hele stack: htmlparser2 en parse5 voor parsing, domhandler en domutils voor de DOM-boom, cheerio-select voor selectors, plus undici, encoding-sniffer en andere onderdelen — elf directe afhankelijkheden, die samen uitkomen op 22 packages op topniveau en 9,0 MiB op schijf. Die packages leveren parsing- en encodingmogelijkheden, maar vergroten ook de dependency footprint. In deze review is wel getest hoe het met foutieve input omgaat, maar niet of encoding correct wordt verwerkt of welke parser-backend precies verantwoordelijk is.

De meting, en waarom die betrouwbaar is

Deze onderzoeksbasis had al een parser-benchmark: vijf paginagroottes van 1 KB tot 10 MB, 50 iteraties, drie onafhankelijke runs, en — het belangrijkste deel — een pariteitscontrole die de geëxtraheerde content hash’t, gesorteerde titels plus gesorteerde hrefs, vergeleken met een referentieparser. Een parser die stilletjes werk overslaat, kan daar geen snelle tijd mee scoren.

cheerio toevoegen vereiste twee controles voordat een getal mocht meetellen.

Kwam de referentie weer uit op dezelfde plek? selectolax is in dezelfde sessie opnieuw gedraaid op exact dezelfde fixtures. De content hash werd op 5 van de 5 groottes gereproduceerd, en de p50 lag tussen 0,989× en 1,079× van de gepubliceerde waarde. Dit is dus dezelfde machine die ook de originele tabel produceerde.

Leverde cheerio dezelfde gescoorde velden op? De content hash — in Node berekend met exact dezelfde regel, SHA-256 over gesorteerde titels en gesorteerde hrefs — kwam op 5 van de 5 groottes overeen met de referentie. Dat bewijst pariteit voor die gesorteerde velden op deze fixtures, maar niet voor DOM-vorm, documentvolgorde, attributen, tekstnormalisatie of foutafhandeling.

Pas daarna krijgen de timings betekenis.

PaginagrootteselectolaxlxmlPyQuerycheerio (Node)cheerio vs selectolax
1 KB0,0286 ms0,05080,04560,1147 ms4,0×
10 KB0,1725 ms0,18020,17280,3490 ms2,0×
100 KB1,4855 ms1,41451,40933,8399 ms2,6×
1 MB14,97 ms15,0314,9659,37 ms4,0×
10 MB158,10 ms165,25162,862.927,89 ms18,5×

p50 in milliseconden, mediaan van drie runs. parser-bench.json. De drie Python-parsers draaiden in één proces; cheerio draaide in Node 22, dus dit is net zo goed een runtime-grens als een bibliotheekgrens — zie hieronder.

Hoe je die tabel eerlijk leest

Measured results chart: Parser time across page sizes

De rij van 1 KB is ruis. Tussen de drie Python-parsers is de spreiding op die grootte 77,6%, en individuele runs overlappen sterk — selectolax liep van 0,0267 tot 0,0404 ms over zijn drie runs. Bij 28 microseconden bepalen timerresolutie en planning het beeld. Ik zou op 1 KB niets rangschikken, cheerio inbegrepen.

Het midden van de tabel is weinig spectaculair. 2× tot 4× op pagina’s tussen 10 KB en 1 MB. Voor een scraper die een paar honderd pagina’s verwerkt, is dat 45 milliseconden per pagina in plaats van 15, en daar ga je in de praktijk niets van merken.

De rij van 10 MB is geen ruis. cheerio’s drie runs kwamen uit op 2.839, 2.928 en 2.954 ms — strak bij elkaar en duidelijk gescheiden van de andere rijen. Het end-to-end resultaat op 10 MB wijkt scherp af van het patroon bij kleinere groottes. Vijf datapunten bewijzen geen asymptotische complexiteit en zeggen ook niet welke runtime-, parser-, selector-, allocatie- of garbage-collectionlaag de sprong veroorzaakt.

Het zit in de band van BeautifulSoup. De gepubliceerde benchmark mat nog vier andere parsers op exact dezelfde 10 MB-fixture, en cheerio’s 2.927,89 ms daar naast zetten is het nuttigste aan dit artikel:

Parser (10 MB)p50
selectolax (lexbor)159,93 ms
lxml172,93 ms
parsel231,85 ms
selectolax (modest)247,95 ms
BeautifulSoup + lxml2.261,56 ms
BeautifulSoup + html.parser2.788,75 ms
cheerio2.927,89 ms

De vier Python-rijen zijn de gepubliceerde waarden uit bench_parse.json; die van cheerio komt uit deze run. De referentieparser reproduceerde tussen de twee runs binnen 0,989×–1,079×, dus verschillen kleiner dan ongeveer 8% vallen binnen die onzekerheid — cheerio versus BeautifulSoup met html.parser (5% verschil) valt daarbinnen, cheerio versus selectolax (18×) niet.

BeautifulSoup is de bibliotheek die mensen pakken als ze gemak willen en bewust accepteren dat hij traag is — precies de tool die in elke Python-performance-thread wordt aangeraden om te vervangen. Op een document van 10 MB belandt cheerio onderaan diezelfde band, niet in de band van de C-ondersteunde parsers waarmee het vaak op één hoop wordt gegooid.

De vraag naar een Node-vervanger blijft in dit artikel open. Nieuwere Node-alternatieven zijn niet getest, dus deze uitkomst zegt niet dat overstappen onmogelijk is of dat zulke opties minder volwassen zouden zijn. Ze laat alleen het gemeten cheerio-pad zien tegenover de genoemde Python-stacks.

Het is net zo goed een runtimevergelijking als een bibliotheekvergelijking. cheerio’s milliseconden komen uit Node’s JIT en garbage collector; de andere uit CPython dat C-code aanroept. De content hash bewijst dat hetzelfde werk is gedaan, en beide cijfers zijn precies wat een ontwikkelaar bij de keuze van een stack daadwerkelijk ervaart — maar niemand zou dit moeten lezen als “cheerio’s algoritme is 18× slechter dan dat van selectolax”. Zo gebeurde het op deze machine, in de native runtime van elke bibliotheek.

Hoe de setup eruitziet

BibliotheekPackagesSchijfgebruikLicentieStarsLaatste push
cheerio22 (npm)9,0 MiBMIT30.4492026-08-11
PyQuery3 (pip)20,1 MiBBSD2.3802026-07-27

Officiële referentie: Cheerio configuration documentation.

metadata-snapshot.json, opgehaald op de dag van schrijven.

npm install cheerio duurde minder dan twee seconden en trok 9,0 MiB binnen. Een koude import werd in een aparte converter-run op dezelfde machine gemeten op 0,056 s.

Elf directe afhankelijkheden is veel voor een parser, en relevant als je je dependency tree controleert: htmlparser2, parse5, parse5-htmlparser2-tree-adapter, parse5-parser-stream, domhandler, domutils, dom-serializer, cheerio-select, encoding-sniffer, undici en whatwg-mimetype. Er zitten twee volledige parserimplementaties in, omdat cheerio afhankelijk van de situatie beide kan gebruiken.

Dertigduizend sterren en een push de dag vóór de test zijn in deze categorie ongeveer zo gezond als onderhoudssignalen maar kunnen zijn.

Geheugen, en wat kapotte HTML daarmee doet

Geheugenverbruik en gedrag bij foutieve HTML zijn belangrijk voor deployment en foutafhandeling, dus beide zijn hier apart gemeten.

De bredere stress-testcontext staat in de vergelijking van tien bibliotheken op geheugen en kapotte HTML.

Piek resident memory, via /usr/bin/time -l, telkens één vers proces per cel — de import floor is wat de bibliotheek kost als hij geladen en idle is, de pieken bevatten ook het document.

BibliotheekRuntimeImport floorPiek 226 KBPiek 10 MB
html2textpython3.1418,719,971,2
pyquerypython3.1430,333,9172,5
resiliparsepython3.1420,525,1225,1
markdownifypython3.1423,928,9278,5
goose3python3.1444,152,4398,5
cheerionode2266,876,5398,5
justextpython3.1430,336,6431,2
newspaper4kpython3.1452,661,8668,5
trafilaturapython3.1452,564,8927,1
turndownnode2247,868,42947,1

memory-results.json. Python- en Node-baselines zijn onderling niet direct vergelijkbaar; de interpreter zit in beide.

cheerio heeft in deze gemengde context-tabel de hoogste import floor met 66,8 MiB, inclusief de Node-runtime en afhankelijkheden. Het proces piekte op 398,5 MiB bij de 10 MB-fixture. De andere rijen bevatten parsers, converters en article extractors die ander primair werk doen, dus gebruik ze als context voor procesvoetafdruk, niet als vergelijkbare prestatie-ranking. De turndown-rij in dezelfde runtime piekte veel hoger, maar die doet conversie in plaats van de title-and-href-selector-taak die hier voor cheerio is gemeten.

Kapotte HTML. Twaalf documenten die elk precies één ding breken — niet-afgesloten tags, verkeerd geneste inline-elementen, ongequote attributen met spaties, losse sluit-tags, helemaal geen <html>, dubbele attributen, een document dat halverwege een tag afbreekt, slechte entities, een niet-afgesloten <script>, een misleidende charset-declaratie, een commentaar met markup, en 600 niveaus nesting — plus twee goed gevormde controles op dezelfde groottes, want “hij gaf niets terug” zegt alleen iets over malformedness als de library ook stil blijft op een schoon document van dezelfde grootte.

cheerio gooide een fout op 0 van de 14 en gaf ook op 0 niets terug; het herstelde 11/22 gescoorde sentinels over de malformed fixtures heen (malformed-results.json). Voor parsers controleert de scorer heading- en linksentinels over elf scorebare malformed documenten; de paragraph-sentinel wordt niet meegeteld, en de fixture met niet-afgesloten <script> is uitgesloten. Zonder een baseline met hetzelfde contract in deze sectie is 11/22 geen kwaliteitsranking. De ondersteunde conclusie is dat cheerio op alle veertien malformed-plus-control-inputs niet-lege output gaf zonder een fout te gooien, terwijl het de helft van de gescoorde markers terugvond.

Voor- en nadelen

Pluspunten. Vertrouwde jQuery-syntaxis. MIT. Een onderhoudssignaal met tijdstempel van 30.449 sterren en activiteit in de repository de dag vóór de test. Twee parser-backends en encoding-gerelateerde packages zijn aanwezig, al zijn backend-herstel en encodingnauwkeurigheid hier niet afzonderlijk getest. De gehashte combinatie van gesorteerde titels en hrefs kwam op elke fixturegrootte overeen met de referentie.

Minpunten. 18,5× trager dan selectolax op een document van 10 MB, en 4× op 1 MB. Elf directe afhankelijkheden, waaronder twee complete parserimplementaties. Alleen voor Node. En niets in de documentatie suggereert een grootte waarbij het niet langer de voor de hand liggende keuze is.

Wie het wel en niet zou moeten gebruiken

Gebruik cheerio als je in Node werkt, de jQuery-vormige API waardevol vindt, en je representatieve pagina’s lijken op de geteste groottes tot 1 MB. Eén megabyte is het grootste geteste punt vóór de abrupte sprong bij 10 MB; dit artikel stelt geen exacte grens tussen die twee vast en zegt ook niet welk deel van het web daaronder valt.

Benchmark eerst als je zeer grote HTML-documenten verwerkt, zoals gegenereerde rapporten, catalogus-dumps of lange lijstpagina’s. XML-sitemapgedrag is niet getest. Op de 10 MB HTML-fixture is 2,9 seconden per document een serieuze kostenpost die zich snel opstapelt.

Als je in Python zit, zegt deze vergelijking iets anders: selectolax, lxml en PyQuery zijn vanaf 10 KB praktisch gelijkwaardig (binnen 0,5% tot 5,4%, met overlappende run-ranges), dus kies op API en niet op snelheid. cheerio’s verschil met alle drie is het interessante getal, niet de verschillen tussen die drie onderling.

Waar een managed API past

cheerio parseert HTML die je al hebt. Het haalt niet op, rendert geen JavaScript en handelt geen anti-botlaag af — en op veel echte doelwitten is juist dat laatste het moeilijkste deel van de klus.

Een beheerde fetch/render/extract-service, waaronder onze eigen Thunderbit, zit op een ander verantwoordelijkheidsniveau. Thunderbit is hier niet gebenchmarkt. Het relevante onderscheid is: aangeleverde HTML parsen met selectors versus het uitbesteden van ophalen, renderen en extraheren; dit artikel biedt geen vergelijking op basis van dezelfde metric voor kwaliteit, latency of kosten.

Eerlijke formulering: als je de HTML al hebt en je selectors kent, is cheerio gratis en prettig in gebruik. Als je op schaal pagina’s ophaalt, of liever de data beschrijft dan de DOM, dan koop je iets heel anders.

Voor het bredere veld behandelt onze web scraping API-vergelijking gehoste opties en de open-source scraper-pijler de zelf-gehoste varianten. Als de geparseerde output naar een model gaat, laat HTML naar Markdown converteren in Python zien waar fidelity verloren gaat.

Probeer Thunderbit voor webdata-extractie

Moet je cheerio gebruiken?

Ja, in Node, wanneer de match met de API belangrijk is en representatieve documenten dicht bij de geteste kleine-tot-1 MB-range blijven.

De vertrouwdheid van de API en de huidige onderhoudssignalen zijn legitieme selectiecriteria. De benchmark bewijst niet dat er een specifiek supportantwoord bestaat of dat de geteste verdeling van paginagroottes overeenkomt met een productiedataset.

Het getal dat je moet onthouden is dat van 10 MB. Iets tussen 1 MB en 10 MB maakt dat cheerio’s kosten niet meer met de rest meebewegen maar gaan vermenigvuldigen — 4× wordt 18,5×. Als je corpus zulke grote documenten bevat, benchmark dan voordat je beslist, want de bibliotheek zelf waarschuwt je daar niet voor.

Probeer Thunderbit voor webdata-extractie Get Started Free

Veelgestelde vragen

Is cheerio vergelijken met Python-parsers eerlijk? Dit is een vergelijking van stacks, niet van algoritmes. Alle vier leverden onder de hash-regel identieke gesorteerde titels en hrefs op op 5 van de 5 paginagroottes. Dat bewijst geen volledige gelijkwaardigheid van parsers. cheerio’s timings bevatten het gedrag van Node’s runtime, terwijl de andere CPython omvatten dat C-ondersteunde parsers aanroept; de vergelijking beschrijft die end-to-end keuzes.

Waarom staat de rij van 1 KB niet in de ranking? Omdat de meting bij 28 microseconden wordt gedomineerd door ruis. Over drie runs verspreidden de Python-parsers zich met 77,6%, waarbij individuele runs elkaar overlappen. Elke volgorde op die grootte zou een artefact zijn. Vanaf 10 KB is de tabel stabiel genoeg om te lezen.

Waardoor komt de sprong bij 10 MB? Dat zegt deze test niet. Wat wel wordt vastgesteld, is dat de sprong echt is en geen ruis: cheerio’s drie runs eindigden op 2.839, 2.928 en 2.954 ms, duidelijk los van de rest, terwijl het verschil bij 1 MB 4× was. De oorzaak isoleren zou betekenen dat je de parser-backends van cheerio afzonderlijk profileert, en dat viel buiten deze scope.

Hoeveel afhankelijkheden heeft het echt? Elf directe, 22 op topniveau na resolutie, 9,0 MiB op schijf. Twee daarvan zijn volledige parserimplementaties — htmlparser2 en parse5 — omdat cheerio beide kan gebruiken. Dat is de prijs van zowel vergevingsgezinde als standaardspecifieke parsing ondersteunen, en goed om te weten als je dependency trees controleert.

Wat is hier niet getest? De tests dekten de piekgeheugenvoetafdruk van één document van 226 KB en één van 10 MB, plus een set van veertien malformed-plus-control-inputs waarbij cheerio op geen enkele input een fout gaf, op alle inputs niet-lege output gaf, en 11/22 gescoorde sentinels terugvond. Niet getest zijn streaming via parse5-parser-stream, encodingcorrectheid, backendspecifieke recovery, de exacte locatie van de prestatiewissel tussen 1 en 10 MB, XML-parsing of nieuwere Node-alternatieven.

Ke
Ke
CTO bij Thunderbit | Senior Data Scientist & ML-expert Met bijna tien jaar ervaring in machine learning en data science is Ke Shen alumnus van Columbia University en voormalig Senior Data Scientist bij Walmart Labs. Met diepgaande, door vakgenoten erkende expertise in Python, R, Java en statistiek deelt hij praktijkgerichte inzichten over hoe je complexe AI-algoritmen van theorie naar productieklare architectuur brengt.
Inhoudsopgave
Thunderbit · AI-webdata-agent

Gegevens extraheren van elke pagina in 1 klik

Vertrouwd door 250.000+ gebruikers
gratis plan beschikbaar
Van webpagina naar spreadsheet
Beschrijf wat je nodig hebt — Thunderbit's AI Agent scrapt het en exporteert naar Excel, Google Sheets, Airtable of Notion. Gratis om te beginnen.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week