Files
site/content/blog/robotex-browser-automation-api/index.md
T
2026-10-10 19:28:57 +04:00

152 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Robotex API для Автоматизации Браузера
date: 2026-10-09T01:59:39+04:00
draft: false
tags:
- parsing
- anti-bot
- api
- saas
summary: Как боту спарсить сайт за анти-бот защитой или со сложным JS
aliases:
- /blog/robotex-brouser-automation-api/
---
Каждый бот под сайт рано или поздно упирается в одну из трех проблем:
1. капча
2. анти-бот защита
3. сложный JS, который нужно отрендерить, чтобы отправить форму
Паук, который ходит по сайту сырыми http запросами, тут бессилен. Решение одно - запустить браузер и поручить ему пройти сложный момент. Но и браузер нужно уметь прятать. Под капотом он шлет те же http запросы, что и паук на Python, только делает это из контекста работающего JS. А этот контекст полон маркеров, по которым сайт понимает, что браузером кто-то управляет.
Под эту задачу я написал микросервис [Robotex](https://git.sokolab.xyz/s0k0l/robotex). Ниже расскажу, как он устроен и зачем он нужен, если уже есть Scrapling и FlareSolverr.
## Чем пользовались раньше и сейчас
Раньше я брал Selenium. Firefox он запускает через geckodriver по протоколу Marionette и заметно палится: `navigator.webdriver`, следы драйвера в окружении страницы и прочее. Почти все это можно скрыть аддоном, который настраивает контекст страницы до загрузки сайта. Я так и делал, но это постоянная гонка за каждой новой проверкой.
Сейчас появились инструменты, которые решают это на уровне самого браузера:
- **Camoufox** - сборка Firefox, где отпечатки (экран, шрифты, WebGL, число ядер и т.д.) подменяются в коде движка, а не через JS.
- **Patchright** - пропатченный Playwright, который убирает утечки CDP, по которым анти-боты узнают автоматизацию Chromium.
Поверх них работает Scrapling. У него есть готовый режим для прохождения анти-бот страниц, и я подсмотрел у него алгоритм. Оказалось, что прохождение Cloudflare это не решение головоломки. Если окружение браузера выглядит по-человечески, а IP нормальный, достаточно дождаться виджета и тыкнуть чекбокс со случайным смещением и задержкой. Вся сложность в том, чтобы правильно определить, что перед тобой проверка, и чтобы к моменту клика браузер уже не вызывал подозрений.
Для небольших объемов без аккаунтов Scrapling хватает. Проблемы начинаются, когда появляются аккаунты. Тогда IP, User-Agent, куки и отпечаток браузера должны быть связаны в один профиль и жить вместе. Сменил прокси, а куки оставил старые - аккаунт улетает в проверку или в бан. Защита начинает задалбывать капчами, аккаунты дохнут.
## Что такое Robotex
Robotex берет на себя всю работу с браузером: проходит анти-бот, выполняет сценарий на странице и отдает боту куки, с которыми тот спокойно ходит по сайту дальше обычными запросами.
От FlareSolverr и Byparr он отличается тем, что те умеют только открыть страницу и получить `cf_clearance`. Robotex выполняет сценарий: заполнить форму, кликнуть, решить капчу, дождаться элемента. А от Scrapling тем, что это не библиотека внутри вашего процесса, а отдельный сервис. Бот может быть написан на чем угодно, ему нужен только http клиент.
Под капотом FastAPI и настоящий Chrome, которым управляет Patchright. Обертку над браузером я перенес из Scrapling. Начинал я с Camoufox, но в итоге остановился на Chrome.
## Как это работает
Бот отправляет сценарий:
```
POST /v1/solve
Content-Type: application/json
X-API-Key: <key>
{
"url": "https://example.com/login",
"actions": [
{"type": "fill", "selector": "#email", "value": "user@example.com"},
{"type": "fill", "selector": "#password", "value": "..."},
{"type": "mouse_move", "selector": "#submit"},
{"type": "click", "selector": "#submit"},
{"type": "wait_for", "selector": ".dashboard", "timeout": 30}
],
"proxy": "socks5://user:pass@host:port",
"html": true,
"timeout": 120
}
```
Сценарий заполняет форму входа и ждет, пока загрузится личный кабинет. Кроме этих действий есть `submit` (клик с ожиданием перехода на новую страницу), `delay`, `inner_html` (забрать кусок страницы) и `captcha`, про нее ниже.
Так как в запросе нет куки `session_id`, сервис создает новый профиль браузера и возвращает его в заголовке `Set-Cookie`. Профиль хранится на диске: куки, local storage и отпечаток. Локаль и часовой пояс браузера подбираются по гео прокси, чтобы IP и окружение не противоречили друг другу. Если боту снова нужен браузер, он передает эту куку, и Robotex продолжит работу в том же профиле. Для сайта это все тот же пользователь.
В ответе:
```
{
"status": "ok",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
"cookies": [
{"name": "sessionid", "value": "...", "domain": ".example.com", "path": "/"}
],
"actions": [
{"type": "fill", "ok": true},
{"type": "fill", "ok": true},
{"type": "mouse_move", "ok": true},
{"type": "click", "ok": true},
{"type": "wait_for", "ok": true}
],
"html": "<head>...</head><body>...</body>"
}
```
Дальше бот ходит по сайту сам, с этими куками, **тем же User-Agent и через тот же прокси**. Если какое-то действие упало, `status` будет `err`, а в `actions` видно, на каком шаге и почему.
### Капча
Если на форме ожидается капча, добавляем шаг для нее и ключ сервиса распознавания (сейчас подключен 2captcha):
```
{
"url": "https://example.com/login",
"actions": [
{"type": "fill", "selector": "#email", "value": "user@example.com"},
{"type": "fill", "selector": "#password", "value": "..."},
{"type": "captcha", "selector": "#captcha", "value": "hcaptcha"},
{"type": "click", "selector": "#submit"},
{"type": "wait_for", "selector": ".dashboard", "timeout": 30}
],
"captcha": "<ключ 2captcha>",
"proxy": "socks5://user:pass@host:port"
}
```
Капча будет решена до клика на submit.
### Анти-бот страница
Анти-бот страница может появиться в любой момент, а может и не появиться. Поэтому это не шаг сценария, а настройка всего запроса:
```
{
"url": "https://example.com/login",
"actions": [ ... ],
"captcha_type": "cloudflare",
"captcha_detect_locator": "#anti-bot-page-only-id",
"captcha_success_locator": "#site-only-id",
"captcha": "<ключ 2captcha>",
"proxy": "socks5://user:pass@host:port"
}
```
`captcha_detect_locator` это селектор, который есть только на странице проверки, `captcha_success_locator` есть только на самом сайте. Сразу после загрузки страницы и до выполнения сценария Robotex проверяет, не стоит ли перед ним преграда. Если стоит, проходит ее сам: ждет, тыкает чекбокс. Если проверка эскалировалась до полноценной капчи с картинками, отправляет ее в сервис распознавания. Если проверка всплыла посреди сценария, для этого есть отдельное действие `pass_challenge`.
Для тяжелых сайтов есть еще пара полезных опций: `disable_resources` отключает загрузку картинок и шрифтов, `blocked_domains` режет запросы к ненужным доменам вроде аналитики, а через `cookies` можно передать уже готовые куки.
## Ограничения
Серебряной пули тут нет:
- Это ранний MVP. Проверка API ключей, очередь задач и биллинг пока в планах
- браузер ест сотни мегабайт памяти, поэтому на один инстанс сейчас 10 одновременных сессий
- качество прокси решает очень многое, на грязном IP не поможет никакой отпечаток
- Turnstile проходит не на каждом сайте, над стабильностью еще работаю. Анти-боты обновляются, и проход конкретного сайта нужно проверять и поддерживать
Зато бот остается легким: браузер нужен ему только в тех местах, где без него никак, а все остальное время он работает быстрыми http запросами.
## Код
Исходники: [git.sokolab.xyz/s0k0l/robotex](https://git.sokolab.xyz/s0k0l/robotex). Там же в `docs` лежит ТЗ на модуль обхода анти-бот защиты, если интересно, как он устроен изнутри.
Используйте только на сайтах, где у вас есть на это право.