Playwright adalah framework otomatisasi browser dari Microsoft: library berlisensi Apache-2.0 yang mengutamakan TypeScript, menjalankan browser sungguhan, mengendalikannya lewat satu API, lalu mengembalikan halaman setelah JavaScript-nya selesai diproses. Produk ini dipasarkan sebagai framework pengujian end-to-end, tetapi mesin di baliknya justru jadi andalan banyak orang ketika permintaan HTTP cuma menghasilkan halaman kosong di tempat data seharusnya muncul. Dari bentuknya, Playwright bersaing dengan Puppeteer dan Selenium — browser asli yang Anda skrip, bukan klien HTTP yang Anda parse.
Saya menjalankan microsoft/playwright 1.56.0 melalui rangkaian tes scraping yang tetap — katalog statis dengan pagination, sebuah artikel, katalog yang dirender JavaScript, API JSON, error 500, graf crawling kecil, serta dua situs latihan publik — di Node v22.22.3, macOS arm64, hanya Chromium. Bagian rendering berjalan mulus. Bagian crawling memang tidak ada, dan celah itulah hal paling penting untuk dipahami sebelum Anda memutuskan memakainya.
Hal yang paling menonjol
Ada dua hasil utama yang menonjol, dan keduanya mengarah ke arah yang sedikit berbeda.
Yang pertama adalah hasil browser yang memang diharapkan, dibatasi oleh proses tunggu yang saya gunakan. Setelah page.goto(..., { waitUntil: 'domcontentloaded' }), tes fixture dinamis menunggu #dynamic-products article.product-card, dan tes publik Quotes to Scrape menunggu .quote. Selector spesifik aplikasi itu muncul, lalu hasilnya mengembalikan 8/8 item fixture dan 10 kutipan dari situs publik; hasil fixture mencapai recall 1.0 terhadap delapan item ground truth-nya. Tidak perlu loop polling khusus, tetapi Playwright juga tidak menghilangkan masalah kesiapan—teslah yang menentukan kondisi selesai. Screenshot full-page juga berhasil pada percobaan pertama.
Hasil kedua memakai browserContext.request: tepatnya ctx.request.get(...) setelah Chromium sudah diluncurkan dan browser context tersedia. Request ini memanggil endpoint JSON fixture secara langsung dan mengembalikan 8/8 produk tanpa membuat atau merender halaman. Artinya, kerja DOM dilewati, tetapi biaya proses browser tetap ada di harness ini. Request client yang terikat ke context bisa berbagi cookie state dengan halaman browser; sementara playwright.request.newContext() yang berdiri sendiri tidak membutuhkan browser context, tetapi tidak otomatis berbagi sesi itu. Tes ini hanya mencakup jalur pertama.
Playwright juga tidak menyediakan antrean crawl, penulis dataset, atau throttling otomatis. Tes crawl-graph saya — menelusuri tautan internal, melacak depth, dan menghindari kunjungan ulang — mencapai 12 halaman pada depth {0:1, 1:4, 2:7}, tetapi traversal breadth-first itu adalah kode tes yang saya tulis sendiri. Playwright membuka dan memeriksa halaman; penyimpanan frontier, kebijakan URL, retry, dan penjadwalan ada di lapisan lain.
Sebenarnya Playwright itu apa
Tool ini — microsoft/playwright di GitHub — ditulis dengan TypeScript, berlisensi Apache-2.0, dan dikelola oleh Microsoft. Build yang diuji di sini adalah 1.56.0 pada 9 Juli 2026. Hasil yang dilaporkan merujuk pada build tersebut, bukan pernyataan kompatibilitas untuk versi-versi setelahnya.
Posisi resminya cukup jelas: framework untuk pengujian dan otomatisasi web yang mengendalikan Chromium, Firefox, dan WebKit lewat satu API. Jalur utama Playwright adalah test runner dengan fixture, assertion, dan trace viewer. Memakainya sebagai alat scraping berarti mengikuti Library mode yang didokumentasikan: chromium.launch(), lalu context, lalu page, di luar harness pengujian. Semua yang ada di ulasan ini memakai API publik itu. Saya tidak menjalankan tes kompatibilitas lintas versi, jadi ini bukan klaim bahwa semua perilaku yang diuji tetap stabil di setiap rilis.
Cakupan yang terdokumentasi itu memang menjadi fitur utama di tempat lain, jadi saya akan menyebutkannya dengan hati-hati. Playwright menggerakkan tiga engine browser — Chromium, Firefox, dan WebKit — lewat satu API, dan juga menyediakan client resmi untuk Python, Java, dan .NET di atas JavaScript. Itu memang terdokumentasi, dan benar-benar menjadi pembeda utama tool ini dari sisi bentuk. Namun apa yang benar-benar diuji di sini lebih sempit:
| Kemampuan | Status dalam ulasan ini |
|---|---|
| Engine Chromium | Diuji — semua tes di sini berjalan di Chromium |
| Engine Firefox | Terdokumentasi, tidak diverifikasi di sini |
| Engine WebKit | Terdokumentasi, tidak diverifikasi di sini |
| Satu API untuk ketiga engine | Terdokumentasi, tidak diverifikasi di sini |
| Client Python, Java, dan .NET | Terdokumentasi, tidak diverifikasi di sini |
| Proxying | Tidak diuji |
| Skala multi-context paralel | Tidak diuji |
| Intersepsi jaringan untuk scraping berbasis API | Tidak diuji |
Jika target merender berbeda di WebKit Safari, atau tim Anda memakai Python, cakupan itulah argumen Playwright — hanya saja jangan anggap hasil saya sebagai bukti paritas Firefox atau WebKit, karena saya memang tidak mengujinya.
Cara kerjanya di balik layar
Model mentalnya adalah mesin browser yang Anda skrip. chromium.launch() memulai proses browser. context adalah sesi terisolasi dengan cookie, storage, dan cache sendiri; page adalah tab di dalam context itu. Anda memanggil page.goto(url), menunggu kondisi yang mewakili kesiapan aplikasi, lalu membaca DOM hasilnya dengan helper seperti page.$$eval. Ini lebih dekat ke browser yang dipakai pengguna daripada mem-parsing respons HTTP, tetapi bukan berarti identik dengan kondisi nyata di lingkungan produksi: sinyal headless, viewport, locale, font, state profil, jalur TLS/jaringan, dan perlindungan situs tetap bisa mengubah apa yang disajikan. Ulasan ini tidak menguji perilaku anti-bot atau paritas browser produksi.
page.screenshot() menangkap halaman yang sudah dirender, baik full-page maupun terpotong, dan pada run saya berhasil pada percobaan pertama. Sementara API request yang saya sebut tadi — context.request.get — memakai cookie context yang sama tetapi melewati rendering, jadi Anda bisa menggabungkan pola “muat halaman dan baca DOM” dengan “langsung panggil endpoint JSON” dalam satu skrip tanpa berpindah tool.
Yang tidak termasuk di dalamnya adalah mesin crawling. Tidak ada scheduler request, visited-set yang disimpan, kebijakan politeness, atau pipeline ekspor. Traversal terbatas memang mudah digambar, tetapi pekerjaan frontier yang andal juga butuh normalisasi URL, penanganan redirect, retry, aturan scope, throttling, dan pemulihan. Lapisan itu harus Anda bangun sendiri atau gunakan framework yang membungkus browser engine.
Realita instalasi dan setup
Instalasinya dua langkah, dan langkah kedua yang membawa beban deployment terbesar. npm install playwright akan mengambil library-nya; lalu npx playwright install terpisah untuk mengunduh build browser (dalam kasus saya Chromium). Siapkan ruang disk, waktu unduh, caching browser di CI, dan pembersihan proses, jangan menganggap paket npm itu sudah mencakup seluruh sistem yang bisa dijalankan.
Kalau Anda memasang Playwright dengan ekspektasi sebagai scraper lalu mengikuti tutorial testing, Anda akan mulai dari file tes dan assertion expect(). Kode scraping justru memakai API library secara langsung. Keduanya terdokumentasi, tetapi perbedaannya penting saat mencari contoh dan menentukan perintah deployment.
Pada run ini, sisi ergonomis yang paling terasa cukup konkret: browser context mengisolasi state sesi, panggilan async tersusun rapi, screenshot cukup satu panggilan, dan HTTP 500 tetap bisa diperiksa lewat objek response. Yang agak merepotkan justru operasional, bukan sintaks: build browser harus diinstal dan lifecycle-nya dikelola terpisah dari library.
Hasil praktik langsung

Semua angka lokal dijalankan terhadap fixture server di 127.0.0.1 dengan ground truth yang sudah ditulis sebelum crawling dimulai. Harness lengkapnya ada di run_playwright_material_tests.mjs, dan artefak mentah yang dikomit mencakup ground truth dan output per tes. Semua ini tetap merupakan observasi dari penulis, satu mesin, satu kali run; tautannya membuka permukaan reproduksi, bukan mengubahnya menjadi benchmark luas.
| Tes | Target | Hasil |
|---|---|---|
| Katalog statis + pagination | fixture lokal | 12/12 produk, recall 1.0 |
| Ekstraksi artikel | fixture lokal | judul + 3/3 paragraf, boilerplate dipisahkan |
| Halaman JS dinamis (render native) | fixture lokal | 8/8, recall 1.0, screenshot full-page tersimpan |
API JSON dinamis (page.request) | fixture lokal | 8/8, recall 1.0, tanpa render DOM |
| Penanganan HTTP 500 | fixture lokal | status 500 bisa diperiksa, navigasi tidak melempar error |
| Graf crawl (BFS buatan tangan) | fixture lokal | 12 halaman, depth {0:1, 1:4, 2:7} |
| Books to Scrape | demo publik | 20 produk |
| Quotes JS (dirender JS) | demo publik | 10 kutipan, dirender secara native |
Loop pagination mengikuti link berikutnya secara eksplisit; Playwright tidak menemukan halaman sendiri. Selector artikel memisahkan navigasi dan teks footer dari hasil body. Pada jalur gagal, navigasi mengembalikan objek response dengan status 500 alih-alih melempar error, sehingga caller yang memutuskan apakah akan log, retry, atau lanjut. Dua target latihan publik mengembalikan jumlah yang ditunjukkan di tabel.
Ada batas yang perlu disebutkan secara tegas: semuanya di sini berjalan di Chromium, pada satu mesin, satu kali. Tabel kemampuan memisahkan cakupan yang terdokumentasi dari perilaku yang benar-benar diuji. Saya tidak menjalankan suite ini lagi pada build Playwright lain, jadi tidak ada kesimpulan lintas versi. Timing per tes juga tidak saya tampilkan sebagai benchmark; satu kali pengukuran dengan stopwatch di satu laptop tidak cukup untuk perbandingan kecepatan.
Kesiapan adalah bagian dari kontrak ekstraksi
Hasil dinamis bergantung pada wait yang mewakili data yang saya butuhkan, bukan sekadar navigasi browser. Untuk katalog lokal, harness bernavigasi dengan waitUntil: 'domcontentloaded' lalu memanggil waitForSelector('#dynamic-products article.product-card') dengan timeout 15 detik. Run Quotes JS publik memakai state navigasi yang sama dan menunggu .quote dengan timeout 20 detik. Ekstraksi baru dilakukan setelah selector itu muncul.
Pembedaan ini penting saat Anda menyesuaikan skrip. domcontentloaded hanya berarti dokumen awal sudah diparse; itu tidak berarti respons API yang terlambat sudah datang, hydration selesai, daftar infinite berhenti bertambah, atau baris virtualized sudah masuk viewport. Selector berguna ketika keberadaan satu elemen yang cocok sudah cukup. Jika kelengkapan bergantung pada respons yang diketahui, jumlah item, state aplikasi, atau jendela jaringan yang sudah tenang, tunggu kondisi itu sebagai gantinya. Kondisinya harus terikat pada kontrak output: “minimal ada satu kartu” dan “semua halaman yang diharapkan sudah dimuat” adalah dua pernyataan yang berbeda.

Penanganan timeout juga ada di sisi caller. Tes ini memakai timeout selector yang terbatas, tetapi tidak mempelajari kebijakan retry atau membedakan halaman yang lambat dari selector yang memang sudah berubah permanen. Wrapper produksi sebaiknya mencatat kondisi kesiapan mana yang gagal, menangkap state halaman yang cukup untuk diagnosis, dan memutuskan apakah percobaan navigasi ulang aman. Playwright memberi Anda event dan DOM; tool ini tidak bisa menebak apa arti “data lengkap” untuk pekerjaan Anda.
Batas itu sebaiknya didokumentasikan di samping setiap extractor, bukan dibiarkan menjadi timeout implisit.
Jalur API punya kontrak paralel. ctx.request.get sesuai digunakan karena browser context sudah ada dan berbagi sesi bisa berguna. Jika sebuah pekerjaan menemukan bahwa endpoint datanya bekerja tanpa sesi browser apa pun, request context mandiri adalah arsitektur berbeda dengan lifecycle dan perilaku cookie yang berbeda. Run ini tidak membandingkan keduanya. Perlakukan “tanpa render DOM” sebagai fakta yang terukur, lalu putuskan secara terpisah apakah proses browser memang dibutuhkan oleh workflow yang lebih luas.
Pertanyaan tentang crawling
Hasil crawl-graph adalah yang paling menentukan cara Anda memandang Playwright. Dua belas halaman, tiga depth, benar — dan seluruh logika penelusurannya saya yang buat. Playwright menyediakan bagian “buka URL ini dan baca isinya”; saya yang menyediakan antrean, visited-set, dan pelacakan depth.
Untuk pekerjaan kecil dan terbatas, ini bukan masalah besar. Tetapi untuk kerja skala crawl, artinya Anda harus membangun crawler di atas library browser atau memasangkan Playwright dengan sesuatu yang sudah melakukannya. Pola yang terdokumentasi adalah Crawlee, yang membungkus Playwright (dan Puppeteer) dengan request queue nyata, penyimpanan dataset, dan auto-throttling — Anda tetap memakai rendering Playwright dan meminjam orkestrasinya. Jika Anda ingin queue sudah ada di framework itu sendiri, bukan ditambahkan belakangan, itulah seluruh desain Scrapy, meski Scrapy bersifat HTTP-first dan tidak merender JavaScript secara native. Intinya bukan Playwright kurang bagus; intinya “browser automation” dan “crawling” adalah dua pekerjaan berbeda, dan Playwright hanya mengklaim salah satunya.

BFS 12 halaman itu membuat batas kepemilikan jadi konkret. Ia menyediakan queue, visited set, dan pelacakan depth untuk graf yang terkendali. Frontier produksi masih harus mendefinisikan canonicalization URL, penanganan redirect, host yang diizinkan, duplicate key, retry, concurrency, delay per host, persistence, dan semantik restart. Ekspor juga pilihan lain: fixture menulis JSON dan CSV karena harness-nya memang begitu, bukan karena Playwright menyediakan abstraksi dataset.
Desain sesi juga memengaruhi wrapper. Satu browser bisa memuat beberapa context dengan cookie dan storage yang terisolasi, tetapi ulasan ini tidak mengukur skala paralel antar-context atau isolasi kegagalan. Menggunakan ulang context bisa mempertahankan login dan mengurangi setup; membuat context terpisah bisa mencegah state bocor antar pekerjaan. Itu semua kebijakan di level crawler, meski Playwright menyediakan primitive context. Benchmark lifecycle yang Anda pilih dengan build browser dan environment deployment yang benar-benar akan Anda pakai.
Kelebihan dan kekurangan
Kelebihan:
- Eksekusi JavaScript lewat engine Chromium sungguhan; dua target dinamis mencapai selector yang dipakai sebagai kondisi kesiapan.
- Screenshot full-page berhasil pada percobaan pertama.
- Selector mengekstrak field katalog statis dan artikel seperti yang diharapkan dari fixture terkendali.
browserContext.requestmencapai endpoint JSON tanpa merender halaman, sementara proses browser yang sudah berjalan tetap menjadi bagian dari harness.- Tahan terhadap respons buruk: HTTP 500 bisa diperiksa dan navigasi tidak melempar error.
- Dukungan tiga engine yang terdokumentasi (Chromium, Firefox, WebKit) lewat satu API, plus client Python, Java, dan .NET (terdokumentasi; hanya Chromium yang diuji di sini).
- Apache-2.0 dan dikelola oleh Microsoft.
- Pengalaman developer bersih begitu Anda masuk ke library mode: satu API lintas engine, async yang rapi, screenshot yang sangat mudah.
Kekurangan:
- Tidak ada queue crawl, dataset, atau auto-throttle bawaan — kerja skala crawl harus Anda bangun sendiri atau dibungkus tool seperti Crawlee.
- Bobot browser: unduhan binary dan biaya per halaman adalah “pajak” nyata dibanding tool berbasis HTTP saja.
- Framing default-nya adalah test runner; untuk scraping, Anda harus tahu bahwa library mode ada dan keluar dari jalur pemasaran utamanya.
- Hanya Playwright 1.56.0 dan Chromium yang diuji; paritas lintas versi dan lintas engine tidak diuji.
- Tidak punya output structured JSON berbasis schema secara native; Anda sendiri yang menulis selector dan membentuk datanya.
Cocok untuk siapa, dan siapa yang sebaiknya melewatkannya
Jika masalah Anda adalah merender halaman yang datanya muncul setelah JavaScript berjalan, atau mengumpulkan screenshot bersama data DOM, Playwright adalah kandidat yang masuk akal untuk diuji pada target Anda. Tim yang sudah memakai Playwright untuk testing bisa menggunakan konsep dan keahlian selector yang sama di library mode. Client Python, Java, dan .NET adalah opsi yang terdokumentasi, tetapi ulasan ini hanya menguji Node dan Chromium.
Pertimbangkan lapisan lain dalam tiga kasus. Jika data yang dibutuhkan sudah ada di respons HTTP, tool HTTP-first akan menghindari biaya startup browser dan rendering; Colly adalah library crawler di kategori itu, sedangkan Trafilatura menargetkan ekstraksi artikel. Jika Anda membutuhkan queueing, persistence, dan throttling, pakai framework crawler atau wrapper Playwright. Jika Anda butuh output berbentuk schema tanpa harus memelihara selector, bandingkan layanan ekstraksi terkelola. Tidak ada satu pun alternatif itu yang dibenchmark dalam ulasan ini.
Kalau Anda sedang memilih antara Playwright dan Puppeteer, itu perbandingan tersendiri; perbandingan side-by-side kami menjalankan keduanya pada fixture yang sama dan membahas di mana pilihan itu benar-benar berakhir.
Alternatif, dan posisi ekstraksi terkelola
Playwright gratis, berlisensi Apache-2.0, dan di-host sendiri. Anda yang mengurus deployment browser, selector, readiness condition, kode crawl, update, dan penanganan kegagalan. Ulasan ini tidak mengukur performa anti-bot atau membandingkan total biaya operasional dengan layanan terkelola.
Di antara open source, perbandingan yang paling berguna adalah berdasarkan jenis pekerjaan. Untuk kerja skala crawl di atas browser, Crawlee menambahkan queue dan dataset yang tidak dimiliki Playwright. Jika tujuan output Anda adalah Markdown siap LLM dari browser sungguhan, bukan baris data yang dibentuk manual, Crawl4AI menjalankan browser dan menghasilkan Markdown untuk pipeline itu. Dan jika Anda sedang mempertimbangkan beberapa opsi sekaligus, roundup scraper open source kami menyajikan kategori-kategori tersebut berdampingan.
Pengungkapan: Thunderbit adalah produk penerbit dan tidak dijalankan melalui fixture Playwright ini. Produk ini mewakili kategori ekstraksi terkelola: layanan mengoperasikan rendering dan mengembalikan teks halaman atau record berbentuk schema, sementara Playwright menyerahkan pengoperasian browser dan logika selector kepada developer. Jadi perbandingannya adalah model hosting, bentuk output, dan model biaya—bukan hasil performa dari ulasan ini.
Coba Thunderbit untuk Ekstraksi Data Web
Putusan akhir
Gunakan Playwright ketika target Anda membutuhkan browser engine dan Anda siap menangani readiness condition, selector, dan orkestrasi crawl sendiri. Tabel hasil menunjukkan bahwa library mode Chromium-nya menangani fixture statis, dinamis, API, screenshot, dan kegagalan yang terkontrol sebagaimana mestinya dalam pass yang dijalankan penulis ini.
Pertahankan batas bukti itu: hanya Chromium dan Node yang diuji, penelusuran 12 halaman bergantung pada BFS buatan tangan, browserContext.request melewati rendering halaman tetapi bukan proses browser yang sudah berjalan, dan setiap ekstraksi dinamis memakai selector kesiapan yang dinyatakan. Batasan itu membuat Playwright menjadi primitive browser dalam ulasan ini, bukan sistem crawling end-to-end yang diukur secara penuh.
Coba Thunderbit untuk Ekstraksi Data Web Get Started Free
FAQ
Apakah saya masih perlu wait saat scraping dengan Playwright?
Ya. Eksekusi browser tidak memberi tahu skrip Anda kapan data aplikasi sudah siap. Tes-tes ini bernavigasi ke domcontentloaded lalu menunggu selector spesifik target sebelum ekstraksi. Halaman produksi mungkin membutuhkan sinyal lain, seperti response, state locator, atau event aplikasi.
Bisakah Playwright melakukan crawl seluruh website sendiri? Tidak secara bawaan. Tidak ada request queue, dataset writer, atau auto-throttle bawaan — tes crawl-graph saya mencapai 12 halaman pada depth {0:1, 1:4, 2:7} hanya karena saya menulis breadth-first search-nya secara manual. Untuk kerja skala crawl, pasangkan Playwright dengan Crawlee, yang membungkusnya dengan lapisan crawling nyata, atau gunakan framework crawler saja.
Kapan saya harus memakai browserContext.request versus request context mandiri?
Gunakan browserContext.request saat panggilan HTTP harus berbagi cookie dengan halaman di browser context yang sudah ada. Gunakan playwright.request.newContext() saat Anda ingin context khusus API tanpa meluncurkan browser dan tidak membutuhkan pembagian cookie otomatis dengan halaman browser. Hanya jalur pertama yang diuji di sini.
Apakah Firefox dan WebKit diuji di sini? Tidak. Semua tes dijalankan di Chromium, pada satu mesin, satu kali run. Dukungan tiga engine Playwright (Chromium, Firefox, WebKit) dan client Python, Java, serta .NET adalah kemampuan terdokumentasi yang saya laporkan sebagaimana adanya, bukan yang diverifikasi — paritas Firefox dan WebKit, proxying, skala paralel, dan intersepsi jaringan semuanya berada di luar cakupan angka ini.
Lingkungan apa yang dicakup ulasan ini? Playwright 1.56.0, Node v22.22.3, macOS arm64, dan hanya Chromium. Firefox, WebKit, proxying, skala paralel, perilaku anti-bot, dan versi Playwright yang lebih baru berada di luar run ini. Instalasi membutuhkan library plus unduhan build browser terpisah.


