2025-11-20 11:42:18 +08:00
|
|
|
|
import os
|
|
|
|
|
|
import time
|
|
|
|
|
|
import aiohttp
|
|
|
|
|
|
import asyncio
|
|
|
|
|
|
import requests
|
|
|
|
|
|
from loguru import logger
|
|
|
|
|
|
from functools import wraps
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def retry(max_retries: int = 3, delay: float = 1.0, backoff: float = 1.0):
|
|
|
|
|
|
"""
|
|
|
|
|
|
通用重试装饰器
|
|
|
|
|
|
:param max_retries: 最大重试次数
|
|
|
|
|
|
:param delay: 每次重试的初始延迟(秒)
|
|
|
|
|
|
:param backoff: 每次重试延迟的递增倍数
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def decorator(func):
|
|
|
|
|
|
@wraps(func)
|
|
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
|
|
retries = 0
|
|
|
|
|
|
current_delay = delay
|
|
|
|
|
|
while retries < max_retries:
|
|
|
|
|
|
try:
|
|
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
retries += 1
|
|
|
|
|
|
if retries >= max_retries:
|
|
|
|
|
|
logger.warning(f"函数 {func.__name__} 在尝试了 {max_retries} 次后失败,错误信息: {e}")
|
|
|
|
|
|
return None # 重试次数用尽后返回 None
|
|
|
|
|
|
logger.warning(f"正在重试 {func.__name__} {retries + 1}/{max_retries} 因错误: {e}")
|
|
|
|
|
|
time.sleep(current_delay)
|
|
|
|
|
|
current_delay *= backoff
|
|
|
|
|
|
|
|
|
|
|
|
return None # 三次重试仍未成功,返回 None
|
|
|
|
|
|
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
|
|
|
return decorator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def async_retry(max_retries: int = 3, delay: float = 1.0, backoff: float = 1.0):
|
|
|
|
|
|
"""
|
|
|
|
|
|
支持异步函数的通用重试装饰器
|
|
|
|
|
|
:param max_retries: 最大重试次数
|
|
|
|
|
|
:param delay: 每次重试的初始延迟(秒)
|
|
|
|
|
|
:param backoff: 每次重试延迟的递增倍数
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def decorator(func):
|
|
|
|
|
|
@wraps(func)
|
|
|
|
|
|
async def wrapper(*args, **kwargs):
|
|
|
|
|
|
retries = 0
|
|
|
|
|
|
current_delay = delay
|
|
|
|
|
|
while retries < max_retries:
|
|
|
|
|
|
try:
|
|
|
|
|
|
return await func(*args, **kwargs) # 直接执行原始方法
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
retries += 1
|
|
|
|
|
|
if retries >= max_retries:
|
|
|
|
|
|
logger.warning(f"函数 {func.__name__} 在尝试了 {max_retries} 次后失败,错误信息: {e}")
|
|
|
|
|
|
return None # 重试次数用尽后返回 None
|
|
|
|
|
|
logger.warning(f"正在重试 {func.__name__} {retries + 1}/{max_retries} 因错误: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(current_delay) # 异步延迟
|
|
|
|
|
|
current_delay *= backoff # 根据backoff递增延迟
|
|
|
|
|
|
|
|
|
|
|
|
return None # 三次重试仍未成功,返回 None
|
|
|
|
|
|
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
|
|
|
return decorator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 比特浏览器模块
|
|
|
|
|
|
class BitBrowser:
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
self.bit_host = "http://127.0.0.1"
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
# 创建比特币浏览器
|
|
|
|
|
|
@retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
def bit_browser_create(self, remark: str = '指纹浏览器', ua: str = None, host: str = None, port: str = None,
|
|
|
|
|
|
proxy_user: str = None,
|
|
|
|
|
|
proxy_pwd: str = None, proxy_type: str = 'noproxy', urls: str = None,
|
|
|
|
|
|
bit_port: str = "54345") -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
创建比特币浏览器
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:param ua: 可选,默认随机
|
|
|
|
|
|
:param proxy_type: 代理类型 (可选) ['noproxy', 'http', 'https', 'socks5', 'ssh']
|
|
|
|
|
|
:param urls: 额外打开的url (可选) 多个用,分割
|
|
|
|
|
|
:param host: 代理IP地址 (可选)
|
|
|
|
|
|
:param port: 代理IP端口 (可选)
|
|
|
|
|
|
:param proxy_user: 代理账号 (可选)
|
|
|
|
|
|
:param proxy_pwd: 代理密码 (可选)
|
|
|
|
|
|
:param remark: 备注 (可选)
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 返回浏览器ID
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/update"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {
|
|
|
|
|
|
'name': f'{remark if len(remark) < 40 else remark[:40]}', # 窗口名称
|
|
|
|
|
|
'remark': f'{remark}', # 备注
|
|
|
|
|
|
'proxyMethod': 2, # 代理方式 2自定义 3 提取IP
|
|
|
|
|
|
# 代理类型 ['noproxy', 'http', 'https', 'socks5', 'ssh']
|
|
|
|
|
|
'proxyType': f'{proxy_type}',
|
|
|
|
|
|
"browserFingerPrint": {"userAgent": ua} # 留空,随机指纹
|
|
|
|
|
|
}
|
|
|
|
|
|
if host is not None:
|
|
|
|
|
|
data['host'] = host
|
|
|
|
|
|
if port is not None:
|
|
|
|
|
|
data['port'] = port
|
|
|
|
|
|
if proxy_user is not None:
|
|
|
|
|
|
data['proxyUserName'] = proxy_user
|
|
|
|
|
|
if proxy_pwd is not None:
|
|
|
|
|
|
data['proxyPassword'] = proxy_pwd
|
|
|
|
|
|
if urls is not None:
|
|
|
|
|
|
data['url'] = urls # 额外打开的url 多个用,分割
|
|
|
|
|
|
res = requests.post(url, json=data, headers=headers).json()
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
browser_pk = res['data']['id']
|
|
|
|
|
|
return browser_pk
|
|
|
|
|
|
|
|
|
|
|
|
# 修改比特币浏览器
|
|
|
|
|
|
@retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
def bit_browser_update(self, pk: str, remark: str = None, proxyType: str = 'noproxy', host: str = None,
|
|
|
|
|
|
port: str = None, proxy_user: str = None, proxy_pwd: str = None, urls: str = None,
|
|
|
|
|
|
bit_port: str = "54345") -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
修改比特币浏览器 传入某个参数则修改某个参数
|
|
|
|
|
|
:param proxyType: 代理类型 noproxy|http|https|socks5(默认noproxy)
|
|
|
|
|
|
:param pk: # 浏览器ID
|
|
|
|
|
|
:param remark: # 备注
|
|
|
|
|
|
:param host: # 代理主机
|
|
|
|
|
|
:param port: # 代理端口
|
|
|
|
|
|
:param proxy_user: # 代理账号
|
|
|
|
|
|
:param proxy_pwd: # 代理密码
|
|
|
|
|
|
:param urls: # 额外打开的url 多个用,分割
|
|
|
|
|
|
:param bit_port: # 可选,默认54345
|
|
|
|
|
|
:return: bool
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/update/partial"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = dict()
|
|
|
|
|
|
data['ids'] = [pk]
|
|
|
|
|
|
if remark is not None:
|
|
|
|
|
|
data['remark'] = remark
|
|
|
|
|
|
data['name'] = remark
|
|
|
|
|
|
if urls is not None:
|
|
|
|
|
|
data['url'] = urls
|
|
|
|
|
|
if proxyType != 'noproxy':
|
|
|
|
|
|
data['proxyType'] = proxyType
|
|
|
|
|
|
if host is not None:
|
|
|
|
|
|
data['host'] = host
|
|
|
|
|
|
if port is not None:
|
|
|
|
|
|
data['port'] = port if isinstance(port, int) else int(port)
|
|
|
|
|
|
if proxy_user is not None:
|
|
|
|
|
|
data['proxyUserName'] = proxy_user
|
|
|
|
|
|
if proxy_pwd is not None:
|
|
|
|
|
|
data['proxyPassword'] = proxy_pwd
|
|
|
|
|
|
res = requests.post(url, json=data, headers=headers).json()
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
# 打开比特币浏览器
|
|
|
|
|
|
@retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
def bit_browser_open(self, pk: str, bit_port: str = "54345") -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
打开比特币浏览器
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 返回浏览器地址
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/open"
|
|
|
|
|
|
data = {"id": f'{pk}'}
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
res = requests.post(url, json=data, headers=headers).json()
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
debugger_address = res['data']['http']
|
|
|
|
|
|
return debugger_address
|
|
|
|
|
|
|
|
|
|
|
|
# 关闭比特币浏览器
|
2025-11-26 09:32:53 +08:00
|
|
|
|
@retry(max_retries=3, delay=1.0, backoff=1.0)
|
2025-11-20 11:42:18 +08:00
|
|
|
|
def bit_browser_close(self, pk: str, bit_port: str = "54345"):
|
|
|
|
|
|
"""
|
|
|
|
|
|
关闭比特币浏览器 - 执行后需要等待5s
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 无返回值
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/close"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {'id': f'{pk}'}
|
|
|
|
|
|
requests.post(url, json=data, headers=headers).json()
|
|
|
|
|
|
time.sleep(5) # 等待5s,等待浏览器关闭
|
|
|
|
|
|
# 关闭浏览器进程
|
|
|
|
|
|
# pid = self.bit_browser_pid(pk, bit_port)
|
|
|
|
|
|
# if pid is not None:
|
|
|
|
|
|
# os.system(f"kill -9 {pid}")
|
|
|
|
|
|
|
|
|
|
|
|
# 删除比特币浏览器
|
2025-11-26 09:32:53 +08:00
|
|
|
|
@retry(max_retries=3, delay=1.0, backoff=1.0)
|
2025-11-20 11:42:18 +08:00
|
|
|
|
def bit_browser_delete(self, pk: str, bit_port: str = "54345"):
|
|
|
|
|
|
"""
|
|
|
|
|
|
删除比特币浏览器
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 无返回值
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/delete"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {'id': f'{pk}'}
|
|
|
|
|
|
print(requests.post(url, json=data, headers=headers).json())
|
|
|
|
|
|
|
|
|
|
|
|
# 获取所有比特币浏览器
|
|
|
|
|
|
@retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
def bit_browser_get(self, page: int = 0, limit: int = 10, group_id: str | None = None,
|
|
|
|
|
|
bit_port: str | None = "54345") -> dict:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取所有比特币浏览器
|
|
|
|
|
|
:param page: 页码
|
|
|
|
|
|
:param limit: 每页数量
|
|
|
|
|
|
:param group_id: 组ID(可选)
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: {'success': True, 'data': {'page': 1, 'pageSize': 10, 'totalNum': 128, 'list': [{'id': '12a3126accc14c93bd34adcccfc3083c'},{'id':'edc5d61a56214e9f8a8bbf1a2e1b405d'}]}}
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/list"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {'page': page, 'pageSize': limit}
|
|
|
|
|
|
if group_id is not None:
|
|
|
|
|
|
data['groupId'] = group_id
|
|
|
|
|
|
res = requests.post(url, json=data, headers=headers).json()
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
# 获取比特浏览器窗口详情
|
|
|
|
|
|
@retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
def bit_browser_detail(self, pk: str, bit_port: str = "54345") -> dict:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取比特浏览器窗口详情
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: {'success': True, 'data': {'id': '12a3126accc14c93bd34adcccfc3083c', 'name': '12a3126accc14c93bd34adcccfc3083c', 'remark': '12a3126accc14c93bd34adcccfc3083c', '
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/detail"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {'id': f'{pk}'}
|
|
|
|
|
|
res = requests.post(url, json=data, headers=headers).json()
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
# 获取比特浏览器的进程id
|
|
|
|
|
|
def bit_browser_pid(self, pk: str, bit_port: str = "54345") -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取比特浏览器的进程id
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 返回进程id
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/pids/alive"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {
|
|
|
|
|
|
"ids": [pk]
|
|
|
|
|
|
}
|
|
|
|
|
|
res = requests.post(url, json=data, headers=headers).json()
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
return res['data'][pk]
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
|
async def __request(method: str, url: str, params: dict = None, **kwargs) -> dict:
|
|
|
|
|
|
"""
|
|
|
|
|
|
通用异步请求方法
|
|
|
|
|
|
:param method: HTTP方法 (GET, POST, PUT, DELETE)
|
|
|
|
|
|
:param endpoint: API接口地址
|
|
|
|
|
|
:param kwargs: 其他请求参数 (json, params等)
|
|
|
|
|
|
:return: 返回JSON数据
|
|
|
|
|
|
"""
|
|
|
|
|
|
if params:
|
|
|
|
|
|
# 将布尔值转换为字符串或整数
|
|
|
|
|
|
params = {k: str(v).lower() if isinstance(v, bool) else v for k, v in params.items()}
|
|
|
|
|
|
async with aiohttp.ClientSession() as session:
|
|
|
|
|
|
async with session.request(method, url, params=params, **kwargs) as response:
|
|
|
|
|
|
return await response.json()
|
|
|
|
|
|
|
|
|
|
|
|
# 创建比特币浏览器
|
|
|
|
|
|
@async_retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
async def _bit_browser_create(self, remark: str = '指纹浏览器', ua: str = None, host: str = None, port: str = None,
|
|
|
|
|
|
proxy_user: str = None,
|
|
|
|
|
|
proxy_pwd: str = None, proxy_type: str = 'noproxy', urls: str = None,
|
|
|
|
|
|
bit_port: str = "54345") -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
创建比特币浏览器
|
|
|
|
|
|
:param urls: 额外打开的url (可选) 多个用,分割
|
|
|
|
|
|
:param remark: 备注 (可选)
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 返回浏览器ID
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/update"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {
|
|
|
|
|
|
'name': f'{remark if len(remark) < 40 else remark[:40]}', # 窗口名称
|
|
|
|
|
|
'remark': f'{remark}', # 备注
|
|
|
|
|
|
'proxyType': f'{proxy_type}',
|
|
|
|
|
|
"browserFingerPrint": {"userAgent": ua} # 留空,随机指纹
|
|
|
|
|
|
}
|
|
|
|
|
|
if host is not None:
|
|
|
|
|
|
data['host'] = host
|
|
|
|
|
|
if port is not None:
|
|
|
|
|
|
data['port'] = port
|
|
|
|
|
|
if proxy_user is not None:
|
|
|
|
|
|
data['proxyUserName'] = proxy_user
|
|
|
|
|
|
if proxy_pwd is not None:
|
|
|
|
|
|
data['proxyPassword'] = proxy_pwd
|
|
|
|
|
|
if urls is not None:
|
|
|
|
|
|
data['url'] = urls # 额外打开的url 多个用,分割
|
|
|
|
|
|
res = await self.__request('POST', url, json=data, headers=headers)
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
browser_pk = res['data']['id']
|
|
|
|
|
|
return browser_pk
|
|
|
|
|
|
|
|
|
|
|
|
# 修改比特币浏览器
|
|
|
|
|
|
@async_retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
async def _bit_browser_update(self, pk: str, remark: str = None, proxyType: str = 'noproxy', host: str = None,
|
|
|
|
|
|
port: str = None, proxy_user: str = None, proxy_pwd: str = None, urls: str = None,
|
|
|
|
|
|
bit_port: str = "54345") -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
修改比特币浏览器 传入某个参数则修改某个参数
|
|
|
|
|
|
:param pk: # 浏览器ID
|
|
|
|
|
|
:param remark: # 备注
|
|
|
|
|
|
:param urls: # 额外打开的url 多个用,分割
|
|
|
|
|
|
:param bit_port: # 可选,默认54345
|
|
|
|
|
|
:return:
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/update/partial"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = dict()
|
|
|
|
|
|
data['ids'] = [pk]
|
|
|
|
|
|
if remark is not None:
|
|
|
|
|
|
data['remark'] = remark
|
|
|
|
|
|
data['name'] = remark
|
|
|
|
|
|
if urls is not None:
|
|
|
|
|
|
data['url'] = urls
|
|
|
|
|
|
if proxyType != 'noproxy':
|
|
|
|
|
|
data['proxyType'] = proxyType
|
|
|
|
|
|
if host is not None:
|
|
|
|
|
|
data['host'] = host
|
|
|
|
|
|
if port is not None:
|
|
|
|
|
|
data['port'] = port if isinstance(port, int) else int(port)
|
|
|
|
|
|
if proxy_user is not None:
|
|
|
|
|
|
data['proxyUserName'] = proxy_user
|
|
|
|
|
|
if proxy_pwd is not None:
|
|
|
|
|
|
data['proxyPassword'] = proxy_pwd
|
|
|
|
|
|
res = await self.__request('POST', url, json=data, headers=headers)
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
# 打开比特币浏览器
|
|
|
|
|
|
@async_retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
async def _bit_browser_open(self, pk: str, bit_port: str = "54345") -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
打开比特币浏览器
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 返回浏览器地址
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/open"
|
|
|
|
|
|
data = {"id": f'{pk}'}
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
res = await self.__request('POST', url, json=data, headers=headers)
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
debugger_address = res['data']['http']
|
|
|
|
|
|
return debugger_address
|
|
|
|
|
|
|
|
|
|
|
|
# 关闭比特币浏览器
|
|
|
|
|
|
async def _bit_browser_close(self, pk: str, bit_port: str = "54345"):
|
|
|
|
|
|
"""
|
|
|
|
|
|
关闭比特币浏览器 - 执行后需要等待5s
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 无返回值
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/close"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {'id': f'{pk}'}
|
|
|
|
|
|
await self.__request('POST', url, json=data, headers=headers)
|
|
|
|
|
|
await asyncio.sleep(5) # 等待5s,等待浏览器关闭
|
|
|
|
|
|
|
|
|
|
|
|
# 删除比特币浏览器
|
|
|
|
|
|
async def _bit_browser_delete(self, pk: str, bit_port: str = "54345"):
|
|
|
|
|
|
"""
|
|
|
|
|
|
删除比特币浏览器
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 无返回值
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/delete"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {'id': f'{pk}'}
|
|
|
|
|
|
print(await self.__request('POST', url, json=data, headers=headers))
|
|
|
|
|
|
|
|
|
|
|
|
# 获取所有比特币浏览器
|
|
|
|
|
|
@async_retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
async def _bit_browser_get(self, page: int = 0, limit: int = 10, group_id: str | None = None,
|
|
|
|
|
|
bit_port: str | None = "54345",
|
|
|
|
|
|
) -> dict:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取所有比特币浏览器
|
|
|
|
|
|
:param page: 页码
|
|
|
|
|
|
:param group_id: 分组ID
|
|
|
|
|
|
:param limit: 每页数量
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: {'success': True, 'data': {'page': 1, 'pageSize': 10, 'totalNum': 128, 'list': [{'id': '12a3126accc14c93bd34adcccfc3083c'},{'id':'edc5d61a56214e9f8a8bbf1a2e1b405d'}]}}
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/list"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {'page': page, 'pageSize': limit}
|
|
|
|
|
|
if group_id is not None:
|
|
|
|
|
|
data['groupId'] = group_id
|
|
|
|
|
|
res = await self.__request('POST', url, json=data, headers=headers)
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
# 获取比特浏览器窗口详情
|
|
|
|
|
|
@async_retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
async def _bit_browser_detail(self, pk: str, bit_port: str = "54345") -> dict:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取比特浏览器窗口详情
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: {'success': True, 'data': {'id': '12a3126accc14c93bd34adcccfc3083c', 'name': '12a3126accc14c93bd34adcccfc3083c', 'remark': '12a3126accc14c93bd34adcccfc3083c', 'groupId': '12a3126accc14c93bd34adcccfc3083c', 'proxyType
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/detail"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {
|
|
|
|
|
|
"id": pk
|
|
|
|
|
|
}
|
|
|
|
|
|
res = await self.__request('POST', url, json=data, headers=headers)
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
# 获取比特浏览器的进程id并杀死进程
|
|
|
|
|
|
@async_retry(max_retries=3, delay=1.0, backoff=1.0)
|
|
|
|
|
|
async def _bit_browser_kill_pid(self, pk: str, bit_port: str = "54345") -> str:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取比特浏览器的进程id
|
|
|
|
|
|
:param pk: 浏览器ID
|
|
|
|
|
|
:param bit_port: 可选,默认54345
|
|
|
|
|
|
:return: 返回进程id
|
|
|
|
|
|
"""
|
|
|
|
|
|
url = f"{self.bit_host}:{bit_port}/browser/pids/alive"
|
|
|
|
|
|
headers = {'Content-Type': 'application/json'}
|
|
|
|
|
|
data = {
|
|
|
|
|
|
"ids": [pk]
|
|
|
|
|
|
}
|
|
|
|
|
|
res = await self.__request('POST', url, json=data, headers=headers)
|
|
|
|
|
|
if not res.get('success'):
|
|
|
|
|
|
raise Exception(res)
|
|
|
|
|
|
pid = res['data'][pk]
|
|
|
|
|
|
# 检测系统 并杀死进程
|
|
|
|
|
|
if pid is not None:
|
|
|
|
|
|
if os.name == 'nt':
|
|
|
|
|
|
os.system(f"taskkill /F /PID {pid}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
os.system(f"kill -9 {pid}")
|
|
|
|
|
|
return pid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def main():
|
|
|
|
|
|
bit = BitBrowser()
|
|
|
|
|
|
# res = await bit._bit_browser_get()
|
|
|
|
|
|
jc = 0
|
|
|
|
|
|
while 1:
|
|
|
|
|
|
res = await bit._bit_browser_get(
|
|
|
|
|
|
page=jc,
|
|
|
|
|
|
limit=100,
|
|
|
|
|
|
group_id='4028808b9a52223a019a581bbea1275c')
|
|
|
|
|
|
li = res["data"]["list"]
|
|
|
|
|
|
if len(li) == 0:
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
for i in li:
|
|
|
|
|
|
id = i["id"]
|
|
|
|
|
|
# 读取浏览器详情
|
|
|
|
|
|
res = await bit._bit_browser_detail(id)
|
|
|
|
|
|
|
|
|
|
|
|
# print(f'id -->{id} --> {res}')
|
|
|
|
|
|
data = res["data"]
|
|
|
|
|
|
ua = data["browserFingerPrint"]["userAgent"]
|
|
|
|
|
|
proxy_type = data.get("proxyType")
|
|
|
|
|
|
host = data.get("host")
|
|
|
|
|
|
port = data.get("port")
|
|
|
|
|
|
proxy_account = data.get("proxyUserName")
|
|
|
|
|
|
proxy_password = data.get("proxyPassword")
|
|
|
|
|
|
print(f'id -->{id}')
|
|
|
|
|
|
print(f'ua -->{ua}')
|
|
|
|
|
|
print(f'proxy_type -->{proxy_type}')
|
|
|
|
|
|
print(f'host -->{host}')
|
|
|
|
|
|
print(f'port -->{port}')
|
|
|
|
|
|
print(f'proxy_account -->{proxy_account}')
|
|
|
|
|
|
print(f'proxy_password -->{proxy_password}')
|
|
|
|
|
|
print(f'='*50)
|
|
|
|
|
|
jc += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bit_browser = BitBrowser()
|
|
|
|
|
|
|
|
|
|
|
|
# if __name__ == '__main__':
|
|
|
|
|
|
# asyncio.run(main())
|