Files
mayuqi-crypto_stealth-browser/scripts/proxy_rotate.py

280 lines
8.6 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
Proxy Rotation Manager
Supports residential, datacenter, and SOCKS proxies
"""
import json
import random
import time
import requests
from pathlib import Path
from typing import Optional, List, Dict
from dataclasses import dataclass
from collections import defaultdict
SECRETS_DIR = Path.home() / ".clawdbot" / "secrets"
@dataclass
class ProxyInfo:
url: str
type: str # residential, datacenter, socks5
country: Optional[str] = None
last_used: float = 0
fail_count: int = 0
success_count: int = 0
class ProxyPool:
"""Manage and rotate through proxy pool"""
def __init__(self, config_path: Optional[Path] = None):
self.config_path = config_path or (SECRETS_DIR / "proxies.json")
self.proxies: List[ProxyInfo] = []
self.stats: Dict[str, Dict] = defaultdict(lambda: {"success": 0, "fail": 0})
self._load_config()
def _load_config(self):
"""Load proxies from config file"""
if not self.config_path.exists():
return
config = json.loads(self.config_path.read_text())
# Load residential proxies
for proxy in config.get("residential", []):
if isinstance(proxy, str):
self.proxies.append(ProxyInfo(url=proxy, type="residential"))
else:
self.proxies.append(ProxyInfo(
url=proxy.get("url"),
type="residential",
country=proxy.get("country")
))
# Load datacenter proxies
for proxy in config.get("datacenter", []):
if isinstance(proxy, str):
self.proxies.append(ProxyInfo(url=proxy, type="datacenter"))
else:
self.proxies.append(ProxyInfo(
url=proxy.get("url"),
type="datacenter",
country=proxy.get("country")
))
# Load rotating proxy (single endpoint)
rotating = config.get("rotating")
if rotating:
self.proxies.append(ProxyInfo(url=rotating, type="rotating"))
def get_proxy(self,
proxy_type: Optional[str] = None,
country: Optional[str] = None,
exclude_failed: bool = True) -> Optional[str]:
"""
Get a proxy from the pool
Args:
proxy_type: Filter by type (residential, datacenter, rotating)
country: Filter by country code
exclude_failed: Skip proxies with high fail rate
Returns:
Proxy URL or None
"""
candidates = self.proxies.copy()
if proxy_type:
candidates = [p for p in candidates if p.type == proxy_type]
if country:
candidates = [p for p in candidates if p.country == country]
if exclude_failed:
# Exclude proxies with >50% fail rate and at least 3 attempts
candidates = [p for p in candidates
if p.success_count + p.fail_count < 3 or
p.fail_count / (p.success_count + p.fail_count) < 0.5]
if not candidates:
return None
# Prefer least recently used
candidates.sort(key=lambda p: p.last_used)
chosen = candidates[0]
chosen.last_used = time.time()
return chosen.url
def mark_success(self, proxy_url: str):
"""Mark proxy as successful"""
for p in self.proxies:
if p.url == proxy_url:
p.success_count += 1
break
self.stats[proxy_url]["success"] += 1
def mark_failed(self, proxy_url: str):
"""Mark proxy as failed"""
for p in self.proxies:
if p.url == proxy_url:
p.fail_count += 1
break
self.stats[proxy_url]["fail"] += 1
def get_stats(self) -> Dict:
"""Get proxy usage statistics"""
return {
"total": len(self.proxies),
"by_type": {
"residential": len([p for p in self.proxies if p.type == "residential"]),
"datacenter": len([p for p in self.proxies if p.type == "datacenter"]),
"rotating": len([p for p in self.proxies if p.type == "rotating"])
},
"usage": dict(self.stats)
}
def test_proxy(proxy_url: str, test_url: str = "https://httpbin.org/ip", timeout: int = 10) -> Dict:
"""
Test if a proxy is working
Returns:
dict: {success: bool, ip: str, latency_ms: int, error: str}
"""
proxies = {
"http": proxy_url,
"https": proxy_url
}
start = time.time()
try:
resp = requests.get(test_url, proxies=proxies, timeout=timeout)
latency = int((time.time() - start) * 1000)
if resp.status_code == 200:
data = resp.json()
return {
"success": True,
"ip": data.get("origin"),
"latency_ms": latency
}
else:
return {
"success": False,
"error": f"HTTP {resp.status_code}",
"latency_ms": latency
}
except Exception as e:
return {
"success": False,
"error": str(e)
}
def get_my_ip() -> str:
"""Get current public IP without proxy"""
try:
return requests.get("https://httpbin.org/ip", timeout=5).json()["origin"]
except:
return "unknown"
def create_proxy_config_template():
"""Create template proxies.json"""
template = {
"rotating": "http://user:pass@rotating-proxy.provider.com:port",
"residential": [
"socks5://user:pass@residential1.provider.com:port",
"socks5://user:pass@residential2.provider.com:port"
],
"datacenter": [
"http://user:pass@dc1.provider.com:port",
"http://user:pass@dc2.provider.com:port"
],
"_comment": "Replace with your actual proxy credentials. Types: http, https, socks5"
}
SECRETS_DIR.mkdir(parents=True, exist_ok=True)
config_path = SECRETS_DIR / "proxies.json"
if not config_path.exists():
config_path.write_text(json.dumps(template, indent=2))
print(f"Created template: {config_path}")
return config_path
else:
print(f"Config already exists: {config_path}")
return None
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='Proxy Manager')
subparsers = parser.add_subparsers(dest='command')
# Get proxy
get_parser = subparsers.add_parser('get', help='Get a proxy')
get_parser.add_argument('--type', '-t', choices=['residential', 'datacenter', 'rotating'],
help='Proxy type')
get_parser.add_argument('--country', '-c', help='Country code')
# Test proxy
test_parser = subparsers.add_parser('test', help='Test a proxy')
test_parser.add_argument('proxy', help='Proxy URL')
# Test all
test_all_parser = subparsers.add_parser('test-all', help='Test all proxies')
# Stats
stats_parser = subparsers.add_parser('stats', help='Show statistics')
# Init config
init_parser = subparsers.add_parser('init', help='Create config template')
# My IP
myip_parser = subparsers.add_parser('myip', help='Show current IP')
args = parser.parse_args()
if args.command == 'get':
pool = ProxyPool()
proxy = pool.get_proxy(proxy_type=args.type, country=args.country)
if proxy:
print(proxy)
else:
print("No proxy available")
exit(1)
elif args.command == 'test':
result = test_proxy(args.proxy)
print(json.dumps(result, indent=2))
if not result["success"]:
exit(1)
elif args.command == 'test-all':
pool = ProxyPool()
print(f"Testing {len(pool.proxies)} proxies...")
for p in pool.proxies:
result = test_proxy(p.url)
status = "" if result.get("success") else ""
ip = result.get("ip", result.get("error", "N/A"))
latency = result.get("latency_ms", "N/A")
print(f"{status} [{p.type}] {p.url[:40]}... -> {ip} ({latency}ms)")
elif args.command == 'stats':
pool = ProxyPool()
print(json.dumps(pool.get_stats(), indent=2))
elif args.command == 'init':
create_proxy_config_template()
elif args.command == 'myip':
print(get_my_ip())
else:
parser.print_help()