Мы устали от сломанного chromedriver и написали свой — с SOCKS5, мультипроцессингом и капчей

Расскажу как мы дошли до того, чтобы форкнуть популярную библиотеку, и что из этого вышло.

С чего всё началось

Нам понадобился парсинг. Казалось бы — делов-то, берёшь Selenium и поехал. Но реальность оказалась злее: CloudFlare блокировал нас в секунды, SOCKS5 прокси с авторизацией Chrome вообще не умел нормально готовить, а при запуске нескольких процессов они просто убивали друг друга.

Мы нашли undetected-chromedriver — библиотека обходила детектирование ботов и нас это устраивало. Но разработчик её забросил, и она была сырой именно в тех местах, которые нам были нужны.

Тогда решили: форкнем и допилим сами.

Что мы добавили

SOCKS5 с авторизацией

Chrome из коробки не умеет работать с SOCKS5-прокси, которые требуют логин и пароль. Мы решили это хитро: запускаем локальный прокси-сервер прямо внутри библиотеки. Chrome думает, что шлёт трафик на localhost без авторизации — а наш прокси уже сам добавляет credentials и форвардит всё куда надо.

driver = uc.Chrome(proxy={ "host": "1.2.3.4", "port": 1080, "user": "my_login", "pass": "my_password" })

Мультипроцессинг без боли

Оригинальная библиотека при запуске нескольких воркеров была как коммуналка с одним туалетом — все ломились в одну дверь и мешали друг другу. Каждый новый процесс перезапускал chromedriver, и прошлые воркеры падали.

Мы сделали так: есть одна эталонная (пропатченная) копия драйвера, каждый воркер получает свою изолированную копию и работает только с ней. При завершении копия удаляется. Плюс межпроцессорная блокировка — 100 воркеров не будут скачивать драйвер 100 раз.

from multiprocessing import Pool import rtfox_browser as uc def run_worker(worker_id): driver = uc.Chrome(worker_id=worker_id, proxy={...}) driver.get("https://example.com") driver.quit() with Pool(4) as pool: pool.map(run_worker, ["w1", "w2", "w3", "w4"])

Модуль капчи — просто кидаешь файл в папку

Хотели сделать систему, куда легко добавлять новые солверы без правки самой библиотеки. В итоге: пишешь класс, кладёшь .py файл в папку solvers/ — и метод автоматически появляется в CaptchaService.

captcha = CaptchaService(api_key="YOUR_KEY", driver=driver) print(captcha.available()) # ['ebay_hcaptcha', 'aws_image'] captcha.ebay_hcaptcha()

Итого

Три проблемы — три решения. Библиотека называется rtfox-browser, доступна на PyPI:

pip install rtfox-browser

Если занимаетесь парсингом и сталкивались с теми же болями — попробуйте, будем рады фидбеку.

Начать дискуссию