Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <div class="msg_body">
- <div class="fav-buttons">
- <a id="favs_button" href="#" title="В избранное"><i class="icon-star"></i></a><br><span id="favs_count">1</span><br>
- <a id="memories_button" href="#" title="Отслеживать"><i class="icon-eye"></i></a><br><span id="memories_count">1</span>
- </div>
- <div class="msg-text" itemprop="articleBody">
- <h1>Парсинг сайтов: как мы сделали rtfox-browser — форк undetected-chromedriver с поддержкой SOCKS5, HTTP, HTTPS</h1>
- <blockquote>
- <p><img draggable="false" class="emoji" alt="⚠️" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/26a0.png"> Статья носит познавательный и развлекательный характер. Автор не призывает к нарушению правил сервисов.</p>
- </blockquote>
- <p>Всем привет! Недавно мы столкнулись с темой парсинга. Начали искать инструменты — BeautifulSoup, Selenium, Playwright, Puppeteer. Сразу скажу: мы не конкуренты этим библиотекам, далее объясним почему.</p>
- <p>Нам нужно было обойти CloudFlare, запускать несколько процессов одновременно, и чтобы на каждый процесс был свой прокси с авторизацией.</p>
- <h2>Как мы нашли отправную точку</h2>
- <p>Нам попалась библиотека undetected-chromedriver. Библиотека перестала поддерживаться разработчиком, но функционал сохранялся. При первом запуске сразу столкнулись с ошибкой — проблема была в патчинге ChromeDriver и его скачивании. После исправления запуск удался и капча была пройдена. В дальнейшем возникли проблемы с прокси и многопроцессорностью.</p>
- <p>Тогда пришла мысль: почему бы не взять эту же библиотеку, прикрутить прокси и добавить многопроцессорность? Но чтобы это осуществить, нужно сначала понять как вообще всё работает.</p>
- <h2>Как устроена цепочка Chrome → ChromeDriver → Selenium</h2>
- <p>Прежде чем рассказывать что мы сделали — разберём архитектуру изнутри.</p>
- <h3>Звено 1 — Chrome.exe</h3>
- <p>Обычный браузер при запуске открывает WebSocket-сервер на каком-то порту и слушает команды DevTools Protocol (CDP). Через WebSocket можно отправить например:</p>
- <div class="code"><pre><code class="language-json hljs" data-highlighted="yes"><span class="hljs-punctuation">{</span>
- <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
- <span class="hljs-attr">"method"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Page.navigate"</span><span class="hljs-punctuation">,</span>
- <span class="hljs-attr">"params"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><span class="hljs-attr">"url"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"https://google.com"</span><span class="hljs-punctuation">}</span>
- <span class="hljs-punctuation">}</span>
- </code></pre>
- </div>
- <h3>Звено 2 — ChromeDriver</h3>
- <p>ChromeDriver — это отдельная программа, которая работает как переводчик между вашим кодом (Selenium) и браузером Chrome. Вы пишете на Python <span class="code"><code>driver.get("https://google.com")</code></span>, Selenium превращает это в HTTP-запрос и отправляет ChromeDriver. А ChromeDriver уже объясняет Chrome на его родном языке (DevTools Protocol) что нужно открыть страницу.</p>
- <p>ChromeDriver одновременно является:</p>
- <ul>
- <li>HTTP-сервером (слушает порт, принимает команды от Selenium)</li>
- <li>WebSocket-клиентом (подключается к Chrome, отправляет CDP-команды)</li>
- </ul>
- <h3>Звено 3 — Selenium</h3>
- <p>Selenium — это библиотека для Python которая позволяет программно управлять браузером. Selenium не управляет браузером напрямую — он отправляет команды ChromeDriver, а тот уже разбирается с Chrome.</p>
- <h3>Полная цепочка запуска</h3>
- <div class="code"><pre><code class="no-highlight">Ваш код: driver = webdriver.Chrome()
- ↓
- Selenium запускает ChromeDriver.exe как отдельный процесс
- ↓
- ChromeDriver.exe запускает Chrome.exe с флагами автоматизации
- </code></pre>
- </div>
- <p>При запуске Chrome, ChromeDriver автоматически выставляет флаги автоматизации и сообщает что браузером управляет автоматическое ПО. Библиотека undetected-chromedriver как раз с этим и разбирается — она патчит ChromeDriver.exe, убирает эти флаги и патчит сигнатуру.</p>
- <h3>Полная цепочка запроса</h3>
- <div class="code"><pre><code class="no-highlight">Ваш код: driver.get("https://google.com")
- ↓
- Selenium → ChromeDriver: HTTP POST /session/abc/url
- ↓
- ChromeDriver → Chrome: WebSocket команда Page.navigate
- ↓
- Chrome → Google: HTTP GET /
- ↓
- Google → Chrome: HTML страница
- ↓
- Chrome → ChromeDriver: WebSocket ответ (готово)
- ↓
- ChromeDriver → Selenium: HTTP 200 OK
- ↓
- Selenium: возвращает управление вашему коду
- </code></pre>
- </div>
- <h2>Что мы реализовали</h2>
- <h3>1. Автоматическое определение платформы и версии Chrome</h3>
- <p>Первым делом нам нужно было автоматически определять платформу (Windows, Linux, macOS) чтобы корректно получать версию установленного Chrome.</p>
- <p>Пример для Linux:</p>
- <div class="code"><pre><code class="language-bash hljs" data-highlighted="yes">google-chrome --version
- <span class="hljs-comment"># Google Chrome 124.0.6367.91</span>
- </code></pre>
- </div>
- <p>Из этой строки извлекается major-версия (124).</p>
- <p>Получение версии ChromeDriver:</p>
- <ul>
- <li>Для Chrome ≤ 114: обращается к старому CDN chromedriver.storage.googleapis.com</li>
- <li>Для Chrome ≥ 115: использует новый сервис chrome-for-testing, парсит JSON с актуальными версиями</li>
- </ul>
- <p>Скачивание и распаковка:</p>
- <ul>
- <li>Формирует URL для скачивания ZIP-архива</li>
- <li>Скачивает во временную папку</li>
- <li>Распаковывает архив</li>
- <li>Ищет файл chromedriver (или .exe)</li>
- <li>Перемещает его в папку проекта /drivers</li>
- </ul>
- <p><strong>Патч бинарника — что такое cdc-сигнатура?</strong></p>
- <p>В оригинальном ChromeDriver есть строка <span class="code"><code>{window.cdc_adoqpoas...}</code></span> — её используют сайты для обнаружения ботов. Патч делает следующее:</p>
- <ul>
- <li>Ищет в бинарнике паттерн <span class="code"><code>{window.cdc.*?;}</code></span></li>
- <li>Заменяет его на заглушку <span class="code"><code>{console.log("ok")}</code></span></li>
- </ul>
- <p>Благодаря этому сайты не могут определить что управление идёт через Selenium.</p>
- <h3>2. Многопроцессорность</h3>
- <p>С оригинальной библиотекой при запуске 10 процессов каждый запускал один и тот же chromedriver. Как мы уже знаем, Selenium запускает chromedriver на своём порту. Каждый новый воркер просто перезапускал chromedriver, создавал новый порт — и прошлый воркер падал.</p>
- <p>Решение простое: мы не даём воркерам взаимодействовать с одним chromedriver. У нас есть эталонная версия (пропатченная). Каждый воркер получает только свою копию и работает с ней. При завершении копия удаляется.</p>
- <p>Также реализована межпроцессорная блокировка:</p>
- <ul>
- <li>Если 100 воркеров одновременно вызовут <span class="code"><code>ensure_driver()</code></span>, они не будут скачивать драйвер 100 раз</li>
- <li>Первый процесс захватывает файловую блокировку (через fcntl на Linux/Mac или msvcrt на Windows)</li>
- <li>Остальные ждут пока первый не скачает и не пропатчит драйвер</li>
- <li>Затем все используют уже готовый файл</li>
- </ul>
- <p><span class="code"><code>worker_id</code></span> — опциональный параметр. Если не передан, UUID назначается автоматически. Передавайте явно только если нужны предсказуемые имена в логах:</p>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-comment"># с явным именем</span>
- driver = uc.Chrome(worker_id=<span class="hljs-string">"worker_1"</span>)
- <span class="hljs-comment"># UUID назначится автоматически</span>
- driver = uc.Chrome()
- </code></pre>
- </div>
- <h3>3. Прокси с авторизацией (SOCKS5, HTTP, HTTPS)</h3>
- <p>Chrome из коробки не умеет работать с SOCKS5 и авторизацией — только HTTP/HTTPS, и при этом требует заполнять данные во всплывающем окне. Вот как мы решили эту проблему.</p>
- <p>Мы запускаем локальный прокси-сервер с двумя потоками:</p>
- <ul>
- <li><strong>Поток-слушатель</strong> — принимает трафик от Chrome на localhost</li>
- <li><strong>Поток-отправитель</strong> — подключается к внешнему прокси и отправляет логин/пароль</li>
- </ul>
- <p>Chrome получает флаг <span class="code"><code>--proxy-server=127.0.0.1:56789</code></span> и шлёт туда весь трафик, думая что это обычный прокси без авторизации. А наш локальный прокси сам добавляет логин и пароль и форвардит запросы на внешний прокси-сервер.</p>
- <p>Полная картина:</p>
- <div class="code"><pre><code class="no-highlight">Chrome получает флаг --proxy-server=127.0.0.1:56789
- ↓
- Chrome думает: "Это обычный прокси без авторизации"
- ↓
- Chrome отправляет HTTP-запрос на локальный порт 56789
- ↓
- Поток-слушатель принимает запрос
- ↓
- Поток-отправитель:
- - подключается к внешнему прокси (1.2.3.4:1080)
- - отправляет логин и пароль
- - пересылает HTTP-запрос
- ↓
- Получает ответ от внешнего прокси
- ↓
- Возвращает ответ Chrome через поток-слушатель
- </code></pre>
- </div>
- <p>Поддерживаемые протоколы: <strong>SOCKS5, HTTP, HTTPS</strong>.</p>
- <p>Прокси можно передать тремя способами:</p>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-comment"># Dict style</span>
- driver = uc.Chrome(proxy={
- <span class="hljs-string">"host"</span>: <span class="hljs-string">"1.2.3.4"</span>,
- <span class="hljs-string">"port"</span>: <span class="hljs-number">1080</span>,
- <span class="hljs-string">"type"</span>: <span class="hljs-string">"socks5"</span>, <span class="hljs-comment"># socks5 | http | https</span>
- <span class="hljs-string">"user"</span>: <span class="hljs-string">"my_login"</span>,
- <span class="hljs-string">"pass"</span>: <span class="hljs-string">"my_password"</span>,
- })
- <span class="hljs-comment"># Keyword style</span>
- <span class="hljs-keyword">from</span> rtfox_browser.proxy_types <span class="hljs-keyword">import</span> ProxyType
- driver = uc.Chrome(
- proxy_host=<span class="hljs-string">"1.2.3.4"</span>,
- proxy_port=<span class="hljs-number">1080</span>,
- proxy_type=ProxyType.SOCKS5,
- proxy_user=<span class="hljs-string">"my_login"</span>,
- proxy_pass=<span class="hljs-string">"my_password"</span>,
- )
- <span class="hljs-comment"># ProxyConfig style</span>
- <span class="hljs-keyword">from</span> rtfox_browser.proxy_types <span class="hljs-keyword">import</span> ProxyConfig, ProxyType
- config = ProxyConfig.from_args(
- host=<span class="hljs-string">"1.2.3.4"</span>,
- port=<span class="hljs-number">1080</span>,
- proxy_type=ProxyType.SOCKS5,
- user=<span class="hljs-string">"my_login"</span>,
- password=<span class="hljs-string">"my_password"</span>,
- )
- driver = uc.Chrome(proxy=config)
- </code></pre>
- </div>
- <p><strong>Важная особенность:</strong> локальный туннель запускается всегда — даже если прокси не передан (прозрачный режим). Это позволяет менять прокси на лету в любой момент сессии.</p>
- <h3>4. Замена прокси на лету</h3>
- <p>Одна из ключевых фич — замена прокси без перезапуска браузера:</p>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes">driver = uc.Chrome()
- driver.get(<span class="hljs-string">"https://2ip.ru/"</span>)
- <span class="hljs-comment"># Переключаемся на новый прокси</span>
- driver.proxy_replacement(
- host=<span class="hljs-string">"1.2.3.4"</span>,
- port=<span class="hljs-number">1080</span>,
- proxy_type=ProxyType.SOCKS5,
- user=<span class="hljs-string">"my_login"</span>,
- password=<span class="hljs-string">"my_password"</span>,
- )
- driver.refresh()
- <span class="hljs-comment"># Или через dict</span>
- driver.proxy_replacement({
- <span class="hljs-string">"host"</span>: <span class="hljs-string">"1.2.3.4"</span>,
- <span class="hljs-string">"port"</span>: <span class="hljs-number">1080</span>,
- <span class="hljs-string">"type"</span>: <span class="hljs-string">"http"</span>,
- })
- <span class="hljs-comment"># Отключить прокси — прямое соединение</span>
- driver.proxy_replacement(<span class="hljs-literal">None</span>)
- </code></pre>
- </div>
- <p>По умолчанию после замены очищаются кэш и куки браузера, чтобы Chrome открыл свежие соединения через новый прокси. Передайте <span class="code"><code>clear_connections=False</code></span> чтобы пропустить этот шаг.</p>
- <h3>5. Изолированное логирование через loguru</h3>
- <p>Loguru из коробки поддерживает глобальный логер. Нам это не подходило — для прокси нужен свой изолированный логер с возможностью включать через флаг, для ChromeDriver свой, для пользователя свой.</p>
- <p>Решение — создаём новый экземпляр логера и добавляем фильтры:</p>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes">_lib_logger = Logger(
- core=Core(),
- exception=<span class="hljs-literal">None</span>,
- depth=<span class="hljs-number">0</span>,
- record=<span class="hljs-literal">False</span>,
- lazy=<span class="hljs-literal">False</span>,
- colors=<span class="hljs-literal">False</span>,
- raw=<span class="hljs-literal">False</span>,
- capture=<span class="hljs-literal">True</span>,
- patchers=[],
- extra={},
- )
- _lib_logger.add(sys.stderr, level=<span class="hljs-string">"ERROR"</span>)
- <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_logger</span>(<span class="hljs-params">debug: <span class="hljs-built_in">bool</span> = <span class="hljs-literal">False</span>, debug_proxy: <span class="hljs-built_in">bool</span> = <span class="hljs-literal">False</span></span>):
- _lib_logger.remove()
- _lib_logger.add(
- sys.stderr,
- level=<span class="hljs-string">"DEBUG"</span> <span class="hljs-keyword">if</span> debug <span class="hljs-keyword">else</span> <span class="hljs-string">"ERROR"</span>,
- <span class="hljs-built_in">format</span>=<span class="hljs-string">"<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | "</span>
- <span class="hljs-string">"<cyan>Chrome</cyan> - <level>{message}</level>"</span>,
- <span class="hljs-built_in">filter</span>=<span class="hljs-keyword">lambda</span> r: r[<span class="hljs-string">"extra"</span>].get(<span class="hljs-string">"source"</span>) != <span class="hljs-string">"proxy"</span>
- )
- _lib_logger.add(
- sys.stderr,
- level=<span class="hljs-string">"DEBUG"</span> <span class="hljs-keyword">if</span> debug_proxy <span class="hljs-keyword">else</span> <span class="hljs-string">"ERROR"</span>,
- <span class="hljs-built_in">format</span>=<span class="hljs-string">"<blue>{time:HH:mm:ss}</blue> | <level>{level: <8}</level> | "</span>
- <span class="hljs-string">"<magenta>PROXY</magenta> - <level>{message}</level>"</span>,
- <span class="hljs-built_in">filter</span>=<span class="hljs-keyword">lambda</span> r: r[<span class="hljs-string">"extra"</span>].get(<span class="hljs-string">"source"</span>) == <span class="hljs-string">"proxy"</span>
- )
- <span class="hljs-keyword">return</span> _lib_logger
- </code></pre>
- </div>
- <p>В Chrome и прокси привязываем источник:</p>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-variable language_">self</span>.logger = <span class="hljs-variable language_">self</span>.logger_str.bind(source=<span class="hljs-string">"chrome"</span>)
- </code></pre>
- </div>
- <h3>6. Модуль капчи с автозагрузкой солверов</h3>
- <p>Мы реализовали автоматическую загрузку солверов из папки <span class="code"><code>solvers/</code></span>. Это значит: есть класс с логикой прохождения капчи — просто кладёшь <span class="code"><code>.py</code></span> файл в папку и метод автоматически появляется.</p>
- <p><span class="code"><code>BaseCaptchaSolver</code></span> — базовый класс:</p>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-keyword">from</span> abc <span class="hljs-keyword">import</span> ABC, abstractmethod
- <span class="hljs-keyword">class</span> <span class="hljs-title class_">BaseCaptchaSolver</span>(<span class="hljs-title class_ inherited__">ABC</span>):
- name: <span class="hljs-built_in">str</span> = <span class="hljs-literal">None</span>
- _service = <span class="hljs-literal">None</span>
- <span class="hljs-meta"> @property</span>
- <span class="hljs-keyword">def</span> <span class="hljs-title function_">driver</span>(<span class="hljs-params">self</span>):
- <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>._service.driver
- <span class="hljs-meta"> @property</span>
- <span class="hljs-keyword">def</span> <span class="hljs-title function_">api_key</span>(<span class="hljs-params">self</span>):
- <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>._service.api_key
- <span class="hljs-meta"> @abstractmethod</span>
- <span class="hljs-keyword">def</span> <span class="hljs-title function_">solve</span>(<span class="hljs-params">self, **kwargs</span>) -> <span class="hljs-built_in">bool</span>:
- ...
- </code></pre>
- </div>
- <p>Чтобы написать свой солвер достаточно:</p>
- <ol>
- <li>Унаследоваться от <span class="code"><code>BaseCaptchaSolver</code></span></li>
- <li>Задать <span class="code"><code>name</code></span></li>
- <li>Реализовать метод <span class="code"><code>solve()</code></span></li>
- </ol>
- <p>Loader проходит по всем <span class="code"><code>.py</code></span> файлам в папке <span class="code"><code>solvers/</code></span>, находит классы-солверы и регистрирует их по имени.</p>
- <h2>Итог</h2>
- <p>Четыре основные проблемы решены:</p>
- <ul>
- <li><img draggable="false" class="emoji" alt="✅" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/2705.png"> Обход CloudFlare из коробки</li>
- <li><img draggable="false" class="emoji" alt="✅" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/2705.png"> SOCKS5 / HTTP / HTTPS прокси с авторизацией</li>
- <li><img draggable="false" class="emoji" alt="✅" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/2705.png"> Замена прокси на лету без перезапуска браузера</li>
- <li><img draggable="false" class="emoji" alt="✅" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/2705.png"> Многопроцессорность с изоляцией воркеров</li>
- </ul>
- <p>Плюс добавили изолированное логирование и модуль капчи с плагин-архитектурой.</p>
- <p>Библиотека доступна на GitLab и PyPI:</p>
- <ul>
- <li>🦊 GitLab: <a href="https://gitlab.com/rtf-labs-studio/rtfox-browser" rel="nofollow">https://gitlab.com/rtf-labs-studio/rtfox-browser</a></li>
- <li>📦 PyPI: <a href="https://pypi.org/project/rtfox-browser/" rel="nofollow">https://pypi.org/project/rtfox-browser/</a></li>
- <li>💬 Telegram: <a href="https://t.me/rtf_labs_studio" rel="nofollow">https://t.me/rtf_labs_studio</a></li>
- <li>🎥 YouTube: <a href="https://www.youtube.com/@RTF_Labs_Studio" rel="nofollow">https://www.youtube.com/@RTF_Labs_Studio</a></li>
- </ul>
- <h2>Установка и использование</h2>
- <h3>Установка</h3>
- <div class="code"><pre><code class="language-bash hljs" data-highlighted="yes">pip install rtfox-browser
- </code></pre>
- </div>
- <p>Требования: Python >= 3.9</p>
- <h3>Базовый запуск</h3>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-keyword">import</span> rtfox_browser <span class="hljs-keyword">as</span> uc
- driver = uc.Chrome()
- driver.get(<span class="hljs-string">"https://example.com"</span>)
- driver.quit()
- </code></pre>
- </div>
- <h3>Запуск с прокси</h3>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-keyword">import</span> rtfox_browser <span class="hljs-keyword">as</span> uc
- driver = uc.Chrome(proxy={
- <span class="hljs-string">"host"</span>: <span class="hljs-string">"1.2.3.4"</span>,
- <span class="hljs-string">"port"</span>: <span class="hljs-number">1080</span>,
- <span class="hljs-string">"type"</span>: <span class="hljs-string">"socks5"</span>, <span class="hljs-comment"># socks5 | http | https</span>
- <span class="hljs-string">"user"</span>: <span class="hljs-string">"my_login"</span>,
- <span class="hljs-string">"pass"</span>: <span class="hljs-string">"my_password"</span>,
- })
- driver.get(<span class="hljs-string">"https://example.com"</span>)
- driver.quit()
- </code></pre>
- </div>
- <h3>Запуск нескольких процессов</h3>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-keyword">from</span> multiprocessing <span class="hljs-keyword">import</span> Pool
- <span class="hljs-keyword">import</span> rtfox_browser <span class="hljs-keyword">as</span> uc
- <span class="hljs-keyword">def</span> <span class="hljs-title function_">run_worker</span>(<span class="hljs-params">worker_id</span>):
- driver = uc.Chrome(
- worker_id=worker_id,
- proxy={
- <span class="hljs-string">"host"</span>: <span class="hljs-string">"1.2.3.4"</span>,
- <span class="hljs-string">"port"</span>: <span class="hljs-number">1080</span>,
- <span class="hljs-string">"type"</span>: <span class="hljs-string">"socks5"</span>,
- <span class="hljs-string">"user"</span>: <span class="hljs-string">"my_login"</span>,
- <span class="hljs-string">"pass"</span>: <span class="hljs-string">"my_password"</span>,
- }
- )
- driver.get(<span class="hljs-string">"https://example.com"</span>)
- driver.quit()
- <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
- <span class="hljs-keyword">with</span> Pool(<span class="hljs-number">4</span>) <span class="hljs-keyword">as</span> pool:
- pool.<span class="hljs-built_in">map</span>(run_worker, [<span class="hljs-string">"w1"</span>, <span class="hljs-string">"w2"</span>, <span class="hljs-string">"w3"</span>, <span class="hljs-string">"w4"</span>])
- </code></pre>
- </div>
- <h3>Замена прокси на лету</h3>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-keyword">import</span> rtfox_browser <span class="hljs-keyword">as</span> uc
- <span class="hljs-keyword">from</span> rtfox_browser.proxy_types <span class="hljs-keyword">import</span> ProxyType
- driver = uc.Chrome()
- driver.get(<span class="hljs-string">"https://2ip.ru/"</span>)
- driver.proxy_replacement(
- host=<span class="hljs-string">"1.2.3.4"</span>,
- port=<span class="hljs-number">1080</span>,
- proxy_type=ProxyType.SOCKS5,
- user=<span class="hljs-string">"my_login"</span>,
- password=<span class="hljs-string">"my_password"</span>,
- )
- driver.refresh()
- <span class="hljs-comment"># Вернуться к прямому соединению</span>
- driver.proxy_replacement(<span class="hljs-literal">None</span>)
- </code></pre>
- </div>
- <h3>Решение капчи</h3>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-keyword">import</span> rtfox_browser <span class="hljs-keyword">as</span> uc
- <span class="hljs-keyword">from</span> rtfox_browser.captcha <span class="hljs-keyword">import</span> CaptchaService
- driver = uc.Chrome()
- driver.get(<span class="hljs-string">"https://example.com"</span>)
- captcha = CaptchaService(api_key=<span class="hljs-string">"YOUR_2CAPTCHA_KEY"</span>, driver=driver)
- <span class="hljs-built_in">print</span>(captcha.available()) <span class="hljs-comment"># ['ebay_hcaptcha', 'aws_image']</span>
- captcha.ebay_hcaptcha()
- </code></pre>
- </div>
- <h3>Обработка ошибок прокси</h3>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-keyword">from</span> rtfox_browser.exceptions <span class="hljs-keyword">import</span> (
- ProxyError,
- ProxyConnectionError,
- ProxyAuthError,
- ProxyTimeoutError,
- ProxyInvalidAddressError,
- ProxyConfigError,
- )
- <span class="hljs-keyword">try</span>:
- driver = uc.Chrome(proxy={...})
- <span class="hljs-keyword">except</span> ProxyConfigError:
- <span class="hljs-built_in">print</span>(<span class="hljs-string">"Invalid or incomplete proxy config"</span>)
- <span class="hljs-keyword">except</span> ProxyInvalidAddressError:
- <span class="hljs-built_in">print</span>(<span class="hljs-string">"Malformed host or port"</span>)
- <span class="hljs-keyword">except</span> ProxyAuthError:
- <span class="hljs-built_in">print</span>(<span class="hljs-string">"Wrong credentials"</span>)
- <span class="hljs-keyword">except</span> ProxyTimeoutError:
- <span class="hljs-built_in">print</span>(<span class="hljs-string">"Proxy not responding"</span>)
- <span class="hljs-keyword">except</span> ProxyConnectionError:
- <span class="hljs-built_in">print</span>(<span class="hljs-string">"Could not connect to proxy"</span>)
- <span class="hljs-keyword">except</span> ProxyError:
- <span class="hljs-built_in">print</span>(<span class="hljs-string">"General proxy failure"</span>)
- </code></pre>
- </div>
- <h3>Включение отладочных логов</h3>
- <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-keyword">import</span> rtfox_browser <span class="hljs-keyword">as</span> uc
- <span class="hljs-comment"># Логи ChromeDriver</span>
- driver = uc.Chrome(log_debug=<span class="hljs-literal">True</span>)
- <span class="hljs-comment"># Логи прокси</span>
- driver = uc.Chrome(log_debug_proxy=<span class="hljs-literal">True</span>)
- <span class="hljs-comment"># Все логи</span>
- driver = uc.Chrome(log_debug=<span class="hljs-literal">True</span>, log_debug_proxy=<span class="hljs-literal">True</span>)
- </code></pre>
- </div>
- </div>
- <footer>
- <div class="userpic"><img class="photo" src="https://secure.gravatar.com/avatar/be7938cdd7aa975f9b414bf31689eeeb?s=150&r=g&d=mm&f=y" alt="" height="150" width="150"></div><div class="sign">
- <a rel="author" itemprop="creator" href="/people/Dark_bear/profile">Dark_bear</a> <span class="stars"></span><br>
- <time data-format="default" datetime="2026-05-31T21:31:50.544016+03:00" itemprop="dateCreated">31.05.2026 18:31:50 +00:00</time><span class="sign_more">
- </span>
- </div>
- </footer>
- <div class="reactions ">
- <form class="reactions-form" action="/reactions" method="POST">
- <input name="csrf" value="DHM1BjXkkMi1iZFZWb8C5g==" type="hidden">
- <input name="topic" value="18307226" type="hidden">
- <button name="reaction" value="🔥-true" class="reaction " title="Реакция "огонь": recei" disabled="">
- 🔥 <span class="reaction-count">1</span>
- </button>
- <button name="reaction" value="🚮-false" class="reaction btn-primary" title="Реакция "не нужно!": mittorn" disabled="">
- 🚮 <span class="reaction-count">1</span>
- </button>
- <a class="reaction reaction-show-list" href="/reactions?topic=18307226">?</a>
- </form>
- </div>
- </div>
Advertisement
Add Comment
Please, Sign In to add comment