Node.js'ten gerçek bir tarayıcı açmanız gerekiyor: okumak istediğiniz sayfa içeriğini JavaScript ile oluşturuyor ya da bir HTML raporunun PDF'e dönüşmesi lazım. Akla ilk gelen iki ad Puppeteer ve Playwright. İkisi de ücretsiz, API'leri de birbirine benziyor (page.goto(), page.click(), page.pdf()); bu yüzden kararı söz dizimi belirlemiyor. Kararı şunlar belirler: hangi tarayıcılara ve dillere ihtiyacınız olduğu, proxy'nin nasıl tanımlandığı, test ve yapay zekâ ajanı araçlarından ne beklediğiniz.
Bu yazıda iki aracı tarayıcı ve protokol, dil, bekleme, proxy ayarı, test araçları ve MCP sunucuları açısından karşılaştırıyoruz. Aynı işi Node.js 24 ve Windows 11'de, Puppeteer 25.12.0 (Chrome for Testing 154) ve Playwright 1.63.0 (Chromium 153) ile yazıp kullanıcı adı ve parola isteyen yerel bir proxy üzerinden çalıştırdık. "Hangisini siteler daha az fark eder" sorusu bu yazının konusu değil: ikisi de gerçek bir tarayıcı açar, sitenin kurallarına uymak ikisinde de sizin işinizdir.
Puppeteer ve Playwright nedir?
Puppeteer, Chrome ya da Firefox'u yönetmek için üst düzey bir API sunan bir JavaScript kütüphanesidir. Node.js üzerinde çalışır, başka bir dilde resmî kütüphanesi yoktur; Python'a uyarlanmış sürümler bulunur, ama bunlar üçüncü taraf projelerdir. npm i puppeteer komutu uyumlu bir Chrome for Testing derlemesini ve daha küçük chrome-headless-shell dosyasını da ~/.cache/puppeteer klasörüne indirir; puppeteer-core ise aynı kütüphanenin indirme yapmayan hâlidir.
Playwright, Microsoft'un açık kaynaklı otomasyon kütüphanesidir. Chromium, Firefox ve Safari'nin motoru olan WebKit'i tek API ile yönetir; JavaScript ve TypeScript, Python, Java ve .NET için resmî kütüphaneleri vardır. Yanında, doğrulama ve paralel çalıştırma özellikleri yerleşik gelen Playwright Test adlı test koşucusu durur. Tarayıcılar ayrı bir adımdır: npx playwright install chromium, Playwright sürümünüze sabitlenmiş derlemeyi indirir.
İkisi de içeriği ancak JavaScript çalıştıktan sonra oluşan sayfalar içindir. Veri sayfa kaynağında ya da bir JSON uç noktasında duruyorsa düz bir HTTP istemcisi çok daha az bellekle işi görür.
Tarayıcıyla nasıl konuşurlar?
İki aracın davranışının büyük bölümünü altlarındaki protokol açıklar. Bir Puppeteer betiği şöyle çalışır:
puppeteer.launch(), Chrome for Testing derlemesini önbellekten başlatır;browser: "firefox"verirseniz Firefox'u açar.- Puppeteer, Chrome'un kendi hata ayıklama protokolü olan Chrome DevTools Protocol (CDP) üzerinden ya da çift yönlü tarayıcı otomasyonu için yazılmış W3C standardı WebDriver BiDi üzerinden bağlanır.
page.goto()gibi her çağrı bir dizi protokol mesajına dönüşür.- Olaylar siz sormadan geri gelir: istekler, yanıtlar, konsol mesajları, iletişim kutuları.
Puppeteer'ın WebDriver BiDi sayfası bu ayrımı açıklar: Firefox'ta varsayılan BiDi'dir, Chrome ise her CDP özelliği henüz BiDi'de bulunmadığı için CDP'de kalır. Puppeteer 23. sürümden beri özel bir derlemeyle değil, Firefox'un kararlı sürümüyle çalışır.
Playwright da Chromium ile CDP üzerinden konuşur. Firefox ve WebKit için ise yamalı derlemeler dağıtır; belgesi, bu yamalara dayandığı için markalı Firefox ve Safari ile çalışmadığını açıkça yazar. Google Chrome ve Microsoft Edge'i channel seçeneğiyle kullanabilirsiniz. Python, Java ve .NET'te her çağrı pakete gömülü bir Node.js sürücüsünden geçer, bu yüzden tarayıcı tarafı her dilde aynı davranır. Kullanıcılarınızın kurduğu Firefox'u otomatikleştirmeniz gerekiyorsa Puppeteer ona daha yakındır; WebKit ise yalnızca Playwright'ta var.
Puppeteer ve Playwright karşılaştırma tablosu
| Puppeteer | Playwright | |
|---|---|---|
| Tarayıcılar | Chrome, kararlı Firefox | Chromium, yamalı Firefox, WebKit; channel ile Chrome ve Edge |
| Protokol | Chrome'da CDP, Firefox'ta WebDriver BiDi | Chromium'da CDP; Firefox ve WebKit'te yamalı derlemeler |
| Resmî diller | JavaScript ve TypeScript | JavaScript ve TypeScript, Python, Java, .NET |
| Bekleme | Locator eylemden önce bekler | Locator eylemden önce bekler; test doğrulamaları yeniden dener |
| Test koşucusu | Yerleşik yok | Playwright Test |
| Kaydetme | Chrome DevTools Recorder dışa aktarımı | playwright codegen |
| Çalışma sonrası inceleme | DevTools için performans izi | Trace Viewer |
| Tarayıcı başına proxy | --proxy-server açılış argümanı | launch() içinde proxy |
| Context başına proxy | createBrowserContext() içinde proxyServer | newContext() içinde proxy |
| Proxy kullanıcı adı ve parola | Bir sayfada page.authenticate(), context başına önbelleğe alınır | username ve password alanları |
| MCP sunucusu | Chrome DevTools MCP (Puppeteer tabanlı) | Playwright MCP |
Aynı iş iki araçla nasıl görünür?
Deneme sayfamız shop.test, yüklendikten bir buçuk saniye sonra JavaScript ile altı ürün kartı basan, ardından "Next" bağlantısı gösteren küçük, yerel bir sayfa. İş şu: sayfayı kullanıcı adı ve parola isteyen bir proxy üzerinden açmak, ürün adlarını okumak, "Next" bağlantısına tıklamak ve yeni adresi doğrulamak. Kendi kodunuzda shop.test yerine hedef adresinizi yazın.
Puppeteer ile:
import puppeteer from "puppeteer";
const URL = "http://shop.test/"; // yerel deneme sayfamız; buraya hedefinizi yazın
const browser = await puppeteer.launch({
args: ["--proxy-server=http://pr.proxynet.io:8000"],
});
try {
const page = await browser.newPage();
await page.authenticate({ username: "user", password: "pass" });
const response = await page.goto(URL);
console.log("status:", response.status());
await page.waitForSelector("div.product"); // liste JavaScript ile çiziliyor
const names = await page.$$eval("div.product h2", (els) => els.map((el) => el.textContent));
console.log(names.length, "products, first:", names[0]);
await Promise.all([
page.waitForNavigation(),
page.locator("a.next").click(), // locator, bağlantı tıklanabilir olana kadar bekler
]);
console.log(page.url());
} finally {
await browser.close();
}Playwright ile:
import { chromium } from "playwright";
const URL = "http://shop.test/"; // yerel deneme sayfamız; buraya hedefinizi yazın
const browser = await chromium.launch({
proxy: { server: "http://pr.proxynet.io:8000", username: "user", password: "pass" },
});
try {
const page = await browser.newPage();
const response = await page.goto(URL);
console.log("status:", response.status());
const products = page.locator("div.product h2");
await products.first().waitFor(); // count() ve allTextContents() beklemez
const names = await products.allTextContents();
console.log(names.length, "products, first:", names[0]);
await page.getByRole("link", { name: "Next" }).click(); // kendiliğinden bekler
await page.waitForURL("**/page/2/");
console.log(page.url());
} finally {
await browser.close();
}İki betik de yerel test proxy'miz üzerinden aynı üç satırı bastı:
status: 200
6 products, first: Desk lamp
http://shop.test/page/2/Puppeteer proxy adresini Chrome argümanı olarak, kimlik bilgisini ayrı bir çağrıyla alır; Playwright üçünü tek nesnede toplar. Puppeteer, adres erken okunmasın diye tıklamayı page.waitForNavigation() ile eşler; Playwright bağlantıyı erişilebilir adıyla bulur ve adres kalıbını bekler.
Proxy kaydı bir fark daha gösterdi. Puppeteer'ın varsayılan headless modu tam Chrome for Testing derlemesini çalıştırır ve bu derleme sayfamızın yanında Google servislerine de (update.googleapis.com, accounts.google.com ve başkaları) proxy üzerinden istek gönderdi. Daha hafif chrome-headless-shell dosyasını kullanan headless: "shell" ile bu istekler kayboldu; Playwright'ın varsayılan headless kabuğu ise yalnızca sayfanın kendi isteklerini gönderdi. Residential Proxy gibi trafiği gigabayt başına ödediğiniz bir üründe bu arka plan trafiğini panelinizden kontrol etmeye değer.
Otomatik bekleme ikisinde nasıl çalışır?
Dinamik sayfalardaki hataların çoğu zamanlamadan çıkar: kod, JavaScript'in henüz çizmediği bir öğeyi arar. Eylemler söz konusu olduğunda iki araç da bunu benzer biçimde çözer.
Puppeteer'da önerilen yol locator'dır. Bir locator tıklamadan önce öğenin görünüm alanında (viewport), görünür ve etkin olduğundan, sınır kutusunun da art arda iki animasyon karesi boyunca sabit kaldığından emin olur; sayfanın zaman aşımı içinde bu sağlanmazsa TimeoutError fırlatır. page.$() ve page.click(selector) üzerine kurulu eski kod öğenin ortaya çıkmasını beklemez; bu yazım biçiminde önce page.waitForSelector() çağrılır.
Playwright öğenin görünür, sabit, olayları alabilir ve etkin olduğunu denetler. Üstüne iki şey ekler: öğeyi rolüne, etiketine ya da metnine göre bulan ve CSS sınıfının adı değişince kırılmayan locator'lar; Playwright Test'te ise expect(locator).toHaveText() gibi, koşul sağlanana kadar yeniden deneyen doğrulamalar.
Liste okurken ikisi de beklemez: page.$$eval() ve allTextContents() o an sayfada ne varsa onu döndürür. İki betiğin de önce ilk ürünü beklemesinin nedeni budur.
Proxy ayarları nasıl farklılaşır?
Scraping işlerinde iki aracın en çok ayrıldığı yer burasıdır.
Puppeteer'da --proxy-server argümanı bütün tarayıcıyı bağlar. Oturum başına ayrı proxy için browser context kullanılır: aynı tarayıcının içinde çerezleri ve önbelleği ayrı tutulan, yalıtılmış bir oturum. BrowserContextOptions başvurusu bunun için proxyServer ve proxyBypassList seçeneklerini tanımlar, kullanıcı adını ve parolayı Page.authenticate'e bırakır:
const context = await browser.createBrowserContext({
proxyServer: "http://pr.proxynet.io:8000",
});
const page = await context.newPage();
await page.authenticate({ username: "user", password: "pass" }); // Chrome bunu context için önbelleğe alırBaşvuru, page.authenticate() çağrısının arka planda istek yakalamayı (request interception) açtığını ve bunun performansı etkileyebileceğini de ekler. Çağrı bir sayfada yapılır, ama Chrome kimlik bilgisini context'in tamamı için önbelleğe alır: denemelerimizde hiçbir sayfanın çağrı yapmadığı bir context net::ERR_INVALID_AUTH_CREDENTIALS hatasıyla düştü, kimliği doğrulanmış bir context'te sonradan açılan sayfalar ise geçti. Oturum yönetimini ve çıkış IP'sinin doğrulanmasını Puppeteer proxy kurulum rehberimizde anlattık.
Playwright'ta proxy nesnesi bütün tarayıcı için launch(), tek bir context için newContext() çağrısına verilir; kullanıcı adı ve parola bu nesnenin alanlarıdır:
const context = await browser.newContext({
proxy: { server: "http://pr.proxynet.io:8000", username: "user", password: "pass" },
});Playwright'ın ağ rehberi iki biçimi de gösterir ve sunucu olarak HTTP(S) ile SOCKSv5 proxy kabul eder. Her context kendi kimlik bilgisini taşıdığı için sayfa başına unutulacak bir çağrı yoktur.
Bilinmesi gereken bir davranış: kimlik bilgisini vermediğimizde Playwright hata fırlatmadı, page.goto() 407 durum kodlu bir yanıt döndürdü. Sessiz geçen bir goto çağrısını sayfanın yüklendiğine kanıt saymak yerine response.status() değerine bakın. Kurulumun tamamı Playwright Nedir ve Proxy ile Nasıl Kullanılır? yazımızda.
Üç Chromium kuralı iki araç için de geçerlidir. Chromium'un proxy belgesi, Chrome'un SOCKS5 için hiçbir kimlik doğrulama yöntemini desteklemediğini yazar; bu yüzden parolalı SOCKS5, Chromium'da iki araçla da çalışmaz. Çözüm IP whitelist'tir; bizde bu liste en fazla 10 IP adresi alır. Chrome ayrıca proxy adresine yazılmış kimlik bilgisini kabul etmez: Puppeteer denememizde --proxy-server içindeki user:pass@, Chrome 154'ü net::ERR_NO_SUPPORTED_PROXIES hatasıyla durdurdu; yani bu bir kestirme değildir. Son olarak Chrome, yerel döngü (loopback) adresleri için proxy'yi atlar: denememizde Puppeteer 127.0.0.1 adresini doğrudan açtı, Playwright ise proxy üzerinden gönderdi; --proxy-bypass-list=<-loopback> eklediğimizde Puppeteer de proxy'yi kullandı.
Her context'in farklı bir IP'den çıkması gerekiyorsa kodunuzda adres listesi tutmanız gerekmez. Rotating Proxy ile tek bir ağ geçidi adresi çıkış IP'sini sizin yerinize değiştirir, sticky oturum ise aynı IP'yi 1 ila 60 dakika korur.
Hangi MCP sunucusu: Playwright MCP mi, Chrome DevTools MCP mi?
Bu karşılaştırma artık çoğu zaman Claude Code ya da Cursor gibi bir yapay zekâ kod asistanına tarayıcı verilmek istendiğinde gündeme geliyor. MCP (Model Context Protocol), bu asistanların dış araçları çağırmasının standart yoludur ve iki kütüphanenin de üzerine kurulmuş bir sunucusu vardır.
Playwright MCP, Microsoft'un sunucusudur. Sayfayı modele ekran görüntüsü olarak değil, erişilebilirlik ağacının metni olarak verir; npx @playwright/mcp@latest ile başlar, --proxy-server ve --proxy-bypass bayraklarını alır. README dosyası, kod ajanları için komut satırı yolunun daha az token harcadığını da not eder, çünkü büyük araç şemalarını modelin bağlam penceresine yüklemez. Kurulumu ve proxy kimlik bilgisinin nereye yazıldığını Playwright MCP Nedir? yazımızda anlattık.
Chrome DevTools MCP, bir kod ajanının canlı bir Chrome'u yönetmesini ve incelemesini sağlar; eylemler için Puppeteer'ı, performans izleri için DevTools'u kullanır ve npx -y chrome-devtools-mcp@latest ile başlar. 1.10.1 sürümünde --proxyServer değeri Chrome'a --proxy-server olarak geçer ve kimlik bilgisi için bir alan yoktur; pratik yol IP whitelist'tir. Varsayılan olarak bilgisayarda kurulu kararlı Chrome'u açar ve --no-usage-statistics eklemediğiniz sürece Google'a kullanım istatistiği gönderir.
Sayfalarda gezinip form dolduracak bir ajan için Playwright MCP'yi, kendi sitenizin konsol hatalarını, ağ isteklerini ve performans izlerini okuyacak bir ajan için Chrome DevTools MCP'yi seçin. Hangisi olursa olsun ajanın gidebileceği yerleri sınırlayın (--allowed-origins ya da --allowedUrlPattern), parolaları prompt'a yazmayın ve bir şeyi değiştiren eylemleri onaydan geçirin.
Test koşucusu, kod üretimi ve izler
Playwright'ın farkı en çok burada açılır. Playwright Test; koşucuyu, doğrulamaları, paralel çalıştırmayı, yeniden denemeyi ve HTML raporunu birlikte getirir. Python'da pytest eklentisi, Java ve .NET'te bu dillerin alışılmış test çatıları kullanılır. npx playwright codegen <url>, siz tıkladıkça kodu yazar. Trace Viewer (npx playwright show-trace trace.zip) kaydedilmiş bir çalışmayı DOM görüntüleri, ağ istekleri ve konsol mesajlarıyla bir zaman çizelgesinde yeniden oynatır; gece çalışan bir işin neden boş döndüğünü buradan görürsünüz.
Puppeteer testi size bırakır: Jest, Mocha ya da Node.js'in kendi test koşucusuyla birlikte kullanırsınız. Kayıt için Chrome DevTools'taki Recorder (kaydedici) paneli bir oturumu Puppeteer betiği, Firefox için Puppeteer betiği ya da Lighthouse analizi içeren bir betik olarak dışa aktarır. page.tracing.start() DevTools'ta açılan bir Chrome performans izi yazar; bu iz bir sayfanın neden yavaş olduğunu gösterir, ama betiğinizin adım adım tekrarı değildir.
Hız: neden rakam vermiyoruz?
Yayımlanmış "yüzde X daha hızlı" rakamları başkasının makinesinde ve başkasının sayfasında ölçülmüştür. Chromium'da iki araç da CDP kullanır; proxy üzerinden yapılan bir taramada sürenin büyük kısmı ağda ve hedef sitede geçer. Tam Chrome ile headless kabuk arasındaki seçim gibi kurulum tercihleri kütüphaneden daha çok fark yaratır. Rakama ihtiyacınız varsa kendi hedefinizde, aynı proxy ve eşzamanlılıkla ölçün.
Kullanım alanları
- Node.js servisinden PDF ve ekran görüntüsü: ikisinde de
page.pdf()var ve denememizde ikisi de Chromium'dan PDF üretti; Puppeteer daha hafif bir bağımlılıktır. - Motorlar arası uçtan uca testler: Playwright Test aynı testi Chromium, Firefox ve WebKit'te koşar.
- Python, Java ya da .NET ile veri toplama: Playwright, çünkü Puppeteer yalnızca JavaScript ile kullanılır.
- Firefox'un kararlı sürümünü otomatikleştirme: WebDriver BiDi üzerinden Puppeteer.
Araç ne olursa olsun sitenin robots.txt kurallarına ve kullanım şartlarına uyun, resmî API varsa onu kullanın, istek hızını sitenin kaldırabileceği düzeyde tutun.
Sık yapılan hatalar
- Puppeteer'da bir context'i
page.authenticate()çağırmadan açmak. Chrome kimlik bilgisini context başına önbelleğe alır; hiçbir sayfanın çağrı yapmadığı contextnet::ERR_INVALID_AUTH_CREDENTIALSile düşer. - Proxy kimlik bilgisi istediğinde Playwright'ın hata fırlatacağını sanmak. Denememizde 407 yanıtı döndü;
response.status()değerine bakın. - Proxy adresine
user:pass@yazmak. Chrome kimlik bilgisini adresten almaz; Puppeteer'dapage.authenticate()ile, Playwright'tausernamevepasswordalanlarıyla verin. - Chromium'da parolalı SOCKS5 kullanmak. Chrome'da SOCKS5 kimlik doğrulaması yoktur; IP whitelist kullanın.
- Puppeteer'da proxy'yi
localhostüzerinde denemek.<-loopback>eklemezseniz Chrome yerel döngü adresleri için proxy'yi atlar. - Playwright'ın Firefox'unu kurulu Firefox sanmak. O yamalı bir derlemedir; WebKit de Safari değildir.
Karar rehberi
| İhtiyaç | Öneri |
|---|---|
| Yalnızca Chrome isteyen bir Node.js betiği | İkisi de olur; Puppeteer yeter |
| Python, Java ya da .NET | Playwright |
| WebKit motorunda test | Playwright |
| Firefox'un kararlı sürümünü otomatikleştirme | Puppeteer |
| Context başına bir kez tanımlanan proxy kimlik bilgisi | Playwright |
| Tek tarayıcıda oturum başına ayrı IP | İkisi de, oturum başına bir context |
| Doğrulamaları ve raporları olan bir test paketi | Playwright Test |
| Form dolduran bir ajan | Playwright MCP |
| Chrome'da performans hatası ayıklayan bir ajan | Chrome DevTools MCP |
Sıkça sorulan sorular
Playwright, Puppeteer'dan daha mı iyi?
Her açıdan değil. Playwright daha çok motoru, dili ve test aracını kapsar; Puppeteer daha küçüktür ve Firefox'un kararlı sürümüyle çalışır. Çalışan bir Puppeteer betiği işinizi görüyorsa onu yeniden yazmak için bir neden yok.
Puppeteer Python ile kullanılabilir mi?
Resmî olarak hayır. Puppeteer'ın tek resmî kütüphanesi Node.js üzerindeki JavaScript ve TypeScript içindir; Python uyarlamaları var, ama Puppeteer deposunun dışındaki üçüncü taraf projelerdir. Python ile çalışıyorsanız Playwright'ın, Node.js sürümüyle aynı tarayıcı otomasyonu özelliklerine sahip resmî bir Python kütüphanesi vardır.
Puppeteer Firefox ile çalışır mı?
Evet. 23. sürümden beri Firefox'un kararlı sürümüyle WebDriver BiDi üzerinden çalışır; browser: "firefox" ile açarsınız. İndirme ayarında açmadığınız sürece Firefox paketle birlikte inmez ve yalnızca CDP'de bulunan birkaç özellik BiDi üzerinden kullanılamaz.
Puppeteer'dan Playwright'a geçmek zor mu?
Küçük bir betik hızlı taşınır, çünkü pek çok çağrının adı aynıdır: goto, click, evaluate, pdf. Emek üç yerde harcanır: proxy kimlik bilgisi proxy nesnesine taşınır, waitForNavigation() eşleşmelerinin yerini waitForURL() ve locator'lar alır, yalıtımın birimi browser context olur.
Claude Code ya da başka bir yapay zekâ ajanıyla hangisini kullanmalı?
Göreve bağlı. Playwright MCP, erişilebilirlik ağacı üzerinden sayfa yönetmek için yapılmıştır; Puppeteer tabanlı Chrome DevTools MCP ise konsol mesajlarını, ağ isteklerini ve performans izlerini incelemede daha güçlüdür. İkisini birden kurup her göreve yalnızca ihtiyaç duyduğu sunucuyu verebilirsiniz.
İki araçtan biri kullanıcı adı ve parolalı SOCKS5 proxy kullanabilir mi?
Chromium'da hayır, çünkü Chrome SOCKS5 için kimlik doğrulama desteklemez. SOCKS5'i IP whitelist ile kullanın ya da kullanıcı adı ve parolalı bir HTTP proxy'ye geçin. Panelimizdeki Endpoint Oluşturucu her ürünün SOCKS5 portunu gösterir.
Özet
Puppeteer ve Playwright aynı Chromium'u büyük ölçüde aynı yolla yönetir; fark çevresindekilerdedir. Puppeteer, Chrome ve Firefox'un kararlı sürümü için bir Node.js kütüphanesidir; proxy kimlik bilgisi page.authenticate() ile verilir ve Chrome onu browser context başına önbelleğe alır. Playwright buna WebKit'i, üç resmî dili daha, iz kaydı yapan bir test koşucusunu ve kimlik bilgisini context başına taşıyan bir proxy seçeneğini ekler. Yalnızca Chrome isteyen bir Node.js işi için Puppeteer yeter; birden fazla dil, motor ya da bir test paketi gerekiyorsa Playwright daha uygundur. İki araçla da kullanabileceğiniz proxy türlerini proxy hizmetlerimiz sayfasında bulabilirsiniz.




