Files
autoreg-skills-max/skills/anti-detection-browser/SKILL.md

333 lines
15 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.

---
name: anti-detection-browser
description: Browser automation with Cloudflare Turnstile & CDP-detection bypass. DrissionPage + Turnstile patch extension + proxy auth forwarder. Use when headless browsers are blocked by Cloudflare or anti-bot detection.
category: automation
---
# Anti-Detection Browser Automation
Обход Cloudflare Turnstile и CDP-детекции при автоматизации браузера.
## Когда использовать
- Cloudflare блокирует headless-браузеры (Playwright, Puppeteer, Selenium)
- Страница показывает "Attention Required! | Cloudflare" или "Sorry, you have been blocked"
- `MouseEvent.screenX/screenY = 0` детектится как CDP-браузер
- Нужна регистрация/логин на сайтах с Turnstile (x.ai, Clerk, TokenHarbor)
## Почему Playwright не работает
Playwright использует CDP (Chrome DevTools Protocol). Cloudflare Turnstile детектит CDP-браузеры через:
- `MouseEvent.screenX/screenY = 0` (в headless-режиме координаты мыши не эмулируются)
- `navigator.webdriver = true`
- Отсутствие реальных движений мыши перед кликом
## Решение: DrissionPage + Turnstile Patch
**DrissionPage** — библиотека управления Chromium, которая не использует WebDriver и не выставляет `navigator.webdriver`.
**Turnstile patch** — Chrome extension (Manifest V3), который инжектит скрипт в `MAIN` world на `document_start`, переопределяя `MouseEvent.prototype.screenX/Y` случайными реалистичными значениями.
### Структура расширения
```
turnstilePatch/
├── manifest.json
└── script.js
```
**manifest.json**:
```json
{
"manifest_version": 3,
"name": "Turnstile Patch",
"version": "1.0",
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["script.js"],
"run_at": "document_start",
"world": "MAIN"
}]
}
```
**script.js**:
```javascript
Object.defineProperty(MouseEvent.prototype, 'screenX', {
get: function() { return Math.floor(Math.random() * 400) + 800; }
});
Object.defineProperty(MouseEvent.prototype, 'screenY', {
get: function() { return Math.floor(Math.random() * 200) + 400; }
});
```
### Настройка DrissionPage
```python
from DrissionPage import Chromium, ChromiumOptions
co = ChromiumOptions()
co.auto_port()
co.set_argument("--no-sandbox")
co.set_argument("--disable-gpu")
co.set_argument("--disable-dev-shm-usage")
co.set_argument("--disable-software-rasterizer")
# Загрузка Turnstile patch
EXTENSION_PATH = os.path.abspath("turnstilePatch")
co.add_extension(EXTENSION_PATH)
# Прокси (если без аутентификации)
co.set_proxy("http://proxy:port")
browser = Chromium(co)
```
### Ожидание Turnstile
После навигации нужно ждать 15-30 секунд, пока Turnstile пройдёт в non-interactive режиме:
```python
page.get("https://target.com/sign-up")
run_logger.info("Waiting for Cloudflare Turnstile...")
deadline = time.time() + 30
while time.time() < deadline:
has_challenge = page.run_js(
"return document.title.includes('Attention Required') || "
"document.querySelector('#challenge-running') !== null || "
"document.body.innerText.includes('verifying you are human')"
)
if not has_challenge:
break
time.sleep(2)
```
### Поиск кнопок с fallback
На странице может быть разный язык. Использовать JS-поиск по тексту:
```javascript
const candidates = Array.from(document.querySelectorAll('button, a, [role="button"]'));
const target = candidates.find(node => {
const text = (node.innerText || node.textContent || '').replace(/\s+/g, '').toLowerCase();
return text.includes('signupwithemail') ||
text.includes('continue with email') ||
text.includes('sign up with email') ||
text.includes('use email') ||
text.includes('email');
});
if (target) target.click();
```
## Proxy Auth Forwarder
DrissionPage и nodriver НЕ поддерживают прокси с аутентификацией. Ошибка: "你似乎在设置使用账号密码的代理,暂时不支持这种代理".
Решение: локальный forward proxy, который добавляет `Proxy-Authorization` header.
### ⚠️ HTTP-based forwarder НЕ работает с Chrome
`http.server.HTTPServer` + `BaseHTTPRequestHandler` ломает CONNECT-туннели для Chrome — браузер получает `chrome-error://chromewebdata/`. Curl работает, Chrome — нет.
**Использовать RAW TCP forwarder** (см. `scripts/tcp_forwarder.py`):
```python
import socket, threading, select, base64
UPSTREAM_HOST = 'residential-x.bpproxy.at'
UPSTREAM_PORT = 1000
AUTH = base64.b64encode(b'user:pass').decode()
LOCAL_PORT = 9129
def handle_client(client_sock):
data = b''
while b'\r\n\r\n' not in data:
chunk = client_sock.recv(4096)
if not chunk: return
data += chunk
request = data.decode('latin-1', errors='replace')
first_line = request.split('\r\n')[0]
method, target, _ = first_line.split(' ', 2)
if method == 'CONNECT':
host, port_str = target.rsplit(':', 1)
port = int(port_str)
remote = socket.create_connection((UPSTREAM_HOST, UPSTREAM_PORT), timeout=10)
connect_req = f'CONNECT {host}:{port} HTTP/1.1\r\nHost: {host}:{port}\r\nProxy-Authorization: Basic {AUTH}\r\n\r\n'
remote.send(connect_req.encode())
resp = b''
while b'\r\n\r\n' not in resp:
resp += remote.recv(4096)
if b'200' not in resp.split(b'\r\n')[0]:
client_sock.send(b'HTTP/1.1 502 Bad Gateway\r\n\r\n')
remote.close()
return
client_sock.send(b'HTTP/1.1 200 Connection Established\r\n\r\n')
client_sock.settimeout(30)
remote.settimeout(30)
socks = [client_sock, remote]
while True:
r, _, _ = select.select(socks, [], [], 30)
if not r: break
for s in r:
d = s.recv(8192)
if not d: return
dst = remote if s is client_sock else client_sock
dst.sendall(d)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('127.0.0.1', LOCAL_PORT))
server.listen(50)
while True:
client, addr = server.accept()
threading.Thread(target=handle_client, args=(client,), daemon=True).start()
```
Запуск:
```bash
python tcp_forwarder.py &
# Затем использовать http://127.0.0.1:9129 как browser_proxy
```
## Geo-Blocking
Сервисы типа x.ai гео-блокируют по стране выхода прокси. Проверять перед использованием:
```bash
curl -x "http://user:pass@proxy:port" -s http://ip-api.com/json
# Проверить поле "country" — x.ai доступен из US, CA, UK, EU, но НЕ из IQ, RU, CN
```
## Nodriver: Fallback When DrissionPage Fails
DrissionPage может быть детектирован Cloudflare даже с Turnstile patch. Симптом: `PageDisconnectedError: 与页面的连接已断开` — Cloudflare активно рвёт CDP-соединение.
**Nodriver** (`pip install nodriver`) — альтернатива с встроенной антидетект-защитой. Не требует отдельного Turnstile patch.
### Настройка nodriver
```python
import nodriver as uc
browser = await uc.start(
headless=False,
browser_args=[
"--window-size=1280,900",
"--no-first-run",
"--no-default-browser-check",
"--disable-blink-features=AutomationControlled",
"--proxy-server=http://127.0.0.1:9129", # через proxy forwarder
"--ignore-certificate-errors",
],
)
tab = await browser.get("https://accounts.x.ai/sign-up?redirect=grok-com")
```
### API ключевые отличия от DrissionPage
- **Async**: все методы `await`
- `tab.find(text)` — поиск элемента по тексту (аналог `page.run_js(...find text...)`)
- `tab.select(selector)` — CSS-селектор
- `tab.evaluate(js)` — выполнить JS
- `el.click()`, `el.send_keys(text)` — взаимодействие
- Обернуть в `asyncio.wait_for()` для таймаутов
### Google OAuth Bypass для accounts.x.ai
**Проблема**: `accounts.x.ai` блокирует ВСЕ bpproxy residential IP (403) напрямую, но Google OAuth (`accounts.google.com`) принимает те же прокси (302).
**Решение**: использовать Google OAuth flow вместо прямой email-регистрации:
1. Зайти на `accounts.x.ai/sign-up?redirect=grok-com`
2. Нажать «Continue with Google» (не «Use email»)
3. Google OAuth-страница загружается через прокси (Google принимает bpproxy)
4. Ввести Gmail + пароль + TOTP (если 2FA)
5. Пройти consent screen
6. Редирект обратно на Grok
**Требования**: Gmail аккаунты с 2FA-секретами (формат как в `tusk_gmail_accounts.json`).
```python
# Пример: поиск кнопки Google
clicked = await click_text(tab, [
"Continue with Google", "Sign in with Google",
"Sign up with Google", "Google",
], timeout=10)
```
### Port Conflicts: Multiple Proxy Forwarders
Никогда не запускать несколько экземпляров proxy forwarder на одном порту — они конфликтуют и порт становится недоступным. При смене upstream-прокси:
1. Убить старый forwarder: `taskkill /F /PID <pid>`
2. Проверить что порт свободен: `netstat -ano | grep <port>`
3. Запустить новый forwarder на **уникальном** порту
**Рекомендация**: использовать разные порты для разных upstream-прокси (9128, 9129, 9130...).
### Nodriver `browser.stop()` не awaitable
`browser.stop()` в nodriver возвращает `None` — не использовать `await`:
```python
# ❌ ОШИБКА: TypeError: object NoneType can't be used in 'await' expression
await browser.stop()
# ✅ ПРАВИЛЬНО
browser.stop()
```
### TCP Forwarder: всегда вместо HTTP-based
HTTP-based forwarder (`http.server.HTTPServer`) не работает с Chrome — CONNECT-туннели ломаются. Всегда использовать RAW TCP forwarder (`scripts/tcp_forwarder.py`).
## Pitfalls
### Playwright Headless Blocked by Cloudflare (General)
Playwright's headless Chromium is detected by Cloudflare on many sites, not just those with Turnstile. Symptoms: `page.goto()` times out, empty page content, or Cloudflare challenge page. Use `headless=False` with a persistent Chrome user profile (`launch_persistent_context`), or connect via CDP to an existing Chrome instance (`connect_over_cdp`).
### Playwright CDP Works, Headless Doesn't
`connect_over_cdp("http://127.0.0.1:9222")` to an existing Chrome with remote debugging works reliably because it uses the real Chrome profile. Headless Playwright (`launch()`) is detected. For automation that needs Cloudflare bypass, always prefer CDP connection over headless launch.
### Nodriver Windows Asyncio Crashes (2026-08-21)
Nodriver (`uc.start()`) crashes on Windows with `ValueError: I/O operation on closed pipe` in `asyncio.proactor_events`. This is a Windows-specific asyncio issue. Fall back to Playwright with `headless=False` or CDP connection.
### MCP Browser as Reliable Fallback
When Playwright and nodriver both fail, the Chrome DevTools MCP (`mcp__chrome_devtools__*` tools) works reliably. It uses the existing Chrome instance with the user's profile, avoiding Cloudflare detection entirely. Use `evaluate_script` with nativeInputSetter for fastest form interactions.
### Standalone Chrome + CDP: самопроходящий Turnstile (2026-09-10)
Когда все MCP/headless-пути висят на SPA-бандле (белая страница, бандл pending, хотя curl качает 200), а firecrawl_interact рвёт сессии — поднять отдельный Chrome с `--remote-debugging-port=9333 --user-data-dir=<fresh>` (background=true), подключиться Playwright `connect_over_cdp`, заполнить форму и **поллить скрытое поле `cf-turnstile-response` до length>10** — в реальном Chrome non-interactive Turnstile решается сам за 10-20 сек. Полный разбор (RainProxy): `references/rainproxy-cdp-turnstile.md` — там же pitfalls: `has-text("Login")` ловит "Login with Google", Gmail-алиасы с `+` отклоняются, UTF-7 имена папок Gmail при русской локали.
### accounts.x.ai blocks ALL bpproxy residential IPs (2026-08-14)
Все 25 bpproxy residential прокси возвращают `403` при прямом обращении к `accounts.x.ai`. Google (`accounts.google.com`) принимает те же прокси. Использовать Google OAuth flow вместо прямого email signup.
### DrissionPage CDP disconnection
Cloudflare может детектировать и разрывать CDP-соединение DrissionPage (`PageDisconnectedError`). Переключиться на nodriver.
### DrissionPage proxy auth
DrissionPage не поддерживает `user:pass@host:port` в URL прокси. Использовать proxy forwarder.
### Turnstile timing
Non-interactive Turnstile требует 5-30 секунд. Недостаточное ожидание → кнопки не найдены (страница ещё не загрузилась после challenge).
### Geo-blocking bpproxy
bpproxy residential выходят из разных стран (Ирак, Канада, etc.). Всегда проверять `ip-api.com/json` перед использованием с гео-зависимыми сервисами.
### bpproxy hardsession истекает
Hardsession-прокси могут умереть через несколько часов. Периодически перегенерировать пул через `bpproxy` skill.
## Связанные скиллы
- `bpproxy` — генерация и управление прокси
- `bulk-account-registration` — пайплайн массовой регистрации
## Связанные файлы
- `references/grok-registration-pipeline.md` — конкретный пайплайн регистрации Grok (x.ai) с DrissionPage
- `scripts/proxy_forwarder.py` — HTTP forward proxy (DEPRECATED — не работает с Chrome, используй tcp_forwarder.py)
- `scripts/tcp_forwarder.py` — RAW TCP forward proxy (работает с Chrome, nodriver, DrissionPage)
- `templates/turnstile-patch/` — шаблон Chrome extension для обхода CDP-детекции (manifest.json + script.js)