Guest User

удалённая слопья с ЛОРа

a guest
Jun 4th, 2026
157
0
215 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 32.02 KB | Software | 0 0
  1. <div class="msg_body">
  2.     <div class="fav-buttons">
  3.         <a id="favs_button" href="#" title="В избранное"><i class="icon-star"></i></a><br><span id="favs_count">1</span><br>
  4.         <a id="memories_button" href="#" title="Отслеживать"><i class="icon-eye"></i></a><br><span id="memories_count">1</span>
  5.       </div>
  6.     <div class="msg-text" itemprop="articleBody">
  7.       <h1>Парсинг сайтов: как мы сделали rtfox-browser — форк undetected-chromedriver с поддержкой SOCKS5, HTTP, HTTPS</h1>
  8. <blockquote>
  9. <p><img draggable="false" class="emoji" alt="⚠️" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/26a0.png"> Статья носит познавательный и развлекательный характер. Автор не призывает к нарушению правил сервисов.</p>
  10. </blockquote>
  11. <p>Всем привет! Недавно мы столкнулись с темой парсинга. Начали искать инструменты — BeautifulSoup, Selenium, Playwright, Puppeteer. Сразу скажу: мы не конкуренты этим библиотекам, далее объясним почему.</p>
  12. <p>Нам нужно было обойти CloudFlare, запускать несколько процессов одновременно, и чтобы на каждый процесс был свой прокси с авторизацией.</p>
  13. <h2>Как мы нашли отправную точку</h2>
  14. <p>Нам попалась библиотека undetected-chromedriver. Библиотека перестала поддерживаться разработчиком, но функционал сохранялся. При первом запуске сразу столкнулись с ошибкой — проблема была в патчинге ChromeDriver и его скачивании. После исправления запуск удался и капча была пройдена. В дальнейшем возникли проблемы с прокси и многопроцессорностью.</p>
  15. <p>Тогда пришла мысль: почему бы не взять эту же библиотеку, прикрутить прокси и добавить многопроцессорность? Но чтобы это осуществить, нужно сначала понять как вообще всё работает.</p>
  16. <h2>Как устроена цепочка Chrome → ChromeDriver → Selenium</h2>
  17. <p>Прежде чем рассказывать что мы сделали — разберём архитектуру изнутри.</p>
  18. <h3>Звено 1 — Chrome.exe</h3>
  19. <p>Обычный браузер при запуске открывает WebSocket-сервер на каком-то порту и слушает команды DevTools Protocol (CDP). Через WebSocket можно отправить например:</p>
  20. <div class="code"><pre><code class="language-json hljs" data-highlighted="yes"><span class="hljs-punctuation">{</span>
  21.   <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
  22.   <span class="hljs-attr">"method"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Page.navigate"</span><span class="hljs-punctuation">,</span>
  23.   <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>
  24. <span class="hljs-punctuation">}</span>
  25. </code></pre>
  26. </div>
  27. <h3>Звено 2 — ChromeDriver</h3>
  28. <p>ChromeDriver — это отдельная программа, которая работает как переводчик между вашим кодом (Selenium) и браузером Chrome. Вы пишете на Python <span class="code"><code>driver.get("https://google.com")</code></span>, Selenium превращает это в HTTP-запрос и отправляет ChromeDriver. А ChromeDriver уже объясняет Chrome на его родном языке (DevTools Protocol) что нужно открыть страницу.</p>
  29. <p>ChromeDriver одновременно является:</p>
  30. <ul>
  31. <li>HTTP-сервером (слушает порт, принимает команды от Selenium)</li>
  32. <li>WebSocket-клиентом (подключается к Chrome, отправляет CDP-команды)</li>
  33. </ul>
  34. <h3>Звено 3 — Selenium</h3>
  35. <p>Selenium — это библиотека для Python которая позволяет программно управлять браузером. Selenium не управляет браузером напрямую — он отправляет команды ChromeDriver, а тот уже разбирается с Chrome.</p>
  36. <h3>Полная цепочка запуска</h3>
  37. <div class="code"><pre><code class="no-highlight">Ваш код: driver = webdriver.Chrome()
  38.          ↓
  39. Selenium запускает ChromeDriver.exe как отдельный процесс
  40.          ↓
  41. ChromeDriver.exe запускает Chrome.exe с флагами автоматизации
  42. </code></pre>
  43. </div>
  44. <p>При запуске Chrome, ChromeDriver автоматически выставляет флаги автоматизации и сообщает что браузером управляет автоматическое ПО. Библиотека undetected-chromedriver как раз с этим и разбирается — она патчит ChromeDriver.exe, убирает эти флаги и патчит сигнатуру.</p>
  45. <h3>Полная цепочка запроса</h3>
  46. <div class="code"><pre><code class="no-highlight">Ваш код: driver.get("https://google.com")
  47.          ↓
  48. Selenium → ChromeDriver: HTTP POST /session/abc/url
  49.          ↓
  50. ChromeDriver → Chrome: WebSocket команда Page.navigate
  51.          ↓
  52. Chrome → Google: HTTP GET /
  53.          ↓
  54. Google → Chrome: HTML страница
  55.          ↓
  56. Chrome → ChromeDriver: WebSocket ответ (готово)
  57.          ↓
  58. ChromeDriver → Selenium: HTTP 200 OK
  59.          ↓
  60. Selenium: возвращает управление вашему коду
  61. </code></pre>
  62. </div>
  63. <h2>Что мы реализовали</h2>
  64. <h3>1. Автоматическое определение платформы и версии Chrome</h3>
  65. <p>Первым делом нам нужно было автоматически определять платформу (Windows, Linux, macOS) чтобы корректно получать версию установленного Chrome.</p>
  66. <p>Пример для Linux:</p>
  67. <div class="code"><pre><code class="language-bash hljs" data-highlighted="yes">google-chrome --version
  68. <span class="hljs-comment"># Google Chrome 124.0.6367.91</span>
  69. </code></pre>
  70. </div>
  71. <p>Из этой строки извлекается major-версия (124).</p>
  72. <p>Получение версии ChromeDriver:</p>
  73. <ul>
  74. <li>Для Chrome ≤ 114: обращается к старому CDN chromedriver.storage.googleapis.com</li>
  75. <li>Для Chrome ≥ 115: использует новый сервис chrome-for-testing, парсит JSON с актуальными версиями</li>
  76. </ul>
  77. <p>Скачивание и распаковка:</p>
  78. <ul>
  79. <li>Формирует URL для скачивания ZIP-архива</li>
  80. <li>Скачивает во временную папку</li>
  81. <li>Распаковывает архив</li>
  82. <li>Ищет файл chromedriver (или .exe)</li>
  83. <li>Перемещает его в папку проекта /drivers</li>
  84. </ul>
  85. <p><strong>Патч бинарника — что такое cdc-сигнатура?</strong></p>
  86. <p>В оригинальном ChromeDriver есть строка <span class="code"><code>{window.cdc_adoqpoas...}</code></span> — её используют сайты для обнаружения ботов. Патч делает следующее:</p>
  87. <ul>
  88. <li>Ищет в бинарнике паттерн <span class="code"><code>{window.cdc.*?;}</code></span></li>
  89. <li>Заменяет его на заглушку <span class="code"><code>{console.log("ok")}</code></span></li>
  90. </ul>
  91. <p>Благодаря этому сайты не могут определить что управление идёт через Selenium.</p>
  92. <h3>2. Многопроцессорность</h3>
  93. <p>С оригинальной библиотекой при запуске 10 процессов каждый запускал один и тот же chromedriver. Как мы уже знаем, Selenium запускает chromedriver на своём порту. Каждый новый воркер просто перезапускал chromedriver, создавал новый порт — и прошлый воркер падал.</p>
  94. <p>Решение простое: мы не даём воркерам взаимодействовать с одним chromedriver. У нас есть эталонная версия (пропатченная). Каждый воркер получает только свою копию и работает с ней. При завершении копия удаляется.</p>
  95. <p>Также реализована межпроцессорная блокировка:</p>
  96. <ul>
  97. <li>Если 100 воркеров одновременно вызовут <span class="code"><code>ensure_driver()</code></span>, они не будут скачивать драйвер 100 раз</li>
  98. <li>Первый процесс захватывает файловую блокировку (через fcntl на Linux/Mac или msvcrt на Windows)</li>
  99. <li>Остальные ждут пока первый не скачает и не пропатчит драйвер</li>
  100. <li>Затем все используют уже готовый файл</li>
  101. </ul>
  102. <p><span class="code"><code>worker_id</code></span> — опциональный параметр. Если не передан, UUID назначается автоматически. Передавайте явно только если нужны предсказуемые имена в логах:</p>
  103. <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-comment"># с явным именем</span>
  104. driver = uc.Chrome(worker_id=<span class="hljs-string">"worker_1"</span>)
  105.  
  106. <span class="hljs-comment"># UUID назначится автоматически</span>
  107. driver = uc.Chrome()
  108. </code></pre>
  109. </div>
  110. <h3>3. Прокси с авторизацией (SOCKS5, HTTP, HTTPS)</h3>
  111. <p>Chrome из коробки не умеет работать с SOCKS5 и авторизацией — только HTTP/HTTPS, и при этом требует заполнять данные во всплывающем окне. Вот как мы решили эту проблему.</p>
  112. <p>Мы запускаем локальный прокси-сервер с двумя потоками:</p>
  113. <ul>
  114. <li><strong>Поток-слушатель</strong> — принимает трафик от Chrome на localhost</li>
  115. <li><strong>Поток-отправитель</strong> — подключается к внешнему прокси и отправляет логин/пароль</li>
  116. </ul>
  117. <p>Chrome получает флаг <span class="code"><code>--proxy-server=127.0.0.1:56789</code></span> и шлёт туда весь трафик, думая что это обычный прокси без авторизации. А наш локальный прокси сам добавляет логин и пароль и форвардит запросы на внешний прокси-сервер.</p>
  118. <p>Полная картина:</p>
  119. <div class="code"><pre><code class="no-highlight">Chrome получает флаг --proxy-server=127.0.0.1:56789
  120.          ↓
  121. Chrome думает: "Это обычный прокси без авторизации"
  122.          ↓
  123. Chrome отправляет HTTP-запрос на локальный порт 56789
  124.          ↓
  125. Поток-слушатель принимает запрос
  126.          ↓
  127. Поток-отправитель:
  128.   - подключается к внешнему прокси (1.2.3.4:1080)
  129.   - отправляет логин и пароль
  130.   - пересылает HTTP-запрос
  131.          ↓
  132. Получает ответ от внешнего прокси
  133.          ↓
  134. Возвращает ответ Chrome через поток-слушатель
  135. </code></pre>
  136. </div>
  137. <p>Поддерживаемые протоколы: <strong>SOCKS5, HTTP, HTTPS</strong>.</p>
  138. <p>Прокси можно передать тремя способами:</p>
  139. <div class="code"><pre><code class="language-python hljs" data-highlighted="yes"><span class="hljs-comment"># Dict style</span>
  140. driver = uc.Chrome(proxy={
  141.     <span class="hljs-string">"host"</span>: <span class="hljs-string">"1.2.3.4"</span>,
  142.     <span class="hljs-string">"port"</span>: <span class="hljs-number">1080</span>,
  143.     <span class="hljs-string">"type"</span>: <span class="hljs-string">"socks5"</span>,   <span class="hljs-comment"># socks5 | http | https</span>
  144.     <span class="hljs-string">"user"</span>: <span class="hljs-string">"my_login"</span>,
  145.     <span class="hljs-string">"pass"</span>: <span class="hljs-string">"my_password"</span>,
  146. })
  147.  
  148. <span class="hljs-comment"># Keyword style</span>
  149. <span class="hljs-keyword">from</span> rtfox_browser.proxy_types <span class="hljs-keyword">import</span> ProxyType
  150.  
  151. driver = uc.Chrome(
  152.     proxy_host=<span class="hljs-string">"1.2.3.4"</span>,
  153.     proxy_port=<span class="hljs-number">1080</span>,
  154.     proxy_type=ProxyType.SOCKS5,
  155.     proxy_user=<span class="hljs-string">"my_login"</span>,
  156.     proxy_pass=<span class="hljs-string">"my_password"</span>,
  157. )
  158.  
  159. <span class="hljs-comment"># ProxyConfig style</span>
  160. <span class="hljs-keyword">from</span> rtfox_browser.proxy_types <span class="hljs-keyword">import</span> ProxyConfig, ProxyType
  161.  
  162. config = ProxyConfig.from_args(
  163.     host=<span class="hljs-string">"1.2.3.4"</span>,
  164.     port=<span class="hljs-number">1080</span>,
  165.     proxy_type=ProxyType.SOCKS5,
  166.     user=<span class="hljs-string">"my_login"</span>,
  167.     password=<span class="hljs-string">"my_password"</span>,
  168. )
  169. driver = uc.Chrome(proxy=config)
  170. </code></pre>
  171. </div>
  172. <p><strong>Важная особенность:</strong> локальный туннель запускается всегда — даже если прокси не передан (прозрачный режим). Это позволяет менять прокси на лету в любой момент сессии.</p>
  173. <h3>4. Замена прокси на лету</h3>
  174. <p>Одна из ключевых фич — замена прокси без перезапуска браузера:</p>
  175. <div class="code"><pre><code class="language-python hljs" data-highlighted="yes">driver = uc.Chrome()
  176. driver.get(<span class="hljs-string">"https://2ip.ru/"</span>)
  177.  
  178. <span class="hljs-comment"># Переключаемся на новый прокси</span>
  179. driver.proxy_replacement(
  180.     host=<span class="hljs-string">"1.2.3.4"</span>,
  181.     port=<span class="hljs-number">1080</span>,
  182.     proxy_type=ProxyType.SOCKS5,
  183.     user=<span class="hljs-string">"my_login"</span>,
  184.     password=<span class="hljs-string">"my_password"</span>,
  185. )
  186. driver.refresh()
  187.  
  188. <span class="hljs-comment"># Или через dict</span>
  189. driver.proxy_replacement({
  190.     <span class="hljs-string">"host"</span>: <span class="hljs-string">"1.2.3.4"</span>,
  191.     <span class="hljs-string">"port"</span>: <span class="hljs-number">1080</span>,
  192.     <span class="hljs-string">"type"</span>: <span class="hljs-string">"http"</span>,
  193. })
  194.  
  195. <span class="hljs-comment"># Отключить прокси — прямое соединение</span>
  196. driver.proxy_replacement(<span class="hljs-literal">None</span>)
  197. </code></pre>
  198. </div>
  199. <p>По умолчанию после замены очищаются кэш и куки браузера, чтобы Chrome открыл свежие соединения через новый прокси. Передайте <span class="code"><code>clear_connections=False</code></span> чтобы пропустить этот шаг.</p>
  200. <h3>5. Изолированное логирование через loguru</h3>
  201. <p>Loguru из коробки поддерживает глобальный логер. Нам это не подходило — для прокси нужен свой изолированный логер с возможностью включать через флаг, для ChromeDriver свой, для пользователя свой.</p>
  202. <p>Решение — создаём новый экземпляр логера и добавляем фильтры:</p>
  203. <div class="code"><pre><code class="language-python hljs" data-highlighted="yes">_lib_logger = Logger(
  204.     core=Core(),
  205.     exception=<span class="hljs-literal">None</span>,
  206.     depth=<span class="hljs-number">0</span>,
  207.     record=<span class="hljs-literal">False</span>,
  208.     lazy=<span class="hljs-literal">False</span>,
  209.     colors=<span class="hljs-literal">False</span>,
  210.     raw=<span class="hljs-literal">False</span>,
  211.     capture=<span class="hljs-literal">True</span>,
  212.     patchers=[],
  213.     extra={},
  214. )
  215.  
  216. _lib_logger.add(sys.stderr, level=<span class="hljs-string">"ERROR"</span>)
  217.  
  218. <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>):
  219.     _lib_logger.remove()
  220.  
  221.     _lib_logger.add(
  222.         sys.stderr,
  223.         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>,
  224.         <span class="hljs-built_in">format</span>=<span class="hljs-string">"&lt;green&gt;{time:HH:mm:ss}&lt;/green&gt; | &lt;level&gt;{level: &lt;8}&lt;/level&gt; | "</span>
  225.                <span class="hljs-string">"&lt;cyan&gt;Chrome&lt;/cyan&gt; - &lt;level&gt;{message}&lt;/level&gt;"</span>,
  226.         <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>
  227.     )
  228.  
  229.     _lib_logger.add(
  230.         sys.stderr,
  231.         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>,
  232.         <span class="hljs-built_in">format</span>=<span class="hljs-string">"&lt;blue&gt;{time:HH:mm:ss}&lt;/blue&gt; | &lt;level&gt;{level: &lt;8}&lt;/level&gt; | "</span>
  233.                <span class="hljs-string">"&lt;magenta&gt;PROXY&lt;/magenta&gt; - &lt;level&gt;{message}&lt;/level&gt;"</span>,
  234.         <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>
  235.     )
  236.     <span class="hljs-keyword">return</span> _lib_logger
  237. </code></pre>
  238. </div>
  239. <p>В Chrome и прокси привязываем источник:</p>
  240. <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>)
  241. </code></pre>
  242. </div>
  243. <h3>6. Модуль капчи с автозагрузкой солверов</h3>
  244. <p>Мы реализовали автоматическую загрузку солверов из папки <span class="code"><code>solvers/</code></span>. Это значит: есть класс с логикой прохождения капчи — просто кладёшь <span class="code"><code>.py</code></span> файл в папку и метод автоматически появляется.</p>
  245. <p><span class="code"><code>BaseCaptchaSolver</code></span> — базовый класс:</p>
  246. <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
  247.  
  248. <span class="hljs-keyword">class</span> <span class="hljs-title class_">BaseCaptchaSolver</span>(<span class="hljs-title class_ inherited__">ABC</span>):
  249.     name: <span class="hljs-built_in">str</span> = <span class="hljs-literal">None</span>
  250.     _service = <span class="hljs-literal">None</span>
  251.  
  252. <span class="hljs-meta">    @property</span>
  253.     <span class="hljs-keyword">def</span> <span class="hljs-title function_">driver</span>(<span class="hljs-params">self</span>):
  254.         <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>._service.driver
  255.  
  256. <span class="hljs-meta">    @property</span>
  257.     <span class="hljs-keyword">def</span> <span class="hljs-title function_">api_key</span>(<span class="hljs-params">self</span>):
  258.         <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>._service.api_key
  259.  
  260. <span class="hljs-meta">    @abstractmethod</span>
  261.     <span class="hljs-keyword">def</span> <span class="hljs-title function_">solve</span>(<span class="hljs-params">self, **kwargs</span>) -&gt; <span class="hljs-built_in">bool</span>:
  262.         ...
  263. </code></pre>
  264. </div>
  265. <p>Чтобы написать свой солвер достаточно:</p>
  266. <ol>
  267. <li>Унаследоваться от <span class="code"><code>BaseCaptchaSolver</code></span></li>
  268. <li>Задать <span class="code"><code>name</code></span></li>
  269. <li>Реализовать метод <span class="code"><code>solve()</code></span></li>
  270. </ol>
  271. <p>Loader проходит по всем <span class="code"><code>.py</code></span> файлам в папке <span class="code"><code>solvers/</code></span>, находит классы-солверы и регистрирует их по имени.</p>
  272. <h2>Итог</h2>
  273. <p>Четыре основные проблемы решены:</p>
  274. <ul>
  275. <li><img draggable="false" class="emoji" alt="✅" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/2705.png"> Обход CloudFlare из коробки</li>
  276. <li><img draggable="false" class="emoji" alt="✅" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/2705.png"> SOCKS5 / HTTP / HTTPS прокси с авторизацией</li>
  277. <li><img draggable="false" class="emoji" alt="✅" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/2705.png"> Замена прокси на лету без перезапуска браузера</li>
  278. <li><img draggable="false" class="emoji" alt="✅" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/2705.png"> Многопроцессорность с изоляцией воркеров</li>
  279. </ul>
  280. <p>Плюс добавили изолированное логирование и модуль капчи с плагин-архитектурой.</p>
  281. <p>Библиотека доступна на GitLab и PyPI:</p>
  282. <ul>
  283. <li>🦊 GitLab: <a href="https://gitlab.com/rtf-labs-studio/rtfox-browser" rel="nofollow">https://gitlab.com/rtf-labs-studio/rtfox-browser</a></li>
  284. <li>📦 PyPI: <a href="https://pypi.org/project/rtfox-browser/" rel="nofollow">https://pypi.org/project/rtfox-browser/</a></li>
  285. <li>💬 Telegram: <a href="https://t.me/rtf_labs_studio" rel="nofollow">https://t.me/rtf_labs_studio</a></li>
  286. <li>🎥 YouTube: <a href="https://www.youtube.com/@RTF_Labs_Studio" rel="nofollow">https://www.youtube.com/@RTF_Labs_Studio</a></li>
  287. </ul>
  288. <h2>Установка и использование</h2>
  289. <h3>Установка</h3>
  290. <div class="code"><pre><code class="language-bash hljs" data-highlighted="yes">pip install rtfox-browser
  291. </code></pre>
  292. </div>
  293. <p>Требования: Python &gt;= 3.9</p>
  294. <h3>Базовый запуск</h3>
  295. <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
  296.  
  297. driver = uc.Chrome()
  298. driver.get(<span class="hljs-string">"https://example.com"</span>)
  299. driver.quit()
  300. </code></pre>
  301. </div>
  302. <h3>Запуск с прокси</h3>
  303. <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
  304.  
  305. driver = uc.Chrome(proxy={
  306.     <span class="hljs-string">"host"</span>: <span class="hljs-string">"1.2.3.4"</span>,
  307.     <span class="hljs-string">"port"</span>: <span class="hljs-number">1080</span>,
  308.     <span class="hljs-string">"type"</span>: <span class="hljs-string">"socks5"</span>,   <span class="hljs-comment"># socks5 | http | https</span>
  309.     <span class="hljs-string">"user"</span>: <span class="hljs-string">"my_login"</span>,
  310.     <span class="hljs-string">"pass"</span>: <span class="hljs-string">"my_password"</span>,
  311. })
  312. driver.get(<span class="hljs-string">"https://example.com"</span>)
  313. driver.quit()
  314. </code></pre>
  315. </div>
  316. <h3>Запуск нескольких процессов</h3>
  317. <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
  318. <span class="hljs-keyword">import</span> rtfox_browser <span class="hljs-keyword">as</span> uc
  319.  
  320. <span class="hljs-keyword">def</span> <span class="hljs-title function_">run_worker</span>(<span class="hljs-params">worker_id</span>):
  321.     driver = uc.Chrome(
  322.         worker_id=worker_id,
  323.         proxy={
  324.             <span class="hljs-string">"host"</span>: <span class="hljs-string">"1.2.3.4"</span>,
  325.             <span class="hljs-string">"port"</span>: <span class="hljs-number">1080</span>,
  326.             <span class="hljs-string">"type"</span>: <span class="hljs-string">"socks5"</span>,
  327.             <span class="hljs-string">"user"</span>: <span class="hljs-string">"my_login"</span>,
  328.             <span class="hljs-string">"pass"</span>: <span class="hljs-string">"my_password"</span>,
  329.         }
  330.     )
  331.     driver.get(<span class="hljs-string">"https://example.com"</span>)
  332.     driver.quit()
  333.  
  334. <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
  335.     <span class="hljs-keyword">with</span> Pool(<span class="hljs-number">4</span>) <span class="hljs-keyword">as</span> pool:
  336.         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>])
  337. </code></pre>
  338. </div>
  339. <h3>Замена прокси на лету</h3>
  340. <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
  341. <span class="hljs-keyword">from</span> rtfox_browser.proxy_types <span class="hljs-keyword">import</span> ProxyType
  342.  
  343. driver = uc.Chrome()
  344. driver.get(<span class="hljs-string">"https://2ip.ru/"</span>)
  345.  
  346. driver.proxy_replacement(
  347.     host=<span class="hljs-string">"1.2.3.4"</span>,
  348.     port=<span class="hljs-number">1080</span>,
  349.     proxy_type=ProxyType.SOCKS5,
  350.     user=<span class="hljs-string">"my_login"</span>,
  351.     password=<span class="hljs-string">"my_password"</span>,
  352. )
  353. driver.refresh()
  354.  
  355. <span class="hljs-comment"># Вернуться к прямому соединению</span>
  356. driver.proxy_replacement(<span class="hljs-literal">None</span>)
  357. </code></pre>
  358. </div>
  359. <h3>Решение капчи</h3>
  360. <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
  361. <span class="hljs-keyword">from</span> rtfox_browser.captcha <span class="hljs-keyword">import</span> CaptchaService
  362.  
  363. driver = uc.Chrome()
  364. driver.get(<span class="hljs-string">"https://example.com"</span>)
  365.  
  366. captcha = CaptchaService(api_key=<span class="hljs-string">"YOUR_2CAPTCHA_KEY"</span>, driver=driver)
  367. <span class="hljs-built_in">print</span>(captcha.available())  <span class="hljs-comment"># ['ebay_hcaptcha', 'aws_image']</span>
  368. captcha.ebay_hcaptcha()
  369. </code></pre>
  370. </div>
  371. <h3>Обработка ошибок прокси</h3>
  372. <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> (
  373.     ProxyError,
  374.     ProxyConnectionError,
  375.     ProxyAuthError,
  376.     ProxyTimeoutError,
  377.     ProxyInvalidAddressError,
  378.     ProxyConfigError,
  379. )
  380.  
  381. <span class="hljs-keyword">try</span>:
  382.     driver = uc.Chrome(proxy={...})
  383. <span class="hljs-keyword">except</span> ProxyConfigError:
  384.     <span class="hljs-built_in">print</span>(<span class="hljs-string">"Invalid or incomplete proxy config"</span>)
  385. <span class="hljs-keyword">except</span> ProxyInvalidAddressError:
  386.     <span class="hljs-built_in">print</span>(<span class="hljs-string">"Malformed host or port"</span>)
  387. <span class="hljs-keyword">except</span> ProxyAuthError:
  388.     <span class="hljs-built_in">print</span>(<span class="hljs-string">"Wrong credentials"</span>)
  389. <span class="hljs-keyword">except</span> ProxyTimeoutError:
  390.     <span class="hljs-built_in">print</span>(<span class="hljs-string">"Proxy not responding"</span>)
  391. <span class="hljs-keyword">except</span> ProxyConnectionError:
  392.     <span class="hljs-built_in">print</span>(<span class="hljs-string">"Could not connect to proxy"</span>)
  393. <span class="hljs-keyword">except</span> ProxyError:
  394.     <span class="hljs-built_in">print</span>(<span class="hljs-string">"General proxy failure"</span>)
  395. </code></pre>
  396. </div>
  397. <h3>Включение отладочных логов</h3>
  398. <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
  399.  
  400. <span class="hljs-comment"># Логи ChromeDriver</span>
  401. driver = uc.Chrome(log_debug=<span class="hljs-literal">True</span>)
  402.  
  403. <span class="hljs-comment"># Логи прокси</span>
  404. driver = uc.Chrome(log_debug_proxy=<span class="hljs-literal">True</span>)
  405.  
  406. <span class="hljs-comment"># Все логи</span>
  407. driver = uc.Chrome(log_debug=<span class="hljs-literal">True</span>, log_debug_proxy=<span class="hljs-literal">True</span>)
  408. </code></pre>
  409. </div>
  410. </div>
  411. <footer>
  412.  
  413. <div class="userpic"><img class="photo" src="https://secure.gravatar.com/avatar/be7938cdd7aa975f9b414bf31689eeeb?s=150&amp;r=g&amp;d=mm&amp;f=y" alt="" height="150" width="150"></div><div class="sign">
  414.   <a rel="author" itemprop="creator" href="/people/Dark_bear/profile">Dark_bear</a> <span class="stars"></span><br>
  415.   <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">
  416.   </span>
  417. </div>
  418. </footer>
  419.  
  420. <div class="reactions ">
  421.   <form class="reactions-form" action="/reactions" method="POST">
  422.     <input name="csrf" value="DHM1BjXkkMi1iZFZWb8C5g==" type="hidden">
  423. <input name="topic" value="18307226" type="hidden">
  424.     <button name="reaction" value="🔥-true" class="reaction " title="Реакция &quot;огонь&quot;: recei" disabled="">
  425.           🔥 <span class="reaction-count">1</span>
  426.         </button>
  427.       <button name="reaction" value="🚮-false" class="reaction btn-primary" title="Реакция &quot;не нужно!&quot;: mittorn" disabled="">
  428.           🚮 <span class="reaction-count">1</span>
  429.         </button>
  430.       <a class="reaction reaction-show-list" href="/reactions?topic=18307226">?</a>
  431.       </form>
  432. </div>
  433.  
  434. </div>
Tags: ai slop
Advertisement
Add Comment
Please, Sign In to add comment