本文简单介绍 Clash,通过 Clash 的 RESTful API,实现代码中切换指定节点代理。
名词
- Clash:一个 Go 语言开发的多平台代理客户端,Github
- ClashX:Clash 的 Mac 图形客户端,Github
- ClashForAndroid:Clash 的 Android 图形客户端,Github
- Clash for Windows:Clash 的 Windows/macOS/Linux 图形客户端,Github
- Clash for Linux:基于 clash 、yacd 进行的配置整合。Github
Clash for Windows 下载:Releases · clash_for_windows_pkg
Windows 上 Clash 汉化版软件下载:Clash.for.Windows-0.20.24-win.7z - 蓝奏云
如无特殊说明,缩写CFW指代 Clash for Windows
Clash WebUI
官方面板:Clash
另一个好用的面板:yacd
Clash WebUI 和 Clash for Windows 一样是 Clash 的 GUI,同样基于 RESTful API,运行在 Web 端,Linux 上也可以使用。连接时需要填上 Host、Port 和秘钥,这些信息在 Clash 的配置文件主目录下 config.yaml
文件中可以看到。
RESTful API
基于 API,可以打造自己的可视化操作部分,也是实现 Clash GUI 的重要组成部分。
RESTful API 文档:RESTful API - Clash
Clash API 使用
python 脚本调用 RESTful API,实现在代码中切换想要使用的节点。
在使用 import yaml
之前,需要确保 pyyaml
模块已经安装,否则会报错 ModuleNotFoundError
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
import requests import json import random import os import yaml import platform
if platform.system() == 'Windows': home_dir = os.path.expanduser('~') config_path = os.path.join(home_dir, '.config', 'clash', 'config.yaml') with open(config_path, 'r') as f: config = yaml.safe_load(f) clash_host = config['external-controller'].split(':')[0] clash_port = int(config['external-controller'].split(':')[1]) secret = config['secret'] else:
clash_host = '127.0.0.1' clash_port = '9090' secret = 'Awehome666.'
headers = {"Authorization": f"Bearer {secret}"}
def selector_global_chains(chains): global clash_host, clash_port, headers config_url = "http://%s:%s/configs" % (clash_host, clash_port)
payload = "{\"mode\":\"Global\"}" requests.patch(config_url, headers=headers, data=payload) config_json = requests.get(config_url, headers=headers).json() assert config_json['mode'].lower() == 'global', '切换全局模式失败'
url = "http://%s:%s/proxies/GLOBAL" % (clash_host, clash_port) payload = json.dumps({ "name": chains }) headers.update({'Content-Type': 'application/json'}) r = requests.request("PUT", url, headers=headers, data=payload) if r.status_code == 204: print('切换节点成功') return True else: print('切换节点失败', r.status_code, r.text) assert 0
def toggle_proxies(area=None): """ 全局模式7890端口的所有流量都会走代理。规则模式7890端口 国内的流量不走代理,国外的流量走代理。 """ url = "http://%s:%s/proxies" % (clash_host, clash_port) r = requests.request("GET", url, headers=headers, data={}) if area: lst = json.loads(r.text)['proxies']['GLOBAL']['all'] chains_list = [i for i in lst if area in i] else: chains_list = json.loads(r.text)['proxies']['GLOBAL']['all'] chains_list = [i for i in chains_list if i[0] > '\u4e00' and i[0] < '\u9fa5']
assert chains_list, "没有获取到节点" chains_info_list = [] for chains_name in chains_list: dic = {} dic['name'] = chains_name test_url = "http://%s:%s/proxies/%s/delay?timeout=5000&url=http://www.gstatic.com/generate_204" % ( clash_host, clash_port, chains_name) delay_res = requests.get(test_url, headers=headers) assert "Unauthorized" not in delay_res, f'节点 {chains_name} 延迟测试失败:{delay_res.text}' if delay_res.status_code != 200: continue delay_dic = delay_res.json() dic.update(delay_dic) chains_info_list.append(dic)
chains_list = sorted(chains_info_list, key=lambda x: x['delay']) chains = chains_list[0]['name'] delay = chains_list[0]['delay'] print("本次选择的延迟最小的节点是: %s 延迟 %s" % (chains, delay)) selector_global_chains(chains)
def test_proxy(): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'} proxies = { "http": "http://127.0.0.1:7890/", "https": "http://127.0.0.1:7890/" } res = requests.get('https://api.ip.sb/geoip', proxies=proxies, headers=headers).json() res_dic = {'country': res['country'], 'city': res['city'], 'ip': res['ip']} print('国外API测试', res_dic)
res = requests.get('https://qifu-api.baidubce.com/ip/local/geo/v1/district', proxies=proxies).json() ip = res['ip'] data = res['data'] res_dic = {'country': data['country'], 'city': data['city'], 'ip': ip} print('国内API测试', res_dic)
if __name__ == "__main__": toggle_proxies(area='澳大利亚')
test_proxy()
|