import requests import base64 import json from concurrent.futures import ThreadPoolExecutor, as_completed from collections import defaultdict import time from urllib.parse import quote # ================== 配置区 ================== URL = "https://serverlist.piaservers.net/shadow_socks" THREADS = 5 # 并发线程数 TOTAL_REQUESTS = 200 # 总采集次数(可改大,比如 500) TIMEOUT = 10 # 单次请求超时秒数 # =========================================== def fetch_once(): try: r = requests.get(URL, timeout=TIMEOUT) r.raise_for_status() return r.json() except Exception as e: return None # 失败时返回 None print(f"开始使用 {THREADS} 个线程采集 {TOTAL_REQUESTS} 次...") servers = defaultdict(set) # region -> set of hosts with ThreadPoolExecutor(max_workers=THREADS) as executor: futures = [executor.submit(fetch_once) for _ in range(TOTAL_REQUESTS)] for i, future in enumerate(as_completed(futures), 1): data = future.result() if data and isinstance(data, list): for item in data: region = item.get("region") host = item.get("host") if region and host: servers[region].add(host) # 显示进度 if i % 20 == 0 or i == TOTAL_REQUESTS: print(f"已完成 {i}/{TOTAL_REQUESTS} 次请求...") print("\n采集完成!") print(f"共发现 {sum(len(hosts) for hosts in servers.values())} 个独特节点\n") # 输出节点表格 print("地区\t\tHost 数量\tHosts") print("-" * 60) all_nodes = [] for region, hosts in sorted(servers.items()): host_list = sorted(hosts) print(f"{region:<15} {len(host_list):<8} {', '.join(host_list)}") for host in host_list: all_nodes.append({ "region": region, "host": host, "port": 443, "password": "shadowsocks", "cipher": "aes-128-gcm" }) # 生成 ss:// 链接 print("\n=== 单个 ss:// 节点链接(共 {} 个)===".format(len(all_nodes))) ss_links = [] for node in all_nodes: auth = f"{node['cipher']}:{node['password']}@{node['host']}:{node['port']}" b64 = base64.urlsafe_b64encode(auth.encode()).decode().rstrip("=") name = f"PIA-{node['region']}-{node['host'].split('.')[-1]}" # 简单备注 ss_url = f"ss://{b64}#{quote(name)}" ss_links.append(ss_url) print(ss_url) # 生成一键订阅链接 print("\n=== 一键订阅链接(直接导入客户端)===") subscription_url = "https://api.ss-sub.com/sub?target=ss&url=" + "|".join(ss_links) print(subscription_url) # 保存到文件(可选) with open("pia_shadowsocks_nodes.txt", "w", encoding="utf-8") as f: f.write("\n".join(ss_links)) f.write("\n\n订阅链接:\n" + subscription_url) print("\n节点已保存到 pia_shadowsocks_nodes.txt 文件中。")