Cloudflare umgehen mit Puppeteer
Ausgangspunkt
Ich wollte eine Seite scrapen, die von Cloudflare geschützt wird. Ohne Proxy, ohne Browser – kein Durchkommen: 403 Forbidden
, leere Antwort oder direkt cf-chl-bypass
. Also: Headless-Browser muss her.
Ziel: Seite automatisch aufrufen, DOM lesen, JSON extrahieren. Kein massives Crawling, nur regelmäßiger Pull.
⚙️ Werkzeugwahl
Ich habe mich für Puppeteer entschieden, weil:
- Setup schnell gemacht ist
- Page-Steuerung einfach per JS
- Kein Overhead wie bei Selenium + Webdriver
Alternativen wie Playwright oder undetected-chromedriver habe ich später getestet, aber erstmal: Puppeteer pur.
Probleme
- Cloudflare blockt headless Chrome
→ trotz Wartezeit kommt nur Error-Seite navigator.webdriver = true
→ klarer Fingerabdruck für Bot-Erkennung- Fehlender User-Agent & Headers
→ Chrome ohne Styles, leerer Inhalt
Lösungsschritte
1. Headless deaktivieren
const browser = await puppeteer.launch({ headless: false, args: ['--no-sandbox', '--disable-setuid-sandbox'] });
2. navigator.webdriver
entfernen
await page.evaluateOnNewDocument(() => { Object.defineProperty(navigator, 'webdriver', { get: () => false, }); });
3. User-Agent + Header setzen
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64)...'); await page.setExtraHTTPHeaders({ 'accept-language': 'de-DE,de;q=0.9', });
4. Wartezeit einbauen + Screenshot prüfen
await page.goto(url, { waitUntil: 'networkidle2' }); await page.waitForTimeout(3000); await page.screenshot({ path: 'proof.png' });
5. Proxy einbinden (wenn IP gebannt)
const browser = await puppeteer.launch({ headless: false, args: [ '--proxy-server=http://user:[email protected]:8000', ], });
Was ich gelernt habe
- Headless = sofort blockiert, egal wie nett die Headers sind
navigator.webdriver
muss raus, sonst hat man keine ChancewaitForTimeout
ist oft nötig, um dynamisches JS abzuwarten
Bonus: Minimal-Skript
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.setUserAgent('Mozilla/5.0...'); await page.evaluateOnNewDocument(() => { Object.defineProperty(navigator, 'webdriver', { get: () => false }); }); await page.goto('https://zielseite.com', { waitUntil: 'networkidle2' }); const html = await page.content(); console.log(html); await browser.close(); })();
Fazit
Cloudflare ist nervig, aber nicht unknackbar – mit Browser-Automation kommt man fast immer durch. Headless = raus, Header + Delay = rein.
Test von 04/2025 – kann sich ändern, wenn Cloudflare ihre Detection-Logik anpasst.