Files
cookie/browser_manager.py
T

233 lines
6.7 KiB
Python

"""浏览器管理模块"""
import time
from DrissionPage import ChromiumPage, ChromiumOptions
from logger import get_logger
logger = get_logger(__name__)
class BrowserManager:
"""浏览器管理器"""
def __init__(self, browser_type: str = 'edge', headless: bool = False):
"""
初始化浏览器管理器
Args:
browser_type: 浏览器类型 (edge 或 chrome)
headless: 是否无头模式
"""
self.browser_type = browser_type
self.headless = headless
self.page = None
def init_browser(self):
"""初始化浏览器"""
co = ChromiumOptions()
if self.browser_type == 'edge':
co.set_browser_path(r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe")
co.set_argument('--no-sandbox')
co.set_argument('--disable-dev-shm-usage')
if self.headless:
co.set_argument('--headless')
self.page = ChromiumPage(addr_or_opts=co)
logger.info("浏览器初始化成功")
def wait_page_loaded(self, timeout=30):
"""等待页面加载完成"""
if self.page:
self.page.wait.doc_loaded(timeout=timeout)
self.page.ele('tag:body', timeout=timeout)
def ensure_connection(self):
"""确保浏览器连接正常"""
try:
if self.page:
self.page.get("about:blank")
return True
except:
pass
try:
self.init_browser()
self.page.get("about:blank")
return True
except Exception as e:
logger.error(f"无法建立浏览器连接: {e}")
return False
def import_cookies(self, cookies: list, domain: str):
"""
导入cookies到浏览器
Args:
cookies: cookie列表
domain: 域名
Returns:
成功导入的cookie数量
"""
if not self.ensure_connection():
return 0
if not cookies:
return 0
success_count = 0
# 直接使用DrissionPage的set.cookies方法批量导入
# 该方法内部已经优化了导入逻辑
for cookie in cookies:
try:
if not cookie.get('name') or not cookie.get('value'):
continue
cookie_dict = {
'name': cookie.get('name'),
'value': cookie.get('value'),
'domain': cookie.get('domain', domain),
'path': cookie.get('path', '/')
}
self.page.set.cookies(cookie_dict)
success_count += 1
except Exception as e:
# 忽略导入失败的cookie,继续处理其他cookie
pass
return success_count
def import_local_storage(self, local_storage: dict):
"""
导入localStorage到浏览器
Args:
local_storage: localStorage字典
Returns:
成功导入的项目数量
"""
if not self.ensure_connection():
return 0
ls_count = 0
for domain, items in local_storage.items():
try:
for key, value in items.items():
try:
self.page.set.local_storage(key, value)
ls_count += 1
except Exception as e:
logger.error(f"导入localStorage失败: {key} - {e}")
except Exception as e:
logger.error(f"导入localStorage域失败: {domain} - {e}")
logger.info(f"成功导入 {ls_count} 个 localStorage 项目")
return ls_count
def verify_login(self, url: str, check_selector: str = "", success_text: str = "") -> bool:
"""
验证登录状态
Args:
url: 网站地址
check_selector: 登录检测选择器
success_text: 登录成功时显示的文本
Returns:
是否已登录
"""
if not self.ensure_connection():
return False
try:
self.page.get(url)
self.wait_page_loaded()
time.sleep(3) # 等待网页加载完毕并暂停3秒
for i in range(3):
time.sleep(3) # 每次刷新前暂停3秒
self.page.refresh()
self.wait_page_loaded()
time.sleep(3) # 每次刷新后暂停3秒
if not check_selector and not success_text:
return False
if check_selector:
try:
element = self.page.ele(check_selector, timeout=10)
if element:
element_text = element.text or ""
if not success_text:
return True
if success_text in element_text:
return True
except:
pass
if success_text:
try:
page_text = self.page.html or ""
if success_text in page_text:
return True
except:
pass
return False
except Exception as e:
logger.error(f"验证登录状态失败: {e}")
return False
def get_cookies(self) -> list:
"""
获取当前浏览器的所有cookies
Returns:
cookie列表
"""
if not self.page:
return []
try:
return self.page.cookies()
except Exception as e:
logger.error(f"获取cookies失败: {e}")
return []
def get_local_storage(self) -> dict:
"""
获取当前浏览器的localStorage
Returns:
localStorage字典
"""
if not self.page:
return {}
try:
import json
js_code = """
var result = {};
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
result[key] = localStorage.getItem(key);
}
JSON.stringify(result);
"""
result = self.page.run_js(js_code)
return json.loads(result) if result else {}
except Exception as e:
logger.error(f"获取localStorage失败: {e}")
return {}
def close(self):
"""关闭浏览器"""
if self.page:
try:
self.page.quit()
except Exception as e:
logger.error(f"关闭浏览器失败: {e}")
finally:
self.page = None