提取接口
用 API Key 换取一批免密的 ip:port,全部参数、响应格式、错误码与频率限制。
提取接口把"地区 + 会话配置"提前固定好,换出一批 ip:port。这些端口通过来源 IP 白名单授权,客户端接入时不需要用户名密码。
GET
/api/v1/proxy/extract认证条件(四条同时满足)
API Key 放在查询字符串里,不是请求头。它属于单个代理账号,一个账号恰好一个 Key,在控制台的代理账号页可以看到明文值。
参数
代理账号的 API Key,长度 20–128。放在查询字符串里。
要提取的数量,范围 1–100。
响应格式,txt 或 json。
txt 格式下的分隔符,只接受三种字面值:\n、\r\n、,。
注意:即使 type=json,这个参数也会先被校验。传了非法值同样返回 400。
两位大写 ISO 国家码。服务端强制校验长度为 2 且字符在 A-Z 范围内。
州 / 省名称,最长 100 字符。
兼容行为:country 为空且 region 恰好是 2 个字符时,region 会被当作国家码使用。
城市名称,最长 100 字符。
会话模式,sticky 或 rotating。
出口粘性会话时长,单位分钟,范围 1–120。
session=sticky时必填session=rotating时必须省略,传了会返回400
请求示例
curl 'https://api.example.com/api/v1/proxy/extract?apikey=YOUR_KEY&num=5&type=json&country=US®ion=California&city=Los%20Angeles&session=sticky&time=10'
轮换模式(不带 time):
curl 'https://api.example.com/api/v1/proxy/extract?apikey=YOUR_KEY&num=10&type=txt&country=DE&session=rotating'
响应格式
txt(默认)
1.2.3.4:20001
1.2.3.4:20002
1.2.3.4:20003
换分隔符:
# 逗号分隔
curl '.../extract?apikey=KEY&num=3&format=,'
# → 1.2.3.4:20001,1.2.3.4:20002,1.2.3.4:20003
json
{
"code": 0,
"data": [
{ "ip": "1.2.3.4", "port": 20001 },
{ "ip": "1.2.3.4", "port": 20002 }
]
}
直接用
# 免密,不带任何凭据
curl -x http://1.2.3.4:20001 https://api.ipify.org
SOCKS5 也在同一个端口上(no-auth 方式):
curl -x socks5h://1.2.3.4:20001 https://api.ipify.org
端口的存活时间
端口绑定在这些情况下被删除:
- API Key 被撤销
- 对应的白名单条目被删除
- 白名单条目因连续 10 天未使用被维护任务自动清理
- 提供该端口的网关节点不健康 —— 下次提取时旧绑定会被删除并重新分配
- 代理账号或 API Key 记录被删除
端口范围
端口范围由每个网关节点自己注册,不是固定常量。注册时的约束:
- 起始端口 ≥
1024 - 结束端口 ≤
65535 - 单节点端口跨度 ≤
4096
所以不要在防火墙规则里写死端口段,按接口实际返回的值配置。
频率限制
每分钟 120 次,并且分别对来源 IP 和 API Key 计数——任意一边超限就返回 429,响应带 Retry-After: 60。
全部错误响应
| 状态码 | 错误码 | 含义 |
|---|---|---|
400 | invalid_proxy_extract_time | time 非整数、不在 1–120;sticky 缺 time;rotating 却传了 time |
400 | invalid_proxy_extract_count | num 非整数或不在 1–100 |
400 | invalid_proxy_extract_type | type 不是 txt / json |
400 | invalid_proxy_extract_format | format 不是 \n / \r\n / , |
400 | invalid_proxy_extract_session | session 不是 sticky / rotating |
401 | proxy_api_key_invalid | Key 格式或状态无效;账号/用户不可用或已过期 |
403 | proxy_source_not_whitelisted | 来源 IP 不在白名单里 |
422 | proxy_api_invalid | 所选国家、州省、城市或会话参数组合不可用 |
429 | proxy_extract_rate_limited | 每 IP 或每 Key 超过 120/min,带 Retry-After: 60 |
502 | client_ip_unavailable | 无法确定调用方的公开 IPv4 |
503 | proxy_gateway_unavailable | 没有健康网关;绑定未确认;端口耗尽。带 Retry-After: 2 |
500 | internal_error | 限流存储或其他内部错误 |
一个可用的封装
import time
from dataclasses import dataclass
import requests
API = "https://api.example.com/api/v1/proxy/extract"
@dataclass
class ExtractError(Exception):
status: int
code: str
message: str
def extract(
api_key: str,
*,
count: int = 10,
country: str | None = None,
region: str | None = None,
city: str | None = None,
sticky_minutes: int | None = 10,
attempts: int = 3,
) -> list[str]:
"""提取一批免密代理,返回 http://ip:port 列表。"""
params: dict[str, object] = {
"apikey": api_key,
"num": count,
"type": "json",
}
if country:
params["country"] = country
if region:
params["region"] = region
if city:
params["city"] = city
# sticky 必须带 time,rotating 必须不带
if sticky_minutes is None:
params["session"] = "rotating"
else:
params["session"] = "sticky"
params["time"] = sticky_minutes
for attempt in range(attempts):
response = requests.get(API, params=params, timeout=15)
if response.status_code == 200:
return [
f"http://{item['ip']}:{item['port']}"
for item in response.json()["data"]
]
# 429 和 503 都给了 Retry-After,照它等
if response.status_code in (429, 503) and attempt < attempts - 1:
time.sleep(int(response.headers.get("Retry-After", "2")))
continue
error = response.json().get("error", {})
raise ExtractError(
status=response.status_code,
code=error.get("code", "unknown"),
message=error.get("message", response.text[:200]),
)
raise ExtractError(status=503, code="exhausted", message="重试次数用尽")
pool = extract("YOUR_API_KEY", count=5, country="US", sticky_minutes=10)
print(pool)
什么时候不该用提取接口
| 场景 | 用什么 |
|---|---|
| 出口 IP 会变(家宽、容器、多云) | 用户名参数接 58971,见 快速开始 |
| 需要按运营商(ASN)定位 | 用户名参数,提取接口不支持 |
| 每个请求都要不同的地区 | 用户名参数,地区能按请求变 |
| 高频换 IP | 用户名参数 + 新连接,别打提取接口的 120/min |