|
|
@@ -11,6 +11,7 @@ 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
|
|
|
@@ -53,18 +54,19 @@ class WebsocketClosedException(Exception):
|
|
|
|
|
|
# Grass 类,负责登录、检测代理分数和持久连接
|
|
|
class Grass:
|
|
|
- def __init__(self, _id: int, email: str, password: str, proxy: str = None):
|
|
|
- self.proxy = f"http://{proxy}" if proxy else None # 添加协议
|
|
|
+ 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.password = password
|
|
|
+ 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 = await self.login()
|
|
|
+ user_id = self.user_id
|
|
|
browser_id = str(self.email) # 使用邮箱作为浏览器ID
|
|
|
await self.run(browser_id, user_id)
|
|
|
except Exception as e:
|
|
|
@@ -119,8 +121,27 @@ class Grass:
|
|
|
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:4444/"
|
|
|
+ uri = "wss://proxy.wynd.network:4650/"
|
|
|
headers = {
|
|
|
'Pragma': 'no-cache',
|
|
|
'Origin': 'chrome-extension://ilehaonighjijnmpnagapkhpcdbhclfg',
|
|
|
@@ -139,6 +160,34 @@ class Grass:
|
|
|
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)
|
|
|
|
|
|
@@ -152,24 +201,6 @@ class Grass:
|
|
|
msg = await self.receive_message()
|
|
|
return json.loads(msg)['id']
|
|
|
|
|
|
- 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": "3.3.2"
|
|
|
- }
|
|
|
- }
|
|
|
- )
|
|
|
- await self.send_message(message)
|
|
|
-
|
|
|
async def send_ping(self):
|
|
|
message = json.dumps(
|
|
|
{"id": str(uuid.uuid4()), "version": "1.0.0", "action": "PING", "data": {}}
|
|
|
@@ -183,58 +214,6 @@ class Grass:
|
|
|
)
|
|
|
await self.send_message(message)
|
|
|
|
|
|
- async 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,
|
|
|
- }
|
|
|
- response = await self.session.post(url, headers=headers, json=json_data, proxy=self.proxy)
|
|
|
- if response.status != 200:
|
|
|
- raise aiohttp.ClientConnectionError(f"login | {await response.text()}")
|
|
|
- return await response.json()
|
|
|
-
|
|
|
- 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="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,
|
|
|
- }
|
|
|
- response = await self.session.get(url, headers=headers, proxy=self.proxy)
|
|
|
- res_json = await response.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()
|
|
|
- return next((device['final_score'] for device in devices
|
|
|
- if device['device_ip'] == self.ip), None)
|
|
|
-
|
|
|
async def get_ip(self):
|
|
|
return await (await self.session.get('https://api.ipify.org', proxy=self.proxy)).text()
|
|
|
|
|
|
@@ -245,20 +224,15 @@ class Grass:
|
|
|
|
|
|
# 主函数
|
|
|
async def main():
|
|
|
- accounts = []
|
|
|
- with open(ACCOUNTS_FILE_PATH, 'r') as f:
|
|
|
- accounts = f.readlines()
|
|
|
-
|
|
|
- proxies = []
|
|
|
- with open(PROXIES_FILE_PATH, 'r') as f:
|
|
|
- proxies = f.readlines()
|
|
|
+ account_details = []
|
|
|
+ with open(ACCOUNTS_DETAILS_FILE_PATH, 'r') as f:
|
|
|
+ account_details = f.readlines()
|
|
|
|
|
|
grass_instances = []
|
|
|
tasks = []
|
|
|
- for i, account in enumerate(accounts):
|
|
|
- email, password = account.strip().split(":")
|
|
|
- proxy = proxies[i % len(proxies)].strip() if proxies else None
|
|
|
- grass = Grass(i, email, password, proxy)
|
|
|
+ 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())
|
|
|
|