Selenium과 Playwright의 프록시 인증: 동작하는 모든 방법 (2026)

2026년 6월 4일 게시 · 약 10분 소요

모든 브라우저 자동화 개발자가 딱 한 번씩은 빠지는 함정이 있습니다. Chrome의 실행 플래그에 --proxy-server=http://user:pass@host:port를 추가하면 브라우저는 멀쩡히 시작되지만, 이후 모든 페이지가 스크립트로는 볼 수도 클릭할 수도 없는 인증 팝업에서 멈춰버립니다. Chrome은 프록시 플래그에서 자격 증명을 조용히 제거합니다. 오류도, 로그 한 줄도 없이, 그저 아무도 보고 있지 않은 브라우저에 모달 대화상자만 떠 있을 뿐입니다.

이 가이드는 2026년 Selenium과 Playwright에서 실제로 동작하는 프록시 인증 방법의 완전한 지도입니다 — 무엇을 써야 하고, 무엇을 피해야 하며, 각각의 정확한 코드까지. (이러한 도구에서의 프록시 선택 및 회전 전략은 Playwright & Puppeteer에서 프록시 사용하기를 참고하세요 — 이 글은 오직 자격 증명을 통과시키는 것에만 집중합니다.)

왜 브라우저에서 user:pass@host가 실패하는가

명령줄 HTTP 클라이언트는 프록시 URL에서 자격 증명을 파싱해, 프록시의 407 Proxy Authentication RequiredProxy-Authorization 헤더로 자동 응답합니다. Chromium은 그렇지 않습니다. --proxy-server는 오직 scheme://host:port만 받아들이고, 407이 돌아오면 대화형 대화상자를 띄웁니다. 헤드리스 모드에서는 대화상자조차 없습니다 — 요청이 그냥 실패합니다.

그래서 질문은 결코 "비밀번호를 URL에 어떻게 넣을까"가 아닙니다 — "어떤 계층이 나를 대신해 407에 응답하는가"입니다. 동작하는 답은 네 가지이며, 좋은 순서대로 소개합니다.

방법 1: Playwright 네이티브 인증 (가능하면 이것을 쓰세요)

Playwright는 이 문제를 제대로 해결했습니다. CDP를 통해 프록시 인증 챌린지에 스스로 응답합니다. 자격 증명은 실행 또는 컨텍스트 옵션에 들어갑니다:

# 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',
  }
});

컨텍스트별 프록시는 하나의 브라우저 프로세스가 N개의 서로 다른 sticky 세션 위에서 N개의 컨텍스트를 실행할 수 있다는 뜻입니다 — 모든 본격적인 Playwright 스크래핑 설정의 토대입니다. Playwright를 쓰고 있다면 끝났습니다. 검증 섹션으로 건너뛰세요. 아래의 모든 내용은 Selenium에 이에 상응하는 기능이 없기 때문에 존재합니다.

방법 2: selenium-wire (Selenium, Python)

selenium-wire는 업스트림 인증을 처리하는 로컬 MITM 프록시로 Selenium을 감쌉니다:

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")

프로덕션에 들어가기 전에 알아야 할 주의사항:

방법 3: 자격 증명을 주입하는 Chrome 확장 프로그램 (Selenium, 모든 언어)

고전적인 접근법: 프록시를 설정하고 chrome.webRequest.onAuthRequired를 통해 인증에 응답하는 작은 생성형 확장 프로그램입니다. MITM도, 추가 프로세스도 없이 순수 Selenium에서 동작합니다:

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)

두 가지 함정: 확장 프로그램은 클래식 헤드리스 모드에서 로드되지 않습니다--headless=new(Chrome 109+)를 쓰거나 헤드 모드로 실행하세요. 그리고 Manifest V2 백그라운드 스크립트는 사이드로드된 자동화 확장 프로그램에서는 여전히 동작하지만 Chrome의 MV2 폐기 일정을 주시하세요 — MV3 등가물은 서비스 워커와 동일한 onAuthRequired 리스너가 필요합니다.

방법 4: 로컬 포워더 (만능 폴백)

자격 증명을 보유하는 작은 로컬 프록시를 실행하고, 브라우저를 인증이 전혀 없는 localhost로 향하게 하세요. 모든 브라우저, 모든 드라이버, 모든 언어에서, 헤드리스든 아니든 동작합니다:

# 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)

이것은 Firefox/geckodriver(확장 프로그램 트릭이 적용되지 않는 곳)와 Electron 앱 테스트 같은 특이한 환경에 대한 가장 깔끔한 답이기도 합니다. 비용: 감독해야 할 움직이는 부품이 하나 더 늘고, 컨텍스트별 라우팅에는 세션당 포워더 포트가 하나씩 필요합니다.

방법 비교

방법동작 환경헤드리스컨텍스트별 세션프로덕션 평가
Playwright 네이티브Playwright기본 선택
selenium-wireSelenium (Py)드라이버별중간 규모에서 무난
인증 확장 프로그램Selenium (모든 언어)--headless=new드라이버별탄탄, MV3 주시
로컬 포워더전부세션당 포트 하나만능 폴백

실제로 동작했는지 검증하기

실제 IP로의 조용한 폴백은 계정을 차단당하게 만드는 실패 모드입니다. 매 실행 시작 시 출구 IP를 단언(assert)하세요:

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"
무료 도구 · 가입 불필요

자동화된 브라우저를 눈으로 확인하세요

Selenium/Playwright 브라우저를 저희 What Is My IP 페이지로 보내보세요. 출구 IP, 위치정보, ASN 유형, 프록시/VPN 플래그를 한 화면에서 보여줍니다 — 인증 계층이 동작했고 IP가 주거용임을 즉시 확인할 수 있습니다.

IP 체커 열기 →

"주거용" 프록시에서 데이터센터 ASN이 보이나요? 실제로 주거용인 풀로 전환하세요 — 500MB 무료 트래픽 →

빠른 문제 해결 참고

요약

브라우저는 user:pass@ 프록시 URL을 읽지 않습니다 — 무언가가 대신 407에 응답해야 합니다. Playwright에서는 그 무언가가 내장되어 있고, Selenium에서는 selenium-wire, 생성형 인증 확장 프로그램, 또는 로컬 포워더입니다. 비교 표에서 자신의 스택에 맞게 고른 다음, 매 실행마다 출구 IP를 단언해 조용한 인증 실패가 크롤링 도중 실제 주소를 절대 유출하지 못하게 하세요.

오늘 밤 네 가지 방법을 모두 테스트하세요

500MB 무료 트래픽 — 하나의 게이트웨이, sticky 또는 회전, HTTP와 SOCKS5.

무료 체험 시작

모든 IP 제품 · 언제든 이용 가능한 방대한 노드 풀

지금 가입하고 충전 금액의 최대 100%를 돌려받으세요

신규 사용자는 가입 시 500MB를 받고, 첫 충전 시 추가 보너스를 받습니다. 기간 한정 혜택입니다.