Nodriver 프록시 인증: 효과적인 세 가지 해결책
nodriver 프록시 인증에 대한 최상위 결과는 GitHub 토론이며, 가이드가 아닙니다. nodriver는 기본적인 사용자:비밀번호 지원이 없습니다 — 여기 효과적인 세 가지 해결책과 대부분의 사람들이 놓치는 한 줄의 지름길이 있습니다.
nodriver 프록시 인증을 검색하면 상위 10개 결과는 GitHub 토론, 데모 저장소, 다른 라이브러리에 대한 Stack Overflow 스레드 몇 개, 그리고 Reddit 게시물 하나입니다 — 실제 가이드는 없습니다. 이유는 간단합니다: nodriver는 비동기 CDP로서 undetected-chromedriver의 후속작이며 (그 프로젝트는 GitHub에서 12.8k 스타와 1.3k 포크를 가지고 있습니다), 프록시에 user:pass를 전달하는 기본 방법이 없습니다. Chrome은 명령줄 플래그에 포함된 자격 증명을 무시하며, nodriver는 이를 보완하지 않습니다. 이 가이드는 그 토론 스레드가 되어야 했던 페이지입니다: 무엇이 작동하고, 무엇이 작동하지 않으며, 인증된 프록시를 실행하는 세 가지 해결책입니다.
일반 프록시는 작동합니다; 인증된 프록시는 작동하지 않습니다
인증되지 않은 프록시는 한 줄입니다. 주소를 browser_args에 전달하면 모든 요청이 프록시 IP에서 나갑니다:
import nodriver as uc
async def main():
browser = await uc.start(
browser_args=["--proxy-server=gate.quantumproxies.io:PORT"],
)
page = await browser.get("https://httpbin.org/ip")
print(await page.get_content()) # shows the proxy exit IP
uc.loop().run_until_complete(main())
이제 자격 증명을 추가합니다 — --proxy-server=http://USER:PASS@host:port — 그러면 작동하지 않습니다. Chromium은 플래그 형식에 자격 증명 슬롯이 없기 때문에 USER:PASS@ 세그먼트를 제거하고, 프록시는 407 Proxy Authentication Required로 응답하며, Chrome은 DOM 외부에 존재하는 네이티브 로그인 대화 상자를 띄웁니다. nodriver는 이를 볼 수도, 채울 수도 없습니다. 그 407은 407 오류 수정 가이드에서 다룬 것과 동일한 벽입니다: 브라우저가 아니라 프록시가 당신을 거부하는 것입니다. 따라서 모든 실제 해결책은 다른 방법으로 이 도전에 응답해야 합니다.
해결책 1: IP 화이트리스트 — 자격 증명도, 대화 상자도 없음
이것은 GitHub 스레드에서 언급되지 않는 지름길이며, 가장 간단한 방법입니다. 스크래퍼가 안정적인 공용 IP를 가진 머신에서 실행된다면, 제공자 대시보드에 그 IP를 등록하고 자격 증명을 완전히 제거하세요 — 게이트웨이는 소스 주소로 당신을 인증합니다. nodriver 코드는 위의 일반 --proxy-server 스니펫으로 남아 있으며, 인증 코드가 전혀 없습니다. 모든 QuantumProxies 플랜은 거주지 프록시에서 사용자:비밀번호와 함께 IP 화이트리스트를 지원하므로, egress IP가 고정되어 있을 때 이 방법이 권장됩니다. 유일한 제한은 토폴로지입니다: 스크립트가 아닌 머신을 인증하므로, 일시적인 클라우드 러너, NAT 뒤의 컨테이너, IP가 변경되는 CI 박스는 다음 두 가지 해결책 중 하나가 필요합니다.

해결책 2: CDP Fetch 핸들러로 도전에 응답하기
nodriver는 Chrome DevTools Protocol을 직접 사용하므로, 프로세스 내에서 인증 도전을 가로챌 수 있습니다 — 확장 파일이 필요 없습니다. handle_auth_requests=True로 Fetch 도메인을 활성화한 다음, 각 AuthRequired 이벤트에 continue_with_auth로 응답하세요. 두 가지 세부 사항, 모두 토론 #1798의 답변에서 나온 것으로, 작동과 중단의 차이를 만듭니다:
- 도메인을 활성화하기 전에 핸들러를 등록하세요. nodriver의 내부
enable호출은 핸들러 등록을 덮어쓰므로, 나중에 추가하면 이벤트가 전혀 발생하지 않습니다 — 사람들이 '아무것도 하지 않는다'고 보고하는 주된 이유입니다. - 응답을 발사하고 잊으세요. 핸들러 내부에서 응답을 기다리면 이벤트 루프가 차단되고 브라우저 전체가 교착 상태에 빠집니다. 각 전송을
asyncio.create_task로 감싸서 차단 없이 실행되도록 하세요.
import asyncio
import nodriver as uc
PROXY = "gate.quantumproxies.io:PORT" # host:port for --proxy-server
USER, PASS = "USER", "PASS"
class Scraper:
def __init__(self):
uc.loop().run_until_complete(self.run())
async def run(self):
browser = await uc.start(browser_args=[f"--proxy-server={PROXY}"])
self.tab = await browser.get("draft:,") # blank tab first
# 1) handlers BEFORE enabling the Fetch domain
self.tab.add_handler(uc.cdp.fetch.RequestPaused, self.on_request)
self.tab.add_handler(uc.cdp.fetch.AuthRequired, self.on_auth)
# 2) only now turn on interception with auth handling
await self.tab.send(uc.cdp.fetch.enable(handle_auth_requests=True))
page = await browser.get("https://httpbin.org/ip")
await asyncio.sleep(3)
print(await page.get_content())
async def on_auth(self, event):
# fire-and-forget: awaiting here deadlocks the loop
asyncio.create_task(self.tab.send(uc.cdp.fetch.continue_with_auth(
request_id=event.request_id,
auth_challenge_response=uc.cdp.fetch.AuthChallengeResponse(
response="ProvideCredentials", username=USER, password=PASS,
),
)))
async def on_request(self, event):
asyncio.create_task(self.tab.send(
uc.cdp.fetch.continue_request(request_id=event.request_id)))
if __name__ == "__main__":
Scraper()
같은 스레드에서 나타난 한 가지 경고: 사용자가 이 방법이 일반 HTTP 페이지에서는 작동하지만 HTTPS에서는 실패한다고 발견했으며, 원인은 코드가 아닌 저품질 프록시였습니다 — 더 나은 종료로 교체하면 해결되었습니다. 이는 스텔스 스크래핑의 반복적인 교훈입니다: 핸들러는 도전에 응답하지만, IP 평판이 사이트가 당신을 허용할지 여부를 결정합니다.
해결책 3: 생성된 Chrome 확장 프로그램
다른 커뮤니티 패턴은 시작 시 작은 Chrome 확장 프로그램을 생성하여 프록시를 설정하고 chrome.webRequest.onAuthRequired를 통해 자격 증명 도전에 응답합니다 — Selenium과 Puppeteer에서 작동하는 동일한 트릭입니다. 작은 매니페스트와 백그라운드 작업자를 임시 디렉토리에 작성하고 --load-extension을 통해 로드합니다:
import nodriver as uc
async def main():
# ext_dir holds a Manifest V3 extension: manifest.json + worker.js that
# calls chrome.proxy.settings.set(...) and returns authCredentials from
# chrome.webRequest.onAuthRequired. Generate it once, then load it:
browser = await uc.start(browser_args=[
"--load-extension=" + ext_dir,
"--headless=new", # extensions only load in the NEW headless mode
])
page = await browser.get("https://httpbin.org/ip")
print(await page.get_content())
uc.loop().run_until_complete(main())
전체 매니페스트와 작업자는 Selenium 프록시 인증 가이드의 Manifest V3 파일과 동일합니다 — 그대로 복사하고, 시작 호출만 변경됩니다. 두 가지 주의 사항이 어디서나 반복됩니다: 확장은 --headless=new에서만 로드됩니다 (일반 --headless는 실패), 그리고 압축되지 않은 디렉토리는 Chrome 버전 간에 압축된 zip보다 더 안정적입니다. 확장은 모든 프록시 유형을 처리하므로, CDP 경로가 문제를 일으킬 때 대체 방법이 됩니다.
네 번째 옵션: 로컬 릴레이
nodriver를 전혀 건드리지 않으려면, 자격 증명을 보유하고 127.0.0.1에서 인증 없는 엔드포인트를 제공하는 작은 로컬 릴레이를 실행하세요. nodriver는 루프백 주소를 일반 플래그로 가리키고 도전을 전혀 보지 않습니다. 이는 SOCKS5에 가장 깔끔한 경로로, Chromium은 인증된 프록시를 완전히 거부합니다 (Chromium 버그 40829748로 추적됨). 최소 릴레이, 준비된 도구, 과도한 경우를 프록시 릴레이 가이드에서 다룹니다.
SOCKS5에 대한 주의 사항
인증되지 않은 SOCKS5는 플래그를 통해 작동합니다 — --proxy-server=socks5://host:port — 그러나 인증된 SOCKS5는 작동하지 않으며, Chromium은 SOCKS5 사용자 이름/비밀번호 지원을 제공한 적이 없습니다. 실질적인 답변은 동일한 세 가지입니다: IP를 화이트리스트에 추가하거나, 자격 증명을 추가하는 로컬 릴레이를 실행하거나, 제공자의 HTTP 엔드포인트를 대신 사용하세요. 모든 QuantumProxies 플랜은 동일한 게이트웨이에서 HTTP 및 SOCKS5 프록시를 노출하므로, HTTP 엔드포인트로 전환하는 것이 종종 가장 빠른 SOCKS5 해결책입니다. 안티디텍트 브라우저 패밀리로서, 인증된 프록시 맵은 nodriver, zendriver 및 나머지를 나란히 비교합니다.

자주 묻는 질문
nodriver는 인증된 프록시를 지원하나요?
기본적으로는 아닙니다. 인증되지 않은 프록시는 browser_args=["--proxy-server=host:port"]를 통해 전달할 수 있지만, 그 플래그의 user:pass는 Chromium에 의해 제거됩니다. 인증하려면 제공자와 함께 IP를 화이트리스트에 추가하거나, CDP Fetch.AuthRequired 핸들러로 도전에 응답하거나, 프록시 인증 Chrome 확장을 생성하거나, 자격 증명을 보유하는 로컬 릴레이를 실행해야 합니다.
왜 내 nodriver 인증 핸들러가 이벤트를 받지 않나요?
거의 항상 핸들러를 등록하기 전에 Fetch 도메인을 활성화했기 때문입니다. nodriver의 내부 enable은 등록을 덮어쓰므로, 이벤트가 콜백에 도달하지 않습니다. RequestPaused 및 AuthRequired 핸들러를 먼저 추가한 다음, fetch.enable(handle_auth_requests=True)를 호출하세요. 또한 응답을 asyncio.create_task로 감싸서 기다리는 동안 루프를 차단할 수 없도록 하세요.
nodriver가 사용자 이름과 비밀번호가 있는 SOCKS5 프록시를 사용할 수 있나요?
아니요. Chromium은 인증된 SOCKS5를 지원하지 않으며 (Chromium 버그 40829748), nodriver는 그 제한을 상속받습니다. 인증되지 않은 SOCKS5는 --proxy-server=socks5://host:port를 통해 작동합니다. 인증된 SOCKS5의 경우, IP를 화이트리스트에 추가하거나, 자격 증명을 추가하는 로컬 릴레이를 실행하거나, 기본 인증을 깔끔하게 처리하는 제공자의 HTTP 엔드포인트로 전환하세요.
nodriver 또는 zendriver 중 인증된 프록시에 더 적합한 것은?
둘 다 동일한 격차와 동일한 해결책을 공유합니다, 왜냐하면 zendriver는 nodriver의 커뮤니티 포크이기 때문입니다. zendriver는 인증 문제를 공개적으로 논의하는 더 활발한 이슈 트래커를 가지고 있지만, 작동하는 방법은 동일합니다. 포크를 사용 중이라면, 포크 전용 설정은 여기의 모든 것을 반영합니다 — CDP 핸들러와 화이트리스트는 동일하게 작동합니다.
정직한 요약: nodriver는 프록시 인증을 자동으로 처리하지 않으며, 지도를 알면 괜찮습니다. IP가 안정적일 때는 화이트리스트를 사용하고, 그렇지 않을 때는 CDP 핸들러나 확장을 사용하며, SOCKS5를 위해서는 로컬 릴레이를 준비해 두세요. 위의 코드는 도전에 응답하지만, 실제로 문을 통과하게 하는 것은 깨끗한 거주지 출구입니다.