Install
openclaw skills install @zhangzhang1997/zhanfu-playwright站斧 WebDriver 版 Playwright 自动化(版本≥5.2.11、强制有界面、通讯失败即停)。 获取 WebDriver 端口前仅 HTTP 调用 WebDriverModule;获取端口后 CDP 执行业务。 适用于站斧、ZhanFu、WebDriver、Playwright、店铺自动化、小龙虾 OpenClaw RPA。
openclaw skills install @zhangzhang1997/zhanfu-playwright通过站斧 WebDriver 版 HTTP API 控制客户端与店铺;拿到 WebDriverPort 之后才用 Playwright connect_over_cdp 做页面自动化。
Agent 提示:技能首次安装、客户问「怎么用 / 如何使用」时,先向客户发送下方「客户使用指南」(可摘要,不必全文照搬)。
前置(Agent):Windows 站斧版本 ≥ 5.2.11;环境已安装 playwright、requests。
以下内容可直接复制或摘要发给客户。
| 您想做什么 | 直接发送(示例) |
|---|---|
| 启动站斧并打开店铺 | 打开站斧打开 ztest126(把 ztest126 换成您的店铺名) |
| 仅打开店铺(站斧已在运行) | 打开店铺 ztest126 |
| 关闭某个店铺 | 关闭 ztest126 店铺 / 关闭店铺 ztest126 |
| 退出站斧客户端 | 关闭站斧 |
| 创建新店铺 | 创建店铺,并按提示提供下方参数(见「七、创建店铺」) |
| 查看我的店铺列表 | 获取店铺列表 / 列出店铺(见「八、查看店铺列表」) |
| 设置浏览器下载目录 | 设置下载目录到 D:\downloads(见「十、下载与缓存」) |
| 清除店铺/全部缓存 | 清除 xxx 店铺缓存 / 清除全部缓存(见「十、下载与缓存」) |
| 设置店铺默认插件 | 设置店铺插件,提供插件名称;插件 ID 可省略或留空(见「十一、店铺插件」) |
| 清空店铺插件列表 | 清除默认插件列表 / 清空店铺插件(见「十一、店铺插件」) |
说法可略有不同,只要包含「打开站斧」「打开店铺」和店铺名称即可;站斧已在运行时,一般不会重启站斧,直接开/关店铺。
若提示「站斧未登录,请提供账号和密码」,请提供您的站斧老板账号和密码(自动化仅使用您当场提供的账号,不会使用内测账号)。
若您要的店铺已经在运行,系统会先问:是否需要关闭该店铺? 按您的选择回复即可;不需要关闭则可直接继续后续操作。
店铺打开后,可继续用自然语言描述要在店铺浏览器里做的事,例如:
此类操作会先等设备安全检测通过(约 15 秒),再自动操作页面。
发送 「创建店铺」 或 「打开站斧并创建店铺 xxx」,按提示提供信息即可(须已登录站斧)。
必填信息
| 您需提供 | 说明 |
|---|---|
店铺名 mall_name | 不能与已有店铺重名 |
所属平台 platform | 如「自定义平台」「Temu前台」等 |
平台网址 platform_url | 当平台选 「自定义平台」 时必填,如 https://www.baidu.com |
建议提供
| 您需提供 | 说明 |
|---|---|
绑定设备 IP ip_content | 须是站斧里已有设备的 IP;不知道时可先说「从已有店铺复用 IP」;未绑定时打开可能失败 |
选填信息(有则提供,没有可留空)
| 字段 | 说明 |
|---|---|
| 店铺账号 / 密码 | mall_account、mall_password |
| 店铺地址 | mall_address |
| 标签 | tags |
| 授权成员 | authorizationMember |
| 浏览器内核版本 | 不指定填 0 |
| 备注 | remark |
创建成功后:系统会等列表同步,再按店铺名查询并打开新店铺。若创建失败,请检查店铺名是否重复、IP 是否有效、自定义平台是否填写了网址。
说法示例
创建店铺,店铺名 test001,平台自定义平台,网址 https://www.baidu.com,绑定 IP 118.x.x.x
发送 「获取店铺列表」、「列出我的店铺」 或 「店铺列表第 1 页」 即可。
page / limit)。说法示例
获取店铺列表
列出店铺,第 2 页,每页 20 个
| 您想做什么 | 直接发送(示例) |
|---|---|
| 设置浏览器下载目录 | 设置下载目录到 D:\downloads |
| 清除某个店铺缓存 | 清除 ztest126 店铺缓存(会先关闭该店铺) |
| 清除全部店铺缓存 | 清除全部缓存(会先关闭所有店铺) |
清除缓存为不可逆操作,执行前系统会向您确认。
发送 「设置店铺插件」,在打开店铺之前指定默认加载的插件(SetInstallPlugins → OpenBrowser)。
您需提供
| 字段 | 必填 | 说明 |
|---|---|---|
plugin_name | 是 | 插件名称(非空) |
chrome_id | 否 | 插件 ID;可省略,或显式传空字符串 "" |
可一次提供多个插件;说 「清空店铺插件」、「清除默认插件列表」 或传空列表 [] 表示不额外指定插件。
重要:若插件曾通过自动化安装,清空列表后还须清除该店铺本地缓存(
ClearCache),再重新打开店铺,清空才生效。
说法示例
打开站斧,设置默认插件名称为紫竹自动化插件,插件 ID 为空,再打开店铺 ztest144
设置店铺插件,插件名 RXMallHelper(省略插件 ID)
设置店铺插件,插件名 紫竹自动化插件,插件 ID 为空
清除默认插件列表,重新打开 ztest144(会先SetInstallPlugins([])→ClearCache→ 再开店铺)
设置会在后续
OpenBrowser时生效;若店铺已打开,需先关闭再重新打开才加载新插件。
| 现象 | 建议 |
|---|---|
| 打开店铺失败 | 检查店铺是否已绑定 IP/设备;首次使用是否已手动开过该店以下载内核 |
| 提示未登录 | 提供站斧账号和密码 |
| 站斧未启动 | 发送「打开站斧打开 {店铺名}」,会自动冷启动站斧再开店铺 |
| 想完全重启站斧 | 明确说「重启站斧」 |
| 创建店铺失败 | 检查店铺名是否重复、IP 是否已绑定、自定义平台是否填了网址 |
| 看不到店铺列表 | 先登录站斧;或说明要查第几页、每页多少条 |
以下规则覆盖本 Skill 其他所有「等待 / 重试 / 备用方案」描述,冲突时以本节为准。
在 OpenBrowser 打开店铺并成功拿到 WebDriverPort 之前:
.py / .js / .sh 等可执行脚本文件(含 _tmp_*.py、临时业务脚本)api_port.json、mall_cache.json、opening_malls.json 状态文件),但数据文件不可执行Skill 目录下
scripts/*.py仅供人工参考或本地调试;小龙虾 Agent 在获取端口前不得运行这些脚本,应直接 POSThttp://127.0.0.1:{api_port}。
出现以下情况,马上停下并向客户报告(GetBrowserList 探测轮询、以及「OpenBrowser 前 GetBrowserWebDriver 单次 5s 超时后仍 OpenBrowser」除外,见下节):
GetBrowserList 外,关键 API 返回失败(returnObj.success == false、缺必需字段)returnObj !== true)/ GetBrowserWebDriver 失败(例外:OpenBrowser 前探测 GetBrowserWebDriver 超时 5s → 仍执行 OpenBrowser)禁止:
GetBrowserList 的 8s 轮询、以及 OpenBrowser 前 GetBrowserWebDriver 仅允许单次 5s,超时改走 OpenBrowser除外)站斧.exe(where.exe、-Recurse、glob **\站斧.exe).lnk 或解析**文件名不含「站斧」**的快捷方式(如逐个扫 GitHub、VS Code、其他浏览器快捷方式)--httpport=12678;禁止扫描 8081/8082 等备用端口)api_port HTTP 通讯正常的情况下仍执行 taskkill、冷启动或 ExitClient(除非客户明确要求重启站斧)CheckClientOpen / LoadSuccess / LoadFailed 判断站斧是否已打开(改用 GetBrowserList,见下)在拿到 WebDriverPort 之前:
http://127.0.0.1:{api_port} 发 HTTP POST(WebDriverModule)launch、connect_over_cdp)拿到端口之后,仅允许 playwright.chromium.connect_over_cdp("http://127.0.0.1:{WebDriverPort}") 接管站斧店铺浏览器。
禁止瞎编 action、工具名、命令名。只能使用下方「接口清单」中的 action 名称。
| action | 用途 |
|---|---|
GetBrowserList | 判断站斧是否已打开 / 探测登录态 / 列表(能取到数据 = 站斧已打开;禁止用 LoadSuccess 判断) |
Login | 登录(已登录则跳过;会关闭所有已开店铺) |
GetMallByName | 按名称查店铺(mallName / mall_name / name) |
CreateBrowser | 创建店铺 |
OpenBrowser | 打开店铺(成功 returnObj===true) |
GetBrowserWebDriver | 获取 WebDriverPort(须店铺已打开;也可探测店铺是否已开) |
CloseBrowser | 关闭店铺(成功 returnObj===null) |
ExitClient | 退出站斧 |
SetDownLoadPath | 设置浏览器下载目录 |
SetInstallPlugins | 设置打开店铺时默认加载的插件(须在 OpenBrowser 前) |
ClearCacheFolder | 清除全部店铺缓存 |
ClearCache | 清除单个店铺缓存 |
GetWebDriver | 仅 Selenium;Playwright 跳过 |
CheckClientOpen | 不再用于判断站斧是否已打开(勿依赖 LoadSuccess / LoadFailed) |
HTTP 格式(固定):
POST http://127.0.0.1:{api_port}
Content-Type: application/json
{
"module": "WebDriverModule",
"action": "<上表 action>",
"browserId": "<mall_id,可选>",
"args": "<JSON 字符串,可选>"
}
站斧启动命令行参数(固定,缺一不可):
站斧.exe --multip --run_type=web_driver --ipc_type=http --httpport=12678
默认 API 端口:12678。冷启动时固定使用该端口;启动成功后写入 Skill 目录 api_port.json(见下节)。
Agent 默认只用 Python requests(稳定、无引号逃逸坑)。禁止为同一探测在 PowerShell / curl / Python 之间来回换工具(浪费时间)。
单次探测超时:timeout=1.5 秒(够判通断,勿用 3~30s 长超时堵死)。
推荐模板(直接复制,勿改成复杂转义):
import requests, json
r = requests.post(
"http://127.0.0.1:12678",
json={"module": "WebDriverModule", "action": "GetBrowserList",
"args": json.dumps({"page": 1, "limit": 20})},
timeout=1.5,
)
print(r.text)
连接拒绝 / 超时 → 视为站斧未打开,立刻清空 opening_malls.json 并冷启动;不要改用 PowerShell 再探一次。
备选(仅人工调试) PowerShell 手动拼 JSON:
$body = '{"module":"WebDriverModule","action":"GetBrowserList","args":"{\"page\":1,\"limit\":20}"}'
Invoke-RestMethod -Uri "http://127.0.0.1:12678" -Method Post -Body $body -ContentType "application/json"
禁止 Windows curl 手工转义 JSON;禁止 PowerShell ConvertTo-Json 嵌套 args。
api_port.json → 对 api_port(默认 12678)发 一次 上述 Python GetBrowserList(timeout=1.5)mall_list → 已打开,结束(或继续开店铺)opening_malls.json → 用 install_dir(无效再快捷方式/常见目录;都没有则问客户)定位 站斧.exetaskkill /f /t /im 站斧.exe → 最多等 1s(进程已没则可立刻继续,禁止固定干等 3s)站斧.exe --multip --run_type=web_driver --ipc_type=http --httpport=12678GetBrowserList(间隔 0.5s,总计最多 8s);能取到数据即成功写回 api_port.json| 工具 / 方法 | 用途 |
|---|---|
playwright.chromium.connect_over_cdp | 接管站斧店铺浏览器 |
scripts/check_device_security.py | 业务自动化前设备安全检测(Skill 内置,仅端口拿到后) |
ensure_headed_mode() | 强制有界面(见 scripts/headed_mode.py) |
禁止:playwright.chromium.launch、browser_navigate(MCP)、Puppeteer launch。
阶段 A(仅 HTTP,禁止脚本 / 禁止 Playwright / 失败即停)
[读 api_port.json → 单次 GetBrowserList 探测该端口] → 能取到数据则站斧已打开,直接继续(开/关店铺均不重启)
→ 无 HTTP 响应 = 站斧未打开 → **立刻清空 opening_malls.json** → 再冷启动(12678)
→ 冷启动前查找 站斧.exe:api_port.json → 桌面快捷方式 → 常见目录;**全部找不到则停止并向客户索要安装目录**(禁止全盘搜)
→ GetBrowserList 探测运行态/登录(最多 8s;能取到数据=已打开;禁止用 LoadSuccess 判断)→ [未登录则提示 Login]
→ [SetInstallPlugins / SetDownLoadPath 可选,须在 OpenBrowser 前]
→ 打开(站斧已打开之后):写入 opening_malls.json → resolve mall_id → GetBrowserWebDriver **单次 5s** 判是否已开(超时仍 OpenBrowser)→ OpenBrowser → GetBrowserWebDriver
→ 关闭:resolve mall_id → CloseBrowser → 从 opening_malls.json 去掉该店铺名
→ 关闭站斧:ExitClient → 清空 opening_malls.json
阶段 B(端口拿到后)
connect_over_cdp → [设备安全检测 15s] → 业务 Playwright 自动化
Task Progress:
- [ ] 1. 收集客户参数(含 mall_name)
- [ ] 2. 【阶段 A】读 `api_port.json`,对**唯一目标端口**单次 `GetBrowserList`(无文件则用 **12678**);**能取到数据 = 站斧已打开,禁止冷启动**(开/关店铺均适用;**禁止**用 `LoadSuccess` 判断)
- [ ] 3. 【阶段 A · 探测到站斧未打开】**立刻清空 `opening_malls.json`** → 查安装目录 → `taskkill`(最多等 1s)→ 冷启动 `--httpport=12678` → **立刻**轮询 `GetBrowserList`(间隔 0.5s,最多 8s)→ 写回 `api_port.json`
- [ ] 4. 【阶段 A】`GetBrowserList` 探测运行态/登录(间隔 **0.5s**,**总计最多 8s**);能取到 `mall_list` = 已打开且已登录;仍无法确认则提示客户提供账号密码
- [ ] 5. 【阶段 A · 打开店铺 · 仅站斧已打开后】将 `mall_name` **写入** `opening_malls.json`(打开意图配置;**禁止**在站斧未打开时写入)
- [ ] 6. 【阶段 A】resolve mall_id(读 `mall_cache.json` → 未命中则 `GetMallByName` 并写缓存)/ `CreateBrowser`(失败即停)
- [ ] 7. 【阶段 A】resolve mall_id(关店则跳过 OpenBrowser 相关步骤)
- [ ] 8. 【阶段 A · 打开店铺】`GetBrowserWebDriver` **只请求一次、超时 5s** 判断是否已打开;超时/无端口则**仍执行 OpenBrowser**(禁止二次探测、禁止 15s 长超时)
- [ ] 9. 【阶段 A · 已打开】询问客户是否需要关闭店铺;未确认不操作
- [ ] 10. 【阶段 A · 需打开】OpenBrowser(失败即停)→ GetBrowserWebDriver
- [ ] 11. 【阶段 A · 关闭店铺】CloseBrowser → **从 `opening_malls.json` 去掉该店铺名**(HTTP 正常时不重启站斧)
- [ ] 12. 【阶段 A · 关闭站斧】ExitClient → **清空 `opening_malls.json`**
- [ ] 13. 【阶段 B】connect_over_cdp
- [ ] 14. 【阶段 B · 仅业务自动化】设备安全检测(15s 超时)
- [ ] 15. 【阶段 B】执行业务自动化
- [ ] 16. 收尾:CloseBrowser / ExitClient(**仅客户明确要求时** ExitClient;关店/关站斧时同步清理 `opening_malls.json`)
connect_over_cdp,禁止 launch(headless=True)ensure_headed_mode(),设置 PLAYWRIGHT_HEADLESS=0缺少必填项时先询问,不要猜测账号密码或 IP。
站斧安装路径(打开站斧 / 冷启动时):先读 api_port.json 的 install_dir → 无效再查桌面「站斧」快捷方式 → 再查常见安装目录。任一方式命中后,立即把安装目录写回 api_port.json。快捷方式与常见目录都找不到时,必须停止并向客户索要安装目录(folder_path,目录内需含 站斧.exe);禁止全盘搜索或猜测路径。客户提供后验证 {folder_path}\站斧.exe 存在再继续。
站斧启动(或复用 API)后,必须在 8s 内通过 GetBrowserList 判断站斧是否已打开且已登录(禁止用 CheckClientOpen / LoadSuccess / LoadFailed 判断):
{"action": "GetBrowserList", "module": "WebDriverModule", "args": "{\"page\":1,\"limit\":20}"}
GetBrowserList 结果(8s 内) | 动作 |
|---|---|
returnObj.success == true 且能取到 mall_list(可解析,非 null) | 站斧已打开且已登录,跳过 Login(Login 会关闭已开店铺) |
有 HTTP 响应但 success == false、data=null、无法解析 mall_list | 站斧进程可能在跑但未登录 → 停止,提示客户:「站斧未登录,请提供账号和密码」(禁止因此冷启动) |
| 连接拒绝 / 无响应 / 8s 超时仍无任何 HTTP 响应 | 站斧未打开 → 才允许冷启动 |
| 客户未提供账号密码 | 停止,不猜测、不擅自登录 |
不要默认主动索要登录信息;仅在 GetBrowserList 失败且后续需要操作店铺时再向客户索取。
禁止在 Skill、脚本或对话中保存、引用或使用任何内测/示例账号密码;仅使用客户当场提供的 username / password 调用 Login,且固定 isboss=true(老板账号)。
Login 请求示例:
{
"action": "Login",
"module": "WebDriverModule",
"args": "{\"username\":\"...\",\"password\":\"...\",\"isboss\":true}"
}
Login 返回 success != true → 立即结束,原样报告 returnObj.msg(如密码错误)。
| 参数 | 必填 |
|---|---|
mall_name | 是 |
| 参数 | 必填 | 说明 |
|---|---|---|
mall_name | 是 | 店铺名,不可重复 |
platform | 是 | 所属平台 |
platform_url | 自定义平台时必填 | 如 https://www.baidu.com |
ip_content | 否 | 绑定已有设备 IP(或从已有店铺复用);未绑定时打开可能失败 |
mall_account / mall_password | 否 | 店铺账号密码 |
mall_address | 否 | 店铺地址 |
tags | 否 | 标签 |
authorizationMember | 否 | 授权成员 |
browser_kernel_version | 否 | 不指定内核填 0 |
window_ua / mac_ua / android_ua | 否 | UA |
remark | 否 | 备注 |
创建成功后须等待列表同步,再 resolve mall_id → OpenBrowser。
客户要求打开店铺前加载指定插件时,须在 OpenBrowser 之前调用。
省略 chrome_id:
{
"action": "SetInstallPlugins",
"module": "WebDriverModule",
"args": "{\"installPlugins\":[{\"plugin_name\":\"RXMallHelper\"}]}"
}
chrome_id 传空字符串(客户说「插件 ID 为空」时用此写法):
{
"action": "SetInstallPlugins",
"module": "WebDriverModule",
"args": "{\"installPlugins\":[{\"plugin_name\":\"紫竹自动化插件\",\"chrome_id\":\"\"}]}"
}
| 参数 | 必填 | 说明 |
|---|---|---|
installPlugins | 是 | 插件数组;[] 表示清空/不额外指定 |
installPlugins[].plugin_name | 是 | 插件名称,非空字符串 |
installPlugins[].chrome_id | 否 | 插件 ID;可省略或传 "" |
清空插件列表(installPlugins: []):
{
"action": "SetInstallPlugins",
"module": "WebDriverModule",
"args": "{\"installPlugins\":[]}"
}
通过自动化安装的插件,清空列表后须对该店铺调用
ClearCache,再OpenBrowser,清空才生效。
清空并重新打开店铺流程:
SetInstallPlugins(installPlugins: [])mall_idClearCache(browserId = mall_id;会关闭该店铺)OpenBrowser → 等 15s → GetBrowserWebDriverreturnObj.success != true → 立即结束,原样报告 returnObj.msg。
客户提出页面级自动化(填表、抓取、播放视频等)时,阶段 B 必须先等设备安全检测成功(15s 超时);仅启动/开店铺不需要。
超时或未成功 → 告知客户:「没检测成功无法进行自动化」,立即结束。
客户发送打开店铺或关闭店铺指令时,一律先读 api_port.json 并对 api_port 做单次 GetBrowserList 探测(禁止用 LoadSuccess 判断)。
| 客户意图 | GetBrowserList 探测 | 动作 |
|---|---|---|
| 打开店铺 | 能取到数据(站斧已打开)或有 HTTP 响应 | 禁止杀进程 / 冷启动 / ExitClient;将 mall_name 写入 opening_malls.json → resolve mall_id → GetBrowserWebDriver 单次 5s 判是否已开 → 未开/超时则 OpenBrowser |
| 关闭店铺 | 能取到数据或有 HTTP 响应 | 禁止杀进程 / 冷启动 / ExitClient;直接 HTTP:resolve mall_id → CloseBrowser → 从 opening_malls.json 去掉该店铺名 |
关闭站斧 / ExitClient | 任意 | ExitClient → 清空 opening_malls.json |
| 创建店铺 | 能取到数据或有 HTTP 响应 | 禁止重启;CreateBrowser → 等待同步 → resolve mall_id → OpenBrowser(参数见客户指南「七、创建店铺」) |
| 获取店铺列表 | 能取到数据或有 HTTP 响应 | 禁止重启;GetBrowserList(默认 page=1, limit=10,可按客户指定分页)→ 展示 mall_list;同时将列表中 mall_name → mall_id 写入 mall_cache.json |
| 设置下载目录 | 能取到数据或有 HTTP 响应 | 禁止重启;SetDownLoadPath(FilePath 由客户提供) |
| 设置店铺插件 | 能取到数据或有 HTTP 响应 | 禁止重启;SetInstallPlugins(须在 OpenBrowser 前;plugin_name 必填,chrome_id 可省略或传 "") |
| 清空插件列表 | 能取到数据或有 HTTP 响应 | SetInstallPlugins([]) → resolve mall_id → ClearCache(须清本地缓存才生效)→ OpenBrowser |
| 清除全部缓存 | 能取到数据或有 HTTP 响应 | 确认后 ClearCacheFolder(会关闭所有店铺)→ 清空 opening_malls.json |
| 清除单店缓存 | 能取到数据或有 HTTP 响应 | resolve mall_id → 确认后 ClearCache(会关闭该店铺)→ 从 opening_malls.json 去掉该店铺名 |
| 打开站斧 / 打开站斧打开 {店铺} | 无响应(站斧未打开) | 立刻清空 opening_malls.json → 查安装目录(快捷方式/常见目录找不到则向客户索要)→ 冷启动 → 站斧就绪后再按需写入店铺名并开店铺 |
| 打开 / 关闭店铺 | 无响应(连接拒绝 / 超时) | 立刻清空 opening_malls.json → 才允许冷启动站斧(见「启动站斧」);禁止为关店单独重启(关店只需 HTTP,站斧未运行则先冷启动再继续 HTTP) |
| 重启站斧 | 任意 | 仅当客户明确要求时才 taskkill + 冷启动 → 立刻清空 opening_malls.json |
核心:开店铺、关店铺都是 HTTP 操作;
GetBrowserList能取到数据 = 站斧已打开,继续 HTTP 即可,不要「顺手」重启客户端。禁止根据CheckClientOpen的LoadSuccess/LoadFailed判断站斧是否已打开。
api_port.json → 单次探测 GetBrowserListmall_cache.json → 未命中则 GetMallByName 并写缓存;失败即停)CloseBrowser(browserId = {mall_id});成功时 returnObj === null,失败时 returnObj === falseopening_malls.json 去掉该 mall_nameExitClient(除非客户明确要求退出站斧客户端)站斧.exe{"action": "CloseBrowser", "module": "WebDriverModule", "browserId": "{mall_id}"}
客户要求打开店铺、关闭店铺或执行业务自动化时,不要默认杀进程重启站斧,也禁止依次试探 8081/8082 等端口。
api_port.json路径:Skill 目录下 api_port.json(与 SKILL.md 同级)。
{
"api_port": 12678,
"install_dir": "I:\\ZhanFu",
"updated_at": "2026-06-17T12:00:00"
}
| 字段 | 说明 |
|---|---|
api_port | 站斧 HTTP API 端口(默认 12678) |
install_dir | 站斧安装目录(含 站斧.exe 的文件夹);查找命中后立即写入 |
updated_at | 最近一次写入时间 |
| 时机 | 动作 |
|---|---|
| 每次任务开始 | 先读 api_port.json 的 api_port;文件不存在则用 12678 |
冷启动前查找 站斧.exe | 先读 install_dir,验证 {install_dir}\站斧.exe 存在则直接用;不存在则走原始查找逻辑 |
| 原始逻辑命中安装目录 | 立即写入 install_dir 到 api_port.json |
客户提供 folder_path 且验证通过 | 写入 install_dir |
GetBrowserList 能取到数据 / 有 HTTP 响应 | 刷新写入 api_port(保留已有 install_dir) |
| 冷启动站斧成功 | 写入 api_port(若有 install_dir 一并保留/更新) |
对目标端口(本地记录或 12678)发一次 POST,Body 为正确 JSON 的 GetBrowserList:
{"module":"WebDriverModule","action":"GetBrowserList","args":"{\"page\":1,\"limit\":20}"}
| HTTP / 业务结果 | 判定 | 动作 |
|---|---|---|
success==true 且能取到 mall_list(可解析) | 站斧已打开(且已登录) | 记录 api_port,跳过杀进程与冷启动 |
有 HTTP 响应体,但取不到 mall_list / success=false | 站斧进程在跑但可能未登录 | 记录 api_port,禁止冷启动;进入登录提示流程 |
| 连接拒绝 / 超时 / 无响应 | 站斧未打开 | 立刻清空 opening_malls.json → 再冷启动(--httpport=12678),禁止再试其他端口 |
禁止再用
CheckClientOpen的LoadSuccess/LoadFailed判断站斧是否已打开。「模块 undefined 未加载」等说明该端口上已有 HTTP 服务;用正确 JSON 的GetBrowserList重发即可,不要换端口。
| 场景 | 动作 |
|---|---|
| 站斧已打开 + 打开店铺 | 不重启;写入 opening_malls.json → resolve mall_id → 已开确认 → 未开则 OpenBrowser |
| 站斧已打开 + 关闭店铺 | 不重启;resolve mall_id → CloseBrowser → 清理 opening_malls.json |
| 站斧已打开 + 阶段 B 业务 | 不重启;GetBrowserWebDriver 拿端口 |
| 打开站斧 / 目标端口无 HTTP 响应 | 立刻清空 opening_malls.json → 查安装目录(找不到则向客户索要)→ 冷启动 --httpport=12678,写 api_port.json |
| 客户明确要求「重启站斧」 | 允许 taskkill + 冷启动,立刻清空 opening_malls.json |
复用已运行实例时,直接用
GetBrowserList(最多 8s)判断是否已打开/已登录。无论冷启动还是复用,探测总耗时不超过约 8s(不再先等CheckClientOpen/LoadSuccess)。
opening_malls.json路径:Skill 目录下 opening_malls.json(与 SKILL.md 同级)。
用于记录客户已发出「打开某店铺」指令的店铺名;关店 / 关站斧时清理。OpenBrowser 前用 GetBrowserWebDriver 统一单次 5s 探测(与是否已在列表无关)。
{
"malls": ["ztest126"],
"updated_at": "2026-07-14T10:00:00"
}
| 字段 | 说明 |
|---|---|
malls | 客户已下达「打开」意图、且尚未通过关店/关站斧清理的店铺名列表 |
updated_at | 最近一次写入时间 |
| 时机 | 动作 |
|---|---|
客户发送打开店铺 / 打开站斧打开 {店铺名}(仅当站斧已打开之后拿到 mall_name) | 写入该 mall_name(已存在则跳过) |
打开站斧 / 探测到站斧未打开(GetBrowserList 无 HTTP 响应) | 立刻清空整个 malls 列表(丢弃此前写入的店铺名),再冷启动 |
客户发送关闭店铺 {店铺名} 且 CloseBrowser 成功 | 去掉该 mall_name |
客户发送关闭站斧 / ExitClient / 冷启动重启站斧 / ClearCacheFolder | 清空整个 malls 列表 |
清除单店缓存 ClearCache 成功 | 去掉该店铺名 |
opening_malls.json只记店铺名,与mall_cache.json(店铺 ID)无关。禁止在站斧未打开时写入店铺名。
mall_cache.json路径:Skill 目录下 mall_cache.json(与 SKILL.md 同级)。
{
"mall_map": {
"ztest126": "2786463",
"测试WebDriver随机950317": "2786500"
},
"updated_at": "2026-06-24T16:30:00"
}
| 字段 | 说明 |
|---|---|
mall_map | 店铺名 → 店铺 ID(mall_id)映射;键为客户提供的店铺名(与 GetMallByName 的 mallName 一致) |
updated_at | 最近一次写入时间 |
凡需 mall_id 的操作(开/关店铺、ClearCache、GetBrowserWebDriver 等),一律先走缓存:
1. 读 mall_cache.json → mall_map[mall_name] 有值?
├─ 是 → 直接用该 mall_id(跳过 GetMallByName)
└─ 否 → 调用 GetMallByName → 成功后立即写入 mall_map
2. 使用 mall_id 调用后续 API
3. 若后续 API 因店铺 ID 无效失败(如 CloseBrowser returnObj===false):
→ 删除 mall_map 中该 mall_name 条目
→ 重新 GetMallByName 取 id 并写回缓存
→ 用新 id 重试一次(仍失败则立即结束)
| 时机 | 动作 |
|---|---|
开/关店铺、清缓存、取 WebDriver 等需 mall_id | 先读 mall_cache.json;命中则跳过 GetMallByName |
| 缓存未命中 | GetMallByName 成功后立即写入 mall_map |
GetBrowserList(登录探测或客户查列表) | 将 mall_list 中每条 mall_name → mall_id 批量写入缓存(已有且相同则跳过) |
CreateBrowser 成功后 | 等待同步 → GetMallByName → 写入缓存 |
使用缓存 id 调用 CloseBrowser / OpenBrowser / GetBrowserWebDriver 等失败 | 删除该条缓存 → GetMallByName 刷新 → 写回 → 仅重试一次 |
注意:
mall_cache.json记录的是店铺 ID,与站斧「清除店铺缓存」(ClearCache) 无关;清浏览器缓存不要清空mall_cache.json。
客户要求打开某店铺时:
mall_name 写入 opening_malls.json(见「打开意图配置」;站斧须已打开)mall_idGetBrowserWebDriver 判断目标店铺是否已打开——只请求一次,超时固定 5 秒{"action": "GetBrowserWebDriver", "module": "WebDriverModule", "browserId": "{mall_id}"}
判定已打开:5s 内 returnObj.success == true 且 WebDriverPort 有值。
| 步骤 | 规则 |
|---|---|
| 次数 / 超时 | 只请求 1 次,HTTP timeout=5;禁止先用 15s 再探测、禁止连打第二次 |
| 5s 内拿到端口 | 按「已打开」处理(询问是否关闭) |
| 5s 超时 / 连接异常 / 无端口 | 视为未开,不要结束流程,直接 OpenBrowser → 等 15s → 再 GetBrowserWebDriver(取端口) |
| 情况 | 动作 |
|---|---|
| 目标店铺未打开(含探测 5s 超时) | 直接 OpenBrowser → 等 15s → GetBrowserWebDriver |
| 目标店铺已打开 | 必须先询问客户:「店铺 {mall_name} 已打开(WebDriverPort={port}),是否需要关闭店铺?」 |
| 客户确认需要关闭 | CloseBrowser → 从 opening_malls.json 去掉该名 → 确认关闭成功后,再询问是否重新 OpenBrowser;确认后再写入配置并 OpenBrowser → 等 15s → GetBrowserWebDriver |
| 客户确认不需要关闭 / 继续使用当前店铺 | 跳过 OpenBrowser 与 CloseBrowser,直接用现有 WebDriverPort 进入阶段 B 或结束 |
| 客户未明确表态 | 不得擅自 OpenBrowser 或 CloseBrowser,等待客户回复 |
禁止:
OpenBrowser(会干扰客户当前页面)CloseBrowserGetBrowserWebDriver 超时而整流程失败退出(应改走 OpenBrowser)GetBrowserWebDriver 重试或拉长超时(整体只许 1 次 × 5s)与客户说「关闭店铺」的区别:客户明确说关闭且 HTTP 正常 → 直接 CloseBrowser 并清理 opening_malls.json,无需再问是否关闭;客户说打开但检测到已开 → 才须询问是否关闭。
仅当 GetBrowserList 探测无 HTTP 响应(站斧未打开)时,才执行:
opening_malls.json(打开站斧命令检测到未打开时必须清理已写入的店铺名)taskkill /f /t /im 站斧.exe
杀进程后最多等 1s(可用短轮询看进程是否消失);进程已退出则立刻继续,禁止固定干等 3s。
GetBrowserList(间隔 0.5s,总计最多 8s),端口/列表就绪即继续;禁止启动后再固定 sleep 再探测。必须按顺序、逐项尝试,命中即停;禁止 where.exe、递归 Get-ChildItem -Recurse、跨盘符 glob、翻代码库猜路径。
| 顺序 | 方式 | 说明 |
|---|---|---|
| 0 | api_port.json 的 install_dir | 读本地记录,验证 {install_dir}\站斧.exe 存在则直接使用;不存在则跳过,继续顺序 1 |
| 1 | 桌面「站斧」快捷方式 | 仅按文件名匹配含「站斧」的 .lnk,解析其 TargetPath 所在目录(见下节) |
| 2 | C:\Users\{用户名}\AppData\Local\Programs\ZhanFu\站斧.exe | {用户名} 取当前 Windows 登录名(如 win、Administrator) |
| 3 | C:\Program Files\ZhanFu\站斧.exe | 固定路径 |
| 4 | 向客户索要 | 快捷方式与常见目录均未命中时必须停止,提示:「未找到站斧安装目录,请提供站斧安装路径(含 站斧.exe 的文件夹)」;禁止继续瞎猜或全盘搜索 |
顺序 0~3 任一命中后:立即把该目录写入 api_port.json 的 install_dir,再冷启动。
顺序 4:客户提供 folder_path 后,仅检查 {folder_path}\站斧.exe 是否存在;验证通过后写入 install_dir;不存在则立即结束并再次提示路径无效。
只查找快捷方式文件名中含「站斧」的 .lnk,禁止遍历桌面全部快捷方式,禁止解析文件名不含「站斧」的 .lnk(无论其目标 exe 名称为何)。
查找范围:当前用户桌面 + 公共桌面(Desktop、Public\Desktop)。
文件名匹配(按序尝试,解析到有效 站斧.exe 即停):
站斧.lnk、站斧浏览器.lnk*站斧*.lnk(仅文件名包含「站斧」者,如 站斧浏览器完成版.lnk)对每个命中的 .lnk:
TargetPath(PowerShell WScript.Shell.CreateShortcut 或等价方式)install_dirTargetPath 本身为 站斧.exe → 直接使用{install_dir}\站斧.exe;存在则使用全部快捷方式均未解析出 站斧.exe → 进入顺序 2(固定安装路径),不得改用其他命名规则的快捷方式兜底。
禁止用 CheckClientOpen / LoadSuccess / LoadFailed 判断站斧是否已打开。冷启动或复用后直接轮询 GetBrowserList:
{"action": "GetBrowserList", "module": "WebDriverModule", "args": "{\"page\":1,\"limit\":20}"}
GetBrowserList,间隔 0.5s,总计最多 8sreturnObj.success == true 且 returnObj.data.mall_list 可解析(非 null)→ 站斧已打开且已登录,禁止无故调用 Login;同时将 mall_list 中 mall_name → mall_id 写入 mall_cache.jsonsuccess=false、data=null、无法解析 mall_list → 停止,提示客户:「站斧未登录,请提供账号和密码」;拿到凭证后再 Login(禁止因此冷启动)timeout=1.5;Agent 只用 Python requests,禁止为通断探测切换 PowerShell/curl
CheckClientOpen不再作为流程步骤;勿等待LoadSuccess。
仅在 GetBrowserList 表明未登录且客户已提供账号密码时调用;isboss 固定 true。禁止使用内测或历史会话中的账号。success != true → 立即结束。
resolve mall_id:先读 mall_cache.json;未命中才调 GetMallByName,成功后立即写缓存。
任一步 GetMallByName / CreateBrowser 的 success != true 或缺字段 → 立即结束,不重试(缓存 id 导致后续 API 失败时的一次刷新重试除外,见「本地店铺 ID 缓存」)。
仅站斧已打开后再写入 opening_malls.json(探测未打开时已清空,禁止未打开就写入)
目标店铺未打开(含 OpenBrowser 前探测 5s 超时)→ 可直接 OpenBrowser
目标店铺已打开(客户要求打开该店)→ 须先询问客户是否需要关闭店铺;确认关闭后再视情况 CloseBrowser / OpenBrowser(见「已打开店铺的确认」)
客户明确说关闭店铺且 HTTP 正常 → 直接 CloseBrowser,清理 opening_malls.json,不重启站斧
OpenBrowser 本身 returnObj !== true 或 ret != 200 → 立即结束,并提醒客户:
打开店铺失败,请确认该店铺是否已绑定 IP / 设备。 可在站斧客户端查看店铺绑定设备后再试。
OpenBrowser 之后的 GetBrowserWebDriver 失败(含「超时未获取到」)→ 同上,一并提醒检查 IP/设备绑定;并提醒客户:首次使用请先在站斧客户端手动打开该店铺以下载内核;不同内核的店铺需分别手动打开一次
{"action": "GetBrowserWebDriver", "module": "WebDriverModule", "browserId": "{mall_id}"}
timeout=5;超时/无端口 → 仍 OpenBrowser;禁止重试、禁止加长超时WebDriverPort 为空或请求失败 → 立即结束(禁止循环重试、禁止「再等一会」方案)OpenBrowser 后允许单次固定等待 15s 再调 GetBrowserWebDriver(不算重试);若仍失败则结束。from headed_mode import ensure_headed_mode
from playwright.sync_api import sync_playwright
ensure_headed_mode()
browser = sync_playwright().start().chromium.connect_over_cdp(
f"http://127.0.0.1:{webdriver_port}"
)
连接失败 → 立即结束,禁止换系统浏览器替代。
找 URL 含 check.html 的标签页,15s 内轮询,满足以下任一条件即视为检测通过:
.openMallOpenBtn,且非 disabled / aria-disabled=true / is-disabled)15s 内仍不满足 → 告知「没检测成功无法进行自动化」,立即结束。
可运行 Skill 内置(仅阶段 B):
python scripts/check_device_security.py --port {webdriver_port} --wait --timeout 15
检测通过后,按客户需求用 Playwright 操作页面。禁止在 Skill 目录新增业务脚本;临时逻辑在对话中执行,不落盘为 .py。
关闭店铺(客户明确要求时):
{"action": "CloseBrowser", "module": "WebDriverModule", "browserId": "{mall_id}"}
成功后从 opening_malls.json 去掉该 mall_name。
退出站斧客户端(仅客户明确要求「退出站斧」时;开/关店铺不要顺带调用):
{"action": "ExitClient", "module": "WebDriverModule", "args": ""}
成功后(或冷启动重启前)清空 opening_malls.json。
| 情况 | 动作 |
|---|---|
| 目标端口无 HTTP 响应 / 打开站斧且站斧未打开 | 立刻清空 opening_malls.json → 查安装目录(快捷方式/常见目录找不到则向客户索要)→ 冷启动 --httpport=12678 并写 api_port.json;仍失败则报告「站斧通讯失败」 |
GetBrowserList 能取到数据 + 打开店铺 | 站斧已打开,不重启;写入 opening_malls.json → HTTP 开店铺流程 |
GetBrowserList 能取到数据 + 关闭店铺 | 不重启;resolve mall_id → CloseBrowser → 清理 opening_malls.json |
| API 已运行 + 开新店铺 | 不重启站斧,直接 HTTP 开店铺 |
| 目标店铺已打开(客户要求打开) | 询问客户是否需要关闭店铺;未确认不调用 OpenBrowser / CloseBrowser |
OpenBrowser 前 GetBrowserWebDriver 5s 超时 | 不结束;继续 OpenBrowser(只许探测 1 次) |
| 客户明确要求关闭已开店铺 | 直接 CloseBrowser → 清理 opening_malls.json |
| 客户明确要求关闭站斧 | ExitClient → 清空 opening_malls.json |
| GetBrowserList 8s 内仍无法确认登录(有 HTTP 响应) | 停止,提示客户提供账号密码;禁止擅自或内测账号 Login;禁止用 LoadSuccess 判断 |
| OpenBrowser / OpenBrowser 后 GetBrowserWebDriver 失败 | 立即结束;OpenBrowser 以 returnObj===true 判成功;提醒检查 IP/设备绑定 及 是否已手动打开该店铺下载内核(版本须 ≥ 5.2.11) |
CloseBrowser 返回 returnObj===false | 立即结束,报告关闭失败 |
| 其他关键 API 失败 | 立即结束,原样报告 returnObj.msg(OpenBrowser/CloseBrowser 无 msg 时报告 returnObj 值) |
| OpenBrowser 后拿不到 WebDriverPort | 立即结束,不 retry |
| 设备安全检测 15s 超时 | 立即结束,告知「没检测成功无法进行自动化」 |
| CDP 连接失败 | 立即结束,禁止换浏览器 |
禁止:重试、翻代码、写备用脚本、写「稍后重跑」方案;禁止用 LoadSuccess 判断站斧是否已打开。
API 详情(含通用约定与全部接口):reference.md