-
Notifications
You must be signed in to change notification settings - Fork 0
Adapters
适配器决定「这个请求实际怎么发出去」。同一份调用代码,换个 adapter= 就换了底层实现。
| 名字 | 装法 | 适合 | 特点 |
|---|---|---|---|
curl_cffi |
默认自带 | 绝大多数场景 | 唯一带 TLS 指纹伪装;HTTP/1.1 + HTTP/2 |
niquests |
pip install "ipclick[niquests]" |
需要 HTTP/3、或纯 API 调用 | HTTP/1.1 + HTTP/2 + HTTP/3 (QUIC);requests 兼容 API |
browser |
见浏览器渲染 | 内容要 JS 跑完才有 | 通用名,引擎由服务端 [BROWSER].engine 定 |
camoufox / patchright / playwright / DrissionPage
|
同上 | 要点名某个引擎时 | 见浏览器渲染 |
请求级选择:
d.get(url) # curl_cffi
d.get(url, adapter="niquests")
d.get(url, adapter="browser") # 引擎由服务端定 —— 推荐这么写
d.get(url, adapter="camoufox") # 点名,服务端没装就报 AdapterError基于 libcurl-impersonate。它的价值在于TLS 指纹:很多站点在 TLS 握手阶段就能看出
「这不是浏览器」,此时改 User-Agent 是没用的,因为 JA3/JA4 指纹对不上。curl_cffi
直接复刻真实浏览器的 ClientHello。
d.get(url, impersonate="chrome124")不传的话用适配器自己的默认。可选值跟随 curl_cffi 版本(chrome* / safari* / edge* 等)。
只有 curl_cffi 支持
impersonate。 别的适配器收到这个参数会报错而不是忽略—— 静默忽略的话你以为伪装开着,实际裸奔,被封了都不知道为什么。
requests 的现代继任者,API 几乎一样。
d.get(url, adapter="niquests")用它的两种情形:
- 目标站点走 HTTP/3。QUIC 在移动网络和高丢包链路上明显更快。
- 对方不做指纹检测(自家 API、公开接口),此时不需要 curl_cffi 的伪装开销。
0.3.0 起
requests和httpx两个适配器都已移除。旧代码传这两个名字会得到一条 明确的迁移提示("请改用 niquests"),而不是笼统的"不支持"。protobuf 枚举值保留并标了deprecated,不会被复用——旧客户端连新服务端时报的是有用的话。
请求 adapter="browser" 是通用写法:客户端只表达「我要渲染」,具体引擎由服务端的
[BROWSER].engine 决定。好处是客户端代码不用关心每台节点装了什么——Windows 节点用
DrissionPage、Linux 节点用 camoufox,同一份调用代码都能跑。
点名(adapter="camoufox")表达的是「我就要这个引擎」。服务端没装就直接失败——
这也是对的:你要的是 camoufox 的反检测特性,悄悄换成 playwright 只会让你以为它生效了。
不管用哪个适配器,下面这些都一样——它们实现在基类里而不是各写一遍:
[DOWNLOADER.retry]
max_attempts = 3
initial_backoff = 1
backoff_exponent = 2.0
max_backoff = 30 # 硬上限 300
retry_codes = [429, 500, 502, 503, 504]等待时间 = initial_backoff × exponent^已重试次数,封顶 max_backoff。
连接层异常总是重试,与 retry_codes 无关。
不会重试的东西:AdapterError(依赖缺失、引擎未就绪、脚本语法错、永久性导航错误)。
这些重试多少次都是同一个结果,只会把失败反馈拖慢好几倍。
单次请求可以覆盖:
d.get(url, max_retries=0, timeout=5)d.get(url, allowed_status_codes=[200, 404])告诉适配器哪些状态码算"正常结束"。默认下 429/5xx 会触发重试;如果你就是要探测 404, 把它列进来可以省掉三次无谓重试。
timeout 是单次尝试的上限,不是总时长。带重试时最坏总耗时约
timeout × (max_retries + 1) + 退避总和。集群转发的默认超时就是按这个公式推的
(见集群)。
并发闸门与 QPS 令牌桶对所有适配器统一生效,见性能。
from ipclick.adapters.base import DownloaderAdapter
from ipclick.adapters.registry import register_adapter
class MyAdapter(DownloaderAdapter):
adapter_name = "my_adapter"
def download(self, task, **kwargs): ...
register_adapter(MyAdapter)注册后 adapter="my_adapter" 就能用了。注意这是服务端行为——注册要在服务端进程里做,
客户端只是传一个名字。
| 报错 | 含义 |
|---|---|
适配器 'httpx' 已移除:请改用 niquests… |
0.3.0 移除了它 |
适配器 'niquests' 需要额外依赖:pip install "ipclick[niquests]" |
包没装 |
引擎 camoufox 的浏览器本体未就绪,请执行 python -m camoufox fetch |
包装了、浏览器本体没下 |
下载器适配器 'xxx' 尚未支持,当前可用: … |
名字拼错了 |
curl_cffi 之外的适配器不支持 impersonate=… |
见上文 |
这四种说法刻意区分开:「装一下就能用」「再下个浏览器」「改配置」「改代码」, 对应的处理动作完全不同。