Files
verify-invoice-default/scripts/service/rpa/browser_session.py
chenfuqiang c5103e2650
All checks were successful
技能自动化发布 / release (push) Successful in 9s
chore: auto release commit (2026-09-14 15:11:41)
2026-09-14 15:11:41 +08:00

104 lines
3.3 KiB
Python
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.
"""浏览器会话管理:基于skill-template的real_browser_rpa示例。"""
from __future__ import annotations
import logging
import os
import random
from typing import Any, Optional, Tuple
from jiangchang_skill_core import config
from jiangchang_skill_core.activity import interruptible_sleep
from jiangchang_skill_core.rpa import launch_persistent_browser, poll_until
logger = logging.getLogger(__name__)
# 目标网站配置
TARGET_URL = "https://sandbox.jc2009.com/industries/campus/smartcampus/app/finance/invoice-precheck"
LOGIN_URL = "https://sandbox.jc2009.com/login"
async def start_browser_session(
profile_dir: str,
headless: bool = False,
) -> Tuple[Any, Any, Any]:
"""启动浏览器会话。
Args:
profile_dir: 浏览器配置目录
headless: 是否无头模式(生产必须为False)
Returns:
(playwright, context, page) 三元组
Raises:
RuntimeError: 浏览器启动失败
"""
if not profile_dir:
raise RuntimeError("ERROR:MISSING_BROWSER 缺少浏览器配置目录")
# 确保有头模式(生产要求)
if headless:
logger.warning("生产环境强制使用有头模式")
headless = False
try:
# 启动持久化浏览器上下文
pw, context = await launch_persistent_browser(
user_data_dir=profile_dir,
headless=headless,
args=[
"--start-maximized",
"--disable-blink-features=AutomationControlled",
],
)
# 创建新页面
page = await context.new_page()
# 导航到目标页面
await page.goto(TARGET_URL, wait_until="domcontentloaded", timeout=60000)
logger.info("browser_started url=%s profile_dir=%s", page.url, profile_dir)
return pw, context, page
except Exception as e:
logger.error("browser_start_failed error=%s", str(e))
raise RuntimeError(f"ERROR:MISSING_BROWSER 浏览器启动失败: {str(e)}")
async def close_browser_context(pw: Any, context: Any) -> None:
"""安全关闭浏览器上下文。"""
try:
if context:
await context.close()
if pw:
await pw.stop()
except Exception as e:
logger.warning("browser_close_error error=%s", str(e))
async def wait_for_page_ready(page: Any, timeout_sec: float = 30.0) -> bool:
"""等待页面加载完成。"""
async def _check_ready():
try:
# 检查页面是否加载完成
if await page.evaluate("document.readyState") == "complete":
return True
# 检查是否有加载指示器
loading_selectors = [".loading", ".spinner", "[data-loading]"]
for sel in loading_selectors:
if await page.locator(sel).count() > 0:
return False
return True
except Exception:
return False
result = await poll_until(_check_ready, timeout_sec=timeout_sec, interval_sec=0.5)
return result.ok
async def random_delay(min_sec: float = 1.0, max_sec: float = 3.0) -> None:
"""随机延迟,模拟人类操作节奏。"""
delay = random.uniform(min_sec, max_sec)
await interruptible_sleep(delay)