wimotek-chromium-sync 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -56
- package/chromium_sync/__init__.py +5 -4
- package/chromium_sync/cli.py +151 -19
- package/chromium_sync/core.py +729 -205
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,95 +4,197 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/wimotek-chromium-sync)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
专为 Chromium / Chrome 设计的通用会话与 Cookie
|
|
7
|
+
专为 Chromium / Chrome 设计的通用会话与 Cookie 集群同步调度工具。支持 1对1 与 1对多集群、本地直连免密、SSH 私钥内容/文件与密码认证、Cookie 有效期智能融合(Merge)以及轻量静态探针。
|
|
8
8
|
|
|
9
|
-
支持在本地容器与远程服务器容器之间双向热同步登录凭证(Cookie + LocalStorage),全端口可参数化自定义,内置智能流向识别与带心跳保活的 SSH 隧道自愈管理。
|
|
10
9
|
---
|
|
11
10
|
|
|
12
|
-
## 🌟
|
|
11
|
+
## 🌟 核心工程特性
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* 无 TTY 环境自适应:在 Linux Crontab 定时任务、无图形后台或 CI 流程中自动回退,不因无键盘输入而崩溃。
|
|
18
|
-
* 双生态支持:同时发布于 PyPI 与 npm,支持 Python 代码导入与命令行跨语言一键执行。
|
|
13
|
+
1. **统一现代节点模型 (1对1 / 1对多集群)**:
|
|
14
|
+
* 原生支持任意规模的节点集群管理与多隧道并发映射。
|
|
15
|
+
* **本地节点免密直连**:配置本地端口即可直接直连 CDP 探针,跳过 SSH 隧道拉起。
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
2. **原生私钥内容 (PEM String) / 路径与密码认证**:
|
|
18
|
+
* `ssh_key`: 原生支持**私钥文本内容字符串**(如以 `-----BEGIN` 开头的 PEM 文本)或**私钥文件绝对路径**(如 `~/.ssh/id_rsa`),调用方无需配置繁琐的环境变量中转。
|
|
19
|
+
* `ssh_password`: 直接支持 SSH 密码认证,支持集群级默认凭证与单节点重载。
|
|
20
|
+
|
|
21
|
+
3. **结构化执行指标返回 (Structured Return Dict)**:
|
|
22
|
+
* `syncer.run()` 与 `await syncer.run_async()` 执行后返回标准指标字典,上层 Web 控制台可直接捕获迁移量、源端/目标端存量、耗时及明细,无需额外发送 CDP 探针度量。
|
|
23
|
+
|
|
24
|
+
4. **双驱动入口:原生异步协程 + 同步阻塞**:
|
|
25
|
+
* 原生提供 `await syncer.run_async()` 与 `await syncer.inspect_async()`,适配 FastAPI、Tornado、aiohttp 等现代异步服务。
|
|
26
|
+
* 同步环境直接调用 `syncer.run()`,开箱即用。
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
5. **暴露轻量静态探针工具方法 (无需实例化集群)**:
|
|
29
|
+
* 提供单点工具函数:`ChromiumSync.get_cookies(port=9222)`、`ChromiumSync.set_cookies(cookies, port=9222)`、`ChromiumSync.probe(port=9222)`,单点探测仅需 1 行代码。
|
|
23
30
|
|
|
31
|
+
6. **全节点智能 Merge 算法**:
|
|
32
|
+
* 汇总所有节点 Cookie,针对冲突项**优先保留有效期最新(expires 更长 / 最新持久凭证)的 Cookie**,并写回热刷新。
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 📦 安装
|
|
37
|
+
|
|
38
|
+
### Python (PyPI)
|
|
24
39
|
```bash
|
|
25
40
|
pip install wimotek-chromium-sync
|
|
41
|
+
playwright install chromium
|
|
26
42
|
```
|
|
27
43
|
|
|
28
|
-
Node.js
|
|
29
|
-
|
|
44
|
+
### Node.js (npm)
|
|
30
45
|
```bash
|
|
31
|
-
npm install wimotek-chromium-sync
|
|
46
|
+
npm install -g wimotek-chromium-sync
|
|
32
47
|
```
|
|
33
48
|
|
|
34
|
-
|
|
49
|
+
---
|
|
35
50
|
|
|
36
|
-
|
|
51
|
+
## 🚀 极简开发示例
|
|
37
52
|
|
|
53
|
+
### 1. 轻量静态探针工具(无需实例化集群)
|
|
54
|
+
单点探测某个节点时,直接 1 行静态调用:
|
|
38
55
|
```python
|
|
39
56
|
from chromium_sync import ChromiumSync
|
|
40
57
|
|
|
41
|
-
|
|
58
|
+
# 1. 单点探测节点在线状态与页面信息
|
|
59
|
+
info = ChromiumSync.probe(port=9222)
|
|
60
|
+
print(info)
|
|
61
|
+
# {'online': True, 'cookie_count': 42, 'page_title': 'GitHub', 'page_url': 'https://github.com', ...}
|
|
42
62
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
local_cdp_port=16002, # 本地容器的 CDP 端口
|
|
46
|
-
remote_cdp_port=9222, # 远程容器的实际
|
|
47
|
-
CDP 端口 remote_tunnel_port=9222, # 本地用于接收隧道的端口
|
|
48
|
-
direction="auto", # 智能判断: 自动往缺少凭证的一端同步
|
|
49
|
-
timeout=15 # 倒计时等待秒数 (0 为秒执行) )
|
|
63
|
+
# 2. 单点直接提取 Cookie 列表
|
|
64
|
+
cookies = ChromiumSync.get_cookies(port=9222)
|
|
50
65
|
|
|
51
|
-
|
|
66
|
+
# 3. 单点直接批量写入 Cookie 并热刷新页面
|
|
67
|
+
ChromiumSync.set_cookies(cookies, port=9223, reload=True)
|
|
52
68
|
```
|
|
53
69
|
|
|
54
|
-
|
|
70
|
+
---
|
|
55
71
|
|
|
56
|
-
|
|
72
|
+
### 2. 现代多节点集群同步与结构化返回
|
|
57
73
|
|
|
58
|
-
|
|
74
|
+
#### (1) Python 同步调用 (同步脚本 / Celery 任务)
|
|
75
|
+
```python
|
|
76
|
+
from chromium_sync import ChromiumSync
|
|
77
|
+
|
|
78
|
+
syncer = ChromiumSync(
|
|
79
|
+
nodes=[
|
|
80
|
+
{"id": "local", "name": "本地容器", "cdp_port": 9223},
|
|
81
|
+
{
|
|
82
|
+
"id": "kr2",
|
|
83
|
+
"name": "韩国生产服",
|
|
84
|
+
"ssh_host": "kr2.wimotek.com",
|
|
85
|
+
"ssh_user": "root",
|
|
86
|
+
# 直接支持私钥文本内容 (PEM String) 或文件路径
|
|
87
|
+
"ssh_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIB...\n-----END RSA PRIVATE KEY-----",
|
|
88
|
+
"cdp_port": 9222
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "sg1",
|
|
92
|
+
"name": "新加坡服",
|
|
93
|
+
"ssh_host": "sg1.wimotek.com",
|
|
94
|
+
"ssh_user": "ubuntu",
|
|
95
|
+
# 直接支持密码认证
|
|
96
|
+
"ssh_password": "YourStrongPassword123",
|
|
97
|
+
"cdp_port": 9222
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
mode="merge" # "merge" (合并最新凭据) 或 "sync" (单源广播)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# 执行同步并获取度量指标字典
|
|
104
|
+
result = syncer.run()
|
|
105
|
+
print(result)
|
|
106
|
+
```
|
|
107
|
+
**结构化返回值示例**:
|
|
108
|
+
```python
|
|
109
|
+
{
|
|
110
|
+
"status": "success", # "success" | "failed"
|
|
111
|
+
"mode": "merge", # 执行模式
|
|
112
|
+
"transferred_count": 45, # 实际迁移/融合生成的 Cookie 数量
|
|
113
|
+
"source_total": 80, # 源端/融合前凭证总数
|
|
114
|
+
"target_total": 45, # 目标端/融合后凭证总数
|
|
115
|
+
"nodes_synced": ["local", "kr2", "sg1"], # 成功同步的节点列表
|
|
116
|
+
"duration": 1.25, # 耗时(秒)
|
|
117
|
+
"details": "全节点 Merge 成功: 融合 45 条最新凭证至 ['本地容器', '韩国生产服', '新加坡服']",
|
|
118
|
+
"error": None
|
|
119
|
+
}
|
|
120
|
+
```
|
|
59
121
|
|
|
60
|
-
|
|
122
|
+
#### (2) FastAPI / aiohttp 异步协程原生驱动
|
|
123
|
+
```python
|
|
124
|
+
from fastapi import FastAPI
|
|
125
|
+
from chromium_sync import ChromiumSync
|
|
61
126
|
|
|
62
|
-
|
|
127
|
+
app = FastAPI()
|
|
128
|
+
|
|
129
|
+
@app.post("/api/sync")
|
|
130
|
+
async def trigger_sync():
|
|
131
|
+
syncer = ChromiumSync(
|
|
132
|
+
nodes=[
|
|
133
|
+
{"id": "local", "cdp_port": 9222},
|
|
134
|
+
{"id": "cloud", "ssh_host": "remote.host.com", "ssh_key": "~/.ssh/id_rsa", "cdp_port": 9222}
|
|
135
|
+
],
|
|
136
|
+
mode="merge"
|
|
137
|
+
)
|
|
138
|
+
# 原生 asyncio 协程,零线程切换开销,高并发性能极佳
|
|
139
|
+
result = await syncer.run_async()
|
|
140
|
+
return result
|
|
141
|
+
```
|
|
63
142
|
|
|
64
|
-
|
|
143
|
+
---
|
|
65
144
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
--
|
|
72
|
-
--
|
|
145
|
+
### 3. 命令行 CLI 执行
|
|
146
|
+
|
|
147
|
+
#### (1) 内联语法直接启动多节点 Merge
|
|
148
|
+
```bash
|
|
149
|
+
chromium-sync \
|
|
150
|
+
--node id=local,port=9223 \
|
|
151
|
+
--node id=kr2,ssh=root@kr2.wimotek.com,port=9222,key=~/.ssh/id_rsa \
|
|
152
|
+
--node id=sg1,ssh=ubuntu@sg1.wimotek.com,port=9222,pass=SecretPass123 \
|
|
153
|
+
--mode merge
|
|
73
154
|
```
|
|
74
155
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
| 参数名称 | 命令行选项 | 对应环境变量 | 默认值 | 详细说明 |
|
|
78
|
-
| :------------------- | :------------- | :-------------------------- | :--------------------- | :------------------- |
|
|
79
|
-
| remote\_ssh | \--remote-ssh | CHROMIUM\_REMOTE\_SSH | <root@xx.xx.xx> | 远程 SSH 连接主机 |
|
|
80
|
-
| remote\_ssh\_port | \--ssh-port | CHROMIUM\_SSH\_PORT | 22 | 远程服务器的 SSH 端口 |
|
|
81
|
-
| local\_cdp\_port | \--local-port | CHROMIUM\_LOCAL\_PORT | 16002 | 运行在本机的容器 CDP 端口 |
|
|
82
|
-
| remote\_cdp\_port | \--remote-port | CHROMIUM\_REMOTE\_CDP\_PORT | 9222 | 运行在远端服务器上的容器实际端口 |
|
|
83
|
-
| remote\_tunnel\_port | \--tunnel-port | CHROMIUM\_TUNNEL\_PORT | 9222 | SSH 隧道映射到本机的监听端口 |
|
|
84
|
-
| direction | \--direction | CHROMIUM\_DIRECTION | push | 默认同步流向 (push 或 pull 或 auto) |
|
|
85
|
-
| timeout | \--timeout | CHROMIUM\_TIMEOUT | 15 | 倒计时交互等待秒数,0 为免打扰秒执行 |
|
|
86
|
-
| auto\_close\_tunnel | \--auto-close | \- | False | 任务完成后是否关闭创建的 SSH 隧道 |
|
|
87
|
-
|
|
88
|
-
## 🤖 自动化与定时任务配置示例
|
|
89
|
-
配合 Linux Crontab,每天凌晨自动将本地维护好的登录态推送到云端远程容器:
|
|
156
|
+
#### (2) 仅查看节点状态与 Cookie 数量 (ASCII 表格)
|
|
90
157
|
```bash
|
|
91
|
-
|
|
92
|
-
crontab -e
|
|
93
|
-
添加此行:每天凌晨 3:00 自动执行同步且不弹任何提示
|
|
94
|
-
0 3 * * * /usr/local/bin/chromium-sync --direction push --timeout 0 --auto-close >> /tmp/chromium_sync.log 2>&1
|
|
158
|
+
chromium-sync --config cluster.json --status
|
|
95
159
|
```
|
|
160
|
+
输出样例:
|
|
161
|
+
```text
|
|
162
|
+
==========================================================================================
|
|
163
|
+
节点 ID | 节点名称 | 类型 | CDP端口/映射 | Cookie数 | 当前页面状态
|
|
164
|
+
------------------------------------------------------------------------------------------
|
|
165
|
+
local | 本地容器 | 本地直连 | 9223 | 42 条 | [Google] https://google.com
|
|
166
|
+
kr2 | 韩国节点 | SSH远程 | 19222 | 38 条 | [GitHub] https://github.com
|
|
167
|
+
==========================================================================================
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### (3) 导出 Cookie 详情或执行结果为 JSON
|
|
171
|
+
```bash
|
|
172
|
+
# 1. 导出所有节点及 Cookie 列表为 JSON
|
|
173
|
+
chromium-sync --config cluster.json --status --json > /tmp/cluster_data.json
|
|
174
|
+
|
|
175
|
+
# 2. 执行同步并将结构化指标以 JSON 打印 (方便 CI/CD 或流水线捕获)
|
|
176
|
+
chromium-sync --config cluster.json --mode merge --json
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## ⚙️ 节点参数配置规范 (NodeConfig)
|
|
182
|
+
|
|
183
|
+
| 字段 | 类型 | 默认值 | 详细说明 |
|
|
184
|
+
| :--- | :--- | :--- | :--- |
|
|
185
|
+
| `id` | str | 必填 | 节点唯一标识符 (例如 `local`, `kr2`) |
|
|
186
|
+
| `name` | str | `id` | 节点显示名称 |
|
|
187
|
+
| `is_local` | bool | 自动识别 | 是否为本地节点 (不填 `ssh_host` 或填回环地址自动判定为本地,免密直连) |
|
|
188
|
+
| `cdp_host` | str | `127.0.0.1` | 节点 CDP 服务监听的主机地址 |
|
|
189
|
+
| `cdp_port` | int | `9222` | 节点暴露的 CDP 端口 |
|
|
190
|
+
| `ssh_host` | str | `None` | 远程服务器 IP 或主机名 (提供该字段时识别为远程 SSH 节点) |
|
|
191
|
+
| `ssh_port` | int | `22` | 远程服务器 SSH 端口 |
|
|
192
|
+
| `ssh_user` | str | `root` | 远程 SSH 用户名 |
|
|
193
|
+
| `ssh_key` | str | `None` | **SSH 私钥 (同时支持文件绝对路径 或 私钥 PEM 文本字符串)** |
|
|
194
|
+
| `ssh_password` | str | `None` | SSH 登录密码 (自动适配 `sshpass` 与原生 `SSH_ASKPASS`) |
|
|
195
|
+
| `tunnel_port` | int | 自动分配 | 本地用于映射隧道的端口 (多节点自动分配防冲突) |
|
|
196
|
+
|
|
197
|
+
---
|
|
96
198
|
|
|
97
199
|
## 📄 License
|
|
98
200
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
wimotek-chromium-sync Package
|
|
3
|
+
Universal Chromium Session & Cookie Synchronizer with SSH Tunnel and Cluster Support
|
|
3
4
|
"""
|
|
4
|
-
from .core import ChromiumSync
|
|
5
|
+
from .core import ChromiumSync, NodeConfig, merge_cookies
|
|
5
6
|
|
|
6
|
-
__version__ = "1.
|
|
7
|
-
__all__ = ["ChromiumSync"]
|
|
7
|
+
__version__ = "1.2.0"
|
|
8
|
+
__all__ = ["ChromiumSync", "NodeConfig", "merge_cookies"]
|
package/chromium_sync/cli.py
CHANGED
|
@@ -1,33 +1,165 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Chromium Sync CLI (现代多节点调度版)
|
|
5
|
+
"""
|
|
3
6
|
|
|
4
7
|
import argparse
|
|
5
|
-
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
try:
|
|
12
|
+
from .core import ChromiumSync, NodeConfig
|
|
13
|
+
except (ImportError, ValueError):
|
|
14
|
+
from core import ChromiumSync, NodeConfig
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def parse_node_str(val: str) -> dict:
|
|
18
|
+
"""
|
|
19
|
+
解析内联节点定义参数:
|
|
20
|
+
例如:
|
|
21
|
+
--node id=local,port=9222
|
|
22
|
+
--node id=kr2,ssh=root@kr2.wimotek.com,port=9222,key=~/.ssh/id_rsa
|
|
23
|
+
--node id=sg1,ssh=ubuntu@sg1.wimotek.com,port=9222,pass=Secret123
|
|
24
|
+
--node '{"id": "local", "cdp_port": 9222}'
|
|
25
|
+
"""
|
|
26
|
+
val = val.strip()
|
|
27
|
+
if val.startswith("{") and val.endswith("}"):
|
|
28
|
+
return json.loads(val)
|
|
29
|
+
|
|
30
|
+
res = {}
|
|
31
|
+
for part in val.split(","):
|
|
32
|
+
if "=" in part:
|
|
33
|
+
k, v = part.split("=", 1)
|
|
34
|
+
k = k.strip().lower()
|
|
35
|
+
v = v.strip()
|
|
36
|
+
if k in ("port", "cdp_port"):
|
|
37
|
+
res["cdp_port"] = int(v)
|
|
38
|
+
elif k in ("ssh_port",):
|
|
39
|
+
res["ssh_port"] = int(v)
|
|
40
|
+
elif k in ("tunnel_port",):
|
|
41
|
+
res["tunnel_port"] = int(v)
|
|
42
|
+
elif k in ("local", "is_local"):
|
|
43
|
+
res["is_local"] = v.lower() in ("true", "1", "yes")
|
|
44
|
+
elif k in ("host", "cdp_host"):
|
|
45
|
+
res["cdp_host"] = v
|
|
46
|
+
elif k in ("ssh", "ssh_host"):
|
|
47
|
+
if "@" in v:
|
|
48
|
+
user, host = v.split("@", 1)
|
|
49
|
+
res["ssh_user"] = user
|
|
50
|
+
res["ssh_host"] = host
|
|
51
|
+
else:
|
|
52
|
+
res["ssh_host"] = v
|
|
53
|
+
elif k in ("user", "ssh_user"):
|
|
54
|
+
res["ssh_user"] = v
|
|
55
|
+
elif k in ("key", "ssh_key", "ssh_key_path"):
|
|
56
|
+
res["ssh_key"] = v
|
|
57
|
+
elif k in ("pass", "password", "ssh_pass", "ssh_password"):
|
|
58
|
+
res["ssh_password"] = v
|
|
59
|
+
elif k in ("id", "name"):
|
|
60
|
+
res[k] = v
|
|
61
|
+
else:
|
|
62
|
+
res[k] = v
|
|
63
|
+
|
|
64
|
+
if "id" not in res:
|
|
65
|
+
res["id"] = res.get("name") or res.get("ssh_host") or "local"
|
|
66
|
+
return res
|
|
6
67
|
|
|
7
68
|
|
|
8
69
|
def main():
|
|
9
|
-
parser = argparse.ArgumentParser(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
70
|
+
parser = argparse.ArgumentParser(
|
|
71
|
+
description="现代多节点 Chromium 会话同步与 Cookie 集群调度工具",
|
|
72
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
73
|
+
epilog="""
|
|
74
|
+
使用示例:
|
|
75
|
+
# 1. 快速查看节点状态与 Cookie 数量 (ASCII 表格)
|
|
76
|
+
chromium-sync --node id=local,port=9222 --node id=kr2,ssh=root@kr2.wimotek.com,port=9222,key=~/.ssh/id_rsa --status
|
|
77
|
+
|
|
78
|
+
# 2. 导出节点状态与 Cookie 详情为 JSON (便于程序直接提取 Cookie 列表)
|
|
79
|
+
chromium-sync --config cluster.json --status --json
|
|
80
|
+
|
|
81
|
+
# 3. 全节点 Cookie 智能 Merge (合并所有节点并保留最新有效期)
|
|
82
|
+
chromium-sync --config cluster.json --mode merge
|
|
83
|
+
|
|
84
|
+
# 4. 指定单源节点广播同步并输出结构化指标 JSON
|
|
85
|
+
chromium-sync --config cluster.json --mode sync --source local --json
|
|
86
|
+
|
|
87
|
+
# 5. 极简命令行多节点直接同步
|
|
88
|
+
chromium-sync \\
|
|
89
|
+
--node id=local,port=9223 \\
|
|
90
|
+
--node id=kr2,ssh=root@kr2.wimotek.com,port=9222,key=~/.ssh/id_rsa \\
|
|
91
|
+
--mode merge
|
|
92
|
+
"""
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# 节点输入方式
|
|
96
|
+
parser.add_argument("--config", help="集群节点配置文件路径 (JSON 格式)")
|
|
97
|
+
parser.add_argument("--node", action="append", default=[], help="定义节点 (可多次传入,如 id=local,port=9222)")
|
|
98
|
+
parser.add_argument("--nodes", help="JSON 数组格式的节点配置字符串")
|
|
99
|
+
|
|
100
|
+
# 全局默认 SSH 凭据
|
|
101
|
+
parser.add_argument("--ssh-key", help="集群默认 SSH 私钥 (支持私钥文件绝对路径 或 私钥 PEM 文本内容)")
|
|
102
|
+
parser.add_argument("--ssh-password", help="集群默认 SSH 连接密码")
|
|
103
|
+
|
|
104
|
+
# 同步模式
|
|
105
|
+
parser.add_argument("--mode", choices=["sync", "merge"], default="sync",
|
|
106
|
+
help="同步方式: 'merge'(合并所有节点最新Cookie), 'sync'(单源广播同步,默认)")
|
|
107
|
+
parser.add_argument("--source", default=None, help="sync 模式下的源节点 ID (默认第一个节点)")
|
|
108
|
+
parser.add_argument("--targets", nargs="*", default=None, help="sync 模式下的目标节点 ID 列表 (默认其余所有节点)")
|
|
109
|
+
|
|
110
|
+
# 探测与数据查询
|
|
111
|
+
parser.add_argument("--status", action="store_true", help="仅探测并输出各节点的 Cookie 数与详情表格,不执行写入")
|
|
112
|
+
parser.add_argument("--json", action="store_true", help="以 JSON 格式输出节点数据或执行结果指标")
|
|
113
|
+
|
|
114
|
+
# 隧道与连接
|
|
115
|
+
parser.add_argument("--auto-close", action="store_true", help="任务完成后关闭拉起的 SSH 隧道")
|
|
116
|
+
parser.add_argument("-v", "--verbose", action="store_true", help="显示详细调试日志")
|
|
117
|
+
|
|
18
118
|
args = parser.parse_args()
|
|
19
119
|
|
|
120
|
+
# 聚合节点配置
|
|
121
|
+
raw_nodes = []
|
|
122
|
+
if args.config:
|
|
123
|
+
if not os.path.exists(args.config):
|
|
124
|
+
sys.exit(f"[-] 配置文件不存在: {args.config}")
|
|
125
|
+
with open(args.config, "r", encoding="utf-8") as f:
|
|
126
|
+
raw_nodes.extend(json.load(f))
|
|
127
|
+
|
|
128
|
+
if args.nodes:
|
|
129
|
+
raw_nodes.extend(json.loads(args.nodes))
|
|
130
|
+
|
|
131
|
+
if args.node:
|
|
132
|
+
for n_str in args.node:
|
|
133
|
+
raw_nodes.append(parse_node_str(n_str))
|
|
134
|
+
|
|
135
|
+
# 默认兜底:若未传入任何节点参数,尝试使用标准默认本地节点
|
|
136
|
+
if not raw_nodes:
|
|
137
|
+
raw_nodes = [
|
|
138
|
+
{"id": "local", "name": "本地容器", "is_local": True, "cdp_port": 9222}
|
|
139
|
+
]
|
|
140
|
+
|
|
20
141
|
syncer = ChromiumSync(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
142
|
+
nodes=raw_nodes,
|
|
143
|
+
mode=args.mode,
|
|
144
|
+
source=args.source,
|
|
145
|
+
targets=args.targets,
|
|
146
|
+
ssh_key=args.ssh_key,
|
|
147
|
+
ssh_password=args.ssh_password,
|
|
148
|
+
auto_close_tunnel=args.auto_close,
|
|
149
|
+
verbose=args.verbose
|
|
29
150
|
)
|
|
30
|
-
|
|
151
|
+
|
|
152
|
+
if args.status:
|
|
153
|
+
report = syncer.inspect()
|
|
154
|
+
if args.json:
|
|
155
|
+
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
156
|
+
else:
|
|
157
|
+
print(syncer.get_summary_table(report))
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
result = syncer.run()
|
|
161
|
+
if args.json:
|
|
162
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
31
163
|
|
|
32
164
|
|
|
33
165
|
if __name__ == "__main__":
|