Voici le piège dans lequel tout développeur d'automatisation de navigateur tombe exactement une fois : vous ajoutez --proxy-server=http://user:pass@host:port aux flags de lancement de Chrome, le navigateur démarre sans souci, puis chaque page reste bloquée sur un popup d'authentification que votre script ne peut ni voir ni cliquer. Chrome supprime silencieusement les identifiants du flag du proxy. Aucune erreur, aucune ligne de log, juste une boîte de dialogue modale dans un navigateur que personne ne regarde.
Ce guide est la carte complète des méthodes d'authentification de proxy qui fonctionnent vraiment dans Selenium et Playwright en 2026 — laquelle utiliser, laquelle éviter, et le code exact pour chacune. (Pour la sélection des proxies et la stratégie de rotation dans ces outils, voir Utiliser des proxies avec Playwright & Puppeteer — cet article porte uniquement sur le fait de faire passer les identifiants.)
Les clients HTTP en ligne de commande extraient les identifiants des URL de proxy et répondent au 407 Proxy Authentication Required du proxy avec un en-tête Proxy-Authorization automatiquement. Chromium, non : --proxy-server n'accepte que scheme://host:port, et quand le 407 revient il affiche une boîte de dialogue interactive. En mode headless il n'y a même pas de dialogue — la requête échoue tout simplement.
Donc la question n'est jamais « comment mettre le mot de passe dans l'URL » — c'est « quelle couche répond au 407 à ma place ». Quatre réponses qui fonctionnent, la meilleure en premier.
Playwright a résolu le problème correctement : il répond lui-même aux défis d'authentification de proxy via CDP. Les identifiants vont dans les options de lancement ou de contexte :
# Python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={
"server": "http://us.jibaoproxy.com:913",
"username": "USERNAME-session-job1",
"password": "PASSWORD",
}
)
// Node.js - and per-context, which is where it gets powerful:
const browser = await chromium.launch({
proxy: { server: 'per-context' } // declare intent at launch
});
const ctx = await browser.newContext({
proxy: {
server: 'http://us.jibaoproxy.com:913',
username: 'USERNAME-session-job2',
password: 'PASSWORD',
}
});
Les proxies par contexte signifient qu'un seul processus de navigateur peut exécuter N contextes sur N sessions sticky distinctes — le fondement de toute configuration sérieuse de scraping avec Playwright. Si vous êtes sur Playwright, c'est terminé ; passez à la section de vérification. Tout ce qui suit existe parce que Selenium n'a pas d'équivalent.
selenium-wire enveloppe Selenium d'un proxy MITM local qui gère l'authentification en amont :
from seleniumwire import webdriver # pip install selenium-wire
options = {
"proxy": {
"http": "http://USERNAME:[email protected]:913",
"https": "https://USERNAME:[email protected]:913",
}
}
driver = webdriver.Chrome(seleniumwire_options=options)
driver.get("https://example.com")
Mises en garde à connaître avant la production :
L'approche classique : une petite extension générée qui configure le proxy et répond à l'authentification via chrome.webRequest.onAuthRequired. Pas de MITM, pas de processus supplémentaire, fonctionne dans Selenium pur :
import zipfile, json
HOST, PORT = "us.jibaoproxy.com", 913
USER, PASS = "USERNAME-session-sel1", "PASSWORD"
manifest = {
"version": "1.0.0", "manifest_version": 2, "name": "Proxy Auth",
"permissions": ["proxy", "webRequest", "webRequestBlocking", ""],
"background": {"scripts": ["background.js"]},
}
background = f"""
chrome.proxy.settings.set({{value: {{mode: "fixed_servers", rules: {{
singleProxy: {{scheme: "http", host: "{HOST}", port: {PORT}}}
}}}}, scope: "regular"}}, () => {{}});
chrome.webRequest.onAuthRequired.addListener(
() => ({{authCredentials: {{username: "{USER}", password: "{PASS}"}}}}),
{{urls: [""]}}, ["blocking"]
);
"""
with zipfile.ZipFile("proxy_auth.zip", "w") as zp:
zp.writestr("manifest.json", json.dumps(manifest))
zp.writestr("background.js", background)
from selenium import webdriver
opts = webdriver.ChromeOptions()
opts.add_extension("proxy_auth.zip")
driver = webdriver.Chrome(options=opts)
Deux pièges : les extensions ne se chargent pas en mode headless classique — utilisez --headless=new (Chrome 109+) ou exécutez en mode headed ; et les scripts d'arrière-plan de Manifest V2 fonctionnent encore pour les extensions d'automatisation chargées en sideload, mais surveillez le calendrier d'obsolescence de MV2 par Chrome — l'équivalent en MV3 nécessite un service worker et le même listener onAuthRequired.
Exécutez un petit proxy local qui détient les identifiants ; pointez le navigateur vers localhost sans aucune authentification. Fonctionne avec tous les navigateurs, tous les drivers, tous les langages, headless ou non :
# Using pproxy (pip install pproxy) - terminal 1:
pproxy -l http://127.0.0.1:8899 \
-r "http://USERNAME:[email protected]:913"
# Your script - terminal 2: plain Selenium, no auth needed
opts = webdriver.ChromeOptions()
opts.add_argument("--proxy-server=http://127.0.0.1:8899")
driver = webdriver.Chrome(options=opts)
C'est aussi la réponse la plus propre pour Firefox/geckodriver (où l'astuce de l'extension ne s'applique pas) et pour des environnements exotiques comme les tests d'apps Electron. Coût : une pièce mobile de plus à superviser, et le routage par contexte requiert un port de transitaire par session.
| Méthode | Fonctionne dans | Headless | Sessions par contexte | Verdict en production |
|---|---|---|---|---|
| Natif Playwright | Playwright | Oui | Oui | Choix par défaut |
| selenium-wire | Selenium (Py) | Oui | Par driver | Bien à échelle modérée |
| Extension d'authentification | Selenium (tout langage) | --headless=new uniquement | Par driver | Solide, surveillez MV3 |
| Transitaire local | Tout | Oui | Un port par session | Repli universel |
Le repli silencieux vers votre vraie IP est le mode de défaillance qui fait bannir les comptes. Affirmez l'IP de sortie au début de chaque exécution :
ip = driver.execute_script(
"return fetch('https://api.ipify.org').then(r => r.text())"
) if hasattr(driver, 'execute_script') else page.evaluate(
"fetch('https://api.ipify.org').then(r => r.text())"
)
assert ip != MY_REAL_IP, "Proxy not applied - aborting before we leak"
--proxy-server ; Chrome les a abandonnés. Utilisez l'une des quatre méthodes.ERR_PROXY_CONNECTION_FAILED — hôte/port incorrects ou protocole non concordant. Testez d'abord la même ligne avec curl -x ; si curl fonctionne, le problème vient du câblage de votre navigateur.--headless=new.Les navigateurs ne lisent pas les URL de proxy user:pass@ — quelque chose doit répondre au 407 à leur place. Dans Playwright, ce quelque chose est intégré ; dans Selenium, c'est selenium-wire, une extension d'authentification générée ou un transitaire local. Choisissez selon votre stack à partir du tableau comparatif, puis affirmez l'IP de sortie à chaque exécution pour qu'un échec d'authentification silencieux ne puisse jamais divulguer votre vraie adresse en plein crawl.
500 Mo de trafic résidentiel gratuit — une passerelle, sticky ou rotative, HTTP et SOCKS5.
Démarrer l'essai gratuitLes nouveaux utilisateurs reçoivent 500 Mo à l'inscription, plus un bonus sur la première recharge. Offre à durée limitée.