Puppeteer ile Proxy Kullanımı: Kurulum ve Kimlik Doğrulama

Yayın tarihi:

12 dk okuma

Acar Diveroli
Yazar: Acar Diveroli
Teknik bir çerçevede yan yana duran Proxynet yazı logosu ve beyaz Puppeteer logosu, aralarında ince bir çarpı işareti

Başlatma argümanlarına, cURL'de alıştığınız gibi --proxy-server=http://user:pass@host:port yazıyorsunuz ve ilk page.goto() çağrısı net::ERR_NO_SUPPORTED_PROXIES hatasıyla duruyor. Kimlik bilgilerini adresten çıkarınca bu kez net::ERR_INVALID_AUTH_CREDENTIALS geliyor. Puppeteer'ın kendine ait bir proxy seçeneği yoktur. Chrome'u başlatır, proxy'nin nasıl kullanılacağına Chrome karar verir; bu yüzden cevapların çoğu Puppeteer'ın API'sinde değil, Chrome'un kurallarındadır.

Bu yazıda başlatma bayrağını ve page.authenticate() çağrısını, her browser context için ayrı proxy'yi, sticky ve rotating oturumları, SOCKS5'i, bypass listesini, çıkış IP'sinin kontrolünü, karşınıza çıkacak hataları ve yeniden denemeli tam bir betiği ele alıyoruz. Bütün örnekleri 6 Ekim 2026'da, Puppeteer 25.12.0 ve onun indirdiği Chrome 154 ile çalıştırdık. Test düzeneğinde kullanıcı adı ve parola isteyen yerel bir HTTP proxy'si ve yerel bir SOCKS5 sunucusu vardı; aktardığımız hata mesajları bu testlerde aldıklarımızdır.

Puppeteer trafiği proxy'den nasıl geçirir?

Puppeteer, gerçek bir tarayıcıyı koddan yöneten bir Node.js kütüphanesidir. Ağ bağlantılarını kendisi açmaz, tarayıcı açar. Dolayısıyla proxy bir Chrome ayarıdır ve iki yerde verilir: tarayıcı başlarken komut satırı bayrağı olarak ya da bir browser context oluşturulurken seçenek olarak. Browser context (tarayıcı bağlamı), tek tarayıcının içinde kendi çerezleri, önbelleği ve depolaması olan yalıtılmış bir oturumdur; gizli pencereye benzer. Yazının devamında kısaca context diyeceğiz.

Proxy'ye giriş ayrı bir adımdır, çünkü Chrome proxy adresindeki kimlik bilgisini okumaz. Test proxy'mizin tek bir HTTPS sayfası için kaydettiği sıra şöyleydi:

  1. Chrome proxy'ye CONNECT httpbin.org:443 gönderir, yani siteye bir tünel açmasını ister. http:// ile başlayan bir sayfada isteğin kendisini gönderir.
  2. İstekte kimlik bilgisi olmadığı için proxy 407 Proxy Authentication Required cevabı verir. RFC 9110, 407'yi 401'in proxy'deki karşılığı olarak tanımlar.
  3. Puppeteer bu doğrulama talebini yakalar ve page.authenticate() çağrısına verilen kullanıcı adı ve parolayla cevaplar.
  4. Chrome isteği Proxy-Authorization başlığıyla tekrarlar, proxy 200 döner ve siteyle şifreli bağlantı tünelin içinde kurulur. Proxy sayfanın içeriğini değil, yalnızca sunucu adını görür.
  5. Chrome kimlik bilgisini context'in kimlik doğrulama önbelleğine yazar ve sonraki bağlantılarda doğrudan gönderir.

Aşağıdaki testlerde kimlik bilgisinin sayfaya değil context'e ait çıkmasının nedeni bu beşinci adımdır.

--proxy-server ve page.authenticate() ile proxy nasıl ayarlanır?

npm i puppeteer kütüphaneyi kurar ve onunla uyumlu bir Chrome indirir; puppeteer-core ise indirme yapmayan aynı API'dir. En sade kurulum şöyledir:

js
import puppeteer from "puppeteer";

const browser = await puppeteer.launch({
  args: ["--proxy-server=http://pr.proxynet.io:8000"],
});
const page = await browser.newPage();
await page.authenticate({ username: "user", password: "pass" });

await page.goto("https://httpbin.org/ip");
console.log(await page.$eval("body", (el) => el.innerText)); // sitenin gördüğü çıkış IP'si

await browser.close();

Bayraktaki http:// sayfaları değil, proxy'ye giden bağlantıyı anlatır. HTTP proxy https:// siteleri de tünel üzerinden taşır ve içerik Chrome ile site arasında şifreli kalır. page.authenticate() belgesi bir not ekler: Puppeteer bu iş için arka planda istek yakalamayı (request interception) açar, bu da performansı biraz etkileyebilir; null verildiğinde kapanır.

Testlerde üç şey ters gitti ve her birinin net bir kuralı var:

  • page.authenticate() ilk goto() çağrısından önce gelmeli. Sonra çağrıldığında ilk gezinme net::ERR_INVALID_AUTH_CREDENTIALS ile düştü, ikincisi ise geçti.
  • Kimlik bilgisi bayrağa yazılmamalı. Adreste user:pass@ olunca Chrome 154 değerin tamamını reddetti ve net::ERR_NO_SUPPORTED_PROXIES verdi. Eski rehberler burada 407 aldığınızı yazar; bugünkü sürümde istek proxy'ye hiç ulaşmıyor.
  • Proxy-Authorization başlığını kendiniz göndermeyin. Başlığı page.setExtraHTTPHeaders() ile eklediğimizde Chrome gezinmeyi net::ERR_INVALID_ARGUMENT ile reddetti.
--proxy-server değeriChrome 154'teki sonuç
http://pr.proxynet.io:8000Çalışır; HTTPS sayfalar CONNECT tünelinden geçer
pr.proxynet.io:8000Çalışır; şema yazılmazsa Chrome HTTP proxy varsayar
http://user:pass@pr.proxynet.io:8000net::ERR_NO_SUPPORTED_PROXIES
socks5://host:portYalnızca sunucu parola istemiyorsa çalışır
socks5h://host:portnet::ERR_NO_SUPPORTED_PROXIES; Chrome bu şemayı tanımaz

Her browser context'e ayrı proxy nasıl verilir?

Puppeteer 22, eski rehberlerde hâlâ geçen createIncognitoBrowserContext() adını browser.createBrowserContext() olarak değiştirdi. Bu çağrının BrowserContextOptions seçeneklerinde iki proxy alanı var: proxyServer ve proxyBypassList. Tarayıcı proxy'siz başlayabilir, her context kendi proxy'sini alır:

js
import puppeteer from "puppeteer";

const PROXY = "http://pr.proxynet.io:8000";
// Her context'e bir sticky oturum: aynı oturum kimliği, 600 saniyeye kadar aynı çıkış IP'si
const sessions = ["a1b2c3", "d4e5f6"];

const browser = await puppeteer.launch(); // tarayıcının kendisi proxy'siz başlar
for (const id of sessions) {
  const context = await browser.createBrowserContext({ proxyServer: PROXY });
  const page = await context.newPage();
  await page.authenticate({ username: `user-session-${id}-ttl-600`, password: "pass" });

  for (let i = 0; i < 2; i++) {
    await page.goto("https://httpbin.org/ip");
    console.log(id, await page.$eval("body", (el) => el.innerText));
  }
  await context.close(); // çerezler, önbellek ve proxy ayarı context'le birlikte kapanır
}
await browser.close();

Test proxy'miz çıkış adreslerini, bir ağ geçidinin (gateway) yaptığı gibi oturum kimliğine göre dağıtıyor. Denemede iki context iki ayrı adresten çıktı ve her biri ikinci istekte de kendi adresinde kaldı. Gerçek işler için iki sonuç daha önemli:

  • Kimlik bilgisi sayfaya değil, context'e aittir. Aynı context'te açtığımız ikinci sayfa page.authenticate() çağrısını başka bir kullanıcı adıyla yaptı, ama gönderdiği her istek yine ilk kullanıcı adını taşıdı. Bu çağrıyı hiç yapmayan bir sayfa da aynı önbellekteki bilgiyle geçti.
  • proxyServer verilmeyen context, başlatma bayrağındaki proxy'yi devralır ama kendi kimlik bilgisini tutar. Tarayıcıda --proxy-server varken kendi oturum kimliğiyle giriş yapan iki context yine iki ayrı çıkış IP'si aldı.
--proxy-server bayrağıcreateBrowserContext({ proxyServer })
KapsamBütün tarayıcıYalnızca o context
Tek tarayıcıda ayrı çıkışlarEvet, her context'e bir kullanıcı adıEvet, hatta ayrı proxy sunucuları
Proxy'yi değiştirmekTarayıcıyı yeniden başlatmakContext'i kapatıp yenisini açmak
Uygun olduğu işTek betik, tek çıkışParalel çalışan çok sayıda bağımsız oturum

Buradan çıkan kural: bir oturum, bir context, bir kullanıcı adı.

Rotating mi sticky mi: tarayıcıya hangi oturum türü uyar?

Tarayıcı bir sayfa için tek istek göndermez. Bir ürün sayfası; HTML belgesini, betikleri, stil dosyalarını, görselleri ve arka plandaki API çağrılarını çoğu zaman birkaç sunucudan ve birkaç bağlantı üzerinden çeker. Rotating bir ağ geçidinde her yeni bağlantı yeni bir çıkış IP'si alabilir; testimizde sayfanın favicon'u bile sayfadan farklı bir adresten çıktı. Birbirinden bağımsız sayfalarda bunun zararı yoktur. Girişte, sepette ya da çok adımlı bir formda ise site tek bir ziyaretçinin adresler arasında atladığını görür ve oturumu sonlandırabilir.

Ağ geçidi oturum türünü kullanıcı adından okur; tam kullanıcı adını paneldeki Endpoint Oluşturucu sizin için yazar. Parçaları kolay okunur: -country-de çıkış ülkesini seçer (şehir de aynı araçtan seçilir), -session-a1b2c3-ttl-600 o oturum kimliğini verilen saniye boyunca aynı çıkışta tutar; süre 1 ile 60 dakika arasında olabilir. Oturum parçası olmayan kullanıcı adı ise rotating çalışır.

Kategori listesi ya da arama sonucu gibi bağımsız sayfalar için Rotating Proxy kullanın ve bu sayfaları kısa ömürlü context'lerde açın.

Durum tutan her iş için Sticky Proxy kullanın: tek context ve süresi akıştan uzun tutulan tek oturum kimliği. İş bitince context'i kapatın ki çerezler ve IP birlikte sona ersin.

Rotasyon bağımsız işi farklı çıkışlara dağıtır; bir sitenin sınırlarını aşmanın yolu değildir. 429 Too Many Requests ya da 403 Forbidden cevabı yavaşlamanızı ister ve yeni bir IP bu cevabı değiştirmez.

Puppeteer SOCKS5 proxy ile çalışır mı?

Çalışır, ama kullanıcı adı ve parola olmadan. Chromium'un proxy belgesi, SOCKSv5 için hiçbir kimlik doğrulama yönteminin desteklenmediğini açıkça yazar. Yerel SOCKS5 sunucumuz aynı şeyi öbür taraftan gördü: Chrome bağlantının açılış mesajında yalnızca 0x00 yöntemini, yani "kimlik doğrulama yok" seçeneğini sundu. Kullanıcı adı ve parola yöntemini (0x02) şart koşan sunucu bu teklifi reddetmek zorunda kaldı ve gezinme net::ERR_SOCKS_CONNECTION_FAILED ile düştü. SOCKS5'te Puppeteer'ın cevaplayacağı 407 benzeri bir talep olmadığından page.authenticate() bir şey değiştirmedi.

Çözüm, kim olduğunuzu parola yerine IP adresinizle kanıtlamaktır. Chrome'u çalıştıran makinenin genel IP adresini paneldeki IP whitelist'e ekleyin (en fazla 10 adres), Endpoint Oluşturucu'nun gösterdiği SOCKS5 portunu alın ve tarayıcıyı kimlik bilgisi olmadan başlatın:

js
import puppeteer from "puppeteer";

// Kullanıcı adı ve parola yok: bu makinenin genel IP'si IP whitelist'te olmalı.
// SOCKS5_PORT: Endpoint Oluşturucu'nun gösterdiği SOCKS5 portu.
const { SOCKS5_PORT } = process.env;

const browser = await puppeteer.launch({
  args: [`--proxy-server=socks5://pr.proxynet.io:${SOCKS5_PORT}`],
});
const page = await browser.newPage();
await page.goto("https://httpbin.org/ip");
console.log(await page.$eval("body", (el) => el.innerText));
await browser.close();

Chrome SOCKS5 sunucusuna IP adresi değil, sunucu adı gönderdi; yani DNS çözümlemesi proxy tarafında yapılıyor ve cURL'den bilinen socks5h:// alışkanlığına gerek kalmıyor. Web sayfaları için HTTP proxy çoğu zaman daha sade bir seçimdir, çünkü page.authenticate() ile çalışır.

Bazı adresler proxy'nin dışında nasıl tutulur?

--proxy-bypass-list bayrağı ya da context'te dizi olarak verilen proxyBypassList, Chrome'un doğrudan bağlanacağı sunucuları listeler. Bayrakta kurallar noktalı virgül ya da virgülle ayrılır: --proxy-bypass-list=*.internal.example;192.168.0.0/16. Testimizde listedeki sunucu proxy'ye hiç uğramadı, adı yerel makinede çözümlendi.

Chrome'un örtük kuralları da vardır: localhost, *.localhost, 127.0.0.1/8 ve [::1] liste boş olsa bile proxy'yi kullanmaz. Yerel bir sunucuyla test ederken proxy kaydı sessiz kalıyorsa nedeni budur. Özel <-loopback> kuralı bu örtük kuralları kaldırır; onu eklediğimizde 127.0.0.1 adresine giden isteğimiz proxy'den geçti.

Çıkış IP'si nasıl kontrol edilir?

Aynı tarayıcıda doğrudan bağlanan bir context'i proxy'li bir context'le karşılaştırın. Adresler farklıysa trafik proxy'den geçiyordur:

js
import puppeteer from "puppeteer";

async function exitIp(context, credentials) {
  const page = await context.newPage();
  if (credentials) await page.authenticate(credentials);
  await page.goto("https://httpbin.org/ip");
  const { origin } = JSON.parse(await page.$eval("body", (el) => el.innerText));
  await page.close();
  return origin;
}

const browser = await puppeteer.launch();
const direct = await browser.createBrowserContext();
const proxied = await browser.createBrowserContext({ proxyServer: "http://pr.proxynet.io:8000" });

const own = await exitIp(direct);
const viaProxy = await exitIp(proxied, { username: "user", password: "pass" });
console.log({ own, viaProxy, proxyWorks: own !== viaProxy });
await browser.close();

Belirli bir ülkeyi hedefliyorsanız çıkış IP'sini bir IP konum servisinde de sorgulayın. Kontrol başarısız olursa Chrome'u devreden çıkarın: Proxy Çalışıyor mu? Proxy Nasıl Test Edilir? yazısındaki komut satırı testleri, sorunun ağda mı kodda mı olduğunu ayırır.

Hangi hataları görürsünüz, ne anlama gelirler?

Aşağıdakilerin her birini yerel test düzeneğinde kendimiz ürettik:

Ne görüyorsunuzNe olduNe yapmalı
net::ERR_PROXY_CONNECTION_FAILEDChrome proxy'ye ulaşamadı: sunucu ya da port yanlış veya giden trafik engelliAdresi ve portu kontrol edin; yeniden denemek işe yaramaz
net::ERR_INVALID_AUTH_CREDENTIALSProxy giriş istedi, Chrome'da kimlik bilgisi yoktuİlk goto() çağrısından önce page.authenticate() çağırın
goto() 407 durum koduyla dönüyorParola yanlış; Puppeteer bir kez denedi ve vazgeçtiresponse.status() değerine bakın, kimlik bilgisini düzeltin
net::ERR_TUNNEL_CONNECTION_FAILEDGiriş başarılı, ama proxy siteye tünel açamadıHedef adresi kontrol edin
net::ERR_NO_SUPPORTED_PROXIESChrome --proxy-server değerini reddettiuser:pass@ kısmını silin, http:// ya da socks5:// kullanın
net::ERR_SOCKS_CONNECTION_FAILEDSOCKS5 sunucusu parola istiyor ya da IP'niz whitelist'te değilIP'nizi whitelist'e ekleyin ya da HTTP portunu kullanın
Sayfa açılıyor ama IP sizinBir bypass kuralı ya da loopback adresi yüzünden proxy atlandıBypass listesine ve <-loopback> kuralına bakın

En uzun süre gözden kaçan, yanlış parola satırıdır: hiçbir yerde hata fırlatılmaz ve betik proxy'nin 407 sayfasıyla devam eder. Masaüstü tarayıcıda tünel hatasının, antivirüsün HTTPS taramasından eskide kalmış bir sistem proxy ayarına kadar başka nedenleri de olabilir; bunlar için err_tunnel_connection_failed Hatası Nedir, Nasıl Çözülür? yazısına bakın. Geliştirme sırasında şu iki dinleyici, zaman aşımının arkasındaki gerçek hatayı gösterir:

js
page.on("requestfailed", (req) => console.log("BAŞARISIZ", req.url(), req.failure()?.errorText));
page.on("response", (res) => res.status() >= 400 && console.log(res.status(), res.url()));

Tam örnek: paralel context'ler, sticky oturumlar ve yeniden deneme

Aşağıdaki betik, JavaScript ile oluşturulan altı sayfayı aynı anda en fazla üç context'le açar. Her deneme yeni bir context ve yeni bir sticky oturum alır; böylece çerezler ve çıkış IP'si birlikte değişir. Trafikten tasarruf için görsel, medya ve font istekleri engellenir; page.setRequestInterception() ile yapılan bu engelleme page.authenticate() çağrısını bozmaz. Zaman aşımları ve tünel hataları üstel bekleme (exponential backoff) ile yeniden denenir; yapılandırma hataları ve siteden gelen 403 ya da 429 ise işi durdurur.

js
import puppeteer from "puppeteer";

const PROXY = "http://pr.proxynet.io:8000";
const USER = "user";
const PASS = "pass";
const URLS = Array.from({ length: 6 }, (_, i) => `https://quotes.toscrape.com/js/page/${i + 1}/`);
const CONCURRENCY = 3; // aynı anda açık context sayısı
const ATTEMPTS = 3;
const BLOCKED = new Set(["image", "media", "font"]);
// Yapılandırma hataları: beklemek ve yeniden denemek bunları düzeltmez
const FATAL = ["ERR_PROXY_CONNECTION_FAILED", "ERR_NO_SUPPORTED_PROXIES", "ERR_INVALID_AUTH_CREDENTIALS"];

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function scrape(browser, url) {
  for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
    // Her denemeye bir context: kendi çerezleri ve kendi sticky oturumu (tek çıkış IP'si)
    const context = await browser.createBrowserContext({ proxyServer: PROXY });
    try {
      const page = await context.newPage();
      const session = crypto.randomUUID().slice(0, 8);
      await page.authenticate({ username: `${USER}-session-${session}-ttl-300`, password: PASS });
      await page.setRequestInterception(true);
      page.on("request", (req) => (BLOCKED.has(req.resourceType()) ? req.abort() : req.continue()));

      const res = await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30_000 });
      const status = res ? res.status() : 0;
      if (status === 403 || status === 429) {
        // Site reddediyor ya da yavaşlamanızı istiyor: çözüm yeni bir IP değil
        throw Object.assign(new Error(`HTTP ${status}: durun ve istek hızını düşürün`), { fatal: true });
      }
      if (status >= 400) throw new Error(`HTTP ${status}`);

      await page.waitForSelector("div.quote span.text", { timeout: 10_000 }); // JavaScript ile oluşuyor
      return await page.$$eval("div.quote span.text", (els) => els.map((el) => el.textContent));
    } catch (err) {
      err.fatal ||= FATAL.some((code) => err.message.includes(code));
      if (err.fatal || attempt === ATTEMPTS) throw err;
      await sleep(2 ** attempt * 1000 + Math.random() * 1000); // sonraki denemeden önce bekle
    } finally {
      await context.close();
    }
  }
}

const browser = await puppeteer.launch();
const queue = [...URLS];
const results = new Map();
await Promise.all(
  Array.from({ length: CONCURRENCY }, async () => {
    while (queue.length) {
      const url = queue.shift();
      try {
        results.set(url, `${(await scrape(browser, url)).length} alıntı`);
      } catch (err) {
        results.set(url, `HATA ${err.message.split("\n")[0]}`);
        if (err.fatal) queue.length = 0; // yalnız bu sayfayı değil, bütün işi durdur
      }
    }
  }),
);
await browser.close();
for (const url of URLS) console.log(url, results.get(url) ?? "atlandı");

Yerel test proxy'si üzerinden altı sayfanın hepsi onar alıntıyla döndü; iş beş saniyeden kısa sürdü. Proxy portunu bilerek yanlış yazdığımızda o anda işlenen üç sayfa yeniden denenmeden, hemen net::ERR_PROXY_CONNECTION_FAILED ile durdu, kalan üçü atlandı; 429 dönen yerel bir test sayfası da işi aynı şekilde bitirdi. CONCURRENCY değerine düşük başlayın: her context bellek tutar, hedef sitenin de kaldırabileceği bir yük sınırı vardır.

Kullanım alanları

  • Düz bir HTTP istemcisinin boş gördüğü, JavaScript ile yüklenen katalog ve fiyat sayfaları.
  • Kendi sitenizin, fiyatlarınızın ya da çerez bildiriminizin başka bir ülkeden nasıl göründüğünü kontrol etmek; her ülkeye bir context.
  • Herkese açık sayfaların, belirli bir ülkedeki ziyaretçinin gördüğü hâliyle ekran görüntüsü ve PDF'i.
  • Kendi sayfalarınızı ve ödeme akışlarınızı ağınızın dışından düzenli olarak izlemek.

Hepsinde aynı çerçeve geçerlidir: sitenin robots.txt kurallarına ve kullanım şartlarına uyun, resmî bir API varsa onu kullanın ve istek hızını sitenin kaldırabileceği düzeyde tutun.

Sık yapılan hatalar

  • --proxy-server değerine user:pass@ yazmak. Chrome değeri net::ERR_NO_SUPPORTED_PROXIES ile reddeder.
  • Her sayfada yeni bir kullanıcı adının geçerli olacağını sanmak. Chrome ilk kimlik bilgisini bütün context boyunca tutar; her oturuma bir context açın.
  • SOCKS5'te parola denemek. Chrome yalnızca "kimlik doğrulama yok" seçeneğini sunar; IP whitelist ya da HTTP portu kullanın.
  • localhost üzerinde test edip sonuca güvenmek. Loopback adresleri, <-loopback> eklenmedikçe proxy'yi atlar.
  • 407 cevabını sayfa sanmak. Yanlış parola hata fırlatmaz; response.status() değerine bakın.
  • 429 ya da 403 sonrasında IP değiştirmek. Bunun yerine yavaşlayın; sınır adresinizle değil, davranışınızla ilgilidir.
  • Context'leri açık bırakmak. Her biri bellek tutar; finally bloğunda kapatın.

Karar rehberi

İhtiyaçÖneri
Tek betik, tek çıkış--proxy-server bayrağı ve page.authenticate()
Tek tarayıcıda çok sayıda bağımsız oturumcreateBrowserContext({ proxyServer }), her context'e bir oturum kimliği
Birbirine bağlı olmayan toplu sayfalarRotating kullanıcı adı, kısa ömürlü context'ler
Giriş, sepet ya da çok adımlı formAkıştan uzun süren sticky oturum, tek context
SOCKS5 zorunluIP whitelist, kimlik bilgisi yok
Yalnızca başlatma bayrağını kabul eden bir araçIP whitelist ya da proxy-chain gibi yerel bir aktarıcı
İç sunucular doğrudan bağlanmalı--proxy-bypass-list ya da proxyBypassList

Sıkça sorulan sorular

puppeteer.launch() çağrısının proxy seçeneği var mı?

Hayır. Proxy, Chrome'un --proxy-server bayrağı olarak args dizisine; giriş bilgisi ise page.authenticate() çağrısına yazılır. Puppeteer'ın kendi API'sinde proxy alanları yalnızca browser.createBrowserContext() çağrısında bulunur: proxyServer ve proxyBypassList.

Her sayfaya ayrı proxy verilebilir mi?

Aynı context içinde verilemez. Proxy ve önbellekteki kimlik bilgisi context'e aittir; testimizde farklı kimlik bilgisi verilen ikinci sayfa yine ilkini kullandı. Kendi çıkışı olması gereken her sayfayı kendi context'inde açın; context açmak yeni bir tarayıcı başlatmaktan çok daha ucuzdur.

proxy-chain nedir, gerekli mi?

proxy-chain, açık kaynaklı bir Node.js paketidir. anonymizeProxy() fonksiyonu parolasız yerel bir proxy başlatır ve trafiği kimlik bilgileriyle birlikte asıl proxy'ye aktarır; Chrome'a da yalnızca sade bir http://127.0.0.1:<port> adresi verilir. Testimizde parola isteyen hem HTTP hem SOCKS5 proxy'yle çalıştı. page.authenticate() ya da IP whitelist kullanıyorsanız buna ihtiyacınız yoktur.

Tarayıcıyı yeniden başlatmadan proxy değiştirilebilir mi?

Evet, context'lerle. Context'i kapatın, başka bir proxyServer ya da oturum kimliğiyle yenisini açın ve page.authenticate() çağrısını tekrarlayın. Tarayıcının ömrü boyunca sabit kalan, yalnızca --proxy-server bayrağıyla verilen proxy'dir.

Proxy kaydında neden sizin göndermediğiniz istekler görünüyor?

Güncelleme denetimleri ve Google servis istekleri gibi Chrome'un kendi arka plan trafiği de aynı proxy'ye gider. Kaydımızda bunların çoğu kimlik bilgisi olmadan geldi ve 407 aldı, çünkü page.authenticate() yalnızca sayfa trafiğinden gelen talepleri cevaplar. Sayfalarınızı etkilemezler.

Proxy, Puppeteer'da CAPTCHA çıkmasını önler mi?

Hayır. Proxy trafiğin nereden geldiğini değiştirir; CAPTCHA ise istek hızına, tarayıcı sinyallerine ve tutarsız oturumlara da tepki verir. Nedenleri ve CAPTCHA'yı azaltmanın meşru yolları Puppeteer ve CAPTCHA: Neden Çıkar, Nasıl Azalır? yazısında anlatılıyor.

Özet

Puppeteer'da proxy bir Chrome ayarıdır: bütün tarayıcı için --proxy-server bayrağı, tek context için proxyServer; giriş bilgisi ise ilk gezinmeden önce page.authenticate() ile verilir. Kimlik bilgisi context başına önbelleğe alındığı için her oturumu bir context olarak kurun, sticky ya da rotating seçimini kullanıcı adıyla yapın ve SOCKS5 için IP whitelist kullanın. response.status() değerini kontrol edin ve istek hızını makul tutun. Sayfaların sıradan ev bağlantılarından açılması gerekiyorsa çıkış IP'lerini Residential Proxy havuzundan alabilirsiniz.

ChatGPT'ye sorClaude'a sor