Add archived/proxy-testing
This commit is contained in:
@@ -0,0 +1,274 @@
|
|||||||
|
---
|
||||||
|
name: proxy-testing
|
||||||
|
description: "代理获取、测试、使用 — 免费代理列表抓取 + 付费代理提供商(Bright Data)API操作 + Playwright浏览器cookie注入绕过登录"
|
||||||
|
version: 2.0
|
||||||
|
---
|
||||||
|
|
||||||
|
# Proxy 代理获取与测试
|
||||||
|
|
||||||
|
涵盖免费代理和付费代理提供商(Bright Data 等)的获取、测试和使用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 免费代理获取
|
||||||
|
|
||||||
|
### proxyscrape.com(推荐,免费无需 API key)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SOCKS5 俄罗斯代理
|
||||||
|
curl -s "https://api.proxyscrape.com/v2/?request=displayproxies&protocol=socks5&timeout=5000&country=ru"
|
||||||
|
|
||||||
|
# HTTP 代理
|
||||||
|
curl -s "https://api.proxyscrape.com/v2/?request=displayproxies&protocol=http&timeout=5000&country=us"
|
||||||
|
|
||||||
|
# 全局所有协议
|
||||||
|
curl -s "https://api.proxyscrape.com/v2/?request=displayproxies&protocol=all&timeout=5000"
|
||||||
|
```
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- `protocol`: http / https / socks5 / socks4 / all
|
||||||
|
- `timeout`: 代理超时(ms),建议 5000-10000
|
||||||
|
- `country`: ISO 两字母代码(如 ru, us, jp),留空=全球
|
||||||
|
- `anonymity`: all / elite / anonymous / transparent
|
||||||
|
- `ssl`: all / yes / no
|
||||||
|
|
||||||
|
返回格式:纯文本,每行 `IP:PORT`
|
||||||
|
|
||||||
|
### 其他免费源
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# free-proxy-list.net(需要 JS 渲染,用 DrissionPage 或 Playwright)
|
||||||
|
# geonode free API
|
||||||
|
curl -s "https://proxylist.geonode.com/api/proxy-list?country=RU&limit=50&page=1&sort_by=lastChecked&sort_type=desc"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 注意:proxy-tools.com 端口不可用
|
||||||
|
|
||||||
|
cn.proxy-tools.com 的端口被 reCAPTCHA + 付费墙保护。用 proxyscrape.com 替代。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 连通性测试
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# HTTP 代理
|
||||||
|
curl -s -m 8 --proxy http://IP:PORT https://api.ipify.org?format=json
|
||||||
|
|
||||||
|
# SOCKS5 代理(本系统用 --socks5 而非 --proxy socks5h)
|
||||||
|
curl -s -m 8 --socks5 IP:PORT https://api.ipify.org?format=json
|
||||||
|
|
||||||
|
# SOCKS4 代理
|
||||||
|
curl -s -m 8 --socks4 IP:PORT https://api.ipify.org?format=json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Python 批量测试脚本
|
||||||
|
|
||||||
|
```python
|
||||||
|
import subprocess, json
|
||||||
|
|
||||||
|
def test_proxy(proto, addr, timeout=8):
|
||||||
|
"""测试代理连通性,返回 (ok, detail)"""
|
||||||
|
if proto == "socks5":
|
||||||
|
cmd = ["curl", "-s", "-m", str(timeout), "--socks5", addr, "https://api.ipify.org?format=json"]
|
||||||
|
elif proto == "socks4":
|
||||||
|
cmd = ["curl", "-s", "-m", str(timeout), "--socks4", addr, "https://api.ipify.org?format=json"]
|
||||||
|
else: # http
|
||||||
|
cmd = ["curl", "-s", "-m", str(timeout), "--proxy", f"{proto}://{addr}", "https://api.ipify.org?format=json"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
r = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout+3)
|
||||||
|
if r.returncode == 0 and r.stdout.strip():
|
||||||
|
try:
|
||||||
|
data = json.loads(r.stdout.strip())
|
||||||
|
return True, data.get("ip", "")
|
||||||
|
except:
|
||||||
|
return True, r.stdout.strip()[:50]
|
||||||
|
return False, "timeout/empty"
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
return False, "timeout"
|
||||||
|
except Exception as e:
|
||||||
|
return False, str(e)[:60]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 匿名度检测
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -m 8 --proxy http://IP:PORT https://httpbin.org/headers
|
||||||
|
```
|
||||||
|
|
||||||
|
判断标准:
|
||||||
|
- **透明代理**:响应中有 `X-Forwarded-For` 头(暴露真实IP)
|
||||||
|
- **匿名代理**:有 `Via` 头但无 `X-Forwarded-For`
|
||||||
|
- **高匿名/精英**:两个头都没有
|
||||||
|
|
||||||
|
SOCKS5/SOCKS4 代理天然高匿名(不会添加额外 header)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 实际浏览验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -m 10 --proxy http://IP:PORT https://ya.ru -L | head -5
|
||||||
|
curl -s -m 10 --proxy http://IP:PORT https://www.amazon.com -L | head -5
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Bright Data 付费代理
|
||||||
|
|
||||||
|
Bright Data 提供三种使用方式,优先级从高到低:
|
||||||
|
|
||||||
|
### 5.1 /request API(推荐 — 不需要 IP 白名单)
|
||||||
|
|
||||||
|
```python
|
||||||
|
import urllib.request, json
|
||||||
|
|
||||||
|
API_KEY = "你的API_KEY"
|
||||||
|
payload = {
|
||||||
|
"zone": "zone9", # Zone 名称
|
||||||
|
"url": "https://httpbin.org/ip",
|
||||||
|
"format": "json",
|
||||||
|
"method": "GET",
|
||||||
|
"country": "us", # 可选:指定国家
|
||||||
|
}
|
||||||
|
req = urllib.request.Request(
|
||||||
|
"https://api.brightdata.com/request",
|
||||||
|
data=json.dumps(payload).encode(),
|
||||||
|
method="POST",
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {API_KEY}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
resp = urllib.request.urlopen(req, timeout=30)
|
||||||
|
result = json.loads(resp.read().decode())
|
||||||
|
# result = {"body": "...", "status_code": 200, "headers": {...}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
- 不需要 IP 白名单
|
||||||
|
- `zone47` 支持 `country` 参数(`us`, `kz`, `ru` 已验证)
|
||||||
|
- zone47 不指定 country 时随机分配国家
|
||||||
|
- 只能用于 Active 的 zone(Disabled 的 zone 返回 407 "zone not found")
|
||||||
|
|
||||||
|
### 5.2 直接代理连接(需要 IP 白名单)
|
||||||
|
|
||||||
|
```
|
||||||
|
服务器: brd.superproxy.io:22225
|
||||||
|
用户名: brd-customer-<account_id>-zone-<zone_name>
|
||||||
|
密码: <zone_password>
|
||||||
|
```
|
||||||
|
|
||||||
|
如果机器 IP 未在白名单中,返回 HTTP 407。
|
||||||
|
|
||||||
|
### 5.3 /zone/info API(查询 zone 状态)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST "https://brightdata.com/api/zone/info" \
|
||||||
|
-H "Authorization: Bearer <API_KEY>" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"zone":"zone9"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意:** API Key 权限不足时返回 403。仅 CP-admin 级别 key 可用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Playwright Cookie 注入(绕过登录)
|
||||||
|
|
||||||
|
从浏览器开发者工具导出 cookies(Application → Cookies → Export)后,可通过 Playwright 注入:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import json
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
def parse_cookies(cookie_str: str) -> list:
|
||||||
|
"""解析 Chrome 导出的 cookie JSON 为 Playwright cookies"""
|
||||||
|
cookies = json.loads(cookie_str)
|
||||||
|
for c in cookies:
|
||||||
|
# 关键修复:domain 去除前导点
|
||||||
|
if c["domain"].startswith("."):
|
||||||
|
c["domain"] = c["domain"][1:]
|
||||||
|
# 处理 secure/httpOnly/sameSite 字段
|
||||||
|
c.setdefault("secure", False)
|
||||||
|
c.setdefault("httpOnly", False)
|
||||||
|
c.setdefault("sameSite", "Lax")
|
||||||
|
c.pop("size", None)
|
||||||
|
c.pop("session", None)
|
||||||
|
# 修复过期时间格式
|
||||||
|
if "expires" in c and isinstance(c["expires"], int) and c["expires"] == -1:
|
||||||
|
c.pop("expires")
|
||||||
|
return cookies
|
||||||
|
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch(headless=True)
|
||||||
|
context = browser.new_context()
|
||||||
|
|
||||||
|
# 先访问目标域名,再注入 cookie(某些 cookie 需要 domain 确认)
|
||||||
|
page = context.new_page()
|
||||||
|
page.goto("https://targetsite.com")
|
||||||
|
context.add_cookies(parsed_cookies)
|
||||||
|
page.reload() # 此时已登录状态
|
||||||
|
```
|
||||||
|
|
||||||
|
**陷阱:**
|
||||||
|
1. Domain 不能有前导点(Chrome 导出格式是 `.domain.com`,Playwright 需要 `domain.com`)
|
||||||
|
2. 某些 cookie(如 `__Secure-` 前缀)需要 secure=True + HTTPS 页面
|
||||||
|
3. `sameSite` 必须是 `"Strict"`, `"Lax"`, `"None"` 三者之一
|
||||||
|
4. 必须先用 `page.goto()` 访问域名再 `add_cookies()`,否则某些严格 cookie 被拒绝
|
||||||
|
|
||||||
|
**使用场景:** Bright Data CP 2FA 绕过、ERP 系统登录跳过验证码、Google 账户绕过密码输入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Playwright React 覆盖层(Overlay)处理技巧
|
||||||
|
|
||||||
|
当页面被 React onboarding/tour 覆盖层挡住时:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 方法1:Escape 键关闭
|
||||||
|
page.keyboard.press("Escape")
|
||||||
|
page.wait_for_timeout(1000)
|
||||||
|
|
||||||
|
# 方法2:点击关闭按钮
|
||||||
|
page.locator('button[class*="close"], button[aria-label*="close"], .onboarding-close, .tour-close').first.click()
|
||||||
|
|
||||||
|
# 方法3:强制点击覆盖层后面的元素(用 force=True)
|
||||||
|
page.locator('text=Enable').first.click(force=True, timeout=5000)
|
||||||
|
```
|
||||||
|
|
||||||
|
**陷阱:**
|
||||||
|
- React 动态渲染的按钮可能在 overlay 关闭后才出现(需 wait_for_timeout)
|
||||||
|
- `force=True` 可能触发 `detached from DOM` 错误(按钮被重新渲染)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 与 CamouFox 集成
|
||||||
|
|
||||||
|
```python
|
||||||
|
from camoufox.sync_api import Camoufox
|
||||||
|
|
||||||
|
with Camoufox(
|
||||||
|
headless=True,
|
||||||
|
proxy={"server": "socks5://IP:PORT"}
|
||||||
|
) as browser:
|
||||||
|
page = browser.new_page()
|
||||||
|
page.goto("https://ya.ru")
|
||||||
|
```
|
||||||
|
|
||||||
|
proxy 格式:
|
||||||
|
- HTTP: `{"server": "http://IP:PORT"}`
|
||||||
|
- SOCKS5: `{"server": "socks5://IP:PORT"}`
|
||||||
|
- 带认证: `{"server": "socks5://IP:PORT", "username": "u", "password": "p"}`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 预期结果
|
||||||
|
|
||||||
|
| 代理类型 | 可用率 | 寿命 | 匿名度 |
|
||||||
|
|---------|--------|------|--------|
|
||||||
|
| 免费代理 | 5-6% | 小时级 | 中高 |
|
||||||
|
| Bright Data DC | ~100% | 分钟-小时 | 高 |
|
||||||
|
| Bright Data Residential | ~100% | 动态IP | 高 |
|
||||||
Reference in New Issue
Block a user