Puppeteer pilote un vrai Chromium, ce qui est exactement ce que vous voulez quand une cible rend son contenu avec JavaScript, cache des données derrière une interaction, ou fait le fingerprint de tout ce qui n’est pas un vrai navigateur. Ajouter un proxy résidentiel, c’est deux lignes, mais Puppeteer répartit la tâche entre deux endroits différents d’une façon qui fait trébucher presque tout le monde la première fois : l’adresse du proxy va dans les arguments de lancement, et les identifiants vont ailleurs entièrement.
Ceci est l’entrée Puppeteer aux côtés de proxys résidentiels avec Playwright ; si vous voulez des clients HTTP simples plutôt qu’un navigateur complet, voyez les proxys en Node.js. Ici nous nous concentrons sur les pièges propres au navigateur.
Tout ci-dessous utilise le gateway résidentiel de Shifter : un point de terminaison, p.shifter.io:443, avec tout le ciblage encodé dans le nom d’utilisateur. Changez l’hôte et les identifiants pour un autre fournisseur ; la forme est la même.
Le modèle du gateway en un paragraphe
Le nom d’utilisateur du proxy porte votre authentification et votre ciblage. Vous ne changez pas de point de terminaison pour changer de pays ou de session, vous changez la chaîne du nom d’utilisateur :
customer-USERNAME-country-us-sid-abc123-ttl-600country-us cible les États-Unis, sid fixe une session sticky, ttl maintient cette IP pendant N secondes. Omettez sid/ttl et chaque nouvelle connexion tourne. Le mot de passe est constant. Dans Puppeteer, l’hôte va dans un flag de lancement et ce nom d’utilisateur va dans page.authenticate.
Le montage : proxy dans les args de lancement, identifiants dans page.authenticate
Chromium prend le serveur proxy comme flag de ligne de commande, --proxy-server, passé via les args de Puppeteer. Il n’acceptera pas user:pass@host là, Chromium ne lit pas les identifiants de ce flag. À la place vous les fournissez par page avec page.authenticate, qui répond au défi 407 du proxy avec le bon Proxy-Authorization.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true, args: ['--proxy-server=http://p.shifter.io:443'], // hote seul, pas d'identifiants});
const page = await browser.newPage();await page.authenticate({ username: `${process.env.SHIFTER_USER}-country-us`, // le ciblage vit ici password: process.env.SHIFTER_PASS,});
await page.goto('https://api.ipify.org');console.log(await page.evaluate(() => document.body.innerText)); // une IP résidentielle américaineawait browser.close();Deux choses à intérioriser. Le nom d’utilisateur inclut les flags de ciblage (-country-us), parce que la géo vit là, pas dans l’URL. Et page.authenticate n’est pas optionnel pour un proxy authentifié, sans lui chaque navigation meurt sur un 407. Cette répartition, hôte dans le flag et identifiants dans page.authenticate, est l’erreur de proxy Puppeteer la plus courante.
Faire tourner géo et sessions via un gateway
Voici la conséquence utile de cette conception. L’hôte du proxy est fixé au lancement du navigateur et vous ne pouvez pas le changer par page, mais vous n’en avez pas besoin. Parce que le ciblage vit dans le nom d’utilisateur et que page.authenticate se pose par page, donner à chaque page un nom d’utilisateur différent la route via une identité différente sur le même gateway. Un navigateur, plusieurs géos, sans relancer.
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'); // session sticky allemandeconst us = await pageFor(browser, 'us', null); // US rotatifDonnez à chaque unité logique de travail son propre sid et tournez entre unités, pas en milieu de session (sticky vs rotatif couvre la distinction), et mappez le travail aux identités comme le décrit le billet sur la répartition de charge. Pour isoler cookies et stockage entre identités, mettez chacune dans son propre contexte de navigateur :
const context = await browser.createBrowserContext(); // cookies/stockage isolesconst page = await context.newPage();await page.authenticate({ username: userFor('gb'), password: pass });Attention au nom : Puppeteer récent appelle cela createBrowserContext(), les anciennes versions l’appelaient createIncognitoBrowserContext(). Même idée, renommée.
Piège 1 : réutilisez le navigateur, ne lancez-en jamais un par requête
Lancer Chromium est lourd, un navigateur frais par requête paie des centaines de millisecondes de démarrage plus de la mémoire réelle à chaque fois, le surcoût que le guide de latence existe pour éliminer. Lancez un navigateur au démarrage et réutilisez-le, en ouvrant des pages ou des contextes pour le travail concurrent et en les fermant une fois finis. Un pool de pages sous un navigateur de longue vie est la bonne forme.
Piège 2 : bloquez les ressources dont vous n’avez pas besoin
Un navigateur récupère tout ce qu’un vrai récupère : images, polices, média, feuilles de style, analytics. Si vous ne voulez que le HTML ou quelques champs, c’est de la bande passante que vous payez et du temps que vous attendez. Puppeteer vous laisse intercepter les requêtes et abandonner celles dont vous n’avez pas besoin, ce qui réduit sensiblement votre temps de chargement et votre facture de bande passante.
await page.setRequestInterception(true);page.on('request', (req) => { const blocked = ['image', 'font', 'media', 'stylesheet']; if (blocked.includes(req.resourceType())) req.abort(); else req.continue();});Soyez sélectif : certains sites ne rendront pas le contenu que vous voulez sans leur CSS ou un script spécifique, alors bloquez agressivement, puis confirmez que les données apparaissent toujours. Quand c’est le cas, c’est l’accélération la moins chère disponible dans un navigateur headless.
Piège 3 : le navigateur n’est que la moitié du fait de ne pas se faire bloquer
Une IP résidentielle gère la moitié réseau du fait de paraître humain, mais Puppeteer pilote toujours Chromium headless, et les sites font le fingerprint du navigateur aussi, navigator.webdriver, particularités spécifiques au headless, et signaux d’automatisation. Une IP propre avec une bonne réputation vous garde hors de beaucoup de défis, mais elle ne déguise pas un navigateur manifestement automatisé. Utilisez un Puppeteer et un Chromium actuels pour obtenir le mode headless moderne plutôt que l’ancien, facilement détectable, gardez le viewport et le user-agent réalistes, et pilotez la page à un rythme humain. Les erreurs qui déclenchent la détection s’appliquent à la couche navigateur autant qu’à la couche IP, et les deux doivent s’aligner.
Piège 4 : bornez votre concurrence
Chaque page ouverte est un vrai onglet de navigateur qui retient de la mémoire réelle, donc vous ne pouvez pas en ouvrir des milliers comme vous tireriez des requêtes HTTP. Gardez un pool borné de pages ou de contextes et réutilisez-les, et bornez le travail en vol par hôte cible pour qu’un site fragile ne soit pas martelé pendant qu’un permissif est affamé. Plus de parallélisme au-delà de la tolérance d’une cible achète des blocages et des plantages par manque de mémoire, pas du débit (comment éviter de se faire bloquer).
Vérifiez que vous êtes bien sur le proxy
Avant de benchmarker ou de déboguer quoi que ce soit d’autre, confirmez l’IP de sortie depuis l’intérieur de la page :
await page.goto('http://ip-api.com/json');console.log(await page.evaluate(() => document.body.innerText)); // attendez le pays cibléVotre propre IP signifie que le flag --proxy-server ne s’est pas appliqué. Un blocage sur un dialogue 407 signifie que page.authenticate manque ou que les identifiants sont mauvais. Un blocage général signifie que la sortie locale est bloquée. Les trois sont couverts dans le guide de diagnostic des timeouts.
FAQ
Pourquoi mettre user:pass@host dans --proxy-server ne marche-t-il pas ?
Chromium ne lit pas les identifiants du proxy depuis le flag --proxy-server. Passez seulement l’hôte là et fournissez les identifiants avec page.authenticate({ username, password }), qui gère le défi 407 du proxy. Parce que le gateway encode le ciblage dans le nom d’utilisateur, le nom d’utilisateur complet (avec -country-...) va dans page.authenticate.
Comment utiliser un pays différent par page si le proxy est fixé au lancement ?
Vous ne changez pas l’hôte du proxy, vous changez le nom d’utilisateur de page.authenticate. Comme le ciblage vit dans le nom d’utilisateur et que l’hôte du gateway est constant, chaque page peut s’authentifier avec un nom d’utilisateur différent et sortir par une identité différente. Un navigateur sert plusieurs géos.
Puis-je faire tourner le proxy sans relancer le navigateur ?
Oui, pour l’identité et la géo, en variant le nom d’utilisateur de page.authenticate par page ou contexte. Vous ne relanceriez que s’il vous fallait un hôte de proxy réellement différent, ce qui n’arrive pas avec un unique point de terminaison de gateway.
Comment réduire la bande passante dans Puppeteer ? Activez l’interception de requêtes et abandonnez les types de ressource dont vous n’avez pas besoin (images, polices, média, souvent feuilles de style). Confirmez que la cible rend toujours les données que vous voulez, puis gardez les blocages. C’est le plus grand levier unique sur la vitesse et le coût dans un navigateur headless.
Puppeteer ou Playwright ?
Les deux pilotent de vrais navigateurs et les deux marchent bien avec les proxys résidentiels. Playwright prend le proxy (avec identifiants) directement dans ses options de contexte ; Puppeteer le répartit dans le flag de lancement plus page.authenticate. Choisissez selon l’ajustement d’écosystème et le code existant ; les concepts du proxy sont les mêmes.
En résumé
Puppeteer plus proxys résidentiels est simple dès que la répartition s’enclenche : l’hôte du proxy va dans --proxy-server au lancement, et les identifiants, portant votre ciblage dans le nom d’utilisateur, vont dans page.authenticate par page. Faites tourner géo et sessions en variant ce nom d’utilisateur plutôt qu’en relançant, isolez les identités avec des contextes de navigateur, réutilisez un navigateur de longue vie, bloquez les ressources dont vous n’avez pas besoin, et souvenez-vous que l’empreinte du navigateur doit paraître aussi humaine que l’IP.
Réussissez cela et Puppeteer gère les cibles chargées de JavaScript que les clients HTTP simples ne peuvent pas. Pointez-le vers le gateway résidentiel, et souvenez-vous que la qualité du pool décide à quelle fréquence vous êtes défié tout court (réputation d’IP). La page tarifs propose les forfaits au Go pour le tester contre vos propres cibles.