ipclick 2.1.0__tar.gz → 2.1.3__tar.gz
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.
- {ipclick-2.1.0 → ipclick-2.1.3}/PKG-INFO +84 -90
- {ipclick-2.1.0 → ipclick-2.1.3}/README.md +80 -86
- {ipclick-2.1.0 → ipclick-2.1.3}/pyproject.toml +6 -6
- {ipclick-2.1.0 → ipclick-2.1.3}/pyproject.toml.orig +6 -6
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/__init__.py +1 -1
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/browser_engines.py +8 -4
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cli/agent.py +2 -1
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/dto/proto/task_pb2_grpc.py +1 -1
- {ipclick-2.1.0 → ipclick-2.1.3}/LICENSE +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/__main__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/base.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/browser_adapter.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/browser_settings.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/curl_cffi_adapter.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/drission_adapter.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/niquests_adapter.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/redirects.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/registry.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/retry.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/sessions.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/adapters/settings.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/aio.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/async_limiter.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/async_server.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/auth.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cli/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cli/main.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cli/output.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cli/skill_cmd.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/async_forwarder.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/balancer.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/client.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/discovery.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/forwarder.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/node.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/pool.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/probe.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/status_page.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/cluster/tokens.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/components.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/compression.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/config_loader/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/config_loader/dotenv.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/config_loader/env_writer.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/config_loader/loader.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/config_loader/placeholders.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/config_loader/writer.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/configs/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/configs/default_config.toml +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/dto/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/dto/models.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/dto/proto/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/dto/proto/generate.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/dto/proto/task.proto +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/dto/proto/task_pb2.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/dto/proto/task_pb2.pyi +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/dto/response.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/exceptions.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/factory.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/health.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/limiter.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/multiprocess.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/ports.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/protocols.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/py.typed +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/resume.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/rpc/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/rpc/channel.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/rpc/options.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/sdk.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/secrets.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/server.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/server_settings.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/services/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/services/async_task_service.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/services/components.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/services/detached.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/services/errors.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/services/task_service.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/skill.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/skills/ipclick/SKILL.md +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/tls.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/trace/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/trace/counters.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/trace/recorder.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/trace/records.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/trace/store.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/utils/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/utils/coerce.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/utils/config_util.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/utils/log_util.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/utils/module_probe.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/utils/path_util.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/utils/secure_util.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/utils/url_util.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/assets.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/auth.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/curl_parser.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/deploy.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/editable.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/installer.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/pages/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/pages/components.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/pages/context.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/pages/sandbox.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/pages/settings.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/pages/skill.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/pages/trace.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/proxy_tunnel.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/server.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/snapshot.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/__init__.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/base.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/components.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/config.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/dashboard.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/deploy.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/login.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/sandbox.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/skill.py +0 -0
- {ipclick-2.1.0 → ipclick-2.1.3}/src/ipclick/web/templates/trace.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipclick
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.3
|
|
4
4
|
Summary: IPClick Tool
|
|
5
5
|
Keywords: http,grpc,downloader,scraping,browser,cluster
|
|
6
6
|
Author: 元气码农少女酱
|
|
@@ -17,15 +17,15 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
17
17
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
19
|
Classifier: Typing :: Typed
|
|
20
|
-
Requires-Dist: curl-cffi>=0.16.0
|
|
21
|
-
Requires-Dist: grpcio>=1.
|
|
20
|
+
Requires-Dist: curl-cffi>=0.16.0
|
|
21
|
+
Requires-Dist: grpcio>=1.85.1,<2.0.0
|
|
22
22
|
Requires-Dist: grpcio-health-checking>=1.83.0,<2.0.0
|
|
23
23
|
Requires-Dist: protobuf>=7.35.1,<8.0.0
|
|
24
24
|
Requires-Dist: click>=8.4.2,<9.0.0
|
|
25
25
|
Requires-Dist: fake-useragent>=2.2.0,<3.0.0
|
|
26
26
|
Requires-Dist: loguru>=0.7.3,<0.8.0
|
|
27
27
|
Requires-Dist: python-box[all]>=7.4.1,<8.0.0
|
|
28
|
-
Requires-Dist: uuid-utils>=0.17.0,<
|
|
28
|
+
Requires-Dist: uuid-utils>=0.17.0,<1.3.0
|
|
29
29
|
Requires-Dist: typing-extensions>=4.16.0,<5.0.0
|
|
30
30
|
Requires-Dist: camoufox>=0.5.4,<1.0.0 ; extra == 'camoufox'
|
|
31
31
|
Requires-Dist: drissionpage>=4.1.1,<5.0.0 ; extra == 'drissionpage'
|
|
@@ -51,14 +51,13 @@ Description-Content-Type: text/markdown
|
|
|
51
51
|
|
|
52
52
|

|
|
53
53
|
|
|
54
|
-
> IPClick
|
|
54
|
+
> IPClick 的名字灵感来自《Link Click》(时光代理人)。项目将 HTTP 请求分发到不同节点执行。
|
|
55
55
|
|
|
56
|
-
IPClick 是一个基于 gRPC 的分布式 HTTP
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
IPClick 是一个基于 gRPC 的分布式 HTTP 请求代理。调用方通过 Python SDK、命令行或 Web
|
|
57
|
+
管理端提交请求,服务端负责适配器选择、TLS 指纹伪装、重试、限流和 URL 准入。
|
|
58
|
+
多机部署时,请求可以由不同节点的出口 IP 发出,执行过程会记录为可查询的链路。
|
|
59
59
|
|
|
60
|
-
> 📚 **完整文档在 [Wiki](https://github.com/yuanqimanong/IPClick/wiki)
|
|
61
|
-
> 深入用法都在 Wiki 里。
|
|
60
|
+
> 📚 **完整文档在 Wiki**。本页介绍安装、启动和常用入口,详细配置与 API 用法见文档目录。[Wiki](https://github.com/yuanqimanong/IPClick/wiki)
|
|
62
61
|
|
|
63
62
|
| | |
|
|
64
63
|
|---|---|
|
|
@@ -81,22 +80,22 @@ IPClick 是一个基于 gRPC 的分布式 HTTP 请求代理。你把请求交给
|
|
|
81
80
|
|
|
82
81
|
## ✨ 特性
|
|
83
82
|
|
|
84
|
-
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
|
|
91
|
-
- **按 host
|
|
83
|
+
- **多适配器**。默认使用带 TLS 指纹伪装的 `curl_cffi`,可按需安装 `niquests`(HTTP/3)
|
|
84
|
+
或浏览器引擎,也支持注册自定义适配器
|
|
85
|
+
- **按需安装**。`pip install ipclick` 安装核心依赖,可选适配器通过 extras 安装
|
|
86
|
+
- **浏览器渲染**。通过 camoufox / patchright / playwright / DrissionPage 执行 JS,
|
|
87
|
+
默认引擎按平台选择
|
|
88
|
+
- **集群与故障转移**。支持轮询、随机、加权均衡和健康探测,以及服务端转发与客户端分发。
|
|
89
|
+
仅 GET/HEAD/OPTIONS 请求会自动换节点重试
|
|
90
|
+
- **按 host 限流**。按目标域名控制并发与 QPS
|
|
92
91
|
- **流式下载 · 断点续传 · 批量 · 异步客户端**
|
|
93
92
|
- **令牌鉴权 · TLS/mTLS · SSRF 准入 · `grpc.health.v1` 健康检查**
|
|
94
|
-
-
|
|
95
|
-
|
|
96
|
-
- **Web
|
|
97
|
-
|
|
98
|
-
- **AI
|
|
99
|
-
-
|
|
93
|
+
- **链路记录**。记录执行节点、重试次数和排队时间,使用内存环形缓冲或可选 SQLite 存储,
|
|
94
|
+
记录模块使用标准库实现
|
|
95
|
+
- **Web 管理端**。提供登录、总览、实时请求流、请求调试、配置写回、集群节点管理和组件装卸,
|
|
96
|
+
前端无需构建
|
|
97
|
+
- **AI 可调用**。提供结构化输出、分类退出码和随包分发的技能包
|
|
98
|
+
- **完整类型标注**。随包提供 `py.typed`
|
|
100
99
|
|
|
101
100
|
## 📦 安装
|
|
102
101
|
|
|
@@ -106,8 +105,8 @@ pip install "ipclick[niquests]" # 加 HTTP/2 + HTTP/3
|
|
|
106
105
|
pip install "ipclick[camoufox]" # 加浏览器渲染(还需下载浏览器本体)
|
|
107
106
|
```
|
|
108
107
|
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
可选适配器按用途安装,项目未提供 `[all]`。浏览器引擎还需要单独准备浏览器本体。
|
|
109
|
+
引擎选择与安装步骤见 [安装](https://github.com/yuanqimanong/IPClick/wiki/Installation)。
|
|
111
110
|
|
|
112
111
|
需要 Python 3.11+。
|
|
113
112
|
|
|
@@ -135,15 +134,14 @@ ipclick run --verbose
|
|
|
135
134
|
ipclick run --port 9628 --web-port 9531 -w
|
|
136
135
|
```
|
|
137
136
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
所以连不上时 IPClick 会额外附一句端口提示。
|
|
137
|
+
默认端口分别为 **gRPC 9528** 与 **Web 9527**。SDK 和其他节点连接 gRPC 端口,
|
|
138
|
+
浏览器访问 Web 端口。客户端误连 Web 端口时会在 gRPC 握手阶段失败,错误信息中会附带端口提示。
|
|
141
139
|
|
|
142
|
-
###
|
|
140
|
+
### 服务端并发与多进程
|
|
143
141
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
服务端默认在线程池中处理请求,`[SERVER].max_workers` 控制单个进程的线程数。
|
|
143
|
+
需要利用多个 CPU 核时,可配置多个工作进程,通过 SO_REUSEPORT 共享监听端口,
|
|
144
|
+
由内核分发连接。客户端仍使用同一个服务地址。
|
|
147
145
|
|
|
148
146
|
```toml
|
|
149
147
|
[SERVER]
|
|
@@ -153,24 +151,25 @@ max_concurrent_rpcs = 0 # 0 = max_workers × 8。决定"排队能排多长",
|
|
|
153
151
|
async_mode = false # true = grpc.aio 协程模式(实验性,默认关)
|
|
154
152
|
```
|
|
155
153
|
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
**多进程模式仅支持 Unix。** Windows 上缺少 `os.fork` 时会告警并降级为单进程。
|
|
155
|
+
Web 管理端只在 0 号进程中启动。每个工作进程各自持有适配器和连接池,配置进程数时需计算
|
|
156
|
+
这部分内存开销,尤其是启用浏览器渲染的节点。
|
|
158
157
|
|
|
159
|
-
|
|
158
|
+
协程模式控制单个进程内的并发方式,多进程用于利用多个 CPU 核,两项可以组合使用。
|
|
160
159
|
|
|
161
160
|
基准数据、按 host 限流与容量规划见 [性能与容量](https://github.com/yuanqimanong/IPClick/wiki/Performance)。
|
|
162
|
-
|
|
161
|
+
使用以下命令初始化配置。
|
|
163
162
|
|
|
164
163
|
```bash
|
|
165
164
|
ipclick init
|
|
166
165
|
```
|
|
167
166
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
该命令生成 `ipclick.toml`(行为配置)和 `.env`(机密),并在 `.env` 中填入随机 Web 密码。
|
|
168
|
+
POSIX 上 `.env` 使用 **600** 权限,Windows 上由目录的 NTFS ACL 控制访问。
|
|
169
|
+
已有 `.gitignore` 会补入缺少的 `.env` 规则。新目录需要自行创建 `.gitignore` 并加入该项。
|
|
170
|
+
已有配置文件会被保留,需要覆盖时使用 `--force`。
|
|
172
171
|
|
|
173
|
-
|
|
172
|
+
也可以分别导出配置模板。
|
|
174
173
|
|
|
175
174
|
```bash
|
|
176
175
|
ipclick -e > ipclick.toml # 配置模板(-e 等价于 -e toml)
|
|
@@ -195,15 +194,14 @@ IPCLICK_PROXY_AUTH_PASSWORD 代理密码
|
|
|
195
194
|
IPCLICK_CLUSTER_SECRET 集群共享密钥(所有节点一致;每台机器的令牌由它派生)
|
|
196
195
|
```
|
|
197
196
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
两边都写时**环境变量优先**。
|
|
197
|
+
机密也可以写入 `ipclick.toml`,启动时会列出提醒,避免凭据随配置进入 Git、备份或 CI 日志。
|
|
198
|
+
确认允许这种配置时,可设 `[SECURITY].allow_secrets_in_config = true` 关闭提醒。
|
|
199
|
+
同一项同时出现在配置文件和环境变量中时,**环境变量优先**。
|
|
202
200
|
|
|
203
|
-
`ipclick config-info`
|
|
204
|
-
|
|
201
|
+
`ipclick config-info` 会逐项显示机密来源(环境变量 / 配置文件 / 未配置),
|
|
202
|
+
同时列出当前生效的 TLS、鉴权、限流、浏览器引擎和运行模式。
|
|
205
203
|
|
|
206
|
-
|
|
204
|
+
查看生效配置。
|
|
207
205
|
|
|
208
206
|
```bash
|
|
209
207
|
ipclick config-info
|
|
@@ -237,17 +235,17 @@ with Downloader() as downloader:
|
|
|
237
235
|
print(f"请求失败: {response.error}")
|
|
238
236
|
```
|
|
239
237
|
|
|
240
|
-
`request()`
|
|
241
|
-
|
|
238
|
+
`request()` 及各便捷方法在传输失败、DNS 解析失败时返回 `status_code == -1` 且 `error`
|
|
239
|
+
非空的 `DownloadResponse`。参数、准入策略或依赖问题会抛出下表中的异常。
|
|
242
240
|
|
|
243
241
|
| 异常 | 什么时候 |
|
|
244
242
|
|---|---|
|
|
245
243
|
| `ValidationError` | 参数不合法(URL 为空、方法不支持…),**以及重定向超过 10 跳** |
|
|
246
244
|
| `URLNotAllowedError` | 入口 URL **或任何一跳重定向目标**被 `[SECURITY]` 拒绝 |
|
|
247
245
|
| `AdapterError` | 适配器/浏览器没准备好 |
|
|
248
|
-
| `HostLimitTimeout` | 等 per-host 配额超时
|
|
246
|
+
| `HostLimitTimeout` | 等 per-host 配额超时 |
|
|
249
247
|
|
|
250
|
-
|
|
248
|
+
代理、流式下载、断点续传、批量、异步和指定适配器的用法见
|
|
251
249
|
[SDK 用法](https://github.com/yuanqimanong/IPClick/wiki/SDK-Usage)。
|
|
252
250
|
|
|
253
251
|
## 🖥️ Web 管理端
|
|
@@ -256,9 +254,9 @@ with Downloader() as downloader:
|
|
|
256
254
|
ipclick run --web # 或 -w
|
|
257
255
|
```
|
|
258
256
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
257
|
+
启动时会输出访问地址和用户名。未配置密码时会随机生成并打印,重启后失效。
|
|
258
|
+
固定凭据可通过环境变量、`.env` 或 `[WEB].username` / `password` 配置,已配置的密码不会回显。
|
|
259
|
+
推荐将凭据放在环境变量或 `.env` 中。
|
|
262
260
|
|
|
263
261
|
```bash
|
|
264
262
|
IPCLICK_WEB_USER=ops IPCLICK_WEB_PASSWORD=... ipclick run -w
|
|
@@ -273,25 +271,25 @@ IPCLICK_WEB_USER=ops IPCLICK_WEB_PASSWORD=... ipclick run -w
|
|
|
273
271
|
| **配置** `/config` | 75 项配置分 10 组(可折叠),写回 `ipclick.toml`(保留注释、留 `.bak`);隧道代理整串粘贴自动拆分(地址进 toml、凭据进 `.env`);集群节点增删 |
|
|
274
272
|
| **AI 接入** `/skill` | 技能包全文、安装命令与 `SKILL.md` 下载 |
|
|
275
273
|
|
|
276
|
-
|
|
277
|
-
|
|
274
|
+
「试一试」通过本进程的 `TaskService` 执行请求,应用相同的 SSRF 准入、限流和转发规则,
|
|
275
|
+
执行记录也会出现在请求流中。
|
|
278
276
|
|
|
279
|
-
|
|
277
|
+
涉及安全边界的设置需在部署时配置,界面会限制编辑这些项目。
|
|
278
|
+
包括 `[SECURITY]` 全部、Web 登录凭据、集群共享密钥与节点 token、
|
|
280
279
|
`[BROWSER].allow_scripts`、`[BROWSER].executable_path`、`[CLUSTER].allow_remote_install`。
|
|
281
|
-
|
|
282
|
-
表单里让人顺手划过去。
|
|
280
|
+
后三项分别影响页内脚本执行、本机程序启动和远程装包权限。
|
|
283
281
|
|
|
284
282
|
> ⚠️ 界面本身是**明文 HTTP**,默认只监听 `127.0.0.1`。要远程访问请用 SSH 隧道,或放在做了
|
|
285
283
|
> TLS 终止的反向代理之后。局域网自用可以 `--web-lan`(等价于 `--web-host 0.0.0.0`),但开
|
|
286
284
|
> 之前先把 `[SECURITY].auth_token` 配上——同网段的人绕过网页直连 gRPC 端口是更省事的那条路。
|
|
287
285
|
|
|
288
|
-
|
|
286
|
+
页面功能、配置写回机制、CSP 和会话设计见
|
|
289
287
|
[Web 管理端](https://github.com/yuanqimanong/IPClick/wiki/Web-Console)。
|
|
290
288
|
|
|
291
289
|
## 🤖 命令行(给人,也给 AI)
|
|
292
290
|
|
|
293
|
-
|
|
294
|
-
|
|
291
|
+
`init` / `run` / `health` / `config-info` 用于部署和诊断,仅提供可读文本输出。
|
|
292
|
+
供脚本和 AI 代理调用的命令支持 `-J/--json`,常用入口如下。
|
|
295
293
|
|
|
296
294
|
```bash
|
|
297
295
|
ipclick status --json # 服务端在不在、这台机器能用哪些适配器
|
|
@@ -302,9 +300,8 @@ ipclick component list --json # 五个可选组件的安装状态
|
|
|
302
300
|
ipclick config show --json # 生效配置(机密脱敏)
|
|
303
301
|
```
|
|
304
302
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
退出码一致。
|
|
303
|
+
启用 `--json` 后,**stdout 仅输出一个 JSON 文档**,日志和进度写入 stderr,可使用
|
|
304
|
+
`ipclick ... --json | jq` 处理结果。文档包含 `ok` 和 `exit_code`,其中 `exit_code` 与进程退出码一致。
|
|
308
305
|
|
|
309
306
|
| 退出码 | 含义 | 往哪儿查 |
|
|
310
307
|
|---|---|---|
|
|
@@ -315,16 +312,14 @@ ipclick config show --json # 生效配置(机密脱敏)
|
|
|
315
312
|
| 4 | 鉴权失败 | 令牌(`IPCLICK_AUTH_TOKEN`) |
|
|
316
313
|
| 5 | 参数被服务端拒绝,或本地配置不合法 | 调用参数或 `ipclick.toml` |
|
|
317
314
|
|
|
318
|
-
`status` 为 `-1` **或 `null`**
|
|
319
|
-
|
|
315
|
+
`status` 为 `-1` **或 `null`** 时表示未收到 HTTP 响应。判断执行结果时先读取
|
|
316
|
+
`exit_code` / `ok`,再用 `reached_server` 区分请求是否到达 IPClick 服务端。
|
|
320
317
|
|
|
321
|
-
`--json`
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
不出任何东西。
|
|
318
|
+
`--json` 输出的 `body` 默认最多保留 **65536 个字符**,超出时标记 `body_truncated: true`。
|
|
319
|
+
`--max-body 0` 可输出完整内容,`-o <file>` 写文件也保留完整响应体。图片、压缩流等非 UTF-8
|
|
320
|
+
响应使用 `body_encoding` 为 `base64` 的表示,超过上限时返回空串,避免输出无法解码的片段。
|
|
325
321
|
|
|
326
|
-
|
|
327
|
-
以及几个最容易踩的坑):
|
|
322
|
+
随 wheel 分发的技能包介绍适用场景、输出格式和调用注意事项。可用以下命令安装到 AI 代理目录。
|
|
328
323
|
|
|
329
324
|
```bash
|
|
330
325
|
ipclick skill install # 写到 .claude/skills/ipclick/SKILL.md
|
|
@@ -343,11 +338,10 @@ docker run -d -p 9528:9528 -p 127.0.0.1:9527:9527 --name ipclick ipclick:latest
|
|
|
343
338
|
ipclick run -w --web-lan
|
|
344
339
|
```
|
|
345
340
|
|
|
346
|
-
镜像基于 **python:3.14-slim
|
|
347
|
-
|
|
348
|
-
JS 页面,不用在容器里再下一遍。
|
|
341
|
+
镜像基于 **python:3.14-slim**,采用多阶段构建并以非 root 用户运行。
|
|
342
|
+
默认包含 patchright 和 Chromium 本体,使用 `-a patchright` 即可渲染 JS 页面。
|
|
349
343
|
|
|
350
|
-
|
|
344
|
+
纯 HTTP 场景可构建精简版,减少约 1.5 GB 的浏览器文件。
|
|
351
345
|
|
|
352
346
|
```bash
|
|
353
347
|
docker build -f docker/Dockerfile --build-arg ENGINE=none -t ipclick:slim .
|
|
@@ -358,21 +352,20 @@ docker build -f docker/Dockerfile --build-arg ENGINE=none -t ipclick:slim .
|
|
|
358
352
|
|
|
359
353
|
## 🚧 已知限制
|
|
360
354
|
|
|
361
|
-
|
|
355
|
+
部署前需了解以下功能边界。
|
|
362
356
|
|
|
363
357
|
- **服务发现只支持 `static` 与 `dns`**。etcd / Consul 的原生 API 没接(Consul 可以走它的
|
|
364
358
|
DNS 接口)。
|
|
365
|
-
-
|
|
359
|
+
- **分块下载与临时存储**未实现。目前可使用流式下载处理大文件。
|
|
366
360
|
- **集群流式只有建流这一步会故障转移**。流建立之后中途断掉不会自动重连——那需要 Range 请求
|
|
367
361
|
才能不重复数据。批量请求整批发给同一个节点,不跨节点拆分。
|
|
368
362
|
- **没有文件上传字段**。要发 multipart 就自己拼好请求体,用 `data=<bytes>` 加上
|
|
369
363
|
`Content-Type: multipart/form-data; boundary=...` 发出去。`files=` 不在协议里,进程内直接
|
|
370
364
|
传给适配器时会抛 `ValidationError`。
|
|
371
365
|
- **查询参数原样传递。** `params={"start": "2024-01-01"}` 发出去就是 `start=2024-01-01`。
|
|
372
|
-
-
|
|
373
|
-
Session
|
|
374
|
-
|
|
375
|
-
由底层库处理。需要保持会话请在请求里显式传 `cookies=`。
|
|
366
|
+
- **两次请求之间不保持 Cookie 会话。** `curl_cffi` / `niquests` 会复用按连接属性缓存的
|
|
367
|
+
Session,并在每次请求前清空 cookie jar,避免不同调用方共用 Cookie。
|
|
368
|
+
单次请求内部(含重定向链)的 Cookie 由底层库处理。需要携带会话状态时,请在请求中显式传入 `cookies=`。
|
|
376
369
|
|
|
377
370
|
## 🛠️ 开发
|
|
378
371
|
|
|
@@ -384,16 +377,17 @@ uv run ruff format src/ tests/ # 代码格式化
|
|
|
384
377
|
uv run basedpyright src/ tests/ # 类型检查
|
|
385
378
|
```
|
|
386
379
|
|
|
387
|
-
修改 `src/ipclick/dto/proto/task.proto`
|
|
380
|
+
修改 `src/ipclick/dto/proto/task.proto` 后需重新生成代码。
|
|
388
381
|
|
|
389
382
|
```bash
|
|
390
383
|
uv run python src/ipclick/dto/proto/generate.py
|
|
391
384
|
```
|
|
392
385
|
|
|
393
|
-
依赖按用途分组(`test` / `lint` / `proto` / `release`,`dev` 是聚合组),
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
386
|
+
依赖按用途分组(`test` / `lint` / `proto` / `release`,`dev` 是聚合组),CI 按任务安装依赖。
|
|
387
|
+
`[camoufox]` 与 `[playwright]`、`[linux]` 与 `[playwright]` 在 `[tool.uv].conflicts` 中分别声明为互斥。
|
|
388
|
+
当前 Camoufox 0.5.9 要求 `playwright<1.63`,锁文件为 Camoufox 和独立 Playwright extra 分别解析依赖。
|
|
389
|
+
安装可选适配器时,请逐项列出 `--extra`。
|
|
390
|
+
同时选择互斥组合或使用 `--all-extras` 会导致解析失败。
|
|
397
391
|
|
|
398
392
|
项目结构、门禁清单、提交规范与发布流程见 [开发](https://github.com/yuanqimanong/IPClick/wiki/Development)。
|
|
399
393
|
|