740 lines
22 KiB
Python
740 lines
22 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Webshare SOCKS代理获取脚本
|
||
使用简单的下载接口直接获取代理列表
|
||
"""
|
||
|
||
import os
|
||
import requests
|
||
import yaml
|
||
import json
|
||
import base64
|
||
from typing import Optional, List, Dict
|
||
|
||
def load_api_key() -> Optional[str]:
|
||
"""
|
||
从.env文件或环境变量中加载API密钥
|
||
|
||
Returns:
|
||
API密钥或None
|
||
"""
|
||
# 首先尝试从.env文件读取
|
||
env_file = ".env"
|
||
if os.path.exists(env_file):
|
||
try:
|
||
with open(env_file, 'r', encoding='utf-8') as f:
|
||
for line in f:
|
||
line = line.strip()
|
||
if not line or line.startswith('#'):
|
||
continue
|
||
if '=' in line:
|
||
# 处理 TOKEN=xxx 格式
|
||
key, value = line.split('=', 1)
|
||
if key.strip() == 'TOKEN':
|
||
return value.strip()
|
||
else:
|
||
# 如果第一行不包含=,则认为是直接的token
|
||
return line
|
||
except Exception as e:
|
||
print(f"读取.env文件时出错: {e}")
|
||
|
||
# 然后尝试从环境变量读取
|
||
api_key = os.getenv('TOKEN') or os.getenv('WEBSHARE_API_KEY')
|
||
if api_key:
|
||
return api_key.strip()
|
||
|
||
return None
|
||
|
||
def get_download_token(api_key: str) -> Optional[str]:
|
||
"""
|
||
获取下载token
|
||
|
||
Args:
|
||
api_key: API密钥
|
||
|
||
Returns:
|
||
下载token或None
|
||
"""
|
||
url = "https://proxy.webshare.io/api/v2/download_token/proxy_list/"
|
||
headers = {
|
||
"Authorization": f"Token {api_key}",
|
||
"Content-Type": "application/json"
|
||
}
|
||
|
||
try:
|
||
print("🔑 正在获取下载token...")
|
||
response = requests.post(url, headers=headers)
|
||
|
||
if response.status_code == 200:
|
||
data = response.json()
|
||
download_token = data.get("key") # API返回的字段是'key'而不是'download_token'
|
||
if download_token:
|
||
print("✅ 成功获取下载token")
|
||
return download_token
|
||
else:
|
||
print("❌ 响应中未找到下载token")
|
||
print(f"🔍 可用的键: {list(data.keys())}")
|
||
return None
|
||
else:
|
||
print(f"❌ 获取下载token失败 {response.status_code}: {response.text}")
|
||
return None
|
||
|
||
except requests.exceptions.RequestException as e:
|
||
print(f"获取下载token时出错: {e}")
|
||
return None
|
||
|
||
def download_proxies(download_token: str, country: str = "-", auth_method: str = "username",
|
||
endpoint_mode: str = "direct", location: str = ""):
|
||
"""
|
||
使用下载token获取代理列表
|
||
|
||
Args:
|
||
download_token: 下载token (不是API key)
|
||
country: 国家代码 (- 表示任意国家)
|
||
auth_method: 认证方式 (username 或 ipauth)
|
||
endpoint_mode: 端点模式 (direct 或 backbone)
|
||
location: 位置过滤 (可选)
|
||
|
||
Returns:
|
||
代理列表文本
|
||
"""
|
||
# 构建下载URL - 正确的格式
|
||
if location:
|
||
# URL编码位置参数
|
||
location_encoded = requests.utils.quote(location)
|
||
url = f"https://proxy.webshare.io/api/v2/proxy/list/download/{download_token}/{country}/any/{auth_method}/{endpoint_mode}/{location_encoded}/"
|
||
else:
|
||
# 没有位置过滤时,不包含最后的路径参数
|
||
url = f"https://proxy.webshare.io/api/v2/proxy/list/download/{download_token}/{country}/any/{auth_method}/{endpoint_mode}/"
|
||
|
||
try:
|
||
print(f"📡 正在从下载接口获取代理: {url}")
|
||
response = requests.get(url)
|
||
|
||
# 检查响应状态
|
||
if response.status_code == 404:
|
||
print("❌ 404错误 - 可能是URL格式不正确或token无效")
|
||
return None
|
||
elif response.status_code == 401:
|
||
print("❌ 401错误 - 下载token无效")
|
||
return None
|
||
elif response.status_code != 200:
|
||
print(f"❌ HTTP错误 {response.status_code}: {response.text}")
|
||
return None
|
||
|
||
# 检查是否返回了错误信息
|
||
if "invalid" in response.text.lower() or "error" in response.text.lower():
|
||
print(f"❌ API返回错误: {response.text}")
|
||
return None
|
||
|
||
return response.text
|
||
|
||
except requests.exceptions.RequestException as e:
|
||
print(f"下载代理列表时出错: {e}")
|
||
return None
|
||
|
||
def format_proxy_list(proxy_text: str, output_format: str = "socks5") -> list:
|
||
"""
|
||
格式化代理列表
|
||
|
||
Args:
|
||
proxy_text: 原始代理文本
|
||
output_format: 输出格式 (socks5, http, raw)
|
||
|
||
Returns:
|
||
格式化的代理列表
|
||
"""
|
||
if not proxy_text:
|
||
return []
|
||
|
||
lines = proxy_text.strip().split('\n')
|
||
formatted_proxies = []
|
||
|
||
for line in lines:
|
||
line = line.strip()
|
||
if not line:
|
||
continue
|
||
|
||
# 假设格式为: ip:port:username:password
|
||
parts = line.split(':')
|
||
if len(parts) >= 4:
|
||
ip, port, username, password = parts[0], parts[1], parts[2], parts[3]
|
||
|
||
if output_format == "socks5":
|
||
formatted_proxy = f"socks5://{username}:{password}@{ip}:{port}"
|
||
elif output_format == "http":
|
||
formatted_proxy = f"http://{username}:{password}@{ip}:{port}"
|
||
else: # raw
|
||
formatted_proxy = line
|
||
|
||
formatted_proxies.append(formatted_proxy)
|
||
elif len(parts) >= 2:
|
||
# 无认证格式: ip:port
|
||
ip, port = parts[0], parts[1]
|
||
if output_format == "socks5":
|
||
formatted_proxy = f"socks5://{ip}:{port}"
|
||
elif output_format == "http":
|
||
formatted_proxy = f"http://{ip}:{port}"
|
||
else: # raw
|
||
formatted_proxy = line
|
||
|
||
formatted_proxies.append(formatted_proxy)
|
||
|
||
return formatted_proxies
|
||
|
||
def save_proxies_to_file(proxies: list, filename: str = "socks_proxies.txt"):
|
||
"""
|
||
保存代理列表到文件
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
filename: 文件名
|
||
"""
|
||
try:
|
||
with open(filename, 'w', encoding='utf-8') as f:
|
||
for proxy in proxies:
|
||
f.write(f"{proxy}\n")
|
||
print(f"✅ 代理列表已保存到 {filename}")
|
||
except Exception as e:
|
||
print(f"❌ 保存文件时出错: {e}")
|
||
|
||
def parse_proxies(proxy_text: str) -> list:
|
||
"""
|
||
解析代理文本,提取代理信息
|
||
|
||
Args:
|
||
proxy_text: 代理文本
|
||
|
||
Returns:
|
||
代理信息列表
|
||
"""
|
||
proxies = []
|
||
lines = proxy_text.strip().split('\n')
|
||
|
||
for line in lines:
|
||
line = line.strip()
|
||
if not line:
|
||
continue
|
||
|
||
# 解析格式: host:port:username:password
|
||
parts = line.split(':')
|
||
if len(parts) >= 4:
|
||
proxy = {
|
||
'host': parts[0],
|
||
'port': parts[1],
|
||
'username': parts[2],
|
||
'password': ':'.join(parts[3:]) # 密码可能包含冒号
|
||
}
|
||
proxies.append(proxy)
|
||
|
||
return proxies
|
||
|
||
def save_proxies(proxies: list, filename: str, format_type: str = "raw"):
|
||
"""
|
||
保存代理列表到文件
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
filename: 文件名
|
||
format_type: 格式类型 ("raw", "http", "socks5")
|
||
"""
|
||
with open(filename, 'w', encoding='utf-8') as f:
|
||
for proxy in proxies:
|
||
if format_type == "raw":
|
||
# 原始格式: host:port:username:password
|
||
line = f"{proxy['host']}:{proxy['port']}:{proxy['username']}:{proxy['password']}"
|
||
elif format_type == "http":
|
||
# HTTP格式: http://username:password@host:port
|
||
line = f"http://{proxy['username']}:{proxy['password']}@{proxy['host']}:{proxy['port']}"
|
||
elif format_type == "socks5":
|
||
# SOCKS5格式: socks5://username:password@host:port
|
||
line = f"socks5://{proxy['username']}:{proxy['password']}@{proxy['host']}:{proxy['port']}"
|
||
else:
|
||
line = f"{proxy['host']}:{proxy['port']}:{proxy['username']}:{proxy['password']}"
|
||
|
||
f.write(line + '\n')
|
||
|
||
print(f"📄 已保存 {len(proxies)} 个代理到 {filename} ({format_type}格式)")
|
||
|
||
def generate_clash_config(proxies: List[Dict[str, str]]) -> Dict:
|
||
"""
|
||
生成Clash配置文件
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
|
||
Returns:
|
||
Clash配置字典
|
||
"""
|
||
clash_proxies = []
|
||
proxy_names = []
|
||
|
||
for i, proxy in enumerate(proxies):
|
||
proxy_name = f"proxy-{i+1}"
|
||
proxy_names.append(proxy_name)
|
||
|
||
# 创建HTTP代理配置
|
||
clash_proxy = {
|
||
"name": proxy_name,
|
||
"type": "http",
|
||
"server": proxy['host'],
|
||
"port": int(proxy['port']),
|
||
"username": proxy['username'],
|
||
"password": proxy['password']
|
||
}
|
||
clash_proxies.append(clash_proxy)
|
||
|
||
# 创建完整的Clash配置
|
||
clash_config = {
|
||
"port": 7890,
|
||
"socks-port": 7891,
|
||
"allow-lan": False,
|
||
"mode": "rule",
|
||
"log-level": "info",
|
||
"external-controller": "127.0.0.1:9090",
|
||
"proxies": clash_proxies,
|
||
"proxy-groups": [
|
||
{
|
||
"name": "🚀 节点选择",
|
||
"type": "select",
|
||
"proxies": ["♻️ 自动选择", "🎯 故障转移"] + proxy_names
|
||
},
|
||
{
|
||
"name": "♻️ 自动选择",
|
||
"type": "url-test",
|
||
"proxies": proxy_names,
|
||
"url": "http://www.gstatic.com/generate_204",
|
||
"interval": 300
|
||
},
|
||
{
|
||
"name": "🎯 故障转移",
|
||
"type": "fallback",
|
||
"proxies": proxy_names,
|
||
"url": "http://www.gstatic.com/generate_204",
|
||
"interval": 300
|
||
},
|
||
{
|
||
"name": "🌍 国外媒体",
|
||
"type": "select",
|
||
"proxies": ["🚀 节点选择", "♻️ 自动选择", "🎯 故障转移"] + proxy_names
|
||
},
|
||
{
|
||
"name": "🍃 应用净化",
|
||
"type": "select",
|
||
"proxies": ["REJECT", "DIRECT"]
|
||
}
|
||
],
|
||
"rules": [
|
||
"DOMAIN-SUFFIX,google.com,🚀 节点选择",
|
||
"DOMAIN-SUFFIX,youtube.com,🌍 国外媒体",
|
||
"DOMAIN-SUFFIX,facebook.com,🌍 国外媒体",
|
||
"DOMAIN-SUFFIX,twitter.com,🌍 国外媒体",
|
||
"DOMAIN-SUFFIX,instagram.com,🌍 国外媒体",
|
||
"DOMAIN-SUFFIX,netflix.com,🌍 国外媒体",
|
||
"DOMAIN-KEYWORD,google,🚀 节点选择",
|
||
"DOMAIN-KEYWORD,youtube,🌍 国外媒体",
|
||
"DOMAIN-KEYWORD,facebook,🌍 国外媒体",
|
||
"DOMAIN-KEYWORD,github,🚀 节点选择",
|
||
"GEOIP,CN,DIRECT",
|
||
"MATCH,🚀 节点选择"
|
||
]
|
||
}
|
||
|
||
return clash_config
|
||
|
||
def save_clash_config(proxies: List[Dict[str, str]], filename: str = "clash_config.yaml"):
|
||
"""
|
||
保存Clash配置文件
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
filename: 文件名
|
||
"""
|
||
clash_config = generate_clash_config(proxies)
|
||
|
||
try:
|
||
with open(filename, 'w', encoding='utf-8') as f:
|
||
yaml.dump(clash_config, f, default_flow_style=False, allow_unicode=True, indent=2)
|
||
print(f"📄 已保存Clash配置到 {filename}")
|
||
except Exception as e:
|
||
print(f"❌ 保存Clash配置时出错: {e}")
|
||
|
||
def generate_singbox_config(proxies: List[Dict[str, str]]) -> Dict:
|
||
"""
|
||
生成SingBox配置
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
|
||
Returns:
|
||
SingBox配置字典
|
||
"""
|
||
outbounds = []
|
||
|
||
# 添加代理节点
|
||
for i, proxy in enumerate(proxies):
|
||
outbound = {
|
||
"type": "http",
|
||
"tag": f"proxy-{i+1}",
|
||
"server": proxy['host'],
|
||
"server_port": int(proxy['port']),
|
||
"username": proxy['username'],
|
||
"password": proxy['password']
|
||
}
|
||
outbounds.append(outbound)
|
||
|
||
# 添加选择器
|
||
proxy_tags = [outbound["tag"] for outbound in outbounds]
|
||
selector = {
|
||
"type": "selector",
|
||
"tag": "proxy",
|
||
"outbounds": proxy_tags + ["auto", "direct"]
|
||
}
|
||
|
||
# 添加自动选择
|
||
auto_select = {
|
||
"type": "urltest",
|
||
"tag": "auto",
|
||
"outbounds": proxy_tags,
|
||
"url": "https://www.gstatic.com/generate_204",
|
||
"interval": "1m",
|
||
"tolerance": 50
|
||
}
|
||
|
||
# 添加直连
|
||
direct = {
|
||
"type": "direct",
|
||
"tag": "direct"
|
||
}
|
||
|
||
# 添加阻断
|
||
block = {
|
||
"type": "block",
|
||
"tag": "block"
|
||
}
|
||
|
||
# 完整配置
|
||
config = {
|
||
"log": {
|
||
"level": "info"
|
||
},
|
||
"dns": {
|
||
"servers": [
|
||
{
|
||
"tag": "google",
|
||
"address": "tls://8.8.8.8",
|
||
"strategy": "prefer_ipv4"
|
||
},
|
||
{
|
||
"tag": "local",
|
||
"address": "223.5.5.5",
|
||
"strategy": "prefer_ipv4"
|
||
}
|
||
],
|
||
"rules": [
|
||
{
|
||
"outbound": "any",
|
||
"server": "local"
|
||
}
|
||
]
|
||
},
|
||
"inbounds": [
|
||
{
|
||
"type": "mixed",
|
||
"tag": "mixed-in",
|
||
"listen": "127.0.0.1",
|
||
"listen_port": 2080
|
||
}
|
||
],
|
||
"outbounds": [selector, auto_select] + outbounds + [direct, block],
|
||
"route": {
|
||
"rules": [
|
||
{
|
||
"protocol": "dns",
|
||
"outbound": "dns-out"
|
||
},
|
||
{
|
||
"network": "udp",
|
||
"port": 443,
|
||
"outbound": "block"
|
||
},
|
||
{
|
||
"geosite": "cn",
|
||
"outbound": "direct"
|
||
},
|
||
{
|
||
"geoip": "cn",
|
||
"outbound": "direct"
|
||
},
|
||
{
|
||
"geosite": "geolocation-!cn",
|
||
"outbound": "proxy"
|
||
}
|
||
],
|
||
"auto_detect_interface": True
|
||
}
|
||
}
|
||
|
||
return config
|
||
|
||
def save_singbox_config(proxies: List[Dict[str, str]], filename: str = "singbox_config.json"):
|
||
"""
|
||
保存SingBox配置文件
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
filename: 文件名
|
||
"""
|
||
singbox_config = generate_singbox_config(proxies)
|
||
|
||
try:
|
||
with open(filename, 'w', encoding='utf-8') as f:
|
||
json.dump(singbox_config, f, indent=2, ensure_ascii=False)
|
||
print(f"📄 已保存SingBox配置到 {filename}")
|
||
except Exception as e:
|
||
print(f"❌ 保存SingBox配置时出错: {e}")
|
||
|
||
def generate_v2ray_subscription(proxies: List[Dict[str, str]]) -> str:
|
||
"""
|
||
生成V2Ray订阅链接
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
|
||
Returns:
|
||
Base64编码的订阅内容
|
||
"""
|
||
vmess_links = []
|
||
|
||
for i, proxy in enumerate(proxies):
|
||
# 生成VMess配置
|
||
vmess_config = {
|
||
"v": "2",
|
||
"ps": f"WebShare-{i+1}",
|
||
"add": proxy['host'],
|
||
"port": proxy['port'],
|
||
"id": "00000000-0000-0000-0000-000000000000", # 默认UUID,实际使用时应该生成随机UUID
|
||
"aid": "0",
|
||
"scy": "auto",
|
||
"net": "tcp",
|
||
"type": "none",
|
||
"host": "",
|
||
"path": "",
|
||
"tls": "",
|
||
"sni": "",
|
||
"alpn": ""
|
||
}
|
||
|
||
# 将配置转换为JSON并编码
|
||
vmess_json = json.dumps(vmess_config, separators=(',', ':'))
|
||
vmess_b64 = base64.b64encode(vmess_json.encode('utf-8')).decode('utf-8')
|
||
vmess_link = f"vmess://{vmess_b64}"
|
||
vmess_links.append(vmess_link)
|
||
|
||
# 将所有链接合并并编码
|
||
subscription_content = '\n'.join(vmess_links)
|
||
subscription_b64 = base64.b64encode(subscription_content.encode('utf-8')).decode('utf-8')
|
||
|
||
return subscription_b64
|
||
|
||
def generate_v2ray_config(proxies: List[Dict[str, str]]) -> Dict:
|
||
"""
|
||
生成V2Ray客户端配置
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
|
||
Returns:
|
||
V2Ray配置字典
|
||
"""
|
||
outbounds = []
|
||
|
||
# 添加代理节点
|
||
for i, proxy in enumerate(proxies):
|
||
outbound = {
|
||
"tag": f"proxy-{i+1}",
|
||
"protocol": "http",
|
||
"settings": {
|
||
"servers": [
|
||
{
|
||
"address": proxy['host'],
|
||
"port": int(proxy['port']),
|
||
"users": [
|
||
{
|
||
"user": proxy['username'],
|
||
"pass": proxy['password']
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
outbounds.append(outbound)
|
||
|
||
# 添加直连
|
||
direct_outbound = {
|
||
"tag": "direct",
|
||
"protocol": "freedom",
|
||
"settings": {}
|
||
}
|
||
|
||
# 添加阻断
|
||
block_outbound = {
|
||
"tag": "blocked",
|
||
"protocol": "blackhole",
|
||
"settings": {}
|
||
}
|
||
|
||
# 完整配置
|
||
config = {
|
||
"log": {
|
||
"loglevel": "warning"
|
||
},
|
||
"inbounds": [
|
||
{
|
||
"tag": "socks",
|
||
"port": 1080,
|
||
"listen": "127.0.0.1",
|
||
"protocol": "socks",
|
||
"sniffing": {
|
||
"enabled": True,
|
||
"destOverride": ["http", "tls"]
|
||
},
|
||
"settings": {
|
||
"auth": "noauth",
|
||
"udp": True
|
||
}
|
||
},
|
||
{
|
||
"tag": "http",
|
||
"port": 1087,
|
||
"listen": "127.0.0.1",
|
||
"protocol": "http",
|
||
"sniffing": {
|
||
"enabled": True,
|
||
"destOverride": ["http", "tls"]
|
||
}
|
||
}
|
||
],
|
||
"outbounds": outbounds + [direct_outbound, block_outbound],
|
||
"routing": {
|
||
"rules": [
|
||
{
|
||
"type": "field",
|
||
"outboundTag": "blocked",
|
||
"protocol": ["bittorrent"]
|
||
},
|
||
{
|
||
"type": "field",
|
||
"outboundTag": "direct",
|
||
"domain": ["geosite:cn"]
|
||
},
|
||
{
|
||
"type": "field",
|
||
"outboundTag": "direct",
|
||
"ip": ["geoip:cn", "geoip:private"]
|
||
},
|
||
{
|
||
"type": "field",
|
||
"outboundTag": "proxy-1",
|
||
"network": "tcp,udp"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
|
||
return config
|
||
|
||
def save_v2ray_subscription(proxies: List[Dict[str, str]], filename: str = "v2ray_subscription.txt"):
|
||
"""
|
||
保存V2Ray订阅文件
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
filename: 文件名
|
||
"""
|
||
try:
|
||
subscription = generate_v2ray_subscription(proxies)
|
||
with open(filename, 'w', encoding='utf-8') as f:
|
||
f.write(subscription)
|
||
print(f"📄 已保存V2Ray订阅到 {filename}")
|
||
except Exception as e:
|
||
print(f"❌ 保存V2Ray订阅时出错: {e}")
|
||
|
||
def save_v2ray_config(proxies: List[Dict[str, str]], filename: str = "v2ray_config.json"):
|
||
"""
|
||
保存V2Ray配置文件
|
||
|
||
Args:
|
||
proxies: 代理列表
|
||
filename: 文件名
|
||
"""
|
||
try:
|
||
config = generate_v2ray_config(proxies)
|
||
with open(filename, 'w', encoding='utf-8') as f:
|
||
json.dump(config, f, indent=2, ensure_ascii=False)
|
||
print(f"📄 已保存V2Ray配置到 {filename}")
|
||
except Exception as e:
|
||
print(f"❌ 保存V2Ray配置时出错: {e}")
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print("🚀 开始获取Webshare代理列表...")
|
||
|
||
# 加载API密钥
|
||
api_key = load_api_key()
|
||
if not api_key:
|
||
print("❌ 无法加载API密钥")
|
||
return
|
||
|
||
# 获取下载token
|
||
download_token = get_download_token(api_key)
|
||
if not download_token:
|
||
print("❌ 获取下载token失败")
|
||
return
|
||
|
||
# 下载代理列表
|
||
proxy_text = download_proxies(download_token)
|
||
if not proxy_text:
|
||
print("❌ 获取代理列表失败")
|
||
return
|
||
|
||
# 解析代理
|
||
proxies = parse_proxies(proxy_text)
|
||
if not proxies:
|
||
print("❌ 未找到有效的代理")
|
||
return
|
||
|
||
print(f"✅ 成功获取 {len(proxies)} 个代理")
|
||
|
||
# 保存原始代理列表
|
||
save_proxies(proxies, "proxies_raw.txt", format_type="raw")
|
||
|
||
# 保存HTTP格式代理列表
|
||
save_proxies(proxies, "proxies_http.txt", format_type="http")
|
||
|
||
# 保存SOCKS5格式代理列表
|
||
save_proxies(proxies, "proxies_socks5.txt", format_type="socks5")
|
||
|
||
# 生成Clash配置文件
|
||
save_clash_config(proxies, "clash_config.yaml")
|
||
|
||
# 生成SingBox配置文件
|
||
save_singbox_config(proxies, "singbox_config.json")
|
||
|
||
# 生成V2Ray订阅和配置文件
|
||
save_v2ray_subscription(proxies, "v2ray_subscription.txt")
|
||
save_v2ray_config(proxies, "v2ray_config.json")
|
||
|
||
print("🎉 代理列表已保存完成!")
|
||
print("📁 文件说明:")
|
||
print(" - proxies_raw.txt: 原始格式 (host:port:username:password)")
|
||
print(" - proxies_http.txt: HTTP格式 (http://username:password@host:port)")
|
||
print(" - proxies_socks5.txt: SOCKS5格式 (socks5://username:password@host:port)")
|
||
print(" - clash_config.yaml: Clash配置文件")
|
||
print(" - singbox_config.json: SingBox配置文件")
|
||
print(" - v2ray_subscription.txt: V2Ray订阅链接 (Base64编码)")
|
||
print(" - v2ray_config.json: V2Ray客户端配置文件")
|
||
|
||
if __name__ == "__main__":
|
||
main() |