添加Webshare代理获取脚本和Clash配置
- 添加fetch_proxies.py脚本,支持从Webshare API获取代理 - 生成多种格式的代理文件:raw、http、socks5 - 生成Clash配置文件clash_config.yaml - 包含代理组配置和分流规则 - 支持自动选择和故障转移
This commit is contained in:
		
							parent
							
								
									24963efa76
								
							
						
					
					
						commit
						064cbe1d5f
					
				|  | @ -0,0 +1,23 @@ | |||
| # 环境变量文件 | ||||
| .env | ||||
| 
 | ||||
| # Python缓存 | ||||
| __pycache__/ | ||||
| *.pyc | ||||
| *.pyo | ||||
| *.pyd | ||||
| .Python | ||||
| *.so | ||||
| 
 | ||||
| # IDE文件 | ||||
| .vscode/ | ||||
| .idea/ | ||||
| *.swp | ||||
| *.swo | ||||
| 
 | ||||
| # 系统文件 | ||||
| .DS_Store | ||||
| Thumbs.db | ||||
| 
 | ||||
| # 日志文件 | ||||
| *.log | ||||
|  | @ -0,0 +1,227 @@ | |||
| allow-lan: false | ||||
| external-controller: 127.0.0.1:9090 | ||||
| log-level: info | ||||
| mode: rule | ||||
| port: 7890 | ||||
| proxies: | ||||
| - name: proxy-1 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6269 | ||||
|   server: 45.196.40.191 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-2 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6452 | ||||
|   server: 130.180.228.168 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-3 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 7926 | ||||
|   server: 72.1.154.35 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-4 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6479 | ||||
|   server: 63.141.62.186 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-5 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6219 | ||||
|   server: 216.170.122.181 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-6 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 5758 | ||||
|   server: 192.53.67.209 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-7 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 8160 | ||||
|   server: 130.180.231.18 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-8 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 5936 | ||||
|   server: 192.53.142.239 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-9 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 5686 | ||||
|   server: 103.130.178.22 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-10 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6563 | ||||
|   server: 216.98.254.253 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-11 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 5896 | ||||
|   server: 192.46.188.237 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-12 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 8932 | ||||
|   server: 45.56.161.56 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-13 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6766 | ||||
|   server: 192.46.201.252 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-14 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6384 | ||||
|   server: 45.196.50.62 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-15 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6363 | ||||
|   server: 193.160.83.42 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-16 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 5898 | ||||
|   server: 103.130.178.234 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-17 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6622 | ||||
|   server: 72.46.139.62 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-18 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6799 | ||||
|   server: 72.46.139.239 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-19 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 5726 | ||||
|   server: 103.130.178.62 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| - name: proxy-20 | ||||
|   password: lvo4zphp2wwj | ||||
|   port: 6247 | ||||
|   server: 72.46.138.21 | ||||
|   type: http | ||||
|   username: fbkjstyt | ||||
| proxy-groups: | ||||
| - name: 🚀 节点选择 | ||||
|   proxies: | ||||
|   - ♻️ 自动选择 | ||||
|   - 🎯 故障转移 | ||||
|   - proxy-1 | ||||
|   - proxy-2 | ||||
|   - proxy-3 | ||||
|   - proxy-4 | ||||
|   - proxy-5 | ||||
|   - proxy-6 | ||||
|   - proxy-7 | ||||
|   - proxy-8 | ||||
|   - proxy-9 | ||||
|   - proxy-10 | ||||
|   - proxy-11 | ||||
|   - proxy-12 | ||||
|   - proxy-13 | ||||
|   - proxy-14 | ||||
|   - proxy-15 | ||||
|   - proxy-16 | ||||
|   - proxy-17 | ||||
|   - proxy-18 | ||||
|   - proxy-19 | ||||
|   - proxy-20 | ||||
|   type: select | ||||
| - interval: 300 | ||||
|   name: ♻️ 自动选择 | ||||
|   proxies: &id001 | ||||
|   - proxy-1 | ||||
|   - proxy-2 | ||||
|   - proxy-3 | ||||
|   - proxy-4 | ||||
|   - proxy-5 | ||||
|   - proxy-6 | ||||
|   - proxy-7 | ||||
|   - proxy-8 | ||||
|   - proxy-9 | ||||
|   - proxy-10 | ||||
|   - proxy-11 | ||||
|   - proxy-12 | ||||
|   - proxy-13 | ||||
|   - proxy-14 | ||||
|   - proxy-15 | ||||
|   - proxy-16 | ||||
|   - proxy-17 | ||||
|   - proxy-18 | ||||
|   - proxy-19 | ||||
|   - proxy-20 | ||||
|   type: url-test | ||||
|   url: http://www.gstatic.com/generate_204 | ||||
| - interval: 300 | ||||
|   name: 🎯 故障转移 | ||||
|   proxies: *id001 | ||||
|   type: fallback | ||||
|   url: http://www.gstatic.com/generate_204 | ||||
| - name: 🌍 国外媒体 | ||||
|   proxies: | ||||
|   - 🚀 节点选择 | ||||
|   - ♻️ 自动选择 | ||||
|   - 🎯 故障转移 | ||||
|   - proxy-1 | ||||
|   - proxy-2 | ||||
|   - proxy-3 | ||||
|   - proxy-4 | ||||
|   - proxy-5 | ||||
|   - proxy-6 | ||||
|   - proxy-7 | ||||
|   - proxy-8 | ||||
|   - proxy-9 | ||||
|   - proxy-10 | ||||
|   - proxy-11 | ||||
|   - proxy-12 | ||||
|   - proxy-13 | ||||
|   - proxy-14 | ||||
|   - proxy-15 | ||||
|   - proxy-16 | ||||
|   - proxy-17 | ||||
|   - proxy-18 | ||||
|   - proxy-19 | ||||
|   - proxy-20 | ||||
|   type: select | ||||
| - name: 🍃 应用净化 | ||||
|   proxies: | ||||
|   - REJECT | ||||
|   - DIRECT | ||||
|   type: select | ||||
| 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,🚀 节点选择 | ||||
| socks-port: 7891 | ||||
|  | @ -0,0 +1,410 @@ | |||
| #!/usr/bin/env python3 | ||||
| """ | ||||
| Webshare SOCKS代理获取脚本 | ||||
| 使用简单的下载接口直接获取代理列表 | ||||
| """ | ||||
| 
 | ||||
| import os | ||||
| import requests | ||||
| import yaml | ||||
| 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 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") | ||||
|      | ||||
|     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配置文件") | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
|  | @ -0,0 +1 @@ | |||
| curl "https://proxy.webshare.io/api/v2/proxy/list/download/ulowafkljtigyvuxlitaakdaqvozmcjrnnhwegdf/-/any/username/direct/san%20francisco/" | ||||
|  | @ -0,0 +1,20 @@ | |||
| http://fbkjstyt:lvo4zphp2wwj@45.196.40.191:6269 | ||||
| http://fbkjstyt:lvo4zphp2wwj@130.180.228.168:6452 | ||||
| http://fbkjstyt:lvo4zphp2wwj@72.1.154.35:7926 | ||||
| http://fbkjstyt:lvo4zphp2wwj@63.141.62.186:6479 | ||||
| http://fbkjstyt:lvo4zphp2wwj@216.170.122.181:6219 | ||||
| http://fbkjstyt:lvo4zphp2wwj@192.53.67.209:5758 | ||||
| http://fbkjstyt:lvo4zphp2wwj@130.180.231.18:8160 | ||||
| http://fbkjstyt:lvo4zphp2wwj@192.53.142.239:5936 | ||||
| http://fbkjstyt:lvo4zphp2wwj@103.130.178.22:5686 | ||||
| http://fbkjstyt:lvo4zphp2wwj@216.98.254.253:6563 | ||||
| http://fbkjstyt:lvo4zphp2wwj@192.46.188.237:5896 | ||||
| http://fbkjstyt:lvo4zphp2wwj@45.56.161.56:8932 | ||||
| http://fbkjstyt:lvo4zphp2wwj@192.46.201.252:6766 | ||||
| http://fbkjstyt:lvo4zphp2wwj@45.196.50.62:6384 | ||||
| http://fbkjstyt:lvo4zphp2wwj@193.160.83.42:6363 | ||||
| http://fbkjstyt:lvo4zphp2wwj@103.130.178.234:5898 | ||||
| http://fbkjstyt:lvo4zphp2wwj@72.46.139.62:6622 | ||||
| http://fbkjstyt:lvo4zphp2wwj@72.46.139.239:6799 | ||||
| http://fbkjstyt:lvo4zphp2wwj@103.130.178.62:5726 | ||||
| http://fbkjstyt:lvo4zphp2wwj@72.46.138.21:6247 | ||||
|  | @ -0,0 +1,20 @@ | |||
| 45.196.40.191:6269:fbkjstyt:lvo4zphp2wwj | ||||
| 130.180.228.168:6452:fbkjstyt:lvo4zphp2wwj | ||||
| 72.1.154.35:7926:fbkjstyt:lvo4zphp2wwj | ||||
| 63.141.62.186:6479:fbkjstyt:lvo4zphp2wwj | ||||
| 216.170.122.181:6219:fbkjstyt:lvo4zphp2wwj | ||||
| 192.53.67.209:5758:fbkjstyt:lvo4zphp2wwj | ||||
| 130.180.231.18:8160:fbkjstyt:lvo4zphp2wwj | ||||
| 192.53.142.239:5936:fbkjstyt:lvo4zphp2wwj | ||||
| 103.130.178.22:5686:fbkjstyt:lvo4zphp2wwj | ||||
| 216.98.254.253:6563:fbkjstyt:lvo4zphp2wwj | ||||
| 192.46.188.237:5896:fbkjstyt:lvo4zphp2wwj | ||||
| 45.56.161.56:8932:fbkjstyt:lvo4zphp2wwj | ||||
| 192.46.201.252:6766:fbkjstyt:lvo4zphp2wwj | ||||
| 45.196.50.62:6384:fbkjstyt:lvo4zphp2wwj | ||||
| 193.160.83.42:6363:fbkjstyt:lvo4zphp2wwj | ||||
| 103.130.178.234:5898:fbkjstyt:lvo4zphp2wwj | ||||
| 72.46.139.62:6622:fbkjstyt:lvo4zphp2wwj | ||||
| 72.46.139.239:6799:fbkjstyt:lvo4zphp2wwj | ||||
| 103.130.178.62:5726:fbkjstyt:lvo4zphp2wwj | ||||
| 72.46.138.21:6247:fbkjstyt:lvo4zphp2wwj | ||||
|  | @ -0,0 +1,20 @@ | |||
| socks5://fbkjstyt:lvo4zphp2wwj@45.196.40.191:6269 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@130.180.228.168:6452 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@72.1.154.35:7926 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@63.141.62.186:6479 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@216.170.122.181:6219 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@192.53.67.209:5758 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@130.180.231.18:8160 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@192.53.142.239:5936 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@103.130.178.22:5686 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@216.98.254.253:6563 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@192.46.188.237:5896 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@45.56.161.56:8932 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@192.46.201.252:6766 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@45.196.50.62:6384 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@193.160.83.42:6363 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@103.130.178.234:5898 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@72.46.139.62:6622 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@72.46.139.239:6799 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@103.130.178.62:5726 | ||||
| socks5://fbkjstyt:lvo4zphp2wwj@72.46.138.21:6247 | ||||
		Loading…
	
		Reference in New Issue