Nodriver Proxy Authentication: Trzy skuteczne rozwiązania
Najwyższy wynik dla nodriver proxy authentication to dyskusja na GitHubie, a nie przewodnik. nodriver nie obsługuje natywnie user:pass — oto trzy skuteczne rozwiązania i jednolinijkowy skrót, który większość osób pomija.
Wyszukaj nodriver proxy authentication i w pierwszej dziesiątce wyników znajdziesz dyskusję na GitHubie, repozytorium demo, kilka wątków na Stack Overflow dotyczących innej biblioteki i jeden post na Reddicie — brak rzeczywistego przewodnika. Powód jest prosty: nodriver, asynchroniczny następca CDP dla undetected-chromedriver (ten projekt ma 12,8 tys. gwiazdek na GitHubie i 1,3 tys. forków), nie ma natywnego sposobu na przekazanie user:pass do proxy. Chrome ignoruje poświadczenia osadzone w flagach wiersza poleceń, a nodriver tego nie ukrywa. Ten przewodnik to strona, którą powinna była stać się ta dyskusja: co działa, co nie, i trzy rozwiązania, które uruchamiają uwierzytelnione proxy.
Zwykłe proxy działa; uwierzytelnione proxy nie działa
Nieuwerzytelnione proxy to jednolinijkowiec. Przekaż adres przez browser_args i każde żądanie wychodzi z IP proxy:
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())
Teraz dodaj poświadczenia — --proxy-server=http://USER:PASS@host:port — i to się psuje. Chromium usuwa segment USER:PASS@, ponieważ format flagi nie ma miejsca na poświadczenia, a następnie proxy odpowiada 407 Proxy Authentication Required, a Chrome wyświetla natywny dialog logowania, który istnieje poza DOM. nodriver nie może go zobaczyć ani wypełnić. Ten 407 to ta sama ściana opisana w naszym przewodniku naprawy błędów 407: to proxy cię odrzuca, nie przeglądarka. Więc każde rzeczywiste rozwiązanie musi odpowiedzieć na wyzwanie w inny sposób.
Rozwiązanie 1: Biała lista IP — brak poświadczeń, brak dialogu
To jest skrót, o którym wątków na GitHubie nigdy nie wspominają, a jest to najprostsze rozwiązanie. Jeśli twój scraper działa z maszyny z stabilnym publicznym IP, zarejestruj to IP w panelu dostawcy i całkowicie zrezygnuj z poświadczeń — brama uwierzytelnia cię na podstawie adresu źródłowego. Kod nodriver pozostaje zwykłym fragmentem --proxy-server powyżej, bez żadnego kodu uwierzytelniającego. Każdy plan QuantumProxies obsługuje białą listę IP obok user:pass na swoich proxy rezydencjalnych, więc jest to zalecana ścieżka, gdy twój egress IP jest stały. Jego jedynym ograniczeniem jest topologia: uwierzytelnia maszynę, a nie skrypt, więc efemeryczne chmury, kontenery za NAT i skrzynki CI z zmieniającymi się IP potrzebują jednego z dwóch kolejnych rozwiązań.

Rozwiązanie 2: odpowiedz na wyzwanie za pomocą handlera CDP Fetch
nodriver komunikuje się bezpośrednio z Chrome DevTools Protocol, więc możesz przechwycić wyzwanie uwierzytelniające w procesie — nie potrzebujesz pliku rozszerzenia. Włącz domenę Fetch z handle_auth_requests=True, a następnie odpowiedz na każde zdarzenie AuthRequired za pomocą continue_with_auth. Dwa szczegóły, oba z odpowiedzi w dyskusji #1798, decydują o różnicy między działaniem a zablokowaniem:
- Zarejestruj handlery przed włączeniem domeny. wewnętrzne wywołanie
enablenodriver nadpisuje twoją rejestrację handlerów, więc jeśli dodasz je później, żadne zdarzenia nigdy się nie uruchomią — to najczęstszy powód, dla którego ludzie zgłaszają 'nic się nie dzieje'. - Wyślij odpowiedzi bez oczekiwania. Oczekiwanie na odpowiedź wewnątrz handlera blokuje pętlę zdarzeń i blokuje całą przeglądarkę. Owiń każde wysłanie w
asyncio.create_task, aby działało bez blokowania.
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()
Jedno zastrzeżenie pojawiło się w tym samym wątku: użytkownik odkrył, że to działało na zwykłych stronach HTTP, ale zawiodło na HTTPS, a winowajcą było niskiej jakości proxy, a nie kod — zmiana na lepszy exit to naprawiła. To jest powracająca lekcja z ukrytego scrapingu: handler odpowiada na wyzwanie, ale reputacja IP decyduje, czy strona cię wpuszcza.
Rozwiązanie 3: wygenerowane rozszerzenie Chrome
Inny wzorzec społecznościowy buduje małe rozszerzenie Chrome przy starcie, które zarówno ustawia proxy, jak i odpowiada na wyzwanie poświadczeń przez chrome.webRequest.onAuthRequired — ten sam trik, który działa w Selenium i Puppeteer. Piszesz mały manifest oraz pracownika w tle do tymczasowego katalogu i ładujesz go przez --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())
Pełny manifest i pracownik są identyczne z plikami Manifest V3 w naszym przewodniku uwierzytelniania proxy w Selenium — skopiuj je dosłownie, zmienia się tylko wywołanie uruchomienia. Dwa haczyki powtarzają się wszędzie: rozszerzenia ładują się tylko pod --headless=new (zwykłe --headless zawodzi), a niepakowany katalog jest bardziej niezawodny w różnych wersjach Chrome niż spakowany zip. Rozszerzenie obsługuje każdy typ proxy, co czyni je rezerwowym rozwiązaniem, gdy ścieżka CDP cię zawodzi.
Czwarta opcja: lokalny przekaźnik
Jeśli wolisz nie dotykać nodriver w ogóle, uruchom mały lokalny przekaźnik, który przechowuje poświadczenia i prezentuje punkt końcowy bez uwierzytelnienia na 127.0.0.1. nodriver wtedy wskazuje na adres loopback z prostą flagą i nigdy nie widzi wyzwania. To najczystsza ścieżka dla SOCKS5, gdzie Chromium całkowicie odmawia uwierzytelnionych proxy (śledzone jako błąd Chromium 40829748). Opisujemy minimalny przekaźnik, gotowe narzędzia i kiedy jest to przesada w przewodniku po narzędziach proxy relay.
Uwaga na temat SOCKS5
Nieuwerzytelniony SOCKS5 działa przez flagę — --proxy-server=socks5://host:port — ale uwierzytelniony SOCKS5 nie działa, i żaden handler CDP cię nie uratuje, ponieważ Chromium nigdy nie dostarczyło wsparcia dla SOCKS5 username/password. Praktyczne odpowiedzi to te same trzy: biała lista IP, uruchomienie przekaźnika lub użycie punktu końcowego HTTP dostawcy zamiast tego. Każdy plan QuantumProxies udostępnia zarówno HTTP, jak i SOCKS5 proxies na tej samej bramie, więc przełączenie na punkt końcowy HTTP jest często najszybszym rozwiązaniem dla SOCKS5. Dla przeglądarek anty-detekcyjnych jako rodziny, mapa uwierzytelnionych proxy porównuje nodriver, zendriver i resztę obok siebie.

Najczęściej zadawane pytania
Czy nodriver obsługuje uwierzytelnione proxy?
Nie natywnie. Możesz przekazać nieuwierzytelnione proxy przez browser_args=["--proxy-server=host:port"], ale user:pass w tej fladze jest usuwane przez Chromium. Aby się uwierzytelnić, musisz albo dodać swój IP do białej listy u dostawcy, odpowiedzieć na wyzwanie za pomocą handlera CDP Fetch.AuthRequired, wygenerować rozszerzenie proxy-auth Chrome, albo uruchomić lokalny przekaźnik, który przechowuje poświadczenia.
Dlaczego mój handler auth nodriver nie otrzymuje zdarzeń?
Prawie zawsze dlatego, że włączyłeś domenę Fetch przed zarejestrowaniem handlerów. wewnętrzne enable nodriver nadpisuje rejestrację, więc zdarzenia nigdy nie docierają do twojego callbacku. Dodaj handlery RequestPaused i AuthRequired najpierw, a następnie wywołaj fetch.enable(handle_auth_requests=True). Owiń również swoje odpowiedzi w asyncio.create_task, aby oczekiwanie na nie nie mogło blokować pętli.
Czy nodriver może używać proxy SOCKS5 z nazwą użytkownika i hasłem?
Nie. Chromium nie obsługuje uwierzytelnionego SOCKS5 (błąd Chromium 40829748), a nodriver dziedziczy to ograniczenie. Nieuwerzytelniony SOCKS5 działa przez --proxy-server=socks5://host:port. Dla uwierzytelnionego SOCKS5, dodaj swój IP do białej listy, uruchom lokalny przekaźnik, który dodaje poświadczenia, lub przełącz się na punkt końcowy HTTP dostawcy, który obsługuje Basic auth bez problemu.
nodriver czy zendriver dla uwierzytelnionych proxy?
Oba mają tę samą lukę i te same rozwiązania, ponieważ zendriver to społecznościowy fork nodriver. zendriver ma bardziej aktywny tracker problemów, gdzie pytanie o auth jest otwarcie dyskutowane, ale działające metody są identyczne. Jeśli jesteś na forku, specyficzne ustawienia forka odzwierciedlają wszystko tutaj — handler CDP i biała lista działają tak samo.
Szczere podsumowanie: nodriver nie zrobi proxy auth za ciebie, i to jest w porządku, gdy znasz mapę. Biała lista, gdy twój IP jest stabilny, sięgnij po handler CDP lub rozszerzenie, gdy nie jest, i trzymaj przekaźnik w zanadrzu dla SOCKS5. Kod powyżej odpowiada na wyzwanie — ale czysty rezydencjalny exit to, co faktycznie cię przepuszcza.