release: v1.0.50 playwright stealth gemini
All checks were successful
技能自动化发布 / release (push) Successful in 34s
All checks were successful
技能自动化发布 / release (push) Successful in 34s
This commit is contained in:
2
SKILL.md
2
SKILL.md
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: 账号管理
|
name: 账号管理
|
||||||
description: 多平台多账号管理。管理各平台账号与Chrome Profile的对应关系,供publisher类Skill调用获取账号信息。
|
description: 多平台多账号管理。管理各平台账号与Chrome Profile的对应关系,供publisher类Skill调用获取账号信息。
|
||||||
version: 1.0.6
|
version: 1.0.50
|
||||||
author: 深圳匠厂科技有限公司
|
author: 深圳匠厂科技有限公司
|
||||||
metadata:
|
metadata:
|
||||||
openclaw:
|
openclaw:
|
||||||
|
|||||||
@@ -168,6 +168,13 @@ def _run_login_browser_session(
|
|||||||
if verbose_ui:
|
if verbose_ui:
|
||||||
print(f"正在为账号 [{target['name']}] 打开 {browser_name} …")
|
print(f"正在为账号 [{target['name']}] 打开 {browser_name} …")
|
||||||
print(f"访问地址:{url}")
|
print(f"访问地址:{url}")
|
||||||
|
if platform == "gemini":
|
||||||
|
print(
|
||||||
|
"Gemini / Google 登录:若提示「浏览器不安全」或「无法登录」,请关闭本窗口后,"
|
||||||
|
"用普通 Chrome 启动参数 --user-data-dir= 指向下面 profile 目录,在普通浏览器里完成"
|
||||||
|
" Google 登录后完全退出 Chrome,再执行本 login;详见 llm-manager Gemini 引擎说明。"
|
||||||
|
)
|
||||||
|
print(f" (本账号 profile 目录){profile_dir}")
|
||||||
print(
|
print(
|
||||||
"请在窗口内完成登录。系统根据页面是否仍出现「登录」等未登录控件判断;"
|
"请在窗口内完成登录。系统根据页面是否仍出现「登录」等未登录控件判断;"
|
||||||
"成功后自动关闭窗口并写入状态(无需手动关浏览器)。"
|
"成功后自动关闭窗口并写入状态(无需手动关浏览器)。"
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ _scripts_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
if _scripts_dir not in sys.path:
|
if _scripts_dir not in sys.path:
|
||||||
sys.path.insert(0, _scripts_dir)
|
sys.path.insert(0, _scripts_dir)
|
||||||
|
|
||||||
|
from util.playwright_stealth import (
|
||||||
|
STEALTH_INIT_SCRIPT,
|
||||||
|
persistent_context_launch_parts,
|
||||||
|
stealth_enabled,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _is_context_closed_error(ex: BaseException) -> bool:
|
def _is_context_closed_error(ex: BaseException) -> bool:
|
||||||
s = str(ex).lower()
|
s = str(ex).lower()
|
||||||
@@ -224,13 +230,19 @@ def _run_login_child(c: dict) -> None:
|
|||||||
|
|
||||||
with sync_playwright() as p:
|
with sync_playwright() as p:
|
||||||
try:
|
try:
|
||||||
ctx = p.chromium.launch_persistent_context(
|
args, ignore_automation = persistent_context_launch_parts()
|
||||||
|
lc_kw = dict(
|
||||||
user_data_dir=profile_dir,
|
user_data_dir=profile_dir,
|
||||||
headless=False,
|
headless=False,
|
||||||
channel=c["channel"],
|
channel=c["channel"],
|
||||||
no_viewport=True,
|
no_viewport=True,
|
||||||
args=["--start-maximized"],
|
args=args,
|
||||||
)
|
)
|
||||||
|
if ignore_automation is not None:
|
||||||
|
lc_kw["ignore_default_args"] = ignore_automation
|
||||||
|
ctx = p.chromium.launch_persistent_context(**lc_kw)
|
||||||
|
if stealth_enabled():
|
||||||
|
ctx.add_init_script(STEALTH_INIT_SCRIPT)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if _is_context_closed_error(e):
|
if _is_context_closed_error(e):
|
||||||
end_reason = "user_closed"
|
end_reason = "user_closed"
|
||||||
|
|||||||
@@ -4,18 +4,30 @@ import sys
|
|||||||
|
|
||||||
from playwright.sync_api import sync_playwright
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
from util.playwright_stealth import (
|
||||||
|
STEALTH_INIT_SCRIPT,
|
||||||
|
persistent_context_launch_parts,
|
||||||
|
stealth_enabled,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
with open(sys.argv[1], encoding="utf-8") as f:
|
with open(sys.argv[1], encoding="utf-8") as f:
|
||||||
c = json.load(f)
|
c = json.load(f)
|
||||||
with sync_playwright() as p:
|
with sync_playwright() as p:
|
||||||
ctx = p.chromium.launch_persistent_context(
|
args, ignore_automation = persistent_context_launch_parts()
|
||||||
|
lc_kw = dict(
|
||||||
user_data_dir=c["profile_dir"],
|
user_data_dir=c["profile_dir"],
|
||||||
headless=False,
|
headless=False,
|
||||||
channel=c["channel"],
|
channel=c["channel"],
|
||||||
no_viewport=True,
|
no_viewport=True,
|
||||||
args=["--start-maximized"],
|
args=args,
|
||||||
)
|
)
|
||||||
|
if ignore_automation is not None:
|
||||||
|
lc_kw["ignore_default_args"] = ignore_automation
|
||||||
|
ctx = p.chromium.launch_persistent_context(**lc_kw)
|
||||||
|
if stealth_enabled():
|
||||||
|
ctx.add_init_script(STEALTH_INIT_SCRIPT)
|
||||||
try:
|
try:
|
||||||
page = ctx.pages[0] if ctx.pages else ctx.new_page()
|
page = ctx.pages[0] if ctx.pages else ctx.new_page()
|
||||||
page.goto(c["url"], wait_until="domcontentloaded", timeout=60000)
|
page.goto(c["url"], wait_until="domcontentloaded", timeout=60000)
|
||||||
|
|||||||
@@ -62,6 +62,12 @@ PLATFORMS = {
|
|||||||
"prefix": "元宝",
|
"prefix": "元宝",
|
||||||
"aliases": ["元宝"],
|
"aliases": ["元宝"],
|
||||||
},
|
},
|
||||||
|
"gemini": {
|
||||||
|
"url": "https://gemini.google.com",
|
||||||
|
"label": "Gemini",
|
||||||
|
"prefix": "Gemini",
|
||||||
|
"aliases": ["谷歌Gemini", "Google Gemini", "google gemini", "Bard"],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
# 未登录页共性:主行动点含「登录」——submit 按钮、Element 主按钮、Semi 文案、标题、通栏主按钮等,Playwright :has-text 可覆盖多数站点。
|
# 未登录页共性:主行动点含「登录」——submit 按钮、Element 主按钮、Semi 文案、标题、通栏主按钮等,Playwright :has-text 可覆盖多数站点。
|
||||||
|
|||||||
40
scripts/util/playwright_stealth.py
Normal file
40
scripts/util/playwright_stealth.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
"""
|
||||||
|
淡化 Playwright 启动时的自动化指纹,减轻 Google 账号页「此浏览器或应用可能不安全」类拦截。
|
||||||
|
|
||||||
|
关闭:环境变量 OPENCLAW_PLAYWRIGHT_STEALTH=0(或 false/off/no)。
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
STEALTH_INIT_SCRIPT = """
|
||||||
|
(() => {
|
||||||
|
try {
|
||||||
|
Object.defineProperty(navigator, "webdriver", { get: () => undefined });
|
||||||
|
} catch (e) {}
|
||||||
|
})();
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def stealth_enabled() -> bool:
|
||||||
|
v = (os.environ.get("OPENCLAW_PLAYWRIGHT_STEALTH") or "1").strip().lower()
|
||||||
|
return v not in ("0", "false", "no", "off")
|
||||||
|
|
||||||
|
|
||||||
|
def persistent_context_launch_parts(
|
||||||
|
*,
|
||||||
|
extra_args: list[str] | None = None,
|
||||||
|
) -> tuple[list[str], list[str] | None]:
|
||||||
|
"""
|
||||||
|
返回 (args, ignore_default_args)。
|
||||||
|
ignore_default_args 为 None 时不应传给 launch_persistent_context。
|
||||||
|
"""
|
||||||
|
args = ["--start-maximized"]
|
||||||
|
if extra_args:
|
||||||
|
args = args + list(extra_args)
|
||||||
|
if not stealth_enabled():
|
||||||
|
return args, None
|
||||||
|
if "--disable-blink-features=AutomationControlled" not in args:
|
||||||
|
args.append("--disable-blink-features=AutomationControlled")
|
||||||
|
return args, ["--enable-automation"]
|
||||||
Reference in New Issue
Block a user