Puppeteer, Chrome'u koddan yönetmenizi sağlayan bir Node.js kütüphanesidir: sayfa açar, form doldurur, ekran görüntüsü alır, dinamik içerik yüklenene kadar bekler. Uçtan uca testlerden rapor üretimine kadar birçok işte kullanılır. Ancak otomasyon büyüdükçe çoğu ekip aynı engelle karşılaşır: CAPTCHA.
Bu yazı CAPTCHA'yı "çözmenin" değil, neden ortaya çıktığını anlamanın ve meşru bir otomasyonda gereksiz yere tetiklenmesini önlemenin yollarını anlatıyor. CAPTCHA, site sahibinin "bu trafikten emin değilim" deme biçimidir; o sinyali doğru okumak, onunla yarışmaktan her zaman daha sürdürülebilirdir. Yazının sonunda çalışan bir Puppeteer kurulumu, bir kontrol listesi ve yapılmaması gerekenler var.
CAPTCHA türleri ve tetiklenme mantığı
Bugün karşılaşacağınız CAPTCHA'ların çoğu "resimdeki trafik ışıklarını seçin" ekranı değildir. Üç yaygın biçim vardır:
- Görünmez doğrulama. Sayfa yüklenirken tarayıcı ortamı ve davranış arka planda puanlanır; kullanıcı hiçbir şey görmez. Puan düşükse görünür bir adıma geçilir.
- Tek tık onayı. "Robot değilim" kutusu ya da Cloudflare Turnstile gibi hafif bir onay. Çoğu gerçek kullanıcı için tek tıkla geçer.
- Görsel veya etkileşimli bulmaca. Puan çok düşükse gösterilen, insan çabası gerektiren adım.
Bu üç biçim aynı puanlama sisteminin farklı aşamalarıdır. Yani CAPTCHA "çıktı" ya da "çıkmadı" değil, puanınız hangi eşiği geçti sorusudur. Puanı düşük tutan her önlem, görünür adıma hiç ulaşmamanızı sağlar.
CAPTCHA neden çıkar?
Modern bot korumaları tek bir kurala bakmaz; birçok sinyali birlikte puanlar. Puppeteer oturumlarında bu puanı en çok yükselten etkenler şunlardır:
1. IP adresinin türü ve itibarı
İstek bir veri merkezi IP'sinden geliyorsa, sıradan bir ev kullanıcısından gelen isteğe göre baştan daha şüpheli kabul edilir. Aynı IP'den kısa sürede çok sayıda oturum açılması veya adresin daha önce kötüye kullanılmış olması puanı daha da artırır. IP türleri arasındaki farkı Residential ve Datacenter Proxy Farkı yazımızda anlattık.
2. İstek hızı ve örüntüsü
İnsanlar sayfaları okur, kaydırır, bekler. Saniyede onlarca sayfa açan, her sayfada tam aynı sürede aynı tıklamayı yapan bir oturum insan davranışına benzemez. Sabit aralıklı bekleme bile bir örüntüdür; insan beklemeleri düzensizdir.
3. Başsız tarayıcı izleri
Otomasyonla açılan bir tarayıcı, varsayılan ayarlarda kendini ele veren izler taşıyabilir. navigator.webdriver özelliğinin true olması bunların en bilinenidir; bu özellik standart olarak otomasyon altındaki tarayıcıyı belirtmek için vardır. Gerçek dışı pencere boyutları (Puppeteer'ın varsayılanı 800×600'dür), eksik tarayıcı özellikleri ve başsız moda özgü User-Agent değerleri de dikkat çeker.
4. Tutarsız profil
İstanbul'dan gelen bir IP ile en-US dili ve New York saat dilimi kullanan bir tarayıcı; ya da her istekte değişen parmak izine sahip tek bir oturum. Sinyallerin birbiriyle çelişmesi, tek tek her birinden daha şüphelidir. Parmak izinin nasıl oluştuğunu Tarayıcı Parmak İzi Nedir? yazımızda ele aldık.
5. Oturum geçmişinin olmaması
Her çalıştırmada sıfırdan açılan, hiç çerezi olmayan bir tarayıcı, siteyi ilk kez ziyaret eden bir kullanıcı gibi görünür. Bu tek başına sorun değildir; ama diğer sinyallerle birleştiğinde puanı artırır. Daha önce bir doğrulamayı geçmiş oturumun çerezi, sonraki ziyaretlerde puanı düşürür.
6. Davranışsal analiz
Bazı korumalar yalnızca giriş anına değil, oturum boyunca imleç hareketi ve etkileşim tutarlılığına bakar. Bu yeni nesil yaklaşımı Cloudflare Precursor yazımızda ayrıntılı anlattık.
Nedenler ve önlemler tek tabloda
| Neden | Sinyal | Meşru önlem |
|---|---|---|
| Veri merkezi IP'si | ASN türü, IP itibarı | Residential veya ISP proxy |
| Yüksek hız | İstek sıklığı, sabit aralık | Değişken bekleme, düşük eşzamanlılık |
| Başsız izler | navigator.webdriver, varsayılan pencere | Gerçekçi pencere, güncel başsız mod |
| Tutarsız profil | IP konumu ile dil/saat dilimi çelişkisi | Profili IP'ye göre ayarlamak |
| Geçmişsiz oturum | Boş çerez, yeni profil | Kalıcı userDataDir |
| Oturum içinde IP değişimi | Aynı çerez, farklı adres | Sticky veya sabit IP |
CAPTCHA'yı meşru yollarla nasıl azaltırsınız?
Aşağıdaki önlemlerin ortak amacı, otomasyonunuzu gizlemek değil, gereksiz şüphe üretmemesini sağlamaktır.
Hızı düşürün ve istekleri dağıtın
En etkili ve en ucuz önlem budur. Sayfa geçişleri arasına değişken beklemeler ekleyin, aynı anda açık sekme sayısını sınırlayın ve işi günün farklı saatlerine yayın. Hedef sitenin yükünü azaltmak hem sizin için daha az engel hem de karşı taraf için daha az maliyet demektir.
const bekle = (enAz, enCok) =>
new Promise((coz) => setTimeout(coz, enAz + Math.random() * (enCok - enAz)));
for (const url of urls) {
await page.goto(url, { waitUntil: "domcontentloaded" });
// sayfayı işle
await bekle(2000, 6000);
}Oturumları ve çerezleri koruyun
Her çalıştırmada yeni bir profil açmak yerine kalıcı bir kullanıcı veri dizini kullanın. Böylece çerezler ve daha önce geçilmiş doğrulamalar oturumlar arasında korunur:
import puppeteer from "puppeteer";
const browser = await puppeteer.launch({
userDataDir: "./profil-1",
});Birden fazla hesap ya da görev yönetiyorsanız her biri için ayrı bir dizin kullanın; profillerin birbirine karışması, tek bir cihazdan çok sayıda hesabın yönetildiği sinyalini üretir.
Profili tutarlı tutun
Tarayıcının dili, saat dilimi ve pencere boyutu kullandığınız IP'nin konumuyla uyumlu olsun. Aynı oturum boyunca bu değerleri değiştirmeyin:
const page = await browser.newPage();
await page.setViewport({ width: 1366, height: 768 });
await page.emulateTimezone("Europe/Istanbul");
await page.setExtraHTTPHeaders({ "Accept-Language": "tr-TR,tr;q=0.9" });Pencere boyutunu gerçek cihazlarda yaygın olan değerlerden seçin; alışılmadık bir çözünürlük tek başına dikkat çeker.
Oturum başına tek bir IP kullanın
Puppeteer'a proxy, Chrome'un başlatma argümanıyla verilir. Kimlik doğrulama gerekiyorsa page.authenticate kullanılır:
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: "kullanici", password: "parola" });
await page.goto("https://httpbin.org/ip", { waitUntil: "networkidle2" });
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();Burada önemli olan IP'nin oturum boyunca değişmemesidir. Giriş yapılmış bir oturumun ortasında IP adresinin değişmesi, CAPTCHA'nın en sık nedenlerinden biridir. Bu tür akışlarda Sticky Proxy belirli bir süre aynı IP'yi korur; hesap bazlı uzun oturumlarda ISP Proxy daha kararlıdır. Korumalı sitelerde gerçek kullanıcı adreslerinden gelen Residential Proxy, veri merkezi IP'lerine göre daha az şüphe uyandırır.
Gereksiz kaynakları engellemeyin
Bant genişliği kazanmak için görselleri ve stil dosyalarını engellemek yaygın bir alışkanlıktır. Ancak hiç görsel yüklemeyen bir "tarayıcı" gerçek bir kullanıcıya benzemez ve bazı korumalar bu eksikliği sinyal olarak kullanır. Trafik maliyeti sorunsa yalnızca büyük medya dosyalarını (video, büyük görseller) engellemek daha dengeli bir orta yoldur.
Mümkünse resmi kaynağa yönelin
Hedef site bir API sunuyorsa tarayıcı otomasyonuna hiç gerek kalmayabilir. API'ler daha hızlıdır, daha az kaynak tüketir ve CAPTCHA ile karşılaşmazsınız. Kendi sitenizi veya bir müşterinizin sitesini test ediyorsanız, site sahibinden test trafiğinizi koruma kurallarında muaf tutmasını istemek en temiz çözümdür.
Tam örnek: tutarlı bir Puppeteer kurulumu
Yukarıdaki önlemleri bir araya getiren, proxy ile çalışan ve sayfalar arasında değişken bekleyen bir kurulum:
import puppeteer from "puppeteer";
const bekle = (enAz, enCok) =>
new Promise((coz) => setTimeout(coz, enAz + Math.random() * (enCok - enAz)));
const browser = await puppeteer.launch({
userDataDir: "./profil-1",
args: ["--proxy-server=http://pr.proxynet.io:8000", "--window-size=1366,768"],
defaultViewport: { width: 1366, height: 768 },
});
const page = await browser.newPage();
await page.authenticate({ username: "kullanici", password: "parola" });
await page.emulateTimezone("Europe/Istanbul");
await page.setExtraHTTPHeaders({ "Accept-Language": "tr-TR,tr;q=0.9" });
const urls = ["https://httpbin.org/ip", "https://httpbin.org/headers"];
for (const url of urls) {
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 });
console.log(url, (await page.evaluate(() => document.body.innerText)).slice(0, 80));
await bekle(2000, 5000);
}
await browser.close();Bu kurulumda IP oturum boyunca sabittir, profil kalıcıdır, saat dilimi ve dil IP'nin konumuyla (Türkiye) uyumludur ve sayfalar arasında insan benzeri, düzensiz bir bekleme vardır.
Yapmamanız gerekenler
- CAPTCHA çözdürme servisleri kullanmak. İnsanlara ya da modellere CAPTCHA çözdürüp sonucu otomasyona aktaran hizmetler, site sahibinin açıkça kurduğu bir korumayı hedef alır. Birçok sitenin kullanım koşullarını ihlal eder ve hukuki risk doğurabilir.
- Tespit atlatma eklentilerine güvenmek. Otomasyon izlerini gizlediğini iddia eden eklentiler, koruma sağlayıcılarıyla sürekli bir kovalamaca içindedir. Bugün çalışan bir yöntem yarın çalışmayabilir; iş akışınızı bunun üzerine kurmak sürdürülebilir değildir.
- Engellenince hızı artırmak. CAPTCHA bir uyarıdır. Daha fazla istekle karşılık vermek genellikle IP'nin tamamen engellenmesiyle sonuçlanır.
- Her istekte IP değiştirip aynı oturumu sürdürmek. Çerez aynı kalırken adresin sürekli değişmesi, tek başına IP değiştirmekten daha şüpheli bir örüntüdür.
Hangi verinin hangi koşullarda toplanabileceğini Web Scraping Yasal mı? yazımızda anlattık.
CAPTCHA çıktığında ne yapmalı?
Önlemlere rağmen CAPTCHA görüyorsanız bunu bir teşhis fırsatı olarak kullanın:
- Hangi sayfada çıktığını kaydedin. Giriş sayfasında mı, listede mi, detay sayfasında mı? Korumanın nerede yoğunlaştığını gösterir.
- IP'yi değiştirip aynı akışı tekrarlayın. CAPTCHA kayboluyorsa sorun IP itibarındadır; kalıyorsa profil ya da hız kaynaklıdır.
- Hızı yarıya indirin. Oran düşüyorsa eşik hız kaynaklıdır.
- Profili gerçek bir tarayıcıyla karşılaştırın. Aynı siteye normal Chrome ile girip CAPTCHA görmüyorsanız, otomasyon izleri belirleyicidir.
Bu dört adım, hangi sinyalin puanı yükselttiğini birkaç denemede ortaya çıkarır. Kör deneme yerine tek değişkenli test yapmak zaman kazandırır. CAPTCHA yerine 403, 429 veya 503 gibi yanıtlar alıyorsanız her kodun anlamını ve hangisinde yeniden denenmesi gerektiğini Scraping'de HTTP Hata Kodları yazımızda bulabilirsiniz.
Puppeteer yerine başka araçlar daha mı iyi?
Selenium, Playwright ve Puppeteer'ın CAPTCHA karşısındaki durumu temelde aynıdır; hepsi gerçek bir tarayıcıyı koddan yönetir ve aynı sinyallere tabidir. Araç değiştirmek, yukarıdaki nedenleri ortadan kaldırmaz. Çoğu zaman ilk soru hangi aracın seçileceği değil, tarayıcıya gerçekten ihtiyaç olup olmadığıdır; bunu nasıl anlayacağınızı Statik ve Dinamik Sayfalar yazımızda anlattık. Python ekosistemindeki karşılıklar için Selenium, SeleniumBase ile Proxy ve Undetected ChromeDriver yazılarımıza bakabilirsiniz. Dil seçimini etkileyen diğer etkenleri Web Kazıma: JavaScript mi Python mu? yazımızda karşılaştırdık.
Sık sorulan sorular
Başsız mod CAPTCHA'yı artırır mı?
Eski başsız mod, normal tarayıcıdan ayırt edilmesi daha kolay izler taşıyordu. Chrome'un güncel başsız modu normal tarayıcıya çok daha yakındır. Yine de başsız çalışmak, diğer sinyallerle birleştiğinde puanı etkileyebilir.
Proxy CAPTCHA'yı tamamen önler mi?
Hayır. Doğru IP türü şüphe puanını düşürür, ama istek hızı, profil tutarsızlığı ve davranış gibi diğer sinyaller devam eder. IP, çözümün yalnızca bir parçasıdır.
Her istekte IP değiştirmek iyi bir fikir mi?
Oturum gerektirmeyen, birbirinden bağımsız sayfa çekimlerinde evet; Rotating Proxy bu iş için uygundur. Giriş yapılan veya çok adımlı akışlarda ise IP'nin oturum boyunca sabit kalması gerekir; aksi halde CAPTCHA olasılığı artar.
Puppeteer'da SOCKS5 proxy kullanabilir miyim?
Evet. --proxy-server=socks5://sunucu:port biçiminde verilir. Ancak Chrome, SOCKS5 için kullanıcı adı ve parola doğrulamasını desteklemez; SOCKS5 kullanacaksanız proxy panelinden IP yetkilendirmesi yapmanız gerekir. Protokol farkları için SOCKS ve HTTP Proxy Farkı yazımıza bakabilirsiniz.
Mobil site otomasyonunda CAPTCHA daha az mı çıkar?
Mobil görünüm tek başına puanı düşürmez. Mobil bir profil kullanıyorsanız IP'nin de mobil olması tutarlılık sağlar; masaüstü IP'siyle mobil profil çelişkidir. Mobil trafiğin farkını Residential ve Mobil Proxy Arasındaki Farklar yazımızda anlattık.
Puppeteer ile Playwright arasında proxy kullanımı farklı mı?
Mantık aynıdır: Tarayıcı başlatılırken proxy adresi verilir, kimlik bilgileri ayrı bir çağrıyla tanımlanır. Playwright'ta bu ayar launch({ proxy: { server, username, password } }) biçiminde tek nesnede yapılır.
Özetle
Puppeteer'da CAPTCHA'nın arkasında çoğunlukla IP türü, istek hızı, başsız tarayıcı izleri ve tutarsız profil bulunur. Hızı düşürmek, oturumları korumak, profili IP konumuyla uyumlu tutmak ve oturum başına sabit bir IP kullanmak, meşru otomasyonlarda CAPTCHA'yı belirgin şekilde azaltır. CAPTCHA çıktığında tek değişkenli test yaparak nedenini bulmak, kör deneme yanılmadan çok daha hızlıdır. Korumayı atlatmaya çalışmak ise hem kırılgan hem riskli bir yoldur. Otomasyon projeleriniz için uygun IP türlerini proxy çözümlerimizde bulabilirsiniz.




