← Bloga geri dön

Playwright'te Tarayıcı Yerine Proxy Kullanımı: Bellek Tasarrufu ve Temiz IP Rotasyonu

Proxy'nin Playwright'ta BrowserContext'e bağlanmasının neden tüm tarayıcıya bağlanmaktan daha etkili olduğunu, kod, benchmarklar ve hazır döngü desenleri ile inceliyoruz.

📅21 Ekim 2026

Eğer Playwright'ta parsing scriptleri veya çoklu hesap kullanıyorsanız ve her proxy için ayrı bir tarayıcı örneği başlatıyorsanız — gereksiz yere bellek ve CPU harcıyorsunuz. Playwright, proxy'leri BrowserContext seviyesinde, tüm tarayıcıda değil, atayabilir ve bu, scriptlerin mimarisini köklü bir şekilde değiştirir: tek bir tarayıcı süreci, farklı IP'ler, çerezler ve fingerprint ile onlara ait onlarca izole edilmiş context. Bu makalede — bunun nasıl çalıştığı, Python ve Node.js'de kod ve bunun neden özellikle konut ve mobil proxy'lerle çalışırken önemli olduğu.

Sorun: browser.launch() üzerinde proxy — pahalı ve kullanışsız

Birçok Playwright scriptinin klasik yaklaşımı şöyle görünür: her proxy için chromium.launch({ proxy: {...} }) çağrılır, ayrı bir tarayıcı süreci oluşturulur, çalışır, sonra kapanır, yeni proxy ile bir sonraki başlatılır. Eğer 50 IP adresini Wildberries veya Ozon için paralel olarak işlemek gerekiyorsa, bu, aynı anda 50 tam Chromium süreci anlamına gelir — her biri başlangıçta 150 ile 300 MB RAM tüketir, sekmeler ve renderlama hariç.

Pratikte, bu, sıradan bir 8 GB RAM'li VPS'de 15-20 paralel tarayıcıda tıkanır. Sunucu swap yapmaya başlar, scriptler zaman aşımına uğrar, bazı proxy'ler çalışmayı tamamlayamaz. Sorun proxy'de veya Playwright'ta değil — sorun mimaride: her tarayıcı başlatma, tüm render motorunu, GPU sürecini, ağı ve onlarca yardımcı iş parçacığını beraberinde getirir, oysa gerçekte ihtiyacınız olan sadece yeni bir IP ve temiz bir oturumdur.

Playwright bu sorunu zarif bir şekilde çözer: proxy'yi tarayıcı başlatılırken değil, BrowserContext oluşturulurken tanımlayabilirsiniz — aynı tarayıcı süreci içinde hafif izole bir "kum havuzu". Tek bir Chromium süreci, her biri kendi proxy'si, çerezleri ve localStorage'ı ile onca context'i tutabilir, birbirleriyle çakışmadan.

Tarayıcı vs BrowserContext: fark nedir

Browser — motorun (Chromium, Firefox veya WebKit) kendisi, bir kez başlatılır ve uzun süre yaşar. BrowserContext — bu süreç içindeki izole bir ortam, özel bir pencere (incognito) gibi, kendi çerezleri, önbelleği, izinleri ve bizim için önemli olan, kendi ağ ayarları, proxy dahil.

Dolphin Anty veya AdsPower gibi anti-detect tarayıcılarla karşılaştırıldığında — orada her "profil" de aslında çerezler ve fingerprint ile ayrı izole bir konteynerdir. Playwright, benzer bir mantığı programatik olarak inşa etmenizi sağlar: bir tarayıcı — birçok context, her biri kendi IP'si ile ayrı bir "profil" gibi.

Parametre Tarayıcıda Proxy BrowserContext'te Proxy
Bir IP için bellek 150-300 MB (yeni süreç) 15-40 MB (yeni context)
IP değişim hızı 2-5 sn (tarayıcıyı yeniden başlatma) 0.1-0.3 sn (yeni context)
Çerezlerin izolasyonu Tam (farklı süreçler) Tam (context'ler çerez paylaşmaz)
8 GB RAM'de max. paralel oturum sayısı ~20-25 ~150-200

Context üzerinde proxy: Python kodu

Aşağıda temel bir desen: bir tarayıcı bir kez başlatılır, ardından her proxy için ayrı bir context oluşturulur. Bu, Playwright'ın senkron API'sidir, ancak mantık async versiyonu için de aynıdır.

from playwright.sync_api import sync_playwright

proxies = [
    {"server": "http://proxy1.example.com:8000", "username": "user1", "password": "pass1"},
    {"server": "http://proxy2.example.com:8000", "username": "user2", "password": "pass2"},
    {"server": "http://proxy3.example.com:8000", "username": "user3", "password": "pass3"},
]

with sync_playwright() as p:
    # Tarayıcı BİR kez başlatılır, proxy olmadan
    browser = p.chromium.launch(headless=True)

    for proxy in proxies:
        # Proxy tam olarak context'e atanır, tarayıcıya değil
        context = browser.new_context(
            proxy={
                "server": proxy["server"],
                "username": proxy["username"],
                "password": proxy["password"],
            },
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        )
        page = context.new_page()
        page.goto("https://httpbin.org/ip", timeout=30000)
        print(page.content())

        page.close()
        context.close()  # sadece context'i kapatıyoruz, tarayıcı yaşamaya devam ediyor

    browser.close()

Ana nokta — browser.launch() döngü dışında bir kez çağrılırken, browser.new_context() proxy döngüsü içinde çağrılır. Kullanıcı adı ve şifre ile kimlik doğrulama gerektiren proxy'ler için Playwright, ağ seviyesinde Basic Auth başlıklarını otomatik olarak ekler, başka bir ayarlama yapmanıza gerek yoktur.

Context üzerinde proxy: Node.js kodu

JavaScript'te async/await kullanarak aynı mantık — genellikle Node.js'deki parsing framework'leri ile birlikte kullanılır:

const { chromium } = require('playwright');

const proxies = [
  { server: 'http://proxy1.example.com:8000', username: 'user1', password: 'pass1' },
  { server: 'http://proxy2.example.com:8000', username: 'user2', password: 'pass2' },
];

(async () => {
  const browser = await chromium.launch({ headless: true });

  for (const proxy of proxies) {
    const context = await browser.newContext({
      proxy: {
        server: proxy.server,
        username: proxy.username,
        password: proxy.password,
      },
    });

    const page = await context.newPage();
    await page.goto('https://httpbin.org/ip', { timeout: 30000 });
    console.log(await page.content());

    await page.close();
    await context.close();
  }

  await browser.close();
})();

Onlarca proxy'yi paralel olarak işlemek için context'leri Promise.all ile oluşturabilirsiniz, önceki kapanmasını beklemeden — bu, "bir tarayıcı, birçok context" yaklaşımının en büyük avantajıdır.

Tarayıcıyı yeniden başlatmadan temiz proxy dönüşümü

"Temiz dönüşüm", IP değiştiğinde önceki oturumdan hiçbir kalıntı kalmaması anlamına gelir — ne çerezler, ne önbellek, ne de hizmet çalışanları. Tüm tarayıcıyı yeniden başlatırken bu otomatik olarak garanti edilir, ancak kaynaklar açısından pahalıdır. Context'lerle çalışırken, aynı şey eski context'i kapatıp yenisini oluşturarak elde edilir — işlem birkaç saniye sürer.

async function rotateProxy(browser, proxyList, index) {
  const proxy = proxyList[index % proxyList.length];
  const context = await browser.newContext({ proxy });
  const page = await context.newPage();
  return { context, page };
}

// Böyle kullanıyoruz: her N. iterasyonda IP değiştiriyoruz
for (let i = 0; i < 100; i++) {
  if (i % 10 === 0) {
    const { context, page } = await rotateProxy(browser, proxies, i);
    // yeni oturumla 10 istek üzerinde çalışıyoruz
  }
}

Bu desen, özellikle pazar yerlerinde parsing yaparken faydalıdır: örneğin, Wildberries veya Ozon'dan fiyat toplarken, bot koruma sistemleri bir IP'den belirli bir zaman diliminde yapılan istek sayısını izler. Context seviyesinde dönüşüm, IP'yi her 5-10 istekte bir değiştirmeyi sağlar, bu da tarayıcıyı yeniden başlatma sırasında performans kaybı yaşamadan.

Bu tür senaryolar için konut proxy'leri iyi bir seçimdir — gerçek kullanıcıların IP'lerini verirler, bu da pazar yerleri tarafından şüpheli olarak işaretlenme olasılığını azaltır, açıkça sunucu aralıklarına göre.

Bellek ve hız karşılaştırması

8 GB RAM ve 4 vCPU'ya sahip bir test VPS'sinde, farklı IP'lerle 100 sayfayı geçme görevinde iki yaklaşımın testi yapıldı. İlk durumda her IP için ayrı bir chromium.launch() başlatılırken, ikinci durumda bir tarayıcı ile 100 context sırayla oluşturuldu.

Metrik 100 browser.launch() başlatması 1 tarayıcıda 100 context
Zirve bellek ~6.8 GB ~1.9 GB
Toplam çalışma süresi 182 sn 97 sn
Zaman aşımına uğrayan oturum sayısı 7 0

Bu testte bellek tasarrufu yaklaşık %70 oldu ve toplam çalışma süresi, her seferinde Chromium sürecini başlatma ve kapatma yükü olmadan neredeyse yarı yarıya azaldı. Büyük hacimlerde — günde binlerce IP — fark daha belirgin hale gelir ve bu, bir sunucuda donanım yükseltmesi olmadan ne kadar proxy kullanabileceğinizi doğrudan etkiler.

Pratik durumlar: parsing ve çoklu hesap kullanımı

Pazar yerlerinin parsing'i. Wildberries, Ozon veya Avito'dan fiyat toplarken, aynı tarayıcıda onlarca context açık kalır, her biri benzersiz bir IP ve kendi çerez deposuna sahiptir. Bu, isteklerin kalıbı nedeniyle engellenme riskini azaltır ve verileri daha hızlı toplamanızı sağlar, IP'ler arasında süreç yeniden başlatmayı beklemeden.

Çoklu hesap kullanımı ve hesap çiftliği. Facebook Ads veya TikTok Ads'de reklam kampanyalarını test etmek için Playwright scriptleri aracılığıyla her hesabı kendi proxy'si ve user-agent'ı ile ayrı bir context'te tutmak mantıklıdır — bu, Multilogin veya GoLogin gibi anti-detect tarayıcıların davranışını taklit eder, ancak anti-detect lisansı olmadan, tamamen programatik olarak.

Reklamın coğrafi test edilmesi. Farklı ülkelerde bir yaratımın nasıl göründüğünü kontrol etmesi gereken pazarlamacılar için, farklı proxy'lerle context'ler, bir tarayıcı oturumu içinde gerekli bölgelerde "bulunmayı" sağlar, manuel olarak onlarca ayrı pencere açmadan.

Mobil trafiği taklit etmenin önemli olduğu senaryolar için — örneğin, mobil web sitesinin veya TikTok Ads'deki reklamın mobil versiyonunu kontrol etmek — gerçek mobil operatörlerden IP veren mobil proxy'ler düşünülmelidir, bunlar anti-fraud sistemlerinde daha az şüphe uyandırır.

Eğer görev hızlı ve stabil bir parsing ise, yüksek anonimlik gerektirmeyen (örneğin, sıkı anti-bot koruması olmayan sitelerden kamu verilerini toplamak) veri merkezi proxy'leri büyük hacimlerde en iyi hız ve maliyet dengesini sunar.

Sık yapılan hatalar ve bunlardan nasıl kaçınılır

1. Proxy'ler launch() içinde tanımlanıyor, new_context() içinde değil. Bu, yeni başlayanların en sık yaptığı hatadır — tarayıcı başlatılırken belirtilen proxy, tüm context'lere aynı anda uygulanır ve bireysel olarak yeniden tanımlanamaz. Her zaman proxy'yi new_context() içinde geçirin, eğer IP üzerinde esneklik istiyorsanız.

2. Eski context'ler kapatılmıyor. Yüzlerce context oluşturulursa ve context.close() çağrılmazsa, tarayıcının belleği lineer olarak artar, süreç OOM nedeniyle çökene kadar. Her zaman bu IP üzerindeki görev tamamlandıktan sonra context'i kapatın.

3. Tüm context'ler için tek bir user-agent kullanılıyor. Eğer proxy değişirse, ancak tarayıcının fingerprint'i (user-agent, dil, saat dilimi) aynı kalırsa, pazar yerleri ve sosyal medya anti-bot sistemleri yine de oturumları birbirine bağlayabilir. Her context için proxy ile birlikte user-agent ve viewport'u değiştirin.

4. Proxy zaman aşımını göz ardı etmek. Konut ve mobil proxy'ler, gerçek ağ altyapısı nedeniyle veri merkezi proxy'lerine göre bazen daha yavaş yanıt verebilir. page.goto() çağrılırken makul bir zaman aşımı (20-40 saniye) belirleyin, aksi takdirde script çalışır proxy'yi "ölü" olarak değerlendirecektir.

5. Aynı anda bir tarayıcıda çok fazla context. Bellek tasarrufuna rağmen, kontrolsüz bir şekilde 500+ aktif context oluşturmak yine de sürecin limitlerine ulaşır. Makul bir denge — bir tarayıcı süreci başına 30-80 eşzamanlı aktif context, sunucunun RAM miktarına bağlı olarak.

Sonuç

Proxy'lerin BrowserContext seviyesinde atanması, tüm tarayıcıda değil — bu, %70'e kadar bellek tasarrufu sağlayan, IP dönüşümünü on kat hızlandıran ve oturumlar arasında çerezlerin temiz izolasyonunu sağlayan mimari bir çözümdür. Pazar yerlerinin parsing'i, farklı bölgelerde reklam testleri ve çoklu hesap kullanımı için, bu, aynı sunucuda donanım yükseltmesi olmadan paralel oturum sayısını artırmanın doğrudan bir yoludur.

Eğer Wildberries, Ozon'dan veri toplamak veya Facebook Ads ve TikTok Ads reklam panelleri ile çalışmak için Playwright üzerinde bir script oluşturuyorsanız, proxy havuzunun kalitesi, kod mimarisi kadar önemlidir. IP'nin güvenilirliği ve anti-bot sistemlerine karşı dayanıklılığın kritik olduğu görevler için, konut proxy'leri ile başlamak iyi bir fikirdir — bunlar, yukarıda açıklanan "bir tarayıcı, birçok context" yaklaşımı ile iyi bir şekilde uyum sağlar.