chore: auto release commit (2026-06-15 17:32:47)
All checks were successful
技能自动化发布 / release (push) Successful in 7s
All checks were successful
技能自动化发布 / release (push) Successful in 7s
This commit is contained in:
135
examples/real_browser_rpa/scripts/service/browser_session.py
Normal file
135
examples/real_browser_rpa/scripts/service/browser_session.py
Normal file
@@ -0,0 +1,135 @@
|
||||
"""浏览器会话启动(系统 Chrome/Edge + Playwright persistent context)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, Optional, Tuple
|
||||
|
||||
from util.constants import DEFAULT_START_URL
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_PAGE_TIMEOUT_MS = 15_000
|
||||
GOTO_TIMEOUT_MS = 60_000
|
||||
|
||||
STEALTH_INIT_SCRIPT = """
|
||||
(() => {
|
||||
try { Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); } catch (e) {}
|
||||
})();
|
||||
"""
|
||||
|
||||
|
||||
def get_start_url() -> str:
|
||||
return (os.getenv("TARGET_START_URL") or DEFAULT_START_URL).strip() or DEFAULT_START_URL
|
||||
|
||||
|
||||
def _headless_from_env() -> bool:
|
||||
v = (os.getenv("OPENCLAW_BROWSER_HEADLESS") or "0").strip().lower()
|
||||
return v in ("1", "true", "yes", "on")
|
||||
|
||||
|
||||
def _find_chrome_executable() -> str | None:
|
||||
try:
|
||||
from jiangchang_skill_core.runtime_env import find_chrome_executable
|
||||
|
||||
chrome = find_chrome_executable()
|
||||
if chrome and os.path.isfile(chrome):
|
||||
return chrome
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
candidates = [
|
||||
os.path.expandvars(r"%ProgramFiles%\Google\Chrome\Application\chrome.exe"),
|
||||
os.path.expandvars(r"%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe"),
|
||||
os.path.expandvars(r"%ProgramFiles%\Microsoft\Edge\Application\msedge.exe"),
|
||||
os.path.expandvars(r"%ProgramFiles(x86)%\Microsoft\Edge\Application\msedge.exe"),
|
||||
]
|
||||
for path in candidates:
|
||||
if path and os.path.isfile(path):
|
||||
return path
|
||||
return None
|
||||
|
||||
|
||||
async def start_browser_session(
|
||||
profile_dir: str,
|
||||
*,
|
||||
headless: Optional[bool] = None,
|
||||
) -> Tuple[Any, Any, Any]:
|
||||
"""
|
||||
启动持久化 Chrome profile,new_page + goto 入口页,返回 (playwright, context, page)。
|
||||
|
||||
真实 skill 需要安装 playwright 与 jiangchang_skill_core。
|
||||
"""
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
hl = headless if headless is not None else _headless_from_env()
|
||||
start_url = get_start_url()
|
||||
chrome = _find_chrome_executable()
|
||||
if not chrome:
|
||||
raise RuntimeError(
|
||||
"ERROR:MISSING_BROWSER 未检测到 Chrome 或 Edge 浏览器,请先安装系统浏览器后重试。"
|
||||
)
|
||||
|
||||
launch_args = ["--start-maximized", "--disable-blink-features=AutomationControlled"]
|
||||
logger.info(
|
||||
"browser_launch chrome=%s profile_dir=%s start_url=%s args=%s headless=%s",
|
||||
chrome,
|
||||
profile_dir,
|
||||
start_url,
|
||||
launch_args,
|
||||
hl,
|
||||
)
|
||||
print(f"[浏览器] 系统 Chrome: {chrome}")
|
||||
print(f"[浏览器] profile_dir: [{profile_dir}]")
|
||||
print(f"[浏览器] startup_url={start_url}")
|
||||
print(f"[浏览器] args={launch_args}")
|
||||
|
||||
pw = await async_playwright().start()
|
||||
context = None
|
||||
try:
|
||||
context = await pw.chromium.launch_persistent_context(
|
||||
user_data_dir=profile_dir,
|
||||
headless=hl,
|
||||
executable_path=chrome,
|
||||
locale="zh-CN",
|
||||
no_viewport=True,
|
||||
args=launch_args,
|
||||
ignore_default_args=["--enable-automation"],
|
||||
)
|
||||
await context.add_init_script(STEALTH_INIT_SCRIPT)
|
||||
|
||||
page = await context.new_page()
|
||||
page.set_default_timeout(DEFAULT_PAGE_TIMEOUT_MS)
|
||||
|
||||
try:
|
||||
await page.goto(start_url, wait_until="domcontentloaded", timeout=GOTO_TIMEOUT_MS)
|
||||
except Exception as exc:
|
||||
raise RuntimeError(
|
||||
f"浏览器已启动,但未能打开目标首页 {start_url}。"
|
||||
"请检查网络、Chrome profile、代理或页面访问状态。"
|
||||
f"({exc})"
|
||||
) from exc
|
||||
|
||||
return pw, context, page
|
||||
except Exception:
|
||||
if context is not None:
|
||||
try:
|
||||
await context.close()
|
||||
except Exception:
|
||||
pass
|
||||
await pw.stop()
|
||||
raise
|
||||
|
||||
|
||||
async def close_browser_context(pw, context) -> None:
|
||||
try:
|
||||
if context is not None:
|
||||
await context.close()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
if pw is not None:
|
||||
await pw.stop()
|
||||
except Exception:
|
||||
pass
|
||||
Reference in New Issue
Block a user