#代理池 API
源码: https://github.com/x-haose/hs-net/blob/main/examples/proxy/api_proxy.py
api_proxy.py
"""
代理池 API
通过 ApiProxyProvider 对接代理池 API,自动获取代理地址。
通过 Clash 中转连接海外代理。
链路: 引擎 -> ProxyService(本地代理) -> Clash(中转) -> 代理池网关(认证) -> 目标站
运行前请确保:
1. 本地 Clash 已启动(用于中转连接海外代理)
2. 替换 API_URL 为你的代理池 API 地址
3. 替换 PROXY_USER / PROXY_PASS 为你的认证账户
同步 + 异步双模式演示,循环验证所有引擎均支持。
"""
import asyncio
from httpx import Response as HttpxResponse
from hs_net import ApiProxyProvider, EngineEnum, Net, ProxyService, SyncNet
# 代理池 API 地址
API_URL = "https://..."
# 代理认证账户
PROXY_USER = ""
PROXY_PASS = ""
# 本地 Clash 代理地址,用作中转(海外代理不接受国内直连)
CLASH_PROXY = "http://127.0.0.1:7897"
TEST_URL = "http://ip-api.com/json/"
SYNC_ENGINES = [
EngineEnum.HTTPX,
EngineEnum.REQUESTS,
EngineEnum.CURL_CFFI,
EngineEnum.REQUESTS_GO,
]
ASYNC_ENGINES = [
EngineEnum.HTTPX,
EngineEnum.AIOHTTP,
EngineEnum.CURL_CFFI,
EngineEnum.REQUESTS_GO,
]
def parse_proxy(resp: HttpxResponse) -> str:
"""从代理池 API 响应中提取代理地址。
响应格式::
{"code": 0, "success": true, "data": [{"ip": "1.2.3.4", "port": 8080}]}
Returns:
带认证的代理地址,如 ``"https://user:pass@1.2.3.4:8080"``。
Raises:
RuntimeError: API 返回错误(如白名单未配置)。
"""
data = resp.json()
if not data.get("success"):
raise RuntimeError(f"代理池 API 错误: {data.get('msg', '未知错误')}")
item = data["data"][0]
return f"https://{PROXY_USER}:{PROXY_PASS}@{item['ip']}:{item['port']}"
def sync_demo():
"""同步模式演示。"""
print("=== 同步模式 ===")
provider = ApiProxyProvider(API_URL, parser=parse_proxy)
svc = ProxyService(provider=provider, transit=CLASH_PROXY)
for engine in SYNC_ENGINES:
with SyncNet(proxy=svc, engine=engine, retries=0, timeout=5) as net:
resp = net.get(TEST_URL)
ip = resp.json_data["query"]
print(f"{engine.value:12s} -> IP: {ip}")
# 每个引擎换一个新代理
svc.switch()
async def async_demo():
"""异步模式演示。"""
print("\n=== 异步模式 ===")
provider = ApiProxyProvider(API_URL, parser=parse_proxy)
svc = ProxyService(provider=provider, transit=CLASH_PROXY)
for engine in ASYNC_ENGINES:
async with Net(proxy=svc, engine=engine, retries=0, timeout=5) as net:
resp = await net.get(TEST_URL)
ip = resp.json_data["query"]
print(f"{engine.value:12s} -> IP: {ip}")
# 每个引擎换一个新代理(异步版本)
await svc.async_switch()
if __name__ == "__main__":
sync_demo()
asyncio.run(async_demo())
