first commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
yujieccyj11@hotmail.com|||2pcRp86m1r76nSzdtGy1DNpXjrF|||192.168.31.201:52012|||127.0.0.1:7890
|
||||
@@ -0,0 +1,12 @@
|
||||
yujiec0210@gmail.com|||28a3e1c1-3572-45a7-8c66-2843132af302|||192.168.31.201:52001|||192.168.31.201:53001
|
||||
yujieccyj01@hotmail.com|||2oL7nKR3rlHANh08znNYVNYgZXv|||192.168.31.201:52002|||192.168.31.201:53002
|
||||
yujieccyj02@hotmail.com|||2oWgZ1hCAD6u6fZjPcWsDJowo7Y|||192.168.31.201:52003|||192.168.31.201:53003
|
||||
yujieccyj03@hotmail.com|||2oWjwicrgUXjpUxtRNE7ufVSDxl|||192.168.31.201:52004|||192.168.31.201:53004
|
||||
yujieccyj04@hotmail.com|||2oWkFItRXDMW40AYKpDjGa3SJlw|||192.168.31.201:52005|||192.168.31.201:53005
|
||||
yujieccyj05@hotmail.com|||2oY2LqL7JDLSKZ8pScMqeGDXnV3|||192.168.31.201:52006|||192.168.31.201:53006
|
||||
yujieccyj06@hotmail.com|||2pT2P5xXpWgrlZa20ZlW4bdCsZT|||192.168.31.201:52007|||192.168.31.201:53007
|
||||
yujieccyj07@hotmail.com|||2pT2zNB1oYsMbb0okgnBvtTWYpZ|||192.168.31.201:52008|||192.168.31.201:53008
|
||||
yujieccyj08@hotmail.com|||2pT3nzb7IGEIRojfB2vypMgBcUw|||192.168.31.201:52009|||192.168.31.201:53009
|
||||
yujieccyj09@hotmail.com|||2pT49IOTlvXlr8AAqpPa08vBu5o|||192.168.31.201:52010|||192.168.31.201:53010
|
||||
yujieccyj10@hotmail.com|||2pT5tt43UBpk36v3Sf64KBAoQiR|||192.168.31.201:52011|||192.168.31.201:53011
|
||||
yujieccyj11@hotmail.com|||2pcRp86m1r76nSzdtGy1DNpXjrF|||192.168.31.201:52012|||192.168.31.201:53012
|
||||
@@ -0,0 +1,12 @@
|
||||
yujiec0210@gamil.com:aaaAAA111!!!
|
||||
yujieccyj01@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj02@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj03@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj04@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj05@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj06@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj07@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj08@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj09@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj10@hotmail.com:aaaAAA111!!!
|
||||
yujieccyj11@hotmail.com:aaaAAA111!!!
|
||||
@@ -0,0 +1,108 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import random
|
||||
import time
|
||||
|
||||
import httpx
|
||||
|
||||
|
||||
class GrassClient:
|
||||
def __init__(self, email, password, user_agent, proxy_ip, proxy_api_port, proxy_web_port):
|
||||
self.email = email
|
||||
self.password = password
|
||||
self.user_agent = user_agent
|
||||
self.proxy_ip = proxy_ip
|
||||
self.proxy_api_port = proxy_api_port
|
||||
self.proxy_web_port = proxy_web_port
|
||||
self.session = httpx.Client()
|
||||
|
||||
def login(self):
|
||||
url = 'https://api.getgrass.io/login'
|
||||
json_data = {
|
||||
'password': self.password,
|
||||
'username': self.email,
|
||||
}
|
||||
headers = {
|
||||
'authority': 'api.getgrass.io',
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'uk-UA,uk;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||
'content-type': 'application/json',
|
||||
'origin': 'https://app.getgrass.io',
|
||||
'referer': 'https://app.getgrass.io/',
|
||||
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-site',
|
||||
'user-agent': self.user_agent,
|
||||
}
|
||||
|
||||
for retry in range(5):
|
||||
try:
|
||||
# 使用 httpx 发送 POST 请求
|
||||
proxy_web_port = random.choice(self.proxy_web_port)
|
||||
proxy = f"{self.proxy_ip}:{proxy_web_port}"
|
||||
proxies = {
|
||||
"http://": f"http://{proxy}",
|
||||
"https://": f"http://{proxy}",
|
||||
}
|
||||
with httpx.Client(proxies=proxies, headers=headers) as client:
|
||||
response = client.post(url, json=json_data)
|
||||
if response.status_code != 200:
|
||||
error_message = response.text
|
||||
raise httpx.RequestError(f"登录失败,状态码 {response.status_code}: {error_message}")
|
||||
|
||||
data = response.json()
|
||||
userId = data['result']['data']['userId']
|
||||
return userId
|
||||
|
||||
except httpx.RequestError as e:
|
||||
print(e)
|
||||
time.sleep(3)
|
||||
|
||||
def close(self):
|
||||
self.session.close()
|
||||
|
||||
|
||||
# 使用示例
|
||||
def main():
|
||||
email_list = [
|
||||
"yujiec0210@gmail.com",
|
||||
"yujieccyj01@hotmail.com",
|
||||
"yujieccyj02@hotmail.com",
|
||||
"yujieccyj03@hotmail.com",
|
||||
"yujieccyj04@hotmail.com",
|
||||
"yujieccyj05@hotmail.com",
|
||||
"yujieccyj06@hotmail.com",
|
||||
"yujieccyj07@hotmail.com",
|
||||
"yujieccyj08@hotmail.com",
|
||||
"yujieccyj09@hotmail.com",
|
||||
"yujieccyj10@hotmail.com",
|
||||
"yujieccyj11@hotmail.com"
|
||||
]
|
||||
proxy_api_port = ["52001", "52002", "52003", "52004", "52005", "52006", "52007", "52008", "52009", "52010", "52011",
|
||||
"52012"]
|
||||
proxy_web_port = ["53001", "53002", "53003", "53004", "53005", "53006", "53007", "53008", "53009", "53010", "53011",
|
||||
"53012"]
|
||||
password = "aaaAAA111!!!"
|
||||
proxy_ip = "192.168.31.201"
|
||||
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
||||
user_id_list = []
|
||||
for email in email_list:
|
||||
client = GrassClient(email, password, user_agent, proxy_ip, proxy_api_port, proxy_web_port)
|
||||
try:
|
||||
login_response = client.login()
|
||||
print("userId:", f'{email} - {login_response}')
|
||||
user_id_list.append(login_response)
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
if user_id_list:
|
||||
with open("account_details.txt", "w") as file:
|
||||
for email, user_id, api_port, web_port in zip(email_list, user_id_list, proxy_api_port, proxy_web_port):
|
||||
file.write(f"{email}|||{user_id}|||{proxy_ip}:{api_port}|||{proxy_ip}:{web_port}\n")
|
||||
|
||||
|
||||
# 运行主函数
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,256 @@
|
||||
import asyncio
|
||||
import json
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
import uuid
|
||||
|
||||
import aiohttp
|
||||
from fake_useragent import UserAgent
|
||||
from tenacity import stop_after_attempt, retry, retry_if_not_exception_type, wait_random, retry_if_exception_type
|
||||
|
||||
# 配置文件路径
|
||||
ACCOUNTS_DETAILS_FILE_PATH = "account_details.txt"
|
||||
ACCOUNTS_FILE_PATH = "accounts.txt"
|
||||
PROXIES_FILE_PATH = "proxies.txt"
|
||||
MIN_PROXY_SCORE = 50
|
||||
|
||||
|
||||
# 日志记录
|
||||
class Logger:
|
||||
@staticmethod
|
||||
def info(message):
|
||||
print(f"[INFO] {message}")
|
||||
|
||||
@staticmethod
|
||||
def error(message):
|
||||
print(f"[ERROR] {message}")
|
||||
|
||||
@staticmethod
|
||||
def success(message):
|
||||
print(f"[SUCCESS] {message}")
|
||||
|
||||
|
||||
logger = Logger()
|
||||
|
||||
|
||||
# 异常类
|
||||
class ProxyForbiddenException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LowProxyScoreException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ProxyScoreNotFoundException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class WebsocketClosedException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
# Grass 类,负责登录、检测代理分数和持久连接
|
||||
class Grass:
|
||||
def __init__(self, _id: int, email: str, user_id: str, proxy: str = None):
|
||||
self.proxy = f"socks5://{proxy}" if proxy else None # 添加协议
|
||||
self.email = email
|
||||
self.user_id = user_id
|
||||
self.user_agent = UserAgent().random
|
||||
self.proxy_score = None
|
||||
self.id = _id
|
||||
self.session = aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(ssl=False))
|
||||
self.all_proxies_name = []
|
||||
|
||||
async def start(self):
|
||||
try:
|
||||
user_id = self.user_id
|
||||
browser_id = str(self.email) # 使用邮箱作为浏览器ID
|
||||
await self.run(browser_id, user_id)
|
||||
except Exception as e:
|
||||
logger.error(f"{self.id} | Error: {e}")
|
||||
finally:
|
||||
await self.close()
|
||||
|
||||
async def run(self, browser_id: str, user_id: str):
|
||||
while True:
|
||||
try:
|
||||
await self.connection_handler()
|
||||
await self.auth_to_extension(browser_id, user_id)
|
||||
|
||||
if self.proxy_score is None:
|
||||
await asyncio.sleep(1)
|
||||
await self.handle_proxy_score(MIN_PROXY_SCORE)
|
||||
|
||||
while True:
|
||||
await self.send_ping()
|
||||
await self.send_pong()
|
||||
logger.info(f"{self.id} | Mined grass.")
|
||||
await asyncio.sleep(19.9)
|
||||
except WebsocketClosedException as e:
|
||||
logger.info(f"Websocket closed: {e}. Retrying...")
|
||||
except ConnectionResetError as e:
|
||||
logger.info(f"Connection reset: {e}. Retrying...")
|
||||
except TypeError as e:
|
||||
logger.info(f"Type error: {e}. Retrying...")
|
||||
await asyncio.sleep(1)
|
||||
|
||||
@retry(stop=stop_after_attempt(30),
|
||||
retry=(retry_if_exception_type(ConnectionError) | retry_if_not_exception_type(ProxyForbiddenException)),
|
||||
wait=wait_random(0.5, 1),
|
||||
reraise=True)
|
||||
async def connection_handler(self):
|
||||
logger.info(f"{self.id} | Connecting...")
|
||||
await self.connect()
|
||||
logger.info(f"{self.id} | Connected")
|
||||
|
||||
@retry(stop=stop_after_attempt(10),
|
||||
retry=retry_if_not_exception_type(LowProxyScoreException),
|
||||
before_sleep=lambda retry_state, **kwargs: logger.info(f"{retry_state.outcome.exception()}"),
|
||||
wait=wait_random(5, 7),
|
||||
reraise=True)
|
||||
async def handle_proxy_score(self, min_score: int):
|
||||
if (proxy_score := await self.get_proxy_score_by_device_id()) is None:
|
||||
raise ProxyScoreNotFoundException(f"{self.id} | Proxy score not found for {self.proxy}. Guess Bad proxies!")
|
||||
elif proxy_score >= min_score:
|
||||
self.proxy_score = proxy_score
|
||||
logger.success(f"{self.id} | Proxy score: {self.proxy_score}")
|
||||
return True
|
||||
else:
|
||||
raise LowProxyScoreException(f"{self.id} | Too low proxy score: {proxy_score} for {self.proxy}. Exit...")
|
||||
|
||||
async def auth_to_extension(self, browser_id: str, user_id: str):
|
||||
connection_id = await self.get_connection_id()
|
||||
message = json.dumps(
|
||||
{
|
||||
"id": connection_id,
|
||||
"origin_action": "AUTH",
|
||||
"result": {
|
||||
"browser_id": browser_id,
|
||||
"user_id": user_id,
|
||||
"user_agent": self.user_agent,
|
||||
"timestamp": int(time.time()),
|
||||
"device_type": "extension",
|
||||
"version": "4.26.2"
|
||||
}
|
||||
}
|
||||
)
|
||||
print(message)
|
||||
await self.send_message(message)
|
||||
|
||||
async def connect(self):
|
||||
uri = "wss://proxy.wynd.network"
|
||||
headers = {
|
||||
'Pragma': 'no-cache',
|
||||
'Origin': 'chrome-extension://ilehaonighjijnmpnagapkhpcdbhclfg',
|
||||
'Accept-Language': 'uk-UA,uk;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||
'User-Agent': self.user_agent,
|
||||
'Upgrade': 'websocket',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'Upgrade',
|
||||
'Sec-WebSocket-Version': '13',
|
||||
'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
|
||||
}
|
||||
try:
|
||||
self.websocket = await self.session.ws_connect(uri, proxy_headers=headers, proxy=self.proxy)
|
||||
except Exception as e:
|
||||
if 'status' in dir(e) and e.status == 403:
|
||||
raise ProxyForbiddenException(f"Low proxy score. Can't connect. Error: {e}")
|
||||
raise e
|
||||
|
||||
async def get_proxy_score_by_device_id(self):
|
||||
url = 'https://api.getgrass.io/extension/user-score'
|
||||
headers = {
|
||||
'authority': 'api.getgrass.io',
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'uk-UA,uk;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||
'content-type': 'application/json',
|
||||
'origin': 'https://app.getgrass.io',
|
||||
'referer': 'https://app.getgrass.io/',
|
||||
'sec-ch-ua': '"Not(A:Brand";v="99", "Brave";v="133", "Chromium";v="133"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'document',
|
||||
'sec-fetch-mode': 'navigate',
|
||||
'sec-fetch-site': 'none',
|
||||
'user-agent': self.user_agent,
|
||||
}
|
||||
response = await self.session.get(url, headers=headers, proxy=self.proxy)
|
||||
res_json = await response.json()
|
||||
print(res_json)
|
||||
if not (isinstance(res_json, dict) and res_json.get("data", None) is not None):
|
||||
return
|
||||
devices = res_json['data']['currentDeviceData']
|
||||
self.ip = await self.get_ip()
|
||||
logger.info(f"当前代理IP: {self.ip}")
|
||||
return next((device['final_score'] for device in devices
|
||||
if device['device_ip'] == self.ip), None)
|
||||
|
||||
async def send_message(self, message):
|
||||
await self.websocket.send_str(message)
|
||||
|
||||
async def receive_message(self):
|
||||
msg = await self.websocket.receive()
|
||||
if msg.type == aiohttp.WSMsgType.CLOSED:
|
||||
raise WebsocketClosedException(f"Websocket closed: {msg}")
|
||||
return msg.data
|
||||
|
||||
async def get_connection_id(self):
|
||||
msg = await self.receive_message()
|
||||
return json.loads(msg)['id']
|
||||
|
||||
async def send_ping(self):
|
||||
message = json.dumps(
|
||||
{"id": str(uuid.uuid4()), "version": "1.0.0", "action": "PING", "data": {}}
|
||||
)
|
||||
await self.send_message(message)
|
||||
|
||||
async def send_pong(self):
|
||||
connection_id = await self.get_connection_id()
|
||||
message = json.dumps(
|
||||
{"id": connection_id, "origin_action": "PONG"}
|
||||
)
|
||||
await self.send_message(message)
|
||||
|
||||
async def get_ip(self):
|
||||
return await (await self.session.get('https://api.ipify.org', proxy=self.proxy)).text()
|
||||
|
||||
async def close(self):
|
||||
if self.session:
|
||||
await self.session.close()
|
||||
|
||||
|
||||
# 主函数
|
||||
async def main():
|
||||
account_details = []
|
||||
with open(ACCOUNTS_DETAILS_FILE_PATH, 'r') as f:
|
||||
account_details = f.readlines()
|
||||
|
||||
grass_instances = []
|
||||
tasks = []
|
||||
for i, account in enumerate(account_details):
|
||||
email, user_id, proxy_web, proxy_api = account.strip().split("|||")
|
||||
grass = Grass(i, email, user_id, proxy_api)
|
||||
grass_instances.append(grass)
|
||||
tasks.append(grass.start())
|
||||
|
||||
try:
|
||||
await asyncio.gather(*tasks)
|
||||
except Exception as e:
|
||||
logger.error(f"An error occurred: {e}")
|
||||
finally:
|
||||
# 确保所有会话都被关闭
|
||||
for grass in grass_instances:
|
||||
await grass.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if sys.platform == 'win32':
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
loop = asyncio.ProactorEventLoop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.run_until_complete(main())
|
||||
else:
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,12 @@
|
||||
192.168.31.201:53001
|
||||
192.168.31.201:53002
|
||||
192.168.31.201:53003
|
||||
192.168.31.201:53004
|
||||
192.168.31.201:53005
|
||||
192.168.31.201:53006
|
||||
192.168.31.201:53007
|
||||
192.168.31.201:53008
|
||||
192.168.31.201:53009
|
||||
192.168.31.201:53010
|
||||
192.168.31.201:53011
|
||||
192.168.31.201:53012
|
||||
@@ -0,0 +1,172 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
切换到随机代理
|
||||
'''
|
||||
import random
|
||||
|
||||
import httpx
|
||||
import time
|
||||
import logging
|
||||
import subprocess
|
||||
from typing import Optional, List
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
BASE_URL = "http://192.168.31.201"
|
||||
|
||||
PORT_LIST = [
|
||||
["52001", "53001"],
|
||||
["52002", "53002"],
|
||||
["52003", "53003"],
|
||||
["52004", "53004"],
|
||||
["52005", "53005"],
|
||||
["52006", "53006"],
|
||||
["52007", "53007"],
|
||||
["52008", "53008"],
|
||||
["52009", "53009"],
|
||||
["52011", "53012"],
|
||||
["52012", "53012"]
|
||||
]
|
||||
|
||||
|
||||
class ClashProxyManager:
|
||||
def __init__(self, base_url, base_port):
|
||||
self.key_group = 0
|
||||
self.base_url = base_url
|
||||
self.base_port = base_port
|
||||
self.all_proxies = []
|
||||
|
||||
def get_all_proxies(self, clash_tool_url: str) -> List[str]:
|
||||
url = f"{clash_tool_url}/api/proxies"
|
||||
try:
|
||||
response = httpx.get(url)
|
||||
response.raise_for_status()
|
||||
proxies = response.json()
|
||||
logging.info("Available proxies:")
|
||||
# 输出读取的所有代理信息
|
||||
# for proxy_name, proxy_info in proxies['proxies'].items():
|
||||
# logging.info(f"Name: {proxy_name}, Type: {proxy_info.get('type', 'Unknown')}")
|
||||
proxy_list = list(proxies['proxies'].keys())
|
||||
filtered_list = [item for item in proxy_list if item not in {'REJECT', 'GLOBAL', 'DIRECT'}]
|
||||
return filtered_list
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to get proxies: {e}")
|
||||
return []
|
||||
|
||||
def switch_proxy(self, proxy_name: str, url_and_port: str) -> None:
|
||||
logging.info("switch proxy")
|
||||
url = f"{url_and_port}/api/proxies/GLOBAL"
|
||||
data = {"name": proxy_name}
|
||||
try:
|
||||
response = httpx.put(url, json=data)
|
||||
if response.status_code == 204:
|
||||
logging.info(f"Switched to proxy: {proxy_name}")
|
||||
else:
|
||||
logging.error(f"Failed to switch proxy: {response.status_code} - {proxy_name}")
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to switch proxy: {e}")
|
||||
|
||||
def update_configs(self):
|
||||
for base_port in self.base_port:
|
||||
url_and_port = self.base_url + ":" + base_port[0]
|
||||
key = "/api/configs"
|
||||
url = url_and_port + key
|
||||
|
||||
headers = {
|
||||
"accept": "application/json, text/plain, */*",
|
||||
"accept-encoding": "gzip, deflate, br, zstd",
|
||||
"accept-language": "zh-CN,zh",
|
||||
"connection": "keep-alive",
|
||||
"content-type": "application/json",
|
||||
"origin": url_and_port,
|
||||
"referer": url_and_port,
|
||||
"sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Brave";v="132"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"macOS"',
|
||||
"sec-fetch-dest": "empty",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-gpc": "1",
|
||||
"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",
|
||||
}
|
||||
|
||||
# 请求体数据
|
||||
data = {"mode": "Global"} # 替换为实际的请求数据
|
||||
|
||||
# 使用 httpx 发送 PATCH 请求
|
||||
try:
|
||||
with httpx.Client() as client:
|
||||
response = client.patch(url, headers=headers, json=data)
|
||||
if response.status_code == 204:
|
||||
print(f"{url} OK")
|
||||
else:
|
||||
print("响应内容:", response.text)
|
||||
except httpx.RequestError as exc:
|
||||
print(f"请求失败: {exc}")
|
||||
|
||||
def check_proxy(self, proxy_url):
|
||||
# proxy_url: 代理地址, 没有密码
|
||||
# 测试目标地址:
|
||||
command = ["curl", "-x", proxy_url, "ip.sb"]
|
||||
|
||||
# 执行命令并获取输出
|
||||
try:
|
||||
result = subprocess.run(command, capture_output=True, text=True, check=True)
|
||||
# 打印命令的标准输出
|
||||
print("Output:", result.stdout)
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
# 如果命令执行失败,打印错误信息
|
||||
print("Error:", e.stderr)
|
||||
return False
|
||||
|
||||
def main(self) -> None:
|
||||
# 设置全局代理
|
||||
self.update_configs()
|
||||
|
||||
# 读取所有代理
|
||||
if not self.all_proxies:
|
||||
for port_list in self.base_port:
|
||||
base_url = self.base_url + ":" + port_list[0]
|
||||
clash_tool_url = f"{base_url}"
|
||||
proxies = self.get_all_proxies(clash_tool_url)
|
||||
if proxies:
|
||||
self.all_proxies = proxies
|
||||
break
|
||||
|
||||
if not self.all_proxies:
|
||||
logging.error("Failed to get all proxies")
|
||||
return
|
||||
else:
|
||||
logging.info(f"Found {self.all_proxies} proxies.")
|
||||
logging.info(f"Found {len(self.all_proxies)} proxies.")
|
||||
|
||||
# 遍历所有的线路api, 切换不重复代理
|
||||
# 切换后, 检测代理, 如果检测返回失败, 再次切换
|
||||
used_proxy = []
|
||||
for base_port in self.base_port:
|
||||
url_and_port = self.base_url + ":" + base_port[0]
|
||||
proxy_url = self.base_url + ":" + base_port[1]
|
||||
while True:
|
||||
# 选一个代理
|
||||
choose_proxy = random.choice(self.all_proxies)
|
||||
# 如果已经选过就继续下一个
|
||||
if choose_proxy in used_proxy:
|
||||
continue
|
||||
|
||||
# 切换代理
|
||||
self.switch_proxy(choose_proxy, url_and_port)
|
||||
|
||||
# 切换后检测代理
|
||||
if self.check_proxy(proxy_url):
|
||||
print(f"代理 {choose_proxy} 切换成功,检测通过!")
|
||||
used_proxy.append(choose_proxy) # 标记为已使用
|
||||
break # 成功后退出当前代理的重试循环
|
||||
else:
|
||||
print(f"{url_and_port} 切换 {choose_proxy} 检测失败")
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
manager = ClashProxyManager(BASE_URL, PORT_LIST)
|
||||
manager.main()
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,77 @@
|
||||
import asyncio
|
||||
import random
|
||||
from fake_useragent import UserAgent
|
||||
import aiohttp
|
||||
import logging
|
||||
|
||||
class ProxyForbiddenException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class GrassConnect:
|
||||
def __init__(self, proxy: str = None):
|
||||
self.user_agent = UserAgent().random
|
||||
self.proxy = proxy
|
||||
self.session = None
|
||||
self.websocket = None
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
async def __aenter__(self):
|
||||
self.session = aiohttp.ClientSession()
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
await self.close()
|
||||
|
||||
async def connect(self):
|
||||
uri = f"wss://proxy.wynd.network"
|
||||
headers = {
|
||||
'Pragma': 'no-cache',
|
||||
'Origin': 'chrome-extension://ilehaonighjijnmpnagapkhpcdbhclfg',
|
||||
'Accept-Language': 'uk-UA,uk;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||
'User-Agent': self.user_agent,
|
||||
'Upgrade': 'websocket',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'Upgrade',
|
||||
'Sec-WebSocket-Version': '13',
|
||||
'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits'
|
||||
}
|
||||
while True:
|
||||
self.logger.info(f"Attempting to connect to {uri} using proxy {self.proxy}")
|
||||
try:
|
||||
self.websocket = await self.session.ws_connect(
|
||||
uri,
|
||||
headers=headers,
|
||||
proxy=self.proxy,
|
||||
proxy_headers=headers
|
||||
)
|
||||
self.logger.info(f"Successfully connected to {uri}")
|
||||
return self.websocket
|
||||
except aiohttp.ClientResponseError as e:
|
||||
self.logger.error(f"HTTP error occurred: {e}")
|
||||
if e.status == 403:
|
||||
raise ProxyForbiddenException(f"Low proxy score. Can't connect. Error: {e}")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Unexpected error occurred: {e}")
|
||||
self.logger.info("Connection failed. Retrying in 3 seconds...")
|
||||
await asyncio.sleep(3)
|
||||
|
||||
async def close(self):
|
||||
if self.websocket:
|
||||
await self.websocket.close()
|
||||
self.logger.info("Websocket connection closed.")
|
||||
if self.session:
|
||||
await self.session.close()
|
||||
self.logger.info("Client session closed.")
|
||||
|
||||
|
||||
# Example usage
|
||||
async def main():
|
||||
proxy = "socks5://192.168.31.201:53012"
|
||||
async with GrassConnect(proxy=proxy) as connector:
|
||||
websocket = await connector.connect()
|
||||
# 继续处理websocket连接
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
Reference in New Issue
Block a user