Neden Raw Puppeteer Tespit Edilir?
Puppeteer, Chromium'un DevTools Protocol üzerinden otomasyon yapmak için tasarlanmış güçlü bir kütüphanedir — ama tarayıcı parmak izi endüstrisi onu yakalamak için tasarlanmıştır. İlk puppeteer.launch() çağrınızdan itibaren en az üç bariz sinyal sızdırılır:
- navigator.webdriver — W3C standardı gereği otomasyon flag'i
trueolarak ayarlanır. Basit birnavigator.webdriverkontrolü botunuzu anında ele verir. - Plugins dizisi tutarsızlığı — Otomatikleştirilmiş Chromium, normal kullanıcı profillerinden farklı bir
navigator.pluginsdizisi sunar. Uzantı sayısı ve MIME type haritası fingerprint veritabanlarında kataloglanmıştır. - iframe chromedriver eserleri — ChromeDriver, bazı sayfa yüklemelerinde
cdc_önekli gizli iframe'ler enjekte eder. Cloudflare ve DataDome bu iframe'leri tarar.
Bunlar sadece buzdağının görünen kısmı. WebGL render parametreleri, canvas hash sapmaları, window.chrome nesnesinin eksikliği, Permissions.query davranış farklılıkları — hepsi otomasyonu ele verir. Tek bir sinyal bile engellenmeye neden olabilir; onlarca sinyal bir araya geldiğinde ise başarısızlık kaçınılmazdır.
Puppeteer-Extra Stealth Plugin: Hangi Sinyalleri Yamar?
puppeteer-extra, Puppeteer'ı eklenti mimarisiyle genişleten bir sarmalayıcıdır. En popüler eklentisi olan puppeteer-extra-plugin-stealth, dokuz alt modülle fingerprint sızıntılarını sistematik olarak kapatır:
| Stealth Alt Modülü | Patch Edilen Sinyal | Mekanizma |
|---|---|---|
| evasions/navigator.webdriver | navigator.webdriver === true | Property'yi undefined yapar |
| evasions/navigator.plugins | Bozuk plugins dizisi | Gerçekçi plugin listesi enjekte eder |
| evasions/navigator.languages | Eksik dil tercihleri | Tutarlı Accept-Language başlığı sağlar |
| evasions/webgl.vendor | Headless GPU bilgisi | Vendor/renderer string'lerini değiştirir |
| evasions/iframe.contentWindow | ChromeDriver iframe eserleri | cdc_ iframe'lerini kaldırır |
| evasions/media.codecs | Headless codec desteği | MediaSource yeteneklerini simüle eder |
| evasions/user-agent-override | Headless UA string'i | Headless ibaresini kaldırır |
| evasions/console.debug | DevTools debug sızıntısı | Debug çağrılarını sessize alır |
| evasions/stack-trace | Otomasyon kaynaklı stack trace | Stack trace'leri temizler |
Kurulum ve temel kullanım son derece basittir:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
(async () => {
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
await page.goto('https://bot.sannysoft.com/');
// Tüm stealth patch'lerin aktif olduğunu doğrula
const isWebdriver = await page.evaluate(() => navigator.webdriver);
console.log('navigator.webdriver:', isWebdriver); // undefined
await browser.close();
})();
Stealth plugin tek başına güçlüdür — ama IP bazlı engellemeler karşısında çaresizdir. Bir sonraki adım, parmak izi yamalarını IP rotasyonuyla birleştirmektir.
Stealth + Yerel Proxy: En Güçlü Anti-Tespit Yığını
Parmak izi yamaları tarayıcı kimliğinizi gizlerken, yerel proxy'ler ağ kimliğinizi gizler. Veri merkezi IP'leri ASN veritabanlarında kataloglanmış olduğundan, Cloudflare ve benzeri WAF'lar bu IP'leri anında bayraklar. Yerel proxy'ler ise gerçek ISP bağlantılarından gelen IP'ler sunar — bu da trafiğinizi normal kullanıcı trafiğinden ayırt edilemez kılar.
ProxyHat yerel proxy'lerini Puppeteer ile entegre etmek için --proxy-server Chrome bayrağını kullanın:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
(async () => {
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
`--proxy-server=http://gate.proxyhat.com:8080`
]
});
const page = await browser.newPage();
// ProxyHat kimlik doğrulaması
await page.authenticate({
username: 'user-country-US',
password: 'PASSWORD'
});
await page.goto('https://httpbin.org/ip');
const ip = await page.evaluate(() =>
document.querySelector('pre').innerText
);
console.log('Yerel IP:', ip);
await browser.close();
})();
Bu yapılandırma ile her sayfa yüklemesi ABD tabanlı bir yerel IP üzerinden gerçekleşir. Ülke hedeflemesini değiştirmek için kullanıcı adı içindeki country parametresini değiştirmeniz yeterlidir: user-country-DE, user-country-JP vb.
SOCKS5 ile Daha Derin Gizlilik
HTTP proxy'ler CONNECT tüneli kurar ve bazı WAF'lar proxy başlıklarını denetleyebilir. SOCKS5 ise tamamen şeffaf bir tünel sunar — HTTP başlıklarında hiçbir proxy eseri kalmaz:
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--no-sandbox',
`--proxy-server=socks5://gate.proxyhat.com:1080`
]
});
Özel Değerlendiriciler: Canvas ve WebGL Parmak İzi Rastgeleleştirme
Stealth plugin temel sızıntıları kapatır, ancak canvas fingerprint ve WebGL render parametreleri hala benzersiz tanımlayıcılar üretir. Her oturumda tutarlı ama oturumlar arasında farklı olan parmak izleri üretmek için özel evaluateOnNewDocument hook'ları yazmalısınız:
const crypto = require('crypto');
function generateSessionSeed() {
return crypto.randomBytes(16).toString('hex');
}
async function applyFingerprintRandomization(page, seed) {
await page.evaluateOnNewDocument((sessionSeed) => {
// Canvas fingerprint rastgeleleştirme
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function (...args) {
const context = this.getContext('2d');
if (context) {
// Her oturumda benzersiz ama tutarlı gürültü ekle
const noise = parseInt(sessionSeed.slice(0, 8), 16) % 5 - 2;
const imageData = context.getImageData(0, 0, this.width, this.height);
for (let i = 0; i < imageData.data.length; i += 4) {
imageData.data[i] = Math.max(0, Math.min(255, imageData.data[i] + noise));
}
context.putImageData(imageData, 0, 0);
}
return originalToDataURL.apply(this, args);
};
// WebGL vendor/renderer rastgeleleştirme
const getParameter = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function (param) {
if (param === 0x1F00) return 'Google Inc. (NVIDIA)'; // VENDOR
if (param === 0x1F01) { // RENDERER
const renderers = [
'ANGLE (NVIDIA, NVIDIA GeForce GTX 1060)',
'ANGLE (NVIDIA, NVIDIA GeForce RTX 3060)',
'ANGLE (Intel, Intel(R) UHD Graphics 630)'
];
const idx = parseInt(sessionSeed.slice(8, 12), 16) % renderers.length;
return renderers[idx];
}
return getParameter.call(this, param);
};
}, seed);
}
// Kullanım
(async () => {
const browser = await puppeteer.launch({ headless: 'new' });
const page = await browser.newPage();
const seed = generateSessionSeed();
await applyFingerprintRandomization(page, seed);
await page.goto('https://browserleaks.com/canvas');
// ...
})();
Her yeni sayfa veya tarayıcı bağlamı için yeni bir seed üretin. Aynı seed, aynı oturum içinde tutarlı parmak izi verir — bu da parmak izi tutarlılık kontrollerini geçmenizi sağlar.
Tarayıcı Bağlamı Başına Proxy Rotasyonu
Tek bir tarayıcı örneğinde birden fazla BrowserContext açarak, her bağlama farklı bir proxy atayabilirsiniz. Bu, paralel kazıma senaryolarında IP rotasyonunu verimli hale getirir:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
const PROXY_CONFIGS = [
{ username: 'user-country-US', password: 'PASSWORD', country: 'US' },
{ username: 'user-country-DE', password: 'PASSWORD', country: 'DE' },
{ username: 'user-country-JP', password: 'PASSWORD', country: 'JP' }
];
async function createContextWithProxy(browser, config) {
const context = await browser.createIncognitoBrowserContext();
const page = await context.newPage();
await page.authenticate({
username: config.username,
password: config.password
});
// Her bağlam için benzersiz parmak izi
const seed = crypto.randomBytes(16).toString('hex');
await applyFingerprintRandomization(page, seed);
return { context, page, seed };
}
(async () => {
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--no-sandbox',
`--proxy-server=http://gate.proxyhat.com:8080`
]
});
const sessions = await Promise.all(
PROXY_CONFIGS.map(cfg => createContextWithProxy(browser, cfg))
);
// Her bağlamı farklı ülke hedefiyle paralel kullan
for (const session of sessions) {
await session.page.goto('https://httpbin.org/ip');
const ip = await session.page.evaluate(() =>
document.querySelector('pre').innerText
);
console.log(`${session.seed.slice(0, 8)} IP:`, ip);
}
await browser.close();
})();
Önemli Not:--proxy-serverbayrağı tarayıcı düzeyinde ayarlanır ve tüm bağlamları etkiler.page.authenticate()ile her bağlama farklı kimlik bilgisi vererek, ProxyHat'ın ülke hedefleme mekanizması üzerinden bağlam bazlı rotasyon sağlayabilirsiniz. Her bağlamın farklı bir ülke IP'si almasını sağlamak için kullanıcı adı içindekicountryparametresini değiştirin.
Sticky Oturumlar ile Tutarlı IP
Bazı senaryolarda (oturum açma, sepet işlemleri) aynı IP'de kalmanız gerekir. ProxyHat'ın sticky session özelliğini kullanmak için kullanıcı adında bir session parametresi ekleyin:
await page.authenticate({
username: 'user-country-US-session-abc123',
password: 'PASSWORD'
});
Aynı session tanımlayıcısını kullanan tüm istekler aynı yerel IP'ye yönlendirilir — oturum süresi boyunca tutarlı kalır.
Ölçeklendirme: Konteynerleştirilmiş Filolar ve Tarayıcı Havuzları
Tek bir makinede yüzlerce paralel tarayıcı çalıştırmak kaynak yönetimi kabusudur. Doğru yaklaşım, konteynerleştirilmiş tarayıcı filoları oluşturmaktır.
Docker ile İzole Tarayıcı Düğümleri
Her Docker konteyneri bir tarayıcı örneği çalıştırır. Bu, bellek izolasyonu, bağımsız ölçeklendirme ve temiz başlangıç garantisi sağlar:
FROM node:20-slim
RUN apt-get update && apt-get install -y \
chromium \
fonts-ipafont-gothic \
--no-install-recommends && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV MAX_CONCURRENT_PAGES=5
ENV PROXY_GATEWAY=http://gate.proxyhat.com:8080
CMD ["node", "worker.js"]
Tarayıcı Havuzu Yönetimi
Ölçeklendirme sırasında tarayıcı yaşam döngüsünü yönetmek için bir havuz soyutlaması kullanın. Her worker şöyle çalışır:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
const crypto = require('crypto');
puppeteer.use(StealthPlugin());
class BrowserPool {
constructor({ maxBrowsers = 4, maxPagesPerBrowser = 5 } = {}) {
this.maxBrowsers = maxBrowsers;
this.maxPagesPerBrowser = maxPagesPerBrowser;
this.browsers = [];
}
async acquirePage(proxyConfig) {
// Mevcut tarayıcılarda boş yuva ara
for (const entry of this.browsers) {
if (entry.pageCount < this.maxPagesPerBrowser) {
const context = await entry.browser.createIncognitoBrowserContext();
const page = await context.newPage();
await page.authenticate({
username: proxyConfig.username,
password: proxyConfig.password
});
const seed = crypto.randomBytes(16).toString('hex');
await applyFingerprintRandomization(page, seed);
entry.pageCount++;
const originalClose = page.close.bind(page);
page.close = async () => {
await originalClose();
await context.close();
entry.pageCount--;
};
return page;
}
}
// Yeni tarayıcı başlat
if (this.browsers.length < this.maxBrowsers) {
const browser = await puppeteer.launch({
headless: 'new',
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
`--proxy-server=${process.env.PROXY_GATEWAY}`
]
});
const entry = { browser, pageCount: 0 };
this.browsers.push(entry);
return this.acquirePage(proxyConfig);
}
throw new Error('Tarayıcı havuzu dolu — daha sonra tekrar deneyin');
}
async drain() {
await Promise.all(this.browsers.map(e => e.browser.close()));
this.browsers = [];
}
}
module.exports = { BrowserPool };
Kaynak Yönetimi En İyi Uygulamaları
- Bellek sınırı: Her Chromium örneği ~150-300 MB bellek tüketir. Konteyner başına en az 512 MB ayırın ve
--disable-dev-shm-usagebayrağını kullanın. - Sayfa yaşam süresi: Her sayfayı 30 saniyeden uzun açık tutmayın. Bellek sızıntıları birikir ve tarayıcıyı çökertir.
- Otomatik yeniden başlatma: Tarayıcıları her 50-100 sayfadan sonra yeniden başlatın. Chromium'un bellek parçalanması kaçınılmazdır.
- İstek zaman aşımı: Proxy üzerinden yapılan isteklerde 30 saniye zaman aşımı ayarlayın. Yerel proxy'ler veri merkezi proxy'lere göre biraz daha yüksek gecikmeye sahip olabilir.
- Hata oranı izleme: Başarı oranını dakika bazında izleyin. %90'ın altına düşerse, proxy sağlayıcınızın durum sayfasını kontrol edin.
Kubernetes ile Yatay Ölçeklendirme
Üretim ortamında Kubernetes Deployment + HPA (Horizontal Pod Autoscaler) kullanarak CPU/bellek eşiklerine göre otomatik ölçeklendirme yapın. Her Pod bir worker çalıştırır ve ProxyHat'ın oturum bazlı rotasyonu ile çakışma riski olmadan binlerce eşzamanlı oturum yönetebilirsiniz.
Etik Not: Stealth Meşru Kazıma İçindir
Anti-tespit teknikleri güçlü araçlardır ve güçlü araçlar sorumlu kullanım gerektirir. Stealth plugin ve yerel proxy'ler şu amaçlarla kullanılmalıdır:
- SERP izleme ve arama motoru verisi toplama
- E-ticaret fiyat karşılaştırma ve pazar analizi
- Genel erişimli verilerin toplanması
- QA ve erişilebilirlik testleri
- Güvenlik araştırmaları
Bu teknikler asla dolandırıcılık, kimlik sahteciliği, kredi kartı testi veya hizmet koşullarını açıkça ihlal eden faaliyetler için kullanılmamalıdır. Her zaman robots.txt'e saygı gösterin, rate limiting uygulayın ve hedef sitenin altyapısını aşırı yüklemeyin. GDPR ve CCPA kapsamındaki kişisel veri toplama kurallarına uyun. ProxyHat'ın kullanım koşulları da bu etik çerçeveyi gerektirir.
Temel Çıkarımlar
- Raw Puppeteer en az üç bariz sinyal sızdırır:
navigator.webdriver, tutarsız plugins dizisi ve ChromeDriver iframe eserleri.- puppeteer-extra-plugin-stealth dokuz alt modülle bu sızıntıları sistematik olarak kapatır.
- Stealth tek başına yeterli değildir — yerel proxy'lerle birleştirilmeden IP bazlı engellemeler kaçınılmazdır.
- Canvas ve WebGL parmak izlerini her oturumda rastgeleleştirmek için
evaluateOnNewDocumenthook'ları yazın.- BrowserContext başına proxy rotasyonu, paralel kazımada IP çeşitliliği sağlar.
- Ölçeklendirme için konteynerleştirilmiş filolar, tarayıcı havuzları ve düzenli yeniden başlatma stratejileri kullanın.
- Etik kurallara uyun — stealth meşru kazıma içindir, dolandırıcılık değil.
ProxyHat'ın yerel proxy ağı, 190+ ülkede IP rotasyonu ve şehir düzeyinde hedefleme sunar. Ücretsiz deneme ile fiyatlandırma sayfamızı inceleyin veya doğrudan bu rehberdeki kod örneklerini projenize entegre edin. Daha fazla kazıma deseni için web kazıma kullanım senaryomuzu ve SERP izleme sayfamızı ziyaret edin.






