Di satu mesin, cheerio di Node mem-parsing dan mengekstrak judul serta href dari dokumen HTML sintetis berukuran 10 MB dalam 2.927,89 ms. selectolax, yang berjalan lewat CPython dengan parser berbasis C, menyelesaikan ekstraksi field yang sama dalam 158 ms. Teks judul yang sudah diurutkan dan hash href-nya cocok. Ini adalah perbandingan end-to-end lintas runtime, bukan penilaian yang terpisah hanya pada algoritma parser.
Pada halaman 10 KB, selisihnya cuma 2×, dan itu jelas bukan sesuatu yang bakal langsung terasa. Pertanyaan intinya: halaman Anda ada di titik mana pada kurva itu.
Apa itu cheerio
cheerio adalah parser HTML bergaya sintaks jQuery untuk Node, dan memang ini jawaban default di ekosistem itu karena alasan yang kuat: 30.449 bintang GitHub, lisensi MIT, dan ada commit ke repositori sehari sebelum saya menjalankan pengujian ini. Versi yang diuji: 1.2.0.
Referensi resmi: pengantar resmi Cheerio.
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();
Kalau Anda pernah menulis jQuery, Anda sudah paham API-nya. Keakraban seperti ini adalah salah satu alasan utama kenapa ia menang di ekosistemnya.
Di balik layar, ini bukan satu parser, melainkan satu tumpukan: htmlparser2 dan parse5 untuk parsing, domhandler dan domutils untuk tree, cheerio-select untuk selector, ditambah undici, encoding-sniffer, dan lain-lain — sebelas dependensi langsung, yang setelah resolusi menjadi 22 paket level atas dan 9,0 MiB di disk. Paket-paket ini memang memberi kemampuan parsing dan encoding, tapi sekaligus menambah jejak dependensi. Ulasan ini menguji output pada input yang rusak, namun tidak menguji akurasi encoding atau memisahkan backend parser mana pun.
Pengukuran ini, dan mengapa bisa dipercaya
Basis riset ini sudah punya bench parser: lima ukuran halaman dari 1 KB sampai 10 MB, 50 iterasi, tiga run independen, dan — yang paling penting — gerbang parity yang meng-hash konten hasil ekstraksi, berupa judul yang diurutkan plus href yang diurutkan, lalu dibandingkan dengan parser referensi. Parser yang diam-diam melewatkan pekerjaan tidak bisa mengklaim waktu yang cepat.
Menambahkan cheerio ke dalamnya butuh dua pengecekan sebelum angka apa pun dihitung.
Apakah referensinya tetap mendarat di posisi yang sama seperti sebelumnya? selectolax dijalankan ulang pada sesi yang sama dengan fixture yang sama. Hash kontennya terulang pada 5 dari 5 ukuran, dan p50-nya berada di antara 0,989× dan 1,079× dari angka yang dipublikasikan. Jadi, ini memang mesin yang menghasilkan tabel asli.
Apakah cheerio menghasilkan field yang sama? Hash kontennya — dihitung di Node dengan aturan identik, SHA-256 atas teks judul yang diurutkan dan href yang diurutkan — cocok dengan referensi pada 5 dari 5 ukuran. Itu membuktikan parity untuk field yang diurutkan pada fixture ini, bukan bentuk DOM, urutan dokumen, atribut, normalisasi teks, atau error recovery.
Baru setelah itu timing-nya punya arti.
| Ukuran halaman | 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 dalam milidetik, median dari tiga run. parser-bench.json. Tiga parser Python berjalan dalam satu proses; cheerio berjalan di Node 22, yang berarti ada batas runtime sekaligus batas library — lihat di bawah.
Membaca tabel itu dengan jujur

Baris 1 KB itu noise. Di antara tiga parser Python, sebarannya pada ukuran itu mencapai 77,6%, dan run individual saling tumpang tindih secara liar — selectolax berkisar dari 0,0267 sampai 0,0404 ms dalam tiga run-nya. Pada 28 mikrodetik, resolusi timer dan penjadwalan sistem lebih dominan. Saya tidak akan memberi peringkat apa pun pada 1 KB, termasuk cheerio.
Bagian tengah tabel tidak terlalu menarik. Selisih 2× sampai 4× pada halaman antara 10 KB dan 1 MB. Untuk scraper yang memproses beberapa ratus halaman, itu berarti 45 milidetik per halaman alih-alih 15, dan Anda mungkin tidak akan merasakannya.
Baris 10 MB bukan noise. Tiga run cheerio berada di 2.839, 2.928, dan 2.954 ms — rapat, dan jauh terpisah dari baris lain. Hasil end-to-end pada 10 MB menyimpang tajam dari pola ukuran yang lebih kecil. Lima titik ukuran tidak cukup untuk menetapkan kompleksitas asimtotik atau memastikan apakah lonjakan itu berasal dari runtime, parser, selector, alokasi memori, atau lapisan garbage collection.
Hasilnya berada di kisaran BeautifulSoup. Bench yang dipublikasikan mengukur empat parser tambahan pada fixture 10 MB yang sama, dan menaruh 2.927,89 ms milik cheerio di sampingnya adalah hal paling berguna dalam artikel ini:
| 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 |
Empat baris Python di atas adalah angka yang dipublikasikan dari bench_parse.json; angka cheerio berasal dari run ini. Parser referensi terulang dalam rentang 0,989×–1,079× antara dua run, jadi perlakukan perbedaan di bawah kira-kira 8% sebagai masih dalam ketidakpastian itu — cheerio vs backend html.parser milik BeautifulSoup (selisih 5%) masih termasuk, cheerio vs selectolax (18×) tidak.
BeautifulSoup adalah library yang dipilih orang saat mereka mengutamakan kemudahan dan sadar bahwa itu lambat — itulah library yang biasanya disuruh diganti di setiap thread performa Python. Pada dokumen 10 MB, cheerio berada di bagian bawah band yang sama, bukan di band parser berbasis C yang biasanya diasosiasikan dengannya.
Pertanyaan pengganti di sisi Node masih terbuka dalam artikel ini. Alternatif Node yang lebih baru tidak diuji, jadi hasil ini tidak bisa menyatakan bahwa mengganti library itu mustahil atau menganggapnya kurang mapan. Hasil ini hanya menunjukkan jalur cheerio yang terukur dibandingkan stack Python yang tercantum.
Ini perbandingan runtime juga, bukan cuma library. Milidetik cheerio datang dari JIT dan garbage collector Node; yang lain datang dari CPython yang memanggil parser berbasis C. Hash konten membuktikan bahwa pekerjaan yang sama memang dilakukan, dan kedua angka itu adalah yang benar-benar dirasakan developer saat memilih stack — tapi jangan membaca ini sebagai "algoritma cheerio 18× lebih buruk daripada selectolax". Inilah yang terjadi, di mesin ini, pada runtime asli masing-masing library.
Realitas setup
| Library | Paket | Disk | Lisensi | Bintang | Push terakhir |
|---|---|---|---|---|---|
| cheerio | 22 (npm) | 9,0 MiB | MIT | 30.449 | 2026-08-11 |
| PyQuery | 3 (pip) | 20,1 MiB | BSD | 2.380 | 2026-07-27 |
Referensi resmi: dokumentasi konfigurasi Cheerio.
metadata-snapshot.json, diambil pada hari penulisan.
npm install cheerio memakan waktu di bawah dua detik dan menarik 9,0 MiB. Cold import diukur 0,056 s dalam run converter terpisah pada mesin yang sama.
Sebelas dependensi langsung itu cukup banyak untuk sebuah parser, dan layak diketahui kalau Anda sedang mengaudit dependency tree: htmlparser2, parse5, parse5-htmlparser2-tree-adapter, parse5-parser-stream, domhandler, domutils, dom-serializer, cheerio-select, encoding-sniffer, undici, dan whatwg-mimetype. Ada dua implementasi parser lengkap di dalamnya, karena cheerio bisa memakai salah satunya tergantung kebutuhan Anda.
Tiga puluh ribu bintang dan adanya push sehari sebelum pengujian adalah sinyal pemeliharaan yang sangat sehat untuk kategori ini.
Memori, dan apa yang dilakukan HTML rusak terhadapnya
Jejak memori dan perilaku pada HTML yang rusak memengaruhi deployment dan penanganan kegagalan, jadi keduanya diukur terpisah di sini.
Konteks stress test yang lebih luas ada di perbandingan memori dan HTML rusak untuk sepuluh library.
Puncak resident memory, lewat /usr/bin/time -l, satu proses baru per sel — import floor adalah biaya library saat dimuat dan idle, sedangkan puncaknya sudah termasuk dokumen.
| Library | Runtime | Import floor | Puncak 226 KB | Puncak 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. Baseline Python dan Node tidak bisa dibandingkan langsung satu sama lain; interpreter sudah termasuk di keduanya.
cheerio punya import floor tertinggi di tabel konteks campuran ini pada 66,8 MiB, termasuk runtime Node dan dependensinya. Prosesnya mencapai puncak 398,5 MiB pada fixture 10 MB. Baris lain mencakup parser, converter, dan extractor artikel yang melakukan pekerjaan utama yang berbeda, jadi gunakan itu sebagai konteks jejak proses, bukan ranking performa setara. Baris turndown pada runtime yang sama memang mencapai puncak jauh lebih tinggi, tetapi ia melakukan konversi, bukan kontrak selector judul-dan-href yang diukur untuk cheerio.
HTML rusak. Dua belas dokumen yang masing-masing merusak tepat satu hal — tag tak tertutup, elemen inline yang salah nesting, atribut tanpa tanda kutip dengan spasi, penutup liar, tidak ada <html> sama sekali, atribut duplikat, dokumen yang terpotong di tengah tag, entity yang rusak, <script> yang tidak ditutup, deklarasi charset yang menyesatkan, komentar yang berisi markup, dan nesting 600 level — ditambah dua kontrol yang valid secara struktur pada ukuran yang cocok, karena "hasilnya kosong" hanya memberi makna soal malformedness kalau library tersebut juga diam pada dokumen bersih dengan ukuran yang sama.
cheerio menimbulkan error pada 0 dari 14 dan tidak mengembalikan apa pun pada 0, serta berhasil memulihkan 11/22 sentinel yang dinilai pada fixture rusak (malformed-results.json). Untuk parser, scorer memeriksa sentinel heading dan link di sebelas dokumen rusak yang bisa dinilai; ia tidak menilai sentinel paragraf, dan fixture <script> yang tidak ditutup dikecualikan. Tanpa baseline dengan kontrak yang sama di bagian ini, 11/22 bukan ranking kualitas. Kesimpulan yang didukung adalah bahwa cheerio mengembalikan output non-kosong tanpa error pada semua empat belas input rusak-plus-kontrol, sambil memulihkan setengah dari marker yang dinilai.
Kelebihan dan kekurangan
Kelebihan. Sintaks jQuery yang familiar. MIT. Sinyal pemeliharaan bertimestamp berupa 30.449 bintang dan aktivitas repositori sehari sebelum pengujian. Ada dua backend parser dan paket terkait encoding, meski recovery backend dan akurasi encoding tidak diisolasi di sini. Hash gabungan judul plus href yang diurutkan cocok dengan referensi di setiap ukuran fixture.
Kekurangan. 18,5× lebih lambat daripada selectolax pada dokumen 10 MB, dan 4× pada 1 MB. Sebelas dependensi langsung, termasuk dua implementasi parser lengkap. Hanya untuk Node. Dan tidak ada satu pun di dokumentasinya yang memberi petunjuk ukuran di mana ia berhenti menjadi pilihan yang jelas.
Siapa yang sebaiknya memakai, dan siapa yang tidak
Gunakan cheerio kalau Anda berada di Node, API bergaya jQuery itu bernilai, dan halaman representatif Anda mirip dengan ukuran yang diuji hingga 1 MB. Satu megabyte adalah titik uji terbesar sebelum lonjakan tajam di 10 MB; artikel ini tidak menetapkan batas di antaranya atau mengklaim seberapa banyak web yang berada di bawahnya.
Benchmark dulu sebelum memakainya untuk dokumen HTML yang sangat besar seperti laporan hasil generate, dump katalog, atau halaman daftar panjang. Perilaku sitemap XML tidak diuji. Pada fixture HTML 10 MB, 2,9 detik per dokumen adalah biaya material yang akan berlipat.
Kalau Anda di Python, perbandingan ini menyampaikan hal lain: selectolax, lxml, dan PyQuery praktis seri dari 10 KB ke atas (dalam selisih 0,5% hingga 5,4%, dengan rentang run yang saling tumpang tindih), jadi pilih berdasarkan API, bukan kecepatan. Selisih cheerio terhadap ketiganya adalah angka yang menarik, bukan perbedaan di antara mereka.
Di mana API terkelola cocok
cheerio mem-parsing HTML yang sudah Anda miliki. Ia tidak mengambil data, tidak merender JavaScript, dan tidak menangani lapisan anti-bot — padahal pada banyak target nyata, justru itulah setengah pekerjaan yang lebih sulit.
Layanan terkelola untuk fetch/render/extraction, termasuk Thunderbit milik kami, berada di batas tanggung jawab yang berbeda. Thunderbit tidak di-benchmark di sini. Pembedaan yang relevan adalah antara mem-parsing HTML yang disuplai dengan selector versus mengalihdayakan akuisisi, rendering, dan ekstraksi; artikel ini tidak menyediakan perbandingan kualitas, latensi, atau biaya dengan metrik yang sama.
Cara pandang yang adil: kalau Anda memegang HTML-nya dan tahu selector Anda, cheerio gratis dan enak dipakai. Kalau Anda perlu mengambil halaman dalam skala besar, atau lebih suka mendeskripsikan data ketimbang DOM, itu keputusan yang berbeda.
Untuk cakupan yang lebih luas, roundup API web scraping kami membahas opsi hosted dan pilar scraper open-source untuk yang self-hosted. Jika output hasil parsing akan masuk ke model, mengonversi HTML ke Markdown di Python membahas di mana fidelity mulai hilang.
Coba Thunderbit untuk Ekstraksi Data Web
Jadi, apakah Anda harus memakai cheerio?
Ya, di Node, ketika kecocokan API penting dan dokumen representatif tetap berada di kisaran kecil hingga 1 MB yang diuji.
Keakraban API dan sinyal pemeliharaan saat ini adalah input pemilihan yang sah. Benchmark ini tidak membuktikan bahwa jawaban dukungan tertentu tersedia atau bahwa distribusi ukuran halaman yang diuji sama dengan korpus produksi Anda.
Angka yang perlu diingat adalah angka 10 MB. Di suatu titik antara 1 MB dan 10 MB, biaya cheerio berhenti mengikuti yang lain dan mulai melipatgandakan — 4× menjadi 18,5×. Kalau korpus Anda berisi dokumen sebesar itu, benchmark dulu sebelum berkomitmen, karena tidak ada apa pun di library ini yang akan memberi peringatan.
Coba Thunderbit untuk Ekstraksi Data Web Get Started Free
FAQ
Apakah adil membandingkan cheerio dengan parser Python? Ini adalah perbandingan stack, bukan perbandingan algoritma. Keempatnya menghasilkan teks judul dan href terurut yang identik di bawah aturan hash pada 5 dari 5 ukuran halaman. Itu tidak membuktikan kesetaraan penuh parser. Timing cheerio mencakup perilaku runtime Node, sedangkan yang lain mencakup CPython yang memanggil parser berbasis C; perbandingan ini menggambarkan pilihan end-to-end tersebut.
Mengapa baris 1 KB tidak diberi peringkat? Karena pada 28 mikrodetik, pengukuran didominasi oleh noise. Dalam tiga run, parser Python menyebar 77,6%, dengan run individual saling tumpang tindih. Urutan apa pun pada ukuran itu akan menjadi artefak. Mulai 10 KB ke atas, datanya cukup stabil untuk dibaca.
Apa yang menyebabkan lonjakan di 10 MB? Pengujian ini tidak menjelaskannya. Yang bisa dipastikan hanyalah lonjakan itu nyata dan bukan noise: tiga run cheerio berada di 2.839, 2.928, dan 2.954 ms, jauh terpisah dari yang lain, sementara selisih pada 1 MB adalah 4×. Mengisolasi penyebabnya berarti memprofiling backend parser cheerio secara terpisah, dan itu di luar cakupan di sini.
Berapa banyak dependensi yang sebenarnya dimiliki?
Sebelas langsung, 22 paket level atas setelah resolusi, 9,0 MiB di disk. Dua di antaranya adalah implementasi parser lengkap — htmlparser2 dan parse5 — karena cheerio bisa memakai salah satunya. Itulah harga untuk mendukung parsing yang permisif sekaligus yang sesuai spesifikasi, dan itu penting diketahui kalau Anda mengaudit dependency tree.
Apa yang tidak diuji di sini?
Pengujian mencakup puncak memori proses pada satu dokumen 226 KB dan satu dokumen 10 MB, plus set empat belas input rusak-plus-kontrol di mana cheerio tidak menimbulkan error, mengembalikan output non-kosong pada semuanya, dan memulihkan 11/22 sentinel yang dinilai. Yang tidak diuji: streaming lewat parse5-parser-stream, akurasi encoding, recovery spesifik backend, lokasi lonjakan performa antara 1 dan 10 MB, parsing XML, atau alternatif Node yang lebih baru.


