switch_proxy_group_group.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import httpx
  2. import time
  3. import json
  4. import uuid
  5. import logging
  6. import websockets
  7. from typing import Optional, List
  8. from websockets import WebSocketCommonProtocol
  9. logging.basicConfig(level=logging.INFO)
  10. BASE_URL = "http://192.168.31.194"
  11. PORT_LIST = [
  12. ["58001", "59001"],
  13. ["58002", "59002"],
  14. ["58003", "59003"],
  15. ["58004", "59004"],
  16. ["58005", "59005"],
  17. ["58006", "59006"],
  18. ["58007", "59007"],
  19. ["58008", "59008"],
  20. ["58009", "59009"],
  21. ["58010", "59010"],
  22. ]
  23. TEST_URL = "https://httpbin.org/ip"
  24. class ClashProxyManager:
  25. def __init__(self, base_url, base_port, test_url):
  26. self.key_group = 0
  27. self.base_url = base_url
  28. self.base_port = base_port
  29. self.proxy_keyword = [
  30. ['sg', 'SG', '新加坡', '马来西亚'],
  31. ['jp', '日本'],
  32. ]
  33. self.test_url = test_url
  34. self.all_proxies = []
  35. self.selected_proxies = []
  36. def get_all_proxies(self, clash_tool_url: str) -> List[str]:
  37. url = f"{clash_tool_url}/api/proxies"
  38. try:
  39. response = httpx.get(url)
  40. response.raise_for_status()
  41. proxies = response.json()
  42. logging.info("Available proxies:")
  43. # 输出读取的所有代理信息
  44. # for proxy_name, proxy_info in proxies['proxies'].items():
  45. # logging.info(f"Name: {proxy_name}, Type: {proxy_info.get('type', 'Unknown')}")
  46. return list(proxies['proxies'].keys())
  47. except Exception as e:
  48. logging.error(f"Failed to get proxies: {e}")
  49. return []
  50. def filter_proxy(self):
  51. for keyword in self.proxy_keyword[self.key_group]:
  52. for item in self.all_proxies:
  53. if keyword.lower() in item.lower():
  54. self.selected_proxies.append(item)
  55. def switch_proxy(self, proxy_name: str, url_and_port: str) -> None:
  56. logging.info("switch proxy")
  57. url = f"{url_and_port}/api/proxies/GLOBAL"
  58. data = {"name": proxy_name}
  59. try:
  60. response = httpx.put(url, json=data)
  61. if response.status_code == 204:
  62. logging.info(f"Switched to proxy: {proxy_name}")
  63. else:
  64. logging.error(f"Failed to switch proxy: {response.status_code} - {proxy_name}")
  65. except Exception as e:
  66. logging.error(f"Failed to switch proxy: {e}")
  67. def update_configs(self):
  68. for base_port in self.base_port:
  69. url_and_port = self.base_url + ":" + base_port[0]
  70. key = "/api/configs"
  71. url = url_and_port + key
  72. headers = {
  73. "accept": "application/json, text/plain, */*",
  74. "accept-encoding": "gzip, deflate, br, zstd",
  75. "accept-language": "zh-CN,zh",
  76. "connection": "keep-alive",
  77. "content-type": "application/json",
  78. "origin": url_and_port,
  79. "referer": url_and_port,
  80. "sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Brave";v="132"',
  81. "sec-ch-ua-mobile": "?0",
  82. "sec-ch-ua-platform": '"macOS"',
  83. "sec-fetch-dest": "empty",
  84. "sec-fetch-mode": "cors",
  85. "sec-fetch-site": "same-origin",
  86. "sec-gpc": "1",
  87. "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
  88. }
  89. # 请求体数据
  90. data = {"mode": "Global"} # 替换为实际的请求数据
  91. # 使用 httpx 发送 PATCH 请求
  92. try:
  93. with httpx.Client() as client:
  94. response = client.patch(url, headers=headers, json=data)
  95. if response.status_code == 204:
  96. print(f"{url} OK")
  97. else:
  98. print("响应内容:", response.text)
  99. except httpx.RequestError as exc:
  100. print(f"请求失败: {exc}")
  101. def check_proxy(self, proxy_url):
  102. # proxy_url: 代理地址, 没有密码
  103. # 测试目标地址:
  104. try:
  105. # 使用代理发送请求
  106. response = httpx.get(
  107. TEST_URL,
  108. proxies={"http": proxy_url, "https": proxy_url},
  109. timeout=5
  110. )
  111. response.raise_for_status() # 检查请求是否成功
  112. # 如果请求成功,返回 True
  113. return True
  114. except Exception:
  115. # 如果发生任何异常,返回 False
  116. return False
  117. def main(self) -> None:
  118. # 设置全局代理
  119. self.update_configs()
  120. # 读取所有代理
  121. if not self.all_proxies:
  122. for port_list in self.base_port:
  123. base_url = self.base_url + ":" + port_list[0]
  124. clash_tool_url = f"{base_url}"
  125. proxies = self.get_all_proxies(clash_tool_url)
  126. if proxies:
  127. self.all_proxies = proxies
  128. break
  129. if not self.all_proxies:
  130. logging.error("Failed to get all proxies")
  131. return
  132. # 通过关键词过滤出需要的代理
  133. self.filter_proxy()
  134. if not self.selected_proxies:
  135. logging.error("Failed to filter proxies")
  136. return
  137. # 遍历所有的线路api, 切换不重复代理
  138. # 切换后, 检测代理, 如果检测返回失败, 再次切换
  139. used_proxy = []
  140. for base_port in self.base_port:
  141. url_and_port = self.base_url + ":" + base_port[0]
  142. proxy_url = self.base_url + ":" + base_port[1]
  143. for select_proxy in self.selected_proxies:
  144. if select_proxy in used_proxy:
  145. continue
  146. # 尝试切换代理并检测
  147. self.switch_proxy(select_proxy, url_and_port)
  148. if self.check_proxy(proxy_url):
  149. print(f"代理 {select_proxy} 切换成功,检测通过!")
  150. used_proxy.append(select_proxy) # 标记为已使用
  151. break # 成功后退出当前代理的重试循环
  152. else:
  153. print(f"{url_and_port} 切换 {select_proxy} 检测失败")
  154. time.sleep(1) # 等待一段时间后重试
  155. # 如果当前代理成功,直接进入下一个 base_port 的处理
  156. break
  157. if __name__ == "__main__":
  158. manager = ClashProxyManager(BASE_URL, PORT_LIST, TEST_URL)
  159. manager.main()