Zendriver Proxy с аутентификацией: настройка и обходные пути
Zendriver — это поддерживаемая сообществом форк-версия nodriver, которая быстрее исправляется, но имеет ту же проблему с аутентификацией прокси. Вот полная настройка прокси, что на самом деле отличается, и обходные пути, которые позволяют работать user:pass.
zendriver proxy настраивается точно так же, как и nodriver — это и хорошая новость, и подвох. zendriver (проект cdpdriver/zendriver) — это поддерживаемая сообществом форк-версия nodriver: асинхронно-ориентированная, не обнаруживаемая платформа автоматизации браузера, управляющая Chrome напрямую через DevTools Protocol, без WebDriver. Она существует, потому что единственный мейнтейнер nodriver редко принимал внешние исправления, поэтому сообщество создало форк, чтобы принимать исправления ошибок, добавлять функции и решать проблемы на GitHub. Что не было исправлено, так это аутентифицированные прокси. Это руководство охватывает полную настройку прокси, что действительно отличается от nodriver, и обходные пути, которые позволяют работать user:pass.
Установка и базовая настройка прокси
Установка — это одна строка — pip install zendriver — и API почти полностью повторяет nodriver, так что import zendriver as zd часто является единственным изменением при переносе скрипта. Неаутентифицированный прокси проходит через browser_args, и запрос выходит с IP прокси:
import zendriver as zd
async def main():
browser = await zd.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
await browser.stop()
zd.loop().run_until_complete(main())
Это работает, потому что это просто флаг Chrome. Добавьте учетные данные — --proxy-server=http://USER:PASS@host:port — и Chromium тихо отбрасывает часть USER:PASS@, прокси отвечает 407, и появляется нативный диалог входа, который zendriver не может заполнить. Это ограничение Chrome, а не ошибка zendriver, поэтому никакое обновление версии не заставит флаг принимать пароль.
Проблема аутентификации прокси zendriver
Проблема открыто отслеживается в вопросах zendriver — поток запроса функции (#10) и отдельная проблема "Proxy with auth" (#208) — что само по себе является разницей, которую стоит отметить: в nodriver тот же вопрос скрыт в обсуждении, на которое мейнтейнер ответил один раз и двинулся дальше. Один пользователь в вопросе #10 кратко резюмирует текущее состояние: у опции прокси-сервера нет способа аутентификации, поэтому они используют расширение для прокси, и это работает хорошо. Это проверенный на практике консенсус, и он указывает прямо на те же три исправления, на которые полагаются пользователи nodriver.
Исправление 1: белый список IP (самое простое)
Если ваша работа выполняется с машины со стабильным публичным IP, полностью пропустите учетные данные. Зарегистрируйте выходной IP в панели управления вашего провайдера, и шлюз аутентифицирует вас по исходному адресу — код zendriver остается простым фрагментом --proxy-server выше, без логики аутентификации. Каждый план QuantumProxies поддерживает белый список IP наряду с user:pass, что делает его рекомендацией по умолчанию, когда ваш IP фиксирован. Единственное ограничение в том, что он аутентифицирует машину, а не скрипт, поэтому временные раннеры и контейнеры за NAT нуждаются в одном из следующих двух методов.

Исправление 2: ответ на вызов через CDP
Поскольку zendriver предоставляет DevTools Protocol так же, как и nodriver, вы можете перехватить вызов аутентификации в процессе: зарегистрируйте обработчики RequestPaused и AuthRequired, затем включите домен Fetch с handle_auth_requests=True и ответьте с continue_with_auth. Два неочевидных правила идентичны nodriver — добавьте обработчики перед включением домена и отправляйте ответы с asyncio.create_task, чтобы ожидание их не заблокировало цикл:
import asyncio
import zendriver as zd
async def main():
browser = await zd.start(browser_args=["--proxy-server=gate.quantumproxies.io:PORT"])
tab = await browser.get("draft:,") # blank tab first
async def on_auth(event):
asyncio.create_task(tab.send(zd.cdp.fetch.continue_with_auth(
request_id=event.request_id,
auth_challenge_response=zd.cdp.fetch.AuthChallengeResponse(
response="ProvideCredentials", username="USER", password="PASS",
),
)))
async def on_request(event):
asyncio.create_task(tab.send(
zd.cdp.fetch.continue_request(request_id=event.request_id)))
# handlers FIRST, then enable the domain
tab.add_handler(zd.cdp.fetch.RequestPaused, on_request)
tab.add_handler(zd.cdp.fetch.AuthRequired, on_auth)
await tab.send(zd.cdp.fetch.enable(handle_auth_requests=True))
page = await browser.get("https://httpbin.org/ip")
await asyncio.sleep(3)
print(await page.get_content())
await browser.stop()
zd.loop().run_until_complete(main())
Полное руководство о том, почему порядок обработчиков имеет значение и что происходит, когда вы ошибаетесь, находится в нашем руководстве по аутентификации прокси nodriver — механика общая, поэтому нет смысла воспроизводить их дважды.
Исправление 3: расширение для аутентификации прокси и SOCKS5
Маршрут, который поддерживает вопрос #10, — это сгенерированное расширение Chrome: манифест Manifest V3 плюс воркер, который устанавливает прокси и отвечает chrome.webRequest.onAuthRequired, загруженный с --load-extension под --headless=new. Оно обрабатывает любой тип прокси, включая SOCKS5, что важно, потому что аутентифицированный SOCKS5 никогда не работает через флаг — у Chromium нет поддержки имени пользователя/пароля для SOCKS5 (ошибка Chromium 40829748). Альтернатива для SOCKS5 — это локальный релей, который хранит учетные данные и предлагает конечную точку без аутентификации на 127.0.0.1, описанную в руководстве по реле прокси. Каждый план QuantumProxies включает как HTTP, так и конечные точки SOCKS5, так что вы часто можете обойти всю проблему, используя HTTP, который обрабатывает Basic auth без проблем.
Что на самом деле отличается от nodriver
Форк не косметический. В публичных тестах, сравнивающих nodriver, zendriver, Selenium и Playwright с современными антибот-системами, семья nodriver/zendriver была самой сильной в прохождении, с zendriver немного впереди благодаря неслиянным исправлениям, которые он содержит. Практически, различия, влияющие на работу с прокси, таковы: активный трекер проблем, где проблемы классифицируются, более стабильный график выпусков, изолированные контексты браузера, которые можно запускать на сессию, и встроенные удобства, сохраненные от nodriver. Ничто из этого не закрывает проблему аутентификации — но это означает, что исправления появляются быстрее, когда они появляются, и делает zendriver более легким форком для запуска множества параллельных сессий. Для ротации и пуллинга выходов через эти параллельные контексты наши заметки о управлении пулом прокси применимы к zendriver без изменений, независимо от того, маршрутизируете ли вы через ротационные прокси или закрепляете сессии для входа.
Одно уточнение: отдельный Rust crate также назван zendriver существует на docs.rs. Он не имеет отношения к обсуждаемому здесь Python форку — если вы скрапите на Python, pip install zendriver — это то, что вам нужно.

Часто задаваемые вопросы
Как использовать прокси с zendriver?
Передайте адрес через browser_args, когда вызываете zendriver.start(): browser_args=["--proxy-server=host:port"]. Это маршрутизирует весь трафик через прокси для неаутентифицированной конечной точки. Для аутентифицированного прокси вы не можете вставить user:pass в флаг — добавьте ваш IP в белый список, используйте обработчик CDP Fetch.AuthRequired или загрузите расширение для аутентификации прокси.
Поддерживает ли zendriver аутентифицированные прокси?
Не через встроенный параметр — проблема отслеживается в вопросах #10 и #208. Chromium игнорирует учетные данные во флаге прокси, поэтому вы аутентифицируетесь другим способом: белый список IP у провайдера, обработчик CDP, который отвечает на вызов в процессе, сгенерированное расширение Chrome или локальный релей, который хранит учетные данные для вас.
В чем разница между nodriver и zendriver?
zendriver — это поддерживаемая сообществом форк-версия nodriver с той же архитектурой CDP, целями скрытности и API. Разница в поддержке: zendriver принимает вопросы и pull-запросы на GitHub, включает неслиянные исправления ошибок и выпускается более регулярно. Аутентификация прокси ведет себя одинаково в обоих — исправления в этом руководстве работают для обоих.
Может ли zendriver использовать аутентифицированный SOCKS5 прокси?
Не через флаг, потому что Chromium никогда не реализовывал аутентификацию имени пользователя/пароля для SOCKS5 (ошибка Chromium 40829748), и zendriver наследует это. Используйте расширение для аутентификации прокси, запустите локальный релей, который добавляет учетные данные, или направьте zendriver на HTTP конечную точку вашего провайдера — HTTP Basic аутентификация прокси работает надежно там, где аутентификация SOCKS5 не работает.
zendriver — это более продвинутый из двух форков для работы сегодня, но он предоставляет ту же проблему с аутентифицированным прокси, что и nodriver. Используйте белый список, когда ваш IP фиксирован, отвечайте на вызов CDP, когда это не так, и держите расширение и релей в качестве запасных вариантов. Какой бы вы ни выбрали, выходной IP выполняет основную работу — поддерживаемый форк на сгоревшем адресе дата-центра все равно будет заблокирован.