import requests import base64 import json from concurrent.futures import ThreadPoolExecutor, as_completed from collections import defaultdict from urllib.parse import quote # ================== 配置区 ================== URL = "https://serverlist.piaservers.net/shadow_socks" THREADS = 5 # 并发线程数 TOTAL_REQUESTS = 300 # 建议改成 300~500 次,增加获取多IP的机会 TIMEOUT = 8 # 超时时间 # =========================================== def fetch_once(): try: r = requests.get(URL, timeout=TIMEOUT, headers={"User-Agent": "Mozilla/5.0"}) r.raise_for_status() data = r.json() if not isinstance(data, list): return None return data except Exception: return 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: for item in data: if isinstance(item, dict): region = item.get("region") host = item.get("host") if region and host and isinstance(host, str): servers[region.strip()].add(host.strip()) # 进度显示(每 30 次显示一次) if i % 30 == 0 or i == TOTAL_REQUESTS: print(f"已完成 {i}/{TOTAL_REQUESTS} 次请求... 当前发现节点数: {sum(len(hosts) for hosts in servers.values())}") print("\n采集完成!") total_nodes = sum(len(hosts) for hosts in servers.values()) print(f"共发现 {total_nodes} 个独特节点\n") # 输出表格 print("地区\t\tHost数量\tHosts") print("-" * 70) all_nodes = [] for region in sorted(servers.keys()): hosts = sorted(servers[region]) print(f"{region:<18} {len(hosts):<6} {', '.join(hosts)}") for host in hosts: all_nodes.append({ "region": region, "host": host, "port": 443, "password": "shadowsocks", "cipher": "aes-128-gcm" }) if not all_nodes: print("未能采集到任何节点,请检查网络或稍后重试。") else: # 生成 ss:// 链接 print(f"\n=== 单个 ss:// 节点链接(共 {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("utf-8")).decode("utf-8").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(f"\n=== 一键订阅链接(直接导入客户端)===") sub_url = "https://api.ss-sub.com/sub?target=ss&url=" + "|".join(ss_links) print(sub_url) # 保存到文件 with open("pia_shadowsocks_nodes.txt", "w", encoding="utf-8") as f: f.write("\n".join(ss_links)) f.write("\n\n一键订阅链接:\n" + sub_url) print(f"\n所有节点已保存到 pia_shadowsocks_nodes.txt 文件!")