Files
ca_auto_table/app/utils/browser_api.py
2025-11-18 16:46:04 +08:00

144 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import datetime
import asyncio
import httpx
from loguru import logger
from utils.decorators import handle_exceptions_unified
class BrowserApi:
"""
浏览器接口
"""
def __init__(self):
self.local_url = 'http://127.0.0.1:54345'
self.headers = {'Content-Type': 'application/json'}
# 使用异步 HTTP 客户端,启用连接池和超时设置
self.client = httpx.AsyncClient(
base_url=self.local_url,
headers=self.headers,
timeout=httpx.Timeout(30.0, connect=10.0), # 总超时30秒连接超时10秒
limits=httpx.Limits(max_keepalive_connections=50, max_connections=100), # 连接池配置
)
async def __aenter__(self):
"""异步上下文管理器入口"""
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
"""异步上下文管理器出口,关闭客户端"""
await self.aclose()
async def aclose(self):
"""关闭 HTTP 客户端"""
if self.client:
await self.client.aclose()
# 打开指纹浏览器
@handle_exceptions_unified()
async def open_browser(self, id: str, jc: int = 0):
"""
打开指纹浏览器(异步优化版本)
:param jc: 计次
:param id: 浏览器id
:return:http, pid
"""
if jc > 3:
return None, None
url = '/browser/open'
data = {
'id': id
}
try:
res = await self.client.post(url, json=data)
res.raise_for_status() # 检查 HTTP 状态码
res_data = res.json()
logger.info(f'打开指纹浏览器: {res_data}')
if not res_data.get('success'):
logger.error(f'打开指纹浏览器失败: {res_data}')
return await self.open_browser(id, jc + 1)
data = res_data.get('data')
http = data.get('http')
pid = data.get('pid')
logger.info(f'打开指纹浏览器成功: {http}, {pid}')
return http, pid
except httpx.TimeoutException as e:
logger.error(f'打开指纹浏览器超时: {e}')
if jc < 3:
return await self.open_browser(id, jc + 1)
return None, None
except httpx.RequestError as e:
logger.error(f'打开指纹浏览器请求错误: {e}')
if jc < 3:
return await self.open_browser(id, jc + 1)
return None, None
except Exception as e:
logger.error(f'打开指纹浏览器异常: {e}')
if jc < 3:
return await self.open_browser(id, jc + 1)
return None, None
# 关闭指纹浏览器
@handle_exceptions_unified()
async def close_browser(self, id: str, jc: int = 0):
"""
关闭指纹浏览器(异步优化版本)
:param jc: 计次
:param id: 浏览器id
:return:
"""
if jc > 3:
return None
url = '/browser/close'
data = {
'id': id
}
try:
res = await self.client.post(url, json=data)
res.raise_for_status() # 检查 HTTP 状态码
res_data = res.json()
logger.info(f'关闭指纹浏览器: {res_data}')
if not res_data.get('success'):
msg = res_data.get('msg', '')
# 如果浏览器正在打开中,等待后重试(不是真正的错误)
if '正在打开中' in msg or 'opening' in msg.lower():
if jc < 3:
# 等待 1-3 秒后重试(根据重试次数递增等待时间)
wait_time = (jc + 1) * 1.0 # 第1次重试等1秒第2次等2秒第3次等3秒
logger.info(f'浏览器正在打开中,等待 {wait_time} 秒后重试关闭: browser_id={id}')
await asyncio.sleep(wait_time)
return await self.close_browser(id, jc + 1)
else:
# 超过重试次数,记录警告但不作为错误
logger.warning(f'关闭指纹浏览器失败浏览器正在打开中已重试3次: browser_id={id}')
return None
else:
# 其他错误,记录为错误并重试
logger.error(f'关闭指纹浏览器失败: {res_data}')
if jc < 3:
await asyncio.sleep(0.5) # 短暂等待后重试
return await self.close_browser(id, jc + 1)
return None
logger.info(f'关闭指纹浏览器成功: browser_id={id}')
return True
except httpx.TimeoutException as e:
logger.error(f'关闭指纹浏览器超时: {e}')
if jc < 3:
await asyncio.sleep(1.0)
return await self.close_browser(id, jc + 1)
return None
except httpx.RequestError as e:
logger.error(f'关闭指纹浏览器请求错误: {e}')
if jc < 3:
await asyncio.sleep(1.0)
return await self.close_browser(id, jc + 1)
return None
except Exception as e:
logger.error(f'关闭指纹浏览器异常: {e}')
if jc < 3:
await asyncio.sleep(1.0)
return await self.close_browser(id, jc + 1)
return None
browser_api = BrowserApi()