Puppeteer steuert ein echtes Chromium, was genau das ist, was du willst, wenn ein Ziel seinen Inhalt mit JavaScript rendert, Daten hinter Interaktion versteckt, oder alles fingerprintet, was kein echter Browser ist. Einen Residential Proxy hinzuzufügen sind ein paar Zeilen, aber Puppeteer teilt die Aufgabe auf zwei verschiedene Stellen auf, auf eine Weise, die fast jeden beim ersten Mal stolpern lässt: die Proxy-Adresse kommt in die Launch-Argumente, und die Zugangsdaten kommen ganz woandershin.
Das ist der Puppeteer-Beitrag neben Residential Proxies mit Playwright; willst du schlichte HTTP-Clients statt eines vollen Browsers, siehe Proxies in Node.js. Hier konzentrieren wir uns auf die browser-spezifischen Fallen.
Alles unten nutzt Shifters Residential Gateway: ein Endpunkt, p.shifter.io:443, mit dem gesamten Targeting im Benutzernamen kodiert. Tausche Host und Zugangsdaten für einen anderen Anbieter aus; die Form bleibt gleich.
Das Gateway-Modell in einem Absatz
Der Proxy-Benutzername trägt deine Authentifizierung und dein Targeting. Du wechselst nicht den Endpunkt, um Land oder Session zu ändern, du änderst die Benutzernamen-Zeichenkette:
customer-USERNAME-country-us-sid-abc123-ttl-600country-us zielt auf die USA, sid fixiert eine Sticky Session, ttl hält diese IP für N Sekunden. Lässt du sid/ttl weg, rotiert jede neue Verbindung. Das Passwort bleibt konstant. In Puppeteer kommt der Host in ein Launch-Flag und dieser Benutzername in page.authenticate.
Das Setup: Proxy in den Launch-Args, Zugangsdaten in page.authenticate
Chromium nimmt den Proxy-Server als Kommandozeilen-Flag, --proxy-server, durchgereicht über Puppeteers args. Es akzeptiert dort kein user:pass@host, Chromium liest keine Zugangsdaten aus diesem Flag. Stattdessen lieferst du sie pro Seite mit page.authenticate, das die 407-Challenge des Proxys mit der richtigen Proxy-Authorization beantwortet.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true, args: ['--proxy-server=http://p.shifter.io:443'], // nur Host, keine Zugangsdaten});
const page = await browser.newPage();await page.authenticate({ username: `${process.env.SHIFTER_USER}-country-us`, // das Targeting lebt hier password: process.env.SHIFTER_PASS,});
await page.goto('https://api.ipify.org');console.log(await page.evaluate(() => document.body.innerText)); // eine US-Residential-IPawait browser.close();Zwei Dinge zum Verinnerlichen. Der Benutzername enthält die Targeting-Flags (-country-us), weil die Geo dort lebt, nicht in der URL. Und page.authenticate ist für einen authentifizierten Proxy nicht optional, ohne es stirbt jede Navigation an einem 407. Diese Aufteilung, Host im Flag und Zugangsdaten in page.authenticate, ist der häufigste Puppeteer-Proxy-Fehler.
Geo und Sessions über ein Gateway rotieren
Hier ist die nützliche Konsequenz dieses Designs. Der Proxy-Host wird beim Browser-Launch festgelegt und du kannst ihn nicht pro Seite ändern, aber du musst es auch nicht. Da das Targeting im Benutzernamen lebt und page.authenticate pro Seite gesetzt wird, leitet ein anderer Benutzername pro Seite sie über eine andere Identität auf demselben Gateway. Ein Browser, viele Geos, kein Neustart.
async function pageFor(browser, country, sid) { const page = await browser.newPage(); const user = `${process.env.SHIFTER_USER}-country-${country}` + (sid ? `-sid-${sid}-ttl-600` : ''); await page.authenticate({ username: user, password: process.env.SHIFTER_PASS }); return page;}
const de = await pageFor(browser, 'de', 'job-42'); // deutsche Sticky Sessionconst us = await pageFor(browser, 'us', null); // rotierendes USGib jeder logischen Arbeitseinheit ihre eigene sid und rotiere zwischen Einheiten, nicht mitten in der Session (Sticky vs. rotierend behandelt die Unterscheidung), und ordne Arbeit Identitäten so zu, wie es der Beitrag zum Lastausgleich beschreibt. Für Cookie- und Storage-Isolation zwischen Identitäten setze jede in ihren eigenen Browser-Kontext:
const context = await browser.createBrowserContext(); // isolierte Cookies/Storageconst page = await context.newPage();await page.authenticate({ username: userFor('gb'), password: pass });Beachte den Namen: neueres Puppeteer nennt das createBrowserContext(), ältere Versionen nannten es createIncognitoBrowserContext(). Dieselbe Idee, umbenannt.
Falle 1: verwende den Browser wieder, starte nie einen pro Anfrage
Chromium zu starten ist schwer, ein frischer Browser pro Anfrage zahlt jedes Mal Hunderte Millisekunden Startzeit plus echten Speicher, den Overhead, den der Latenz-Leitfaden beseitigen soll. Starte einen Browser beim Hochfahren und verwende ihn wieder, öffne Seiten oder Kontexte für nebenläufige Arbeit und schließe sie, wenn fertig. Ein Pool von Seiten unter einem langlebigen Browser ist die richtige Form.
Falle 2: blockiere die Ressourcen, die du nicht brauchst
Ein Browser holt alles, was ein echter holt: Bilder, Schriften, Media, Stylesheets, Analytics. Willst du nur das HTML oder ein paar Felder, ist das Bandbreite, für die du zahlst, und Zeit, auf die du wartest. Puppeteer lässt dich Anfragen abfangen und die abbrechen, die du nicht brauchst, was sowohl deine Ladezeit als auch deine Bandbreitenrechnung erheblich senkt.
await page.setRequestInterception(true);page.on('request', (req) => { const blocked = ['image', 'font', 'media', 'stylesheet']; if (blocked.includes(req.resourceType())) req.abort(); else req.continue();});Sei selektiv: manche Seiten rendern den Inhalt, den du willst, nicht ohne ihr CSS oder ein bestimmtes Skript, also blockiere aggressiv, dann bestätige, dass die Daten weiter erscheinen. Wenn sie es tun, ist das die billigste verfügbare Beschleunigung in einem Headless-Browser.
Falle 3: der Browser ist nur die Hälfte davon, nicht geblockt zu werden
Eine Residential-IP erledigt die Netzwerk-Hälfte davon, menschlich auszusehen, aber Puppeteer steuert immer noch Headless-Chromium, und Seiten fingerprinten auch den Browser, navigator.webdriver, headless-spezifische Eigenheiten, und Automatisierungssignale. Eine saubere IP mit guter Reputation hält dich aus vielen Challenges heraus, aber sie verschleiert keinen offensichtlich automatisierten Browser. Nutze ein aktuelles Puppeteer und Chromium, damit du den modernen Headless-Modus bekommst statt des alten, leicht erkennbaren, halte Viewport und User-Agent realistisch, und steuere die Seite in menschlichem Tempo. Die Fehler, die Erkennung auslösen, gelten für die Browser-Schicht ebenso wie für die IP-Schicht, und die beiden müssen zusammenpassen.
Falle 4: begrenze deine Nebenläufigkeit
Jede offene Seite ist ein echter Browser-Tab, der echten Speicher hält, also kannst du nicht Tausende öffnen, wie du HTTP-Anfragen abfeuern würdest. Halte einen begrenzten Pool von Seiten oder Kontexten und verwende sie wieder, und begrenze die Arbeit in Flug pro Ziel-Host, damit eine fragile Seite nicht malträtiert wird, während eine großzügige verhungert. Mehr Parallelität jenseits der Toleranz eines Ziels kauft Blockaden und Out-of-Memory-Abstürze, keinen Durchsatz (wie man Blockaden vermeidet).
Prüfe, dass du wirklich über den Proxy läufst
Bevor du irgendetwas anderes benchmarkst oder debuggst, bestätige die Exit-IP von innerhalb der Seite:
await page.goto('http://ip-api.com/json');console.log(await page.evaluate(() => document.body.innerText)); // erwarte das ZiellandDeine eigene IP bedeutet, dass das --proxy-server-Flag nicht angewandt wurde. Ein Hänger an einem 407-Dialog bedeutet, dass page.authenticate fehlt oder die Zugangsdaten falsch sind. Ein allgemeiner Hänger bedeutet, dass der lokale Ausgang blockiert ist. Alle drei werden im Leitfaden zur Timeout-Diagnose behandelt.
FAQ
Warum funktioniert user:pass@host in --proxy-server nicht?
Chromium liest die Proxy-Zugangsdaten nicht aus dem --proxy-server-Flag. Übergib dort nur den Host und liefere die Zugangsdaten mit page.authenticate({ username, password }), das die 407-Challenge des Proxys behandelt. Da das Gateway das Targeting im Benutzernamen kodiert, geht der vollständige Benutzername (mit -country-...) in page.authenticate.
Wie nutze ich ein anderes Land pro Seite, wenn der Proxy beim Launch festgelegt ist?
Du änderst nicht den Proxy-Host, du änderst den page.authenticate-Benutzernamen. Da das Targeting im Benutzernamen lebt und der Gateway-Host konstant ist, kann sich jede Seite mit einem anderen Benutzernamen authentifizieren und über eine andere Identität austreten. Ein Browser bedient viele Geos.
Kann ich den Proxy rotieren, ohne den Browser neu zu starten?
Ja, für Identität und Geo, indem du den page.authenticate-Benutzernamen pro Seite oder Kontext variierst. Du würdest nur neu starten, wenn du einen wirklich anderen Proxy-Host bräuchtest, was du mit einem einzigen Gateway-Endpunkt nicht tust.
Wie senke ich die Bandbreite in Puppeteer? Aktiviere Request-Interception und brich Ressourcentypen ab, die du nicht brauchst (Bilder, Schriften, Media, oft Stylesheets). Bestätige, dass das Ziel die Daten, die du willst, weiter rendert, dann behalte die Blocks. Es ist der größte einzelne Hebel für Geschwindigkeit und Kosten in einem Headless-Browser.
Puppeteer oder Playwright?
Beide steuern echte Browser und beide funktionieren gut mit Residential Proxies. Playwright nimmt den Proxy (mit Zugangsdaten) direkt in seinen Kontext-Optionen; Puppeteer teilt ihn in das Launch-Flag plus page.authenticate. Wähle nach Ökosystem-Passung und bestehendem Code; die Proxy-Konzepte sind dieselben.
Das Fazit
Puppeteer plus Residential Proxies ist unkompliziert, sobald die Aufteilung einrastet: der Proxy-Host kommt beim Launch in --proxy-server, und die Zugangsdaten, die dein Targeting im Benutzernamen tragen, kommen pro Seite in page.authenticate. Rotiere Geo und Sessions, indem du diesen Benutzernamen variierst statt neu zu starten, isoliere Identitäten mit Browser-Kontexten, verwende einen langlebigen Browser wieder, blockiere die Ressourcen, die du nicht brauchst, und denk daran, dass der Browser-Fingerabdruck so menschlich aussehen muss wie die IP.
Mach das richtig, und Puppeteer bewältigt die JavaScript-lastigen Ziele, die schlichte HTTP-Clients nicht können. Richte es auf das Residential Gateway, und denk daran, dass die Pool-Qualität entscheidet, wie oft du überhaupt herausgefordert wirst (IP-Reputation). Die Preisseite hat die Pro-GB-Tarife, um es gegen deine eigenen Ziele zu testen.