Compare commits

..
12 Commits
Author SHA1 Message Date
nafer 0b74efb3e6 добавил browser-data в переменную, чтобы инстансы имели разные аккаунты 2026-04-17 21:32:29 +03:00
nafer 7256e215bb container_name: browser-use удалил, чтобы не было конфликта 2026-04-17 21:26:55 +03:00
nafer 4e75beaeca изменил порты на переменные, чтобы можно было инстансы дублировать 2026-04-17 21:14:03 +03:00
nafer 87b8bbb075 cap_psyho 2026-03-10 20:45:53 +03:00
nafer 6959670729 capsolver_sit_watch 2026-03-10 20:04:22 +03:00
nafer d436d6aaca capsolver_py_wrap 2026-03-10 19:45:43 +03:00
nafer e8143e2627 14 2026-03-10 19:26:38 +03:00
nafer a3c3d65c02 13 2026-03-10 18:49:03 +03:00
nafer 84ccb7bac4 12 2026-03-10 18:35:24 +03:00
nafer b3d31cb2d2 1 2026-03-10 18:33:27 +03:00
nafer 80760b9dd8 cp_naf 2026-03-10 18:11:02 +03:00
nafer 729ada2a6f cap7 2026-03-10 17:02:16 +03:00
4 changed files with 113 additions and 45 deletions

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
# =========================================== # ===========================================
# Browser Use MCP Server Configuration # Browser Use MCP Server Configuration
# =========================================== # ===========================================
#
# OpenRouter API Key (обязательно) # OpenRouter API Key (обязательно)
# Получить на https://openrouter.ai/keys # Получить на https://openrouter.ai/keys
OPENROUTER_API_KEY=your_openrouter_api_key_here OPENROUTER_API_KEY=your_openrouter_api_key_here
+3 -1
View File
@@ -1,10 +1,12 @@
FROM mcr.microsoft.com/playwright/python:v1.49.0-noble FROM mcr.microsoft.com/playwright/python:v1.49.0-noble
# Установка системных зависимостей # Установка системных зависимостей
# socat — проброс портов для CDP # socat — проброс портов для CDP_
# Видеокодеки и мультимедийные библиотеки для воспроизведения видео в Chrome # Видеокодеки и мультимедийные библиотеки для воспроизведения видео в Chrome
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
socat \ socat \
wget \
unzip \
libgstreamer1.0-0 \ libgstreamer1.0-0 \
gstreamer1.0-plugins-base \ gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \ gstreamer1.0-plugins-good \
+103 -38
View File
@@ -40,7 +40,7 @@ CAPSOLVER_API_KEY = os.getenv("CAPSOLVER_API_KEY", "")
AUTO_SOLVE_CAPTCHA = os.getenv("AUTO_SOLVE_CAPTCHA", "false").lower() == "true" AUTO_SOLVE_CAPTCHA = os.getenv("AUTO_SOLVE_CAPTCHA", "false").lower() == "true"
# =========================================== # ===========================================
# Настройки обхода reCAPTCHA # Настройки обхода reCAPTCHA_
# =========================================== # ===========================================
RECAPTCHA_BYPASS = os.getenv("RECAPTCHA_BYPASS", "false").lower() == "true" RECAPTCHA_BYPASS = os.getenv("RECAPTCHA_BYPASS", "false").lower() == "true"
@@ -59,8 +59,28 @@ logger.info(f"USE_XVFB: {USE_XVFB}")
logger.info(f"REMOTE_DEBUGGING_ENABLED: {REMOTE_DEBUGGING_ENABLED}") logger.info(f"REMOTE_DEBUGGING_ENABLED: {REMOTE_DEBUGGING_ENABLED}")
logger.info(f"RECAPTCHA_BYPASS: {RECAPTCHA_BYPASS}") logger.info(f"RECAPTCHA_BYPASS: {RECAPTCHA_BYPASS}")
logger.info(f"AUTO_SOLVE_CAPTCHA: {AUTO_SOLVE_CAPTCHA}") logger.info(f"AUTO_SOLVE_CAPTCHA: {AUTO_SOLVE_CAPTCHA}")
logger.info(f"CAPSOLVER_API_KEY: {'set' if CAPSOLVER_API_KEY else 'not set'}")
logger.info(f"PROXY_URL: {PROXY_URL if PROXY_URL else 'not set'}")
logger.info(f"===========================") logger.info(f"===========================")
# Настраиваем CapSolver расширение с API ключом
if CAPSOLVER_API_KEY:
capsolver_config_path = "/app/capsolver-extension/assets/config.js"
if os.path.exists(capsolver_config_path):
try:
with open(capsolver_config_path, 'r') as f:
config_content = f.read()
# Заменяем apiKey на реальный
import re
config_content = re.sub(r'apiKey:\s*"[^"]*"', f'apiKey: "{CAPSOLVER_API_KEY}"', config_content)
with open(capsolver_config_path, 'w') as f:
f.write(config_content)
logger.info("CapSolver API key configured in extension")
except Exception as e:
logger.warning(f"Failed to configure CapSolver API key: {e}")
else:
logger.warning(f"CapSolver config not found at {capsolver_config_path}")
# Создаём Tools с кастомными действиями # Создаём Tools с кастомными действиями
try: try:
from browser_use import Tools, BrowserSession from browser_use import Tools, BrowserSession
@@ -198,7 +218,7 @@ try:
sitekey = await turnstile_element.get_attribute('data-sitekey') sitekey = await turnstile_element.get_attribute('data-sitekey')
turnstile_frame = await page.query_selector('iframe[src*="turnstile"]') turnstile_frame = await page.query_selector('iframe[src*="turnstile"]')
if turnstile_frame and sitekey: if turnstile_frame and sitekey:
captcha_type = "TurnstileTask" captcha_type = "AntiTurnstileTaskProxyLess"
if not sitekey or not captcha_type: if not sitekey or not captcha_type:
return ActionResult( return ActionResult(
@@ -299,7 +319,7 @@ try:
include_in_memory=True include_in_memory=True
) )
elif captcha_type == "TurnstileTask": elif captcha_type == "AntiTurnstileTaskProxyLess":
token = solution.get("token") token = solution.get("token")
if token: if token:
await page.evaluate(f'''(token) => {{ await page.evaluate(f'''(token) => {{
@@ -418,7 +438,7 @@ async def solve_captcha_with_capsolver(page, capsolver_api_key: str) -> bool:
if sitekey: if sitekey:
turnstile_frame = await page.query_selector('iframe[src*="turnstile"]') turnstile_frame = await page.query_selector('iframe[src*="turnstile"]')
if turnstile_frame: if turnstile_frame:
captcha_type = "TurnstileTask" captcha_type = "AntiTurnstileTaskProxyLess"
if not sitekey or not captcha_type: if not sitekey or not captcha_type:
logger.info("No captcha found on page") logger.info("No captcha found on page")
@@ -487,7 +507,7 @@ async def solve_captcha_with_capsolver(page, capsolver_api_key: str) -> bool:
await textarea.fill(h_captcha_response) await textarea.fill(h_captcha_response)
logger.info("hCaptcha solved successfully!") logger.info("hCaptcha solved successfully!")
return True return True
elif captcha_type == "TurnstileTask": elif captcha_type == "AntiTurnstileTaskProxyLess":
token = solution.get("token") token = solution.get("token")
if token: if token:
# Вставляем токен # Вставляем токен
@@ -791,6 +811,7 @@ async def run_browser_task(task_id: str, task: str, max_steps: int, model: str):
f"--server-args=-screen 0 {width}x{height}x24", f"--server-args=-screen 0 {width}x{height}x24",
]) ])
# Всегда добавляем --no-sandbox
chrome_cmd.extend([ chrome_cmd.extend([
chrome_exe, chrome_exe,
f"--remote-debugging-port={CHROME_INTERNAL_PORT}", f"--remote-debugging-port={CHROME_INTERNAL_PORT}",
@@ -823,18 +844,23 @@ async def run_browser_task(task_id: str, task: str, max_steps: int, model: str):
"--enable-unsafe-swiftshader", "--enable-unsafe-swiftshader",
"--ignore-gpu-blocklist", "--ignore-gpu-blocklist",
"--enable-webgl", "--enable-webgl",
"--use-gl=angle", "--use-gl=desktop",
"--use-angle=swiftshader", "--ignore-gpu-blocklist",
"--test-type", "--enable-accelerated-2d-canvas",
# WebGPU флаги для Cloudflare Turnstile "--enable-gpu-rasterization",
"--enable-webgpu", "--enable-zero-copy",
"--enable-webgpu-developer-features", "--ignore-webgl-blacklist",
"--use-angle=swiftshader", # Добавляем экспериментальные флаги для WebGL
# Отключено: stealth-расширение вызывает ошибки и ломает Cloudflare Turnstile "--enable-experimental-webgl",
# "--load-extension=/app/stealth-extension", "--enable-webgl2-compute-context",
# "--disable-extensions-except=/app/stealth-extension",
]) ])
# Убираем загрузку расширения CapSolver - используем API вместо него
# Расширение конфликтует с Cloudflare Turnstile
# Решение капчи происходит через функцию solve_captcha_with_capsolver
if AUTO_SOLVE_CAPTCHA and CAPSOLVER_API_KEY:
logger.info(f"[{task_id}] CapSolver will solve CAPTCHA via API (not extension)")
# Добавляем специальные флаги для обхода reCAPTCHA если включено # Добавляем специальные флаги для обхода reCAPTCHA если включено
if RECAPTCHA_BYPASS: if RECAPTCHA_BYPASS:
chrome_cmd.extend([ chrome_cmd.extend([
@@ -848,6 +874,14 @@ async def run_browser_task(task_id: str, task: str, max_steps: int, model: str):
"--disable-ipc-flooding-protection", "--disable-ipc-flooding-protection",
]) ])
logger.info(f"[{task_id}] Added reCAPTCHA bypass flags") logger.info(f"[{task_id}] Added reCAPTCHA bypass flags")
else:
# Всегда добавляем --no-sandbox для работы в контейнере
# и --disable-blink-features=AutomationControlled для обхода Cloudflare Turnstile
chrome_cmd.extend([
"--no-sandbox",
"--disable-blink-features=AutomationControlled",
])
logger.info(f"[{task_id}] Added minimal stealth flags for Cloudflare Turnstile")
# Добавляем прокси если есть # Добавляем прокси если есть
chrome_cmd.extend(proxy_args) chrome_cmd.extend(proxy_args)
@@ -913,39 +947,70 @@ async def run_browser_task(task_id: str, task: str, max_steps: int, model: str):
logger.info(f"[{task_id}] Using new Chrome on internal port {CHROME_INTERNAL_PORT}") logger.info(f"[{task_id}] Using new Chrome on internal port {CHROME_INTERNAL_PORT}")
# Инжектируем stealth-скрипты через CDP для дополнительной защиты # Инжектируем stealth-скрипты через CDP для дополнительной защиты
# Отключено: stealth-скрипты вызывают ошибки и ломают Cloudflare Turnstile try:
# try: import json
# import json stealth_script_path = "/app/stealth-extension/stealth.js"
# stealth_script_path = "/app/stealth-extension/stealth.js" if os.path.exists(stealth_script_path):
# if os.path.exists(stealth_script_path): with open(stealth_script_path, 'r') as f:
# with open(stealth_script_path, 'r') as f: stealth_js = f.read()
# stealth_js = f.read()
# # Получаем список целей (вкладок) через CDP
# # Получаем список целей (вкладок) через CDP response = urllib.request.urlopen(f"{cdp_url}/json/list", timeout=5)
# response = urllib.request.urlopen(f"{cdp_url}/json/list", timeout=5) targets = json.loads(response.read().decode())
# targets = json.loads(response.read().decode())
# for target in targets:
# for target in targets: if target.get('type') == 'page':
# if target.get('type') == 'page': ws_url = target.get('webSocketDebuggerUrl')
# ws_url = target.get('webSocketDebuggerUrl') if ws_url:
# if ws_url: logger.info(f"[{task_id}] Injecting stealth scripts via CDP into {target.get('url', 'unknown')}")
# logger.info(f"[{task_id}] Injecting stealth scripts via CDP into {target.get('url', 'unknown')}")
# logger.info(f"[{task_id}] Stealth extension loaded + CDP stealth injection ready")
# logger.info(f"[{task_id}] Stealth extension loaded + CDP stealth injection ready") else:
# else: logger.warning(f"[{task_id}] Stealth script not found at {stealth_script_path}")
# logger.warning(f"[{task_id}] Stealth script not found at {stealth_script_path}") except Exception as e:
# except Exception as e: logger.warning(f"[{task_id}] CDP stealth injection failed (extension should still work): {e}")
# logger.warning(f"[{task_id}] CDP stealth injection failed (extension should still work): {e}")
# Подключаемся через CDP # Подключаемся через CDP
browser = Browser(cdp_url=cdp_url) browser = Browser(cdp_url=cdp_url)
else: else:
# Обычный запуск # Обычный запуск
# Добавляем флаги для работы в контейнере
extra_chromium_args = [
"--no-sandbox",
"--disable-dev-shm-usage",
"--disable-gpu",
"--enable-webgl",
"--use-gl=desktop",
"--ignore-gpu-blocklist",
"--enable-accelerated-2d-canvas",
"--enable-gpu-rasterization",
"--enable-zero-copy",
"--ignore-webgl-blacklist",
"--enable-experimental-webgl",
]
# Используем Google Chrome если доступен
chrome_path = os.getenv("CHROME_PATH", "/usr/bin/google-chrome")
if os.path.exists(chrome_path):
logger.info(f"Using Google Chrome at {chrome_path}")
else:
logger.info("Google Chrome not found, using default Chromium")
chrome_path = None
# Убираем загрузку расширения CapSolver - используем API
# Расширение конфликтует с Cloudflare Turnstile
extensions = []
if AUTO_SOLVE_CAPTCHA and CAPSOLVER_API_KEY:
logger.info("CapSolver will solve CAPTCHA via API (not extension)")
browser_profile = BrowserProfile( browser_profile = BrowserProfile(
user_data_dir="/app/browser-data/main_profile", user_data_dir="/app/browser-data/main_profile",
profile_directory="Default", profile_directory="Default",
headless=False, # Всегда false для поддержки reCAPTCHA headless=False, # Всегда false для поддержки reCAPTCHA
keep_alive=True, keep_alive=True,
extra_chromium_args=extra_chromium_args,
executable_path=chrome_path,
extensions=extensions,
) )
browser = Browser(browser_profile=browser_profile) browser = Browser(browser_profile=browser_profile)
+6 -5
View File
@@ -6,23 +6,24 @@ services:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
image: browser-use-mcp:latest image: browser-use-mcp:latest
container_name: browser-use
security_opt: security_opt:
- seccomp:unconfined - seccomp:unconfined
- apparmor:unconfined - apparmor:unconfined
ports: ports:
- "8383:8383" - "${APP_PORT_8383}:${CONTAINER_PORT_8383}"
- "9222:9222" - "${APP_PORT_9222}:${CONTAINER_PORT_9222}"
environment: environment:
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY} - OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
- LLM_MODEL_NAME=${LLM_MODEL_NAME:-arcee-ai/trinity-large-preview:free} - LLM_MODEL_NAME=${LLM_MODEL_NAME:-arcee-ai/trinity-large-preview:free}
- REMOTE_DEBUGGING_ENABLED=true - REMOTE_DEBUGGING_ENABLED=true
- REMOTE_DEBUGGING_PORT=9222 - REMOTE_DEBUGGING_PORT=${CONTAINER_PORT_9222}
# CapSolver для автоматического решения капчи (Turnstile, reCAPTCHA, hCaptcha) # CapSolver для автоматического решения капчи (Turnstile, reCAPTCHA, hCaptcha)
- CAPSOLVER_API_KEY=${CAPSOLVER_API_KEY:-} - CAPSOLVER_API_KEY=${CAPSOLVER_API_KEY:-}
- AUTO_SOLVE_CAPTCHA=${AUTO_SOLVE_CAPTCHA:-false} - AUTO_SOLVE_CAPTCHA=${AUTO_SOLVE_CAPTCHA:-false}
# ВАЖНО! Прокси обязательна для Turnstile! Без прокси Cloudflare детектит бота
- PROXY_URL=${PROXY_URL:-}
volumes: volumes:
- /home/nafer/dokploy_data/browser-use:/app/browser-data - "${APP_DATA_PATH}:/app/browser-data"
shm_size: '4gb' shm_size: '4gb'
ipc: host ipc: host
deploy: deploy: