Yang bikin Crawlee terasa berguna adalah orkestrasi crawling-nya yang mendukung parsing HTTP sekaligus eksekusi browser. Jadi, URL yang sama bisa saja menghasilkan output yang berbeda, tergantung crawler dan kondisi kesiapan yang dipilih.
Pada halaman publik Quotes to Scrape JS, CheerioCrawler menemukan 0 kutipan target, sedangkan PlaywrightCrawler menemukan 10 setelah menunggu .quote. Alur crawling-nya memang mirip, tapi ini bukan sekadar ganti kelas dalam satu baris: handler Cheerio memakai $, sementara handler Playwright memakai page, explicit wait, dan ekstraksi dari sisi browser.
Apa sebenarnya Crawlee itu
Crawlee (proyek apify/crawlee, versi 3.17.0) adalah library web scraping dan otomasi browser untuk Node.js dan TypeScript. Crawlee mendukung crawling berbasis HTTP dengan Cheerio atau JSDOM, serta crawling berbasis browser dengan Playwright atau Puppeteer. Proyek ini memakai lisensi Apache-2.0; pastikan kamu meninjau kewajiban pemberitahuan dan atribusi sebelum mendistribusikannya.
Model pikir yang paling penting adalah memisahkan “mengambil halaman” dari “membaca halaman.” Satu jalur mengunduh HTML mentah dan tidak menjalankan JavaScript. Jalur lainnya membuka Chromium dan bisa menjalankan skrip halaman, tetapi tetap butuh kondisi kesiapan yang pas, dan masih bisa melewatkan konten yang bergantung pada interaksi, lazy-loaded, shadow DOM, API yang gagal, atau proteksi bot. Crawlee menyediakan konsep lifecycle yang selaras di kedua jalur ini, bukan primitive DOM yang bisa saling ditukar begitu saja.
Itulah hal yang perlu dipahami sebelum kamu menulis selector pertama, karena pilihan antara dua engine ini menentukan apakah scraper kamu mengembalikan data atau malah kosong total di suatu situs.
Fitur utama: dua engine, satu permukaan API

CheerioCrawler mengambil HTML lalu memprosesnya dengan Cheerio; PlaywrightCrawler menjalankan Chromium dan bisa mengambil screenshot. Keduanya memakai requestHandler, menyediakan run(), dan berbagi konsep crawling seperti queue dan penemuan tautan. Tapi konteks handler-nya beda: jalur Cheerio yang diuji mengekstrak lewat $, sedangkan jalur browser memakai page, waitForSelector, dan $$eval. Plumbing queue dan lifecycle memang tetap familiar, tetapi kode ekstraksi mungkin perlu adaptor atau ditulis ulang.
Di balik itu, Crawlee memberi kamu infrastruktur yang memang dibutuhkan untuk crawl sungguhan. RequestQueue mengelola frontier URL yang akan dikunjungi, mencegah duplikasi, dan melacak apa saja yang sudah selesai. enqueueLinks menemukan dan memasukkan URL baru ke queue (dengan filter selector dan same-hostname) supaya crawl bisa berkembang sendiri. Dataset mengumpulkan record hasil scraping untuk diekspor. Secara default, Crawlee menyimpan semuanya ke direktori lokal storage/ di disk — enak untuk melanjutkan proses, tapi agak mengganggu saat pertama kali melihat folder storage/ muncul di proyek tanpa diminta (harness saya mengalihkan penyimpanan ke temp dir dan mematikan persistence supaya pengujian tetap bersih).
Elemen-elemen ini kalau dilihat satu-satu sebenarnya umum saja. Intinya adalah semuanya dipakai bersama di dua engine, jadi queue, link discovery, dan dataset berperilaku sama baik saat crawling lewat HTTP maupun lewat browser. Kamu belajar satu API, lalu dapat dua strategi pengambilan data.
Setup: browser yang harus dipasang terpisah
Pada instalasi yang diuji, executable Chromium belum ikut terpasang setelah paket diinstal.

npm install crawlee playwright berjalan mulus buat saya — 85 paket, 0 vulnerability, tanpa drama. Kalau berhenti di situ lalu menjalankan CheerioCrawler, semuanya berfungsi, karena crawling HTTP memang tidak butuh browser.
Di lingkungan ini, Chromium harus dipasang terpisah dengan npx playwright install chromium; tanpa itu, PlaywrightCrawler gagal dijalankan. Beban browser yang teramati kira-kira 82 MiB, tetapi catatan asli tidak menyimpan apakah angka itu ukuran transfer atau ukuran di disk. Ini observasi setup yang spesifik pada mesin, bukan sifat produk yang permanen. Jalur dokumentasi dan perilaku paket bisa berubah, jadi artikel ini tidak mengklaim bahwa kelalaian tersebut berlaku di semua kasus atau selamanya tidak terdokumentasi.
Anggap setup yang diuji sebagai dua langkah: instal paket Node, lalu instal browser yang dipakai jalur Playwright. Cek lagi instruksi setup terbaru dari Crawlee dan Playwright untuk versi dan platform yang kamu pakai.
Praktik langsung: halaman yang sama, dua jawaban yang sangat berbeda

Pengujian inti mengirim fixture yang dirender JavaScript yang sama ke kedua crawler. URL dan field target-nya sama; primitive ekstraksinya tidak.
Pada fixture lokal, CheerioCrawler mengembalikan 0 kartu target karena elemen itu tidak ada di HTML mentah. PlaywrightCrawler menunggu #dynamic-products article.product-card, lalu mengembalikan seluruh 8 kartu yang diharapkan dan menangkap screenshot. Hasil itu menunjukkan kelengkapan level fixture untuk field yang dipilih setelah wait tersebut; bukan berarti browser bisa melihat semua state halaman yang mungkin. File mentah dan screenshot ada di repo benchmark.

Pada halaman publik Quotes to Scrape JS, CheerioCrawler menemukan 0 kutipan target, sedangkan PlaywrightCrawler menunggu .quote sebelum mengekstrak 10. Ini menegaskan batas HTTP-versus-browser yang sama pada target publik, sementara kelas crawler, konteks handler, kondisi wait, dan primitive ekstraksi semuanya berbeda di masing-masing jalur.
Kesimpulan yang paling berguna lebih sempit: validasi field wajib setelah jalur HTTP, lalu naikkan ke browser crawler ketika response mentah tidak memuatnya. Handler browser juga harus menunggu kondisi yang memang langsung terkait dengan field tersebut.
Jalur HTTP menghasilkan semua record yang diharapkan pada katalog statis dan fixture artikel yang terkontrol, mendekode seluruh delapan item yang diharapkan dari response JSON langsung, menelusuri graph terbatas 11 halaman, dan mengalihkan satu response 500 ke failedRequestHandler. Ini adalah pemeriksaan kemampuan yang terpisah, bukan satu skor akurasi. Pada halaman publik Books to Scrape, selector yang dikonfigurasi mengembalikan 20 produk sebagai smoke test.
| Pengujian | Engine | Hasil |
|---|---|---|
| Ekstraksi statis: katalog + pagination | CheerioCrawler | 12/12 produk yang diharapkan |
| Ekstraksi artikel | CheerioCrawler | judul + 3/3 paragraf |
| Transport: response JSON langsung | CheerioCrawler | 8/8 produk yang diharapkan |
| Traversal: graph internal-link | CheerioCrawler | 11 halaman, depth {0:1, 1:3, 2:7} |
| Penanganan kegagalan: HTTP 500 | CheerioCrawler | status masuk ke failure handler |
| Rendering: fixture lokal | CheerioCrawler | 0 kartu target di HTML mentah |
| Rendering: fixture lokal | PlaywrightCrawler | 8/8 setelah menunggu target selector |
| Rendering: Quotes JS | CheerioCrawler | 0 kutipan target di HTML mentah |
| Rendering: Quotes JS | PlaywrightCrawler | 10 setelah menunggu target selector |
Timing lengkap dan angka per pengujian ada di results/crawlee-test-summary.json.
Sekarang catatan jujurnya, karena pengujian satu mesin satu kali memang punya batas, dan saya tidak akan pura-pura sebaliknya. Ini timing, bukan benchmark — satu mesin, satu run per tes, jadi anggap biaya per halaman yang lebih tinggi pada jalur browser sebagai “jauh lebih lambat daripada run Cheerio yang sub-detik,” bukan angka resmi. Dan ada banyak hal yang tidak saya uji pada putaran ini: proxy rotation, session pool, run skala besar ratusan sampai ribuan halaman, persistence RequestQueue dan resume setelah crash, engine Puppeteer, serta ergonomi export Dataset/KeyValueStore (di sini saya menulis export secara manual). Saya bisa memastikan cerita dua engine dan akurasi level fixture. Saya tidak bisa memastikan skala atau perilaku anti-blocking, jadi saya tidak akan mengklaimnya.
Apa yang sama, dan apa yang harus berubah

Permukaan yang sama adalah orkestrasi crawling. Kedua kelas crawler menerima requestHandler dan menyediakan run(). Queue, metadata request, penemuan tautan, hook kegagalan, dan konsep storage bisa diatur dengan pola yang konsisten di kedua jalur eksekusi. Ini mengurangi jumlah infrastruktur yang perlu dipelajari ulang saat satu target ternyata butuh browser.
Permukaan akses halaman tidak sama. Handler CheerioCrawler menerima akses ala Cheerio seperti $ dan bisa bekerja dengan isi response tanpa browser. Handler PlaywrightCrawler yang diuji menerima page; ia menunggu selector dan melakukan evaluasi pada DOM browser. Walaupun kedua handler bisa menghasilkan skema record yang sama, mereka mencapainya lewat API yang berbeda. Adaptor yang bisa dipakai ulang mungkin dapat menyamarkan sebagian perbedaan ini, tetapi harness ini tidak mengimplementasikan atau mendemonstrasikannya.
Perbedaan ini penting untuk estimasi. Mengganti kelas crawler mungkin mempertahankan queue, dataset, dan kebijakan URL, tetapi selector, pemeriksaan kesiapan, screenshot, langkah interaksi, dan penanganan error tetap bisa berubah. Karena itu artikel ini memperlakukan “shared crawl plumbing” sebagai manfaat yang terbukti, dan menolak “migrasi satu baris” sebagai janji yang tidak didukung.
Alur praktis memilih engine
Pakai jalur HTTP dulu ketika HTML yang dikembalikan atau response JSON langsung memuat field yang dibutuhkan. Tetapkan kontrak kelengkapan — key wajib, jumlah item minimum, atau target selector — lalu gagal secara eksplisit saat tidak terpenuhi. Array kosong bukan bukti bahwa halaman tidak punya data; pada dua kasus JavaScript di sini, itu artinya representasi yang dipilih memang tidak memuat elemen target.
| Kondisi target | Mulai dengan | Naikkan ketika |
|---|---|---|
| Field wajib ada di HTML yang dikembalikan | CheerioCrawler | Selector atau field wajib tidak ada |
| Response JSON yang konsisten berisi data | CheerioCrawler | Request bergantung pada state khusus browser |
| Halaman menambahkan elemen target setelah eksekusi | PlaywrightCrawler | Tidak berlaku; tentukan readiness check khusus target |
| Campuran target belum jelas | HTTP lebih dulu dengan validasi kelengkapan | Validasi gagal dengan hasil bertipe “representation incomplete” |
Naikkan failure yang bertipe itu ke handler browser ketika eksekusi memang diperlukan. Pada harness ini, halaman lokal menunggu #dynamic-products article.product-card, sedangkan halaman quotes publik menunggu .quote. Kondisi-kondisi itu adalah bagian dari kontrak ekstraksi. Event load umum tidak cukup untuk membuktikan data aplikasi sudah datang, dan pengujian ini tidak mendukung aturan wait yang universal.
Setelah naik ke browser, pertahankan skema output tetap stabil meski primitive DOM berbeda. Catat engine mana yang menghasilkan hasil, kondisi kesiapan apa yang lolos, dan apakah validasi field wajib berhasil. Dengan begitu fallback HTTP-ke-browser jadi terlihat, bukan diam-diam mengubah field yang hilang menjadi record yang diterima.
Terakhir, anggap instalasi browser dan biaya operasionalnya sebagai input deployment. Observasi sekitar 82 MiB hanya berguna sebagai perkiraan lokal; ukur build browser yang tepat, platform, perilaku cache, dan dampak image di lingkungan kamu. Proxy rotation, session, persistence, recovery dari crash, dan concurrency yang berkelanjutan tetap perlu diuji sendiri sebelum fixture ini dijadikan dasar keputusan skala produksi.
Kelebihan dan kekurangan
Kelebihan:
- HTTP crawler dan browser crawler berbagi konsep lifecycle, tapi tetap menyediakan konteks ekstraksi spesifik engine.
- Ekstraksi HTTP akurat 1.0 pada katalog statis, artikel, dan API JSON.
- Plumbing yang sama di kedua engine:
RequestQueue,enqueueLinksdengan kontrol depth,Dataset. - Jalur browser menjalankan script fixture dan memulihkan seluruh item target yang diharapkan pada dua pengujian berbasis JS.
- Penanganan kegagalan bersih — HTTP 500 muncul tanpa membuat proses crash.
- Lisensi Apache-2.0; pengguna downstream perlu meninjau kewajiban pemberitahuan dan atribusi.
Kekurangan:
- Di lingkungan yang diuji, browser engine membutuhkan instalasi Chromium terpisah; tanpa itu
PlaywrightCrawlertidak bisa dijalankan. - Jalur HTTP tidak bisa menampilkan elemen target yang tidak ada di HTML mentah; tanpa validasi kelengkapan, hasil kosong bisa terlihat seperti valid.
- Jalur browser membawa binary browser tambahan dan biaya per halaman lokal yang lebih tinggi pada run ini; ukuran dan timing bervariasi Řسب build dan platform.
- Run default meninggalkan direktori
storage/di disk. - Hanya untuk Node/TypeScript — tidak membantu kalau stack kamu Python.
Cocok untuk siapa — dan siapa yang sebaiknya melewati
Crawlee cocok untuk tim Node atau TypeScript yang butuh crawling HTTP dan browser di bawah konsep queue dan lifecycle yang sama. Jalur praktisnya adalah mencoba HTTP crawler, memvalidasi field wajib, lalu menaikkan failure kelengkapan bertipe tertentu ke handler browser dengan readiness condition spesifik target. Kode akses DOM pada handler bersifat spesifik engine walaupun plumbing queue dan link discovery dibagi bersama.
Atur ulang ekspektasi, atau cari alternatif lain, kalau kamu adalah tim Python (Crawlee adalah Node/TS — ada port Python terpisah, tapi paket ini menguji library Node), kalau semua target kamu statis dan kamu lebih memilih scraper HTTP yang lebih ringan dan satu tujuan, atau kalau kamu butuh perilaku yang sudah terbukti pada skala besar — proxy rotation, session pool, resume setelah crash — yang tidak dicakup oleh pengujian langsung ini. Dan kalau kamu memakai PlaywrightCrawler, pasang Chromium dulu atau ia memang tidak akan jalan.
Alternatif, termasuk posisi Thunderbit
Crawlee adalah software open-source yang kamu jalankan dan kelola sendiri. Tidak ada biaya vendor per panggilan, tetapi komputasi browser, bandwidth, proxy, storage, observability, dan engineering tetap jadi biaya operasional. Kamu memegang sendiri pilihan crawler, binary browser, state storage, dan logic kesiapan.
Review terkait: ulasan scrapy-playwright.
Layanan ekstraksi terkelola memindahkan tanggung jawab pengambilan data dan pembentukan skema ke vendor. Kami membangun Thunderbit, tetapi tidak menjalankannya pada fixture ini, jadi artikel ini tidak mendukung perbandingan kualitas, latency, kesetaraan fitur, atau biaya. Keputusan yang relevan adalah apakah tim kamu menginginkan kontrol in-process ala Crawlee atau batas layanan per panggilan.
Review benchmark terkait: perbandingan lengkap scraper open-source, Playwright vs Puppeteer pada halaman yang sama, dan ulasan Scrapy tanpa replay request berbasis browser.
Coba Thunderbit untuk Ekstraksi Data Web
Putusan akhir
Crawlee adalah kandidat kuat untuk tim Node atau TypeScript yang menginginkan orkestrasi crawling bersama untuk HTTP dan eksekusi browser. Handler yang diuji tidak bisa dipertukarkan begitu saja: pindah ke Playwright butuh page, wait untuk target selector, dan ekstraksi dari sisi browser. Proxy, session, persistence, resume, dan perilaku skala besar masih jadi pertanyaan terbuka.
Coba Thunderbit untuk Ekstraksi Data Web Get Started Free
FAQ
Apa perbedaan nyata antara dua crawler milik Crawlee?
CheerioCrawler mengambil HTML lewat HTTP dan tidak menjalankan JavaScript. PlaywrightCrawler menjalankan Chromium dan bisa mengeksekusi script halaman serta mengambil screenshot, dengan biaya per halaman lokal yang lebih tinggi. Keduanya berbagi konsep lifecycle, tapi konteks handler-nya tidak identik: harness ini memakai $ di jalur HTTP dan page, wait untuk target selector, serta evaluasi dari sisi browser di jalur Playwright.
Kenapa PlaywrightCrawler tidak jalan setelah saya install Crawlee?
Pada lingkungan yang diuji, instalasi paket tidak menyediakan executable browser. Menginstal Chromium dengan npx playwright install chromium memperbaiki kegagalan launch. Payload yang teramati sekitar 82 MiB, tetapi pengukuran asli tidak menyimpan apakah itu ukuran transfer atau ukuran disk, jadi ukur ulang untuk platform dan build kamu.
Apakah CheerioCrawler bisa scraping halaman yang dirender JavaScript?
Tidak bisa mengeksekusi JavaScript halaman. Namun ia tetap dapat meminta endpoint JSON yang bisa diakses dan dipakai klien, seperti yang ditunjukkan fixture direct-response. Kalau data yang dibutuhkan baru muncul setelah eksekusi browser, gunakan browser crawler dan readiness condition yang memang langsung terkait dengan field tersebut.
Apakah Crawlee akurat untuk ekstraksi statis biasa? Pada fixture yang terkontrol, handler menghasilkan 12/12 produk katalog yang diharapkan, 3/3 paragraf artikel yang diharapkan, dan 8/8 item direct-JSON yang diharapkan. Ini adalah pemeriksaan kelengkapan fixture, bukan skor akurasi umum untuk situs yang belum diuji.
Apakah Crawlee gratis untuk penggunaan komersial? Crawlee dirilis di bawah Apache-2.0. Pastikan lisensi terkini di repository dan tinjau kewajiban pemberitahuan serta atribusi untuk distribusi kamu.
Sebelum dipakai di produksi, uji bagian yang belum dicakup fixture ini: concurrency berulang pada halaman representatif, perilaku proxy dan session, pemulihan queue persisten setelah gangguan, pembersihan proses browser, dan export dataset saat terjadi failure. Simpan versi browser dan jalur instalasi yang dipakai bersama hasil tersebut. Dua kelas crawler memang mengurangi perbedaan orkestrasi, tetapi tidak menghilangkan kebutuhan akan readiness check spesifik engine, anggaran resource, dan penanganan kegagalan operasional.


