diff --git a/browser_login.py b/browser_login.py index 734d09d..ab494d8 100644 --- a/browser_login.py +++ b/browser_login.py @@ -71,29 +71,34 @@ class BrowserLogin: parsed = urlparse(url) return parsed.netloc - def _get_cookies_dict(self) -> Dict[str, List[Dict]]: + def get_all_cookies(self) -> List[Dict]: """ - 获取当前浏览器的所有 cookie,按域名分组 + 获取当前浏览器实例的所有 cookie Returns: - 按域名分组的 cookie 字典 + 所有 cookie 的列表 """ - cookies = self.tab.cookies.as_dict + # 先获取 cookies 对象,然后调用 as_dict 方法 + cookies_obj = self.tab.cookies + cookies = cookies_obj() if callable(cookies_obj) else cookies_obj + cookies = cookies.as_dict() if hasattr(cookies, 'as_dict') else cookies - # 按域名分组 - cookie_dict = {} + # 确保返回完整的 cookie 列表,包含所有属性 + formatted_cookies = [] for cookie in cookies: - domain = cookie.get('domain', '') - # 统一域名格式(去掉开头的点) - if domain.startswith('.'): - domain = domain[1:] - - if domain not in cookie_dict: - cookie_dict[domain] = [] - - cookie_dict[domain].append(cookie) + formatted_cookie = { + 'name': cookie.get('name', ''), + 'value': cookie.get('value', ''), + 'domain': cookie.get('domain', ''), + 'path': cookie.get('path', '/'), + 'expires': cookie.get('expirationDate', None), + 'secure': cookie.get('secure', False), + 'httpOnly': cookie.get('httpOnly', False), + 'sameSite': cookie.get('sameSite', 'Lax') + } + formatted_cookies.append(formatted_cookie) - return cookie_dict + return formatted_cookies def check_login(self, url: str, check_selector: str, success_text: str) -> bool: """ @@ -146,8 +151,11 @@ class BrowserLogin: fail_count = 0 logger.info(f"开始导入 {len(cookies)} 个 cookie") - for cookie in cookies: - try: + + try: + # 准备所有 cookie 数据 + formatted_cookies = [] + for cookie in cookies: cookie_dict = { 'name': cookie.get('name', ''), 'value': cookie.get('value', ''), @@ -160,11 +168,23 @@ class BrowserLogin: cookie_dict['httpOnly'] = True if cookie.get('sameSite'): cookie_dict['sameSite'] = cookie.get('sameSite') - - self.tab.set.cookies(cookie_dict) - success_count += 1 - except Exception as e: - fail_count += 1 + formatted_cookies.append(cookie_dict) + + # 根据 DrissionPage 文档,set.cookies() 方法可以直接接收列表格式的多个 cookie + logger.info("使用一次性注入方式导入 cookie") + self.tab.set.cookies(formatted_cookies) + success_count = len(formatted_cookies) + + except Exception as e: + logger.error(f"导入 cookie 失败: {e}") + # 回退到逐个注入 + logger.info("回退到逐个注入方式导入 cookie") + for cookie_dict in formatted_cookies: + try: + self.tab.set.cookies(cookie_dict) + success_count += 1 + except Exception as e: + fail_count += 1 logger.info(f"Cookie 导入完成: 成功 {success_count}, 失败 {fail_count}") return fail_count == 0 @@ -309,9 +329,19 @@ class BrowserLogin: time.sleep(3) # 获取 cookies - cookies = self.tab.cookies.as_dict + cookies_obj = self.browser.cookies + cookies = cookies_obj() if callable(cookies_obj) else cookies_obj + cookies = cookies.as_dict() if hasattr(cookies, 'as_dict') else cookies - return cookies + # 确保返回的是列表 + if isinstance(cookies, list): + return cookies + elif isinstance(cookies, dict): + # 如果是字典,转换为列表 + return [cookies] + else: + # 如果是其他类型,返回空列表 + return [] except Exception as e: logger.error(f"刷新页面并保存 cookie 失败: {e}") @@ -323,7 +353,7 @@ class BrowserLogin: class CookieManager: - """Cookie 管理器""" + """Cookie 管理器 - 实现浏览器实例级别的 Cookie 共享""" def __init__(self, cookie_file: str): """ @@ -335,14 +365,25 @@ class CookieManager: self.cookie_file = cookie_file self.cookies = self._load_cookies() - def _load_cookies(self) -> Dict[str, Dict[str, List[Dict]]]: + def _load_cookies(self) -> Dict[str, List[Dict]]: """加载 cookie 文件""" import os if os.path.exists(self.cookie_file): try: with open(self.cookie_file, 'r', encoding='utf-8') as f: - return json.load(f) + data = json.load(f) + # 兼容旧格式 + if isinstance(data, dict) and any(isinstance(v, dict) for v in data.values()): + # 转换旧格式为新格式 + new_data = {} + for user, websites in data.items(): + all_cookies = [] + for site_cookies in websites.values(): + all_cookies.extend(site_cookies) + new_data[user] = all_cookies + return new_data + return data except Exception as e: logger.error(f"加载 cookie 文件失败: {e}") @@ -356,76 +397,203 @@ class CookieManager: except Exception as e: logger.error(f"保存 cookie 文件失败: {e}") - def get_cookies(self, user_name: str, website_name: str) -> List[Dict]: + def get_all_cookies(self, user_name: str) -> List[Dict]: """ - 获取指定用户和网站的 cookie + 获取指定用户的所有 cookie Args: user_name: 用户名 - website_name: 网站名 Returns: cookie 列表 """ - if user_name not in self.cookies: - return [] - - if website_name not in self.cookies[user_name]: - return [] - - return self.cookies[user_name][website_name] + return self.cookies.get(user_name, []) - def save_cookies(self, user_name: str, website_name: str, cookies: List[Dict]): + def save_all_cookies(self, user_name: str, cookies: List[Dict]): """ - 保存指定用户和网站的 cookie + 保存指定用户的所有 cookie Args: user_name: 用户名 - website_name: 网站名 cookies: cookie 列表 """ - if user_name not in self.cookies: - self.cookies[user_name] = {} - - self.cookies[user_name][website_name] = cookies + self.cookies[user_name] = cookies self._save_cookies() - def get_cookies_for_domain(self, domain: str) -> List[Dict]: + def save_cookies(self, user_name: str, website_name: str, cookies: List[Dict]): """ - 获取指定域名的 cookie(从所有用户的 cookie 中查找) + 保存指定用户和网站的 cookie(兼容旧接口) Args: + user_name: 用户名 + website_name: 网站名(未使用,保持兼容) + cookies: cookie 列表 + """ + # 保持向后兼容,将网站的cookie添加到用户的所有cookie中 + if user_name not in self.cookies: + self.cookies[user_name] = [] + + # 合并新cookie到现有cookie中 + existing_cookies = self.cookies[user_name] + + # 创建现有cookie的索引,用于快速查找 + cookie_index = {} + for i, cookie in enumerate(existing_cookies): + if isinstance(cookie, dict): + key = (cookie.get('name'), cookie.get('domain'), cookie.get('path')) + cookie_index[key] = i + + # 添加或更新cookie + if isinstance(cookies, list): + valid_cookies = [] + for cookie in cookies: + if isinstance(cookie, dict): + valid_cookies.append(cookie) + + for cookie in valid_cookies: + key = (cookie.get('name'), cookie.get('domain'), cookie.get('path')) + if key in cookie_index: + # 更新现有cookie + existing_cookies[cookie_index[key]] = cookie + else: + # 添加新cookie + existing_cookies.append(cookie) + + if valid_cookies: + logger.info(f" 已保存 {len(valid_cookies)} 个新 cookie") + + self._save_cookies() + + def add_cookie(self, user_name: str, cookie: Dict): + """ + 为指定用户添加单个 cookie + + Args: + user_name: 用户名 + cookie: cookie 字典 + """ + if user_name not in self.cookies: + self.cookies[user_name] = [] + + # 检查是否已存在相同的 cookie + existing_index = -1 + for i, existing_cookie in enumerate(self.cookies[user_name]): + if (existing_cookie.get('name') == cookie.get('name') and + existing_cookie.get('domain') == cookie.get('domain') and + existing_cookie.get('path') == cookie.get('path')): + existing_index = i + break + + if existing_index >= 0: + # 更新现有 cookie + self.cookies[user_name][existing_index] = cookie + else: + # 添加新 cookie + self.cookies[user_name].append(cookie) + + self._save_cookies() + + def remove_cookie(self, user_name: str, cookie_name: str, domain: str): + """ + 从指定用户中移除指定的 cookie + + Args: + user_name: 用户名 + cookie_name: cookie 名称 + domain: cookie 域名 + """ + if user_name in self.cookies: + self.cookies[user_name] = [ + cookie for cookie in self.cookies[user_name] + if not (cookie.get('name') == cookie_name and cookie.get('domain') == domain) + ] + self._save_cookies() + + def clear_cookies(self, user_name: str): + """ + 清空指定用户的所有 cookie + + Args: + user_name: 用户名 + """ + if user_name in self.cookies: + self.cookies[user_name] = [] + self._save_cookies() + + def get_cookies_for_domain(self, user_name: str, domain: str) -> List[Dict]: + """ + 获取指定用户的指定域名的 cookie + + Args: + user_name: 用户名 domain: 域名 Returns: cookie 列表 """ - all_cookies = [] + user_cookies = self.get_all_cookies(user_name) + filtered_cookies = [] - for user_name, websites in self.cookies.items(): - for website_name, cookies in websites.items(): - for cookie in cookies: - cookie_domain = cookie.get('domain', '') - # 统一域名格式 - if cookie_domain.startswith('.'): - cookie_domain = cookie_domain[1:] - - if domain in cookie_domain or cookie_domain in domain: - all_cookies.append(cookie) + for cookie in user_cookies: + cookie_domain = cookie.get('domain', '') + # 统一域名格式 + if cookie_domain.startswith('.'): + cookie_domain = cookie_domain[1:] + + if domain in cookie_domain or cookie_domain in domain: + filtered_cookies.append(cookie) - return all_cookies + return filtered_cookies if __name__ == "__main__": + # 初始化日志系统 + from applogger import setup_logging + setup_logging() + # 测试代码 manager = CookieManager("cookies.json") - # 保存测试 cookie + # 测试1: 保存所有 cookie test_cookies = [ - {"name": "test", "value": "123", "domain": "example.com", "path": "/"} + {"name": "test", "value": "123", "domain": "example.com", "path": "/"}, + {"name": "session", "value": "abc123", "domain": "example.com", "path": "/", "httpOnly": True}, + {"name": "user", "value": "testuser", "domain": "example.org", "path": "/"} ] - manager.save_cookies("测试用户", "测试网站", test_cookies) + manager.save_all_cookies("测试用户", test_cookies) + logger.info("测试1: 保存所有 cookie 完成") - # 获取 cookie - cookies = manager.get_cookies("测试用户", "测试网站") - logger.info(f"获取到的 cookie: {cookies}") \ No newline at end of file + # 测试2: 获取所有 cookie + all_cookies = manager.get_all_cookies("测试用户") + logger.info(f"测试2: 获取到 {len(all_cookies)} 个 cookie") + + # 测试3: 添加单个 cookie + new_cookie = {"name": "token", "value": "xyz789", "domain": "example.com", "path": "/", "secure": True} + manager.add_cookie("测试用户", new_cookie) + logger.info("测试3: 添加单个 cookie 完成") + + # 测试4: 获取更新后的所有 cookie + updated_cookies = manager.get_all_cookies("测试用户") + logger.info(f"测试4: 获取到 {len(updated_cookies)} 个 cookie") + + # 测试5: 获取指定域名的 cookie + example_cookies = manager.get_cookies_for_domain("测试用户", "example.com") + logger.info(f"测试5: 获取到 {len(example_cookies)} 个 example.com 的 cookie") + + # 测试6: 移除指定 cookie + manager.remove_cookie("测试用户", "test", "example.com") + logger.info("测试6: 移除指定 cookie 完成") + + # 测试7: 检查移除后的 cookie + final_cookies = manager.get_all_cookies("测试用户") + logger.info(f"测试7: 移除后剩余 {len(final_cookies)} 个 cookie") + + # 测试8: 清空所有 cookie + manager.clear_cookies("测试用户") + logger.info("测试8: 清空所有 cookie 完成") + + # 测试9: 检查清空后的 cookie + empty_cookies = manager.get_all_cookies("测试用户") + logger.info(f"测试9: 清空后剩余 {len(empty_cookies)} 个 cookie") + + logger.info("所有测试完成!") \ No newline at end of file diff --git a/config.json b/config.json index 737c680..eb08b57 100644 --- a/config.json +++ b/config.json @@ -20,7 +20,7 @@ "name": "网站A", "url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll", "login_check_selector": "", - "success_text": "" + "success_text": "彭峰" } ] }, diff --git a/cookie_cloud.py b/cookie_cloud.py index 21b15d1..2c9e951 100644 --- a/cookie_cloud.py +++ b/cookie_cloud.py @@ -1,4 +1,4 @@ -"""Cookie Cloud 模块 - 从 Cookie Cloud 服务器获取 cookie 数据""" +"""Cookie Cloud 模块 - 从 Cookie Cloud 服务器获取并处理 cookie 数据""" import json import hashlib import base64 @@ -6,11 +6,21 @@ from typing import Dict, List, Optional, Tuple import urllib.request import urllib.error from Crypto.Cipher import AES +from dataclasses import dataclass from applogger import get_logger logger = get_logger(__name__) +@dataclass +class CookieCloudConfig: + """CookieCloud 配置""" + api_url: str + uuid: str + password: str + timeout: int = 30 + + class CookieCloud: """Cookie Cloud 客户端""" @@ -23,13 +33,16 @@ class CookieCloud: uuid: 用户 UUID password: 用户密码 """ - self.api_url = api_url.rstrip('/') - self.uuid = uuid - self.password = password + self.config = CookieCloudConfig( + api_url=api_url.rstrip('/'), + uuid=uuid, + password=password, + timeout=30 + ) def _get_crypt_key(self) -> bytes: """生成加密密钥""" - combined_string = f"{self.uuid}-{self.password}" + combined_string = f"{self.config.uuid}-{self.config.password}" return hashlib.md5(combined_string.encode('utf-8')).hexdigest()[:16].encode("utf-8") def _bytes_to_key(self, data: bytes, salt: bytes, output: int = 48) -> bytes: @@ -58,10 +71,10 @@ class CookieCloud: padding_length = ord(padding_length) return decrypted_padded[:-padding_length] - def _download_data(self) -> Tuple[Optional[Dict], str]: - """下载并解密所有数据""" + def _download_all(self) -> Tuple[Optional[Dict], str]: + """下载所有cookie和local storage数据""" try: - url = f"{self.api_url}/get/{self.uuid}" + url = f"{self.config.api_url}/get/{self.config.uuid}" request = urllib.request.Request( url, headers={ @@ -71,7 +84,7 @@ class CookieCloud: method='GET' ) - response = urllib.request.urlopen(request, timeout=30) + response = urllib.request.urlopen(request, timeout=self.config.timeout) if response.status != 200: return None, f"服务器返回错误状态码: {response.status}" @@ -98,7 +111,10 @@ class CookieCloud: return result, "" except urllib.error.HTTPError as e: - return None, f"HTTP错误: {e.code} {e.reason}" + if e.code == 401: + return None, "认证失败,请检查用户名和密码" + else: + return None, f"HTTP错误: {e.code} {e.reason}" except urllib.error.URLError as e: return None, f"网络连接失败: {e.reason}" except Exception as e: @@ -112,7 +128,7 @@ class CookieCloud: 按域名分组的 cookie 数据字典 格式: {"domain.com": [{"name": "cookie1", "value": "val1", ...}, ...], ...} """ - data, error = self._download_data() + data, error = self._download_all() if error: logger.error(error) @@ -139,8 +155,32 @@ class CookieCloud: cookie['sameSite'] = 'Lax' processed_cookies[domain].append(cookie) + logger.info(f"获取到 {len(processed_cookies)} 个域名的 cookies") return processed_cookies + def get_local_storage(self) -> Dict[str, Dict]: + """ + 从 Cookie Cloud 服务器获取 local storage 数据 + + Returns: + 按域名分组的 local storage 数据字典 + 格式: {"domain.com": {"key1": "value1", ...}, ...} + """ + data, error = self._download_all() + + if error: + logger.error(error) + return {} + + # 处理数据结构 + local_storage_data = {} + + if isinstance(data, dict) and data.get('local_storage_data'): + local_storage_data = data.get('local_storage_data', {}) + + logger.info(f"获取到 {len(local_storage_data)} 个域名的 local storage") + return local_storage_data + def get_cookies_for_domain(self, domain: str) -> List[Dict]: """ 获取指定域名的 cookie @@ -159,8 +199,61 @@ class CookieCloud: if domain in clean_domain or clean_domain in domain: matched_cookies.extend(cookies) + logger.info(f"获取到 {len(matched_cookies)} 个 {domain} 的 cookies") return matched_cookies + def get_local_storage_for_domain(self, domain: str) -> Dict: + """ + 获取指定域名的 local storage + + Args: + domain: 域名 + + Returns: + local storage 字典 + """ + all_local_storage = self.get_local_storage() + + for ls_domain, data in all_local_storage.items(): + clean_domain = ls_domain.lstrip('.') + if domain in clean_domain or clean_domain in domain: + logger.info(f"获取到 {domain} 的 local storage") + return data + + return {} + + def get_all_data(self) -> Dict: + """ + 获取所有数据(包括 cookies 和 local storage) + + Returns: + 包含所有数据的字典 + """ + data, error = self._download_all() + + if error: + logger.error(error) + return {} + + result = { + 'cookies': {}, + 'local_storage': {} + } + + # 处理 cookies + if isinstance(data, dict): + if not data.get('cookie_data'): + result['cookies'] = data + elif data.get('cookie_data'): + result['cookies'] = data.get('cookie_data', {}) + + # 处理 local storage + if data.get('local_storage_data'): + result['local_storage'] = data.get('local_storage_data', {}) + + logger.info(f"获取到所有数据: {len(result['cookies'])} 个域名的 cookies, {len(result['local_storage'])} 个域名的 local storage") + return result + if __name__ == "__main__": cc = CookieCloud( @@ -169,8 +262,18 @@ if __name__ == "__main__": password="jtDM5dV9AyqXkZdQVeA9f6" ) - cookies = cc.get_cookies() - logger.info(f"获取到 {len(cookies)} 个域名的 cookies") + # 测试获取所有数据 + all_data = cc.get_all_data() + logger.info(f"所有数据: {json.dumps(all_data, indent=2, ensure_ascii=False)[:500]}...") + # 测试获取 cookies + cookies = cc.get_cookies() + + # 测试获取指定域名的 cookies lmkbi_cookies = cc.get_cookies_for_domain('lmkbi.95155.com') - logger.info(f"获取到 {len(lmkbi_cookies)} 个 lmkbi.95155.com 的 cookies") + + # 测试获取 local storage + local_storage = cc.get_local_storage() + + # 测试获取指定域名的 local storage + lmkbi_local_storage = cc.get_local_storage_for_domain('lmkbi.95155.com') diff --git a/cookie_data.json b/cookie_data.json new file mode 100644 index 0000000..55b3db4 --- /dev/null +++ b/cookie_data.json @@ -0,0 +1,11 @@ +{ + "cookies": { + "userType": "2", + "edentoken": "13548569666", + "LMKBIUSS": "eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOiIxMzU0ODU2OTY2NiIsInRpbWVzdGFtcCI6MTc3MjUyNjkxNTQzMiwidG9rZW4iOiIyYTM5OTk2Zi0xY2MyLTQ2MTktOTcwYS01NzdmOWUxZGMyODQifQ==", + "user": "13548569666" + }, + "localStorage": {}, + "url": "https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll", + "timestamp": 1772525977.9257276 +} \ No newline at end of file diff --git a/cookie_extractor.py b/cookie_extractor.py new file mode 100644 index 0000000..abbe1ca --- /dev/null +++ b/cookie_extractor.py @@ -0,0 +1,295 @@ +"""Cookie和LocalStorage提取器 - 使用DrissionPage库""" +import tkinter as tk +from tkinter import ttk, messagebox +import json +import os +from DrissionPage import Chromium, ChromiumOptions +from applogger import setup_logging, get_logger + +# 初始化日志 +setup_logging() +logger = get_logger(__name__) + +class CookieExtractorApp: + """Cookie和LocalStorage提取器应用""" + + def __init__(self, root): + """ + 初始化应用 + + Args: + root: 根窗口 + """ + self.root = root + self.root.title("Cookie和LocalStorage提取器") + self.root.geometry("600x300") + self.root.resizable(True, True) + + # 浏览器实例 + self.browser = None + self.tab = None + + # 创建界面 + self._create_widgets() + + def _create_widgets(self): + """创建界面控件""" + # 主框架 + main_frame = ttk.Frame(self.root, padding="20") + main_frame.pack(fill=tk.BOTH, expand=True) + + # 网址输入区域 + url_frame = ttk.LabelFrame(main_frame, text="网址输入", padding="10") + url_frame.pack(fill=tk.X, pady=10) + + ttk.Label(url_frame, text="网址:").pack(side=tk.LEFT, padx=5) + self.url_var = tk.StringVar(value="https://") + self.url_entry = ttk.Entry(url_frame, textvariable=self.url_var, width=50) + self.url_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) + + # 按钮区域 + button_frame = ttk.Frame(main_frame) + button_frame.pack(fill=tk.X, pady=10) + + self.open_button = ttk.Button(button_frame, text="打开", command=self.open_url, width=15) + self.open_button.pack(side=tk.LEFT, padx=5) + + self.save_button = ttk.Button(button_frame, text="保存", command=self.save_data, width=15, state=tk.DISABLED) + self.save_button.pack(side=tk.LEFT, padx=5) + + self.restore_button = ttk.Button(button_frame, text="恢复", command=self.restore_data, width=15) + self.restore_button.pack(side=tk.LEFT, padx=5) + + self.close_button = ttk.Button(button_frame, text="关闭", command=self.close_app, width=15) + self.close_button.pack(side=tk.RIGHT, padx=5) + + # 状态区域 + self.status_var = tk.StringVar(value="就绪") + status_frame = ttk.Frame(main_frame) + status_frame.pack(fill=tk.X, pady=10) + + ttk.Label(status_frame, text="状态:").pack(side=tk.LEFT, padx=5) + ttk.Label(status_frame, textvariable=self.status_var, foreground="blue").pack(side=tk.LEFT, padx=5) + + def open_url(self): + """打开网址""" + url = self.url_var.get().strip() + + if not url: + messagebox.showerror("错误", "请输入网址") + return + + if not (url.startswith("http://") or url.startswith("https://")): + url = "https://" + url + self.url_var.set(url) + + try: + if not self.browser or not self.tab: + self.status_var.set("正在打开浏览器...") + self.root.update() + + # 创建浏览器实例 + co = ChromiumOptions() + # 设置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') + + self.browser = Chromium(co) + self.tab = self.browser.new_tab() + + self.status_var.set(f"正在访问: {url}") + self.root.update() + + # 在当前页面打开网址 + self.tab.get(url) + + self.status_var.set(f"已打开: {url}") + self.save_button.config(state=tk.NORMAL) + messagebox.showinfo("成功", f"已成功打开网址: {url}\n\n请在浏览器中完成操作后,点击'保存'按钮提取数据") + + except Exception as e: + logger.error(f"打开网址失败: {e}") + messagebox.showerror("错误", f"打开网址失败: {str(e)}") + self.status_var.set("就绪") + self._cleanup_browser() + + def save_data(self): + """保存cookie和localStorage数据""" + if not self.browser or not self.tab: + messagebox.showerror("错误", "请先打开网址") + return + + try: + self.status_var.set("正在提取数据...") + self.root.update() + + # 提取浏览器的cookies信息 + cookies = self.browser.cookies() + + # 提取localStorage数据 + localStorage = self._get_local_storage() + + # 整合数据 + data = { + "cookies": cookies, + "localStorage": localStorage, + "url": self.url_var.get(), + "timestamp": os.path.getmtime(__file__) + } + + # 保存到JSON文件 + output_file = "cookie_data.json" + with open(output_file, 'w', encoding='utf-8') as f: + json.dump(data, f, indent=2, ensure_ascii=False) + + self.status_var.set(f"数据已保存到: {output_file}") + messagebox.showinfo("成功", f"数据已成功保存到: {output_file}\n\n- Cookie数量: {len(cookies)}\n- LocalStorage项目数量: {len(localStorage)}") + + except Exception as e: + logger.error(f"保存数据失败: {e}") + messagebox.showerror("错误", f"保存数据失败: {str(e)}") + self.status_var.set("就绪") + + def _get_local_storage(self): + """获取localStorage数据""" + try: + # 使用JavaScript获取localStorage数据 + 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.tab.run_js(js_code) + return json.loads(result) if result else {} + except Exception as e: + logger.error(f"获取localStorage失败: {e}") + return {} + + def restore_data(self): + """从cookie_data.json恢复数据""" + try: + self.status_var.set("正在恢复数据...") + self.root.update() + + # 检查文件是否存在 + output_file = "cookie_data.json" + if not os.path.exists(output_file): + messagebox.showerror("错误", f"文件不存在: {output_file}") + self.status_var.set("就绪") + return + + # 读取数据 + with open(output_file, 'r', encoding='utf-8') as f: + data = json.load(f) + + # 提取数据 + url = data.get("url", "") + cookies = data.get("cookies", []) + localStorage = data.get("localStorage", {}) + + if not url: + messagebox.showerror("错误", "文件中没有保存的网址") + self.status_var.set("就绪") + return + + # 关闭现有浏览器 + self._cleanup_browser() + + self.status_var.set("正在打开浏览器...") + self.root.update() + + # 创建浏览器实例 + co = ChromiumOptions() + # 设置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') + + self.browser = Chromium(co) + self.tab = self.browser.new_tab() + + # 访问网址(先访问一个空白页面,以便注入localStorage) + self.status_var.set("正在准备注入环境...") + self.root.update() + self.tab.get("about:blank") + + # 注入cookies到浏览器 + if cookies: + self.status_var.set("正在注入cookies...") + self.root.update() + try: + self.browser.set.cookies(cookies) + logger.info(f"成功注入 {len(cookies)} 个 cookies 到浏览器") + except Exception as e: + logger.error(f"注入cookies失败: {e}") + + # 注入localStorage + if localStorage: + self.status_var.set("正在注入localStorage...") + self.root.update() + try: + # 使用更安全的方式注入localStorage + for key, value in localStorage.items(): + # 转义单引号和双引号 + safe_value = value.replace("'", "\\'").replace('"', '\\"') + js_code = f"localStorage.setItem('{key}', '{safe_value}');" + self.tab.run_js(js_code) + logger.info(f"成功注入 {len(localStorage)} 个 localStorage 项目") + except Exception as e: + logger.error(f"注入localStorage失败: {e}") + + # 访问目标网址 + self.status_var.set(f"正在访问: {url}") + self.root.update() + self.tab.get(url) + + # 更新界面 + self.url_var.set(url) + self.status_var.set(f"已恢复: {url}") + self.save_button.config(state=tk.NORMAL) + messagebox.showinfo("成功", f"已成功恢复数据并打开网址: {url}\n\n- Cookie数量: {len(cookies)}\n- LocalStorage项目数量: {len(localStorage)}") + + except Exception as e: + logger.error(f"恢复数据失败: {e}") + messagebox.showerror("错误", f"恢复数据失败: {str(e)}") + self.status_var.set("就绪") + self._cleanup_browser() + + def close_app(self): + """关闭应用""" + self._cleanup_browser() + self.root.destroy() + + def _cleanup_browser(self): + """清理浏览器资源""" + if self.browser: + try: + self.browser.quit() + except Exception as e: + logger.error(f"关闭浏览器失败: {e}") + finally: + self.browser = None + self.tab = None + self.save_button.config(state=tk.DISABLED) + self.status_var.set("就绪") + +def main(): + """主函数""" + root = tk.Tk() + app = CookieExtractorApp(root) + + # 处理窗口关闭事件 + def on_closing(): + app._cleanup_browser() + root.destroy() + + root.protocol("WM_DELETE_WINDOW", on_closing) + root.mainloop() + +if __name__ == "__main__": + main() diff --git a/cookies.json b/cookies.json index 9e26dfe..d72b0cf 100644 --- a/cookies.json +++ b/cookies.json @@ -1 +1,633 @@ -{} \ No newline at end of file +{ + "用户A": [ + "edentoken", + "JSESSIONID", + "LMKBIUSS", + "userType", + "user", + {}, + { + "_C_Auth": "", + "ipqsd": "523111658516671170", + "userId": "f8fbc0f5-e22a-4b74-a542-bd54a720888d", + "Conversion": "EgwIABUAAAAAHQAAAAAYASCkgoXr7trx8XlIAWpcQ2owS0NRaUFpOXJKQmhDWUFSSXNBTHlQRHR0T2VoalVESXRfWkhKSjFQRnlDWWxYb0M1Rl9FU3RBTW5nbFVwZE9UeXNQbmVwMlpoLTNqMGFBbXJfRUFMd193Y0Jwkf3znryvkQOQAYrAvcTUFJgBAA", + "q_c1": "49e8263c177d4ead85368e381cc53b61|1765248965000|1765248965000", + ".MSA.Auth.Nonce.CfDJ8HAK7eZCYw5BifHFeUHnkJEKw3EgsOs5AbSc2JnHTirOIqDhgJ2up5kymkGgmv4pUdQFrQ7YUTtYpBXuGFBsJiPF6Y4AowNSzsqKagfZGaSohxPUVk57RTTEG8w92E4Pab5KThib0WzJ9nOhn3pEy7s9RXS6qetHy9V1Uc5All_sNMg-whZE6GcQb5VmmP3fcUlDTpCqHNwrGSRS9HPho-QDHlCnc7AiNQgzDeS9EIyPi7RoJ09jto3zA-OHGH-g4BIBtOcRhaZnSIppMrHPJPw": "N", + "rtk": "TKr-frr0SNeUB_QS8P3E9Zo88rIIK-IRTro0KKMDdyVBKRUuArGIohdtlQS70ebuYCppbfoyIeopTpMYaummBiySPlO1kcuuiLjPpCpcxpIJRf0pO2RcO2YcQOOjVo1I-KN_Krr0.iNb_qWZHQ069KLOgUbv_Mp_VZR77t5NwK5WK9G7waH2tqTsEZsKeiIDOxOGneOiqP01AoZNWOpqZvOJUo0zcAw", + "rtk_p": "TrDIKMfbcN8k009evoiA0pITTKS_fKoAKQKS38GvjKf6J-IuTKS-IQRktQgpxYLTsTG3pAD1rWL-1of2Zpxo1no0z3wvfZt4W7rf.QbL0hnbKnnKgdg6_wPtMkZ3eX_Q8QDLOuydcIkGaSuOwV9mZ0GA97TknnNdpKyl4K30a1VifIQxU-3rX5M6qWK", + "arms_uid": "a9f7ecf0-8c4b-4ac8-bbc4-243cb97ffb16", + "MUID": "1DDDFDD892586F24108AEB4293A46E7A", + "itk": "TKI-frr0SNeUB_QS8P3E9Zo88rIIK-IRTro0KKMDdyVBKRUuArGIohdtlQS70ebuYCppbfoyIeopTpMYaummBiySPlO1kcuuiLjPpCpcxpIJRf0pO2RcO2YcO7UIKMIpKy-cTlH6rZJkLxFSgpy0YtJyrNOyH8py3rHNiTGOycj_QNgyV3QJ-KN-K6oTTKS.YmX0RbI6_CAWB_v3NGq5GkFRaYwOqvmy8Q3VjseAMSD0SE_0p1HYszbDMEN3WvvznIa3nK6h0-aaXPJXus_5HK", + "_uab_collina": "177190199995692404856444", + "loginWay": "qcloud_wechat", + "Hm_lvt_eabfdea4539c4e941394b0c5200f8cd3": "1770003716", + "yyb_muid": "048D92FAA90262ED311E84BBA8B46303", + "__rubyUX": "false", + "pglt-edgeChromium-ntp": "41", + "pglt-edgeChromium-dhp": "41", + "suid": "Id0Kv/ERdxRGmuCzhI30Yg==", + "__snaker__id": "EawmxniT7FCf1frf", + "SESSIONID": "7bgBuZgiJLQU62XBl9pwOQIIdRsj2kNMuCqq3oj02S1", + "JOID": "UlAdBk5r6elkbpCzaRyTtQ-1wD56QMrHR0i7kEdNwspKTbaYSs-sQQhjmL5kfQ-q7wzkjOvstQPUZf7d5vqjbuE=", + "osd": "UFwXBEpp5eNmapK_Yx6XtwO_wjp4TMDFQ0q3mkVJwMZAT7KaRsWuRQpvkrxgfwOg7QjmgOHusQHYb_zZ5PapbOU=", + "curr_auth_lg_set": "zh", + "IsDeviceID": "43164", + "License_ManageCode": "5bcf5a78-f569-11e7-b3e3-083571f3c87d", + "Mac": "ff%3A0A%3ABE%3A14%3A9C%3A00", + "__aegis_uid": "15657f0000015c36-b995def7eda2097c-6741", + "pt2gguin": "o0007469504", + "qm_logintype": "qq", + "xm_pcache": "13102661032344000&V2@6666oe7RRKuia7PURhf4LAAA@0", + "USRLOC": "HS=1&ELOC=LAT=28.238513946533203|LON=112.57054901123047|N=%E5%AE%81%E4%B9%A1%E5%B8%82%EF%BC%8C%E6%B9%96%E5%8D%97%E7%9C%81|ELT=4|&BID=MjYwMzAzMTI1MzMyX2VmODk1MjBhNmI2ODRjYzkxZWRlMDk3ZjNkYzM5YzMwOWM2NjQ2NmRkYmIxNWRhZTE5MTY4MWRlYjZiY2RjZDY=", + "_EDGE_V": "1", + "MR": "0", + "ANONCHK": "0", + "msaoptout": "0", + "MUIDB": "048D92FAA90262ED311E84BBA8B46303", + "wpsqing_autoLoginV1": "1", + "_ku": "1", + "cid": "0", + "coa_id": "0", + "cv": "oTOvI9IxEkG3ZzsrI9L0_P6hKcFdtaq3fGFmZ8xEQ6A_77c8bQIS8ACrVUgNHxt5FTnsAZm9.wpPASB-U_uB", + "kso_sid": "TKS-f0fbcN8k009evoiA0poTTKS7fKoAKQKS38GvjKf6J-oPTAAWidk0IrbesWNoYXQFR7NFIQoUW6sshtOGpfi9nJNss3yV2Dbob1Y-T2KwY2kzN2kCNUf9v4FHTSrfWrIIKQ.l4UDNR70HIplqBz7IIEHR2b1JMOhiDbfyB5ekhRbRGacmDNm5VnDQpxUEAlbkg-wkBO5UkA7NSEptrZo-zZFhQ", + "uid": "389761826", + "wps_sid": "V02SWFZZptO8hD7jnJNZZey_T4dodcY00a93596500173b4b22", + "kso-wx-quick-login": "511", + "Hm_lvt_cb2fa0997df4ff8e739c666ee2487fd9": "1766039339", + "_bl_uid": "g9mLym0C0Xb0ttkXbuvdhen5ep0L", + "cf": "6007a7c1df9d0e79f49406411a0d02d2", + "RK": "FQUMzzy6EZ", + "ptcz": "0a654e447a09bb38354f0b7e245912a9e209e521ecc0ca40170b58e9ef85d616", + "pac_uid": "0_X5kXAYtmhx20A", + "omgid": "0_X5kXAYtmhx20A", + "_qimei_uuid42": "19b130f171d1005d591b00d4fa2ee39a2bd89a01f3", + "_qimei_fingerprint": "9c821162553742cb776db3593bc6e597", + "_qimei_q36": "", + "_qimei_h38": "fded1891591b00d4fa2ee39a02000009119b13", + "pgv_pvid": "9971545984", + "msnup": "%7B%22cnex%22%3A%22no%22%7D", + "OptanonAlertBoxClosed": "2026-02-06T00:00:43.708Z", + "eupubconsent-v2": "CQVwtgAQVwtgAAcABBZHBfFsAP_gAELgACiQK4tX_G__bXlr8X73aftkeY1f99h77sQxBhaJk-4FzJvW_JwX32E7NAz6tqYKmRIAu3TBAQNlHJDURVCgaIgVqSDMaEyUoTNKJ6BkiFMRY2dYCFxvm4tjeQCY5vr991d52B-t7dr83dzyy4hHv3a5_0S1WAAAAYCNDfv9bROb-9IO9_x8v4v4_F7pE2_eS1l_tWvp7D9-cts_9XW99_bbff9Pn_-uF_-_X_vf_H37v9oK5AACAAAARgkCAAAgAAAAABAAAAAQAAAAAQBgAAARBAEAAgAQGEgAEAAAAIAAAAAgSAAAAAJAAgAAAABQAAAIBAAAAwAIBgAAGAAACABACAAAAgEgYJgQQCBAABCYBAAgQgAAAACwECAABAgiACEQcAQAAAAAAAAEAAoAAEAgDAQkkBCxIIAuIJoAACAAAIIAChFJ2YAggDNlqrwZNoytMCwfMFzymAZAEQRk5JsQmsAoJA1AAQAAuACgAKgAcAA8ACCAGQAagA8ACIAEwAKoAbwA9AB-AEJAIYAiQBHACWAE0AK0AYYAywBsgDvgHsAfEA-wD9AIBARcBGACNAFBAKgAVcAuYBigDaAG4AOIAkQBOwChwFHgKRAWwAuQBd4DDQGSAMnAZcAzmBrAGsgNvAeOEAMAAOAHOAQcAn4CPQEigJWATaAsIBeQDEAGLQMhAyMBowDUwG0ANuAboA8oB8gD9wICAQMAgiOATgAIgAcAB4AFwAfgBoAHOAO4AgEBBwEIAJ-AVAAvQB0gEegJFASsAmIBMoCbQFIAKTAWoAvoBiADFgGQgMmAaMA00BqYDXgG0ANuAeUA-IB9sD9gP3AgeBBEdBAAAXABQAFQAOAAgABdADIANQAeABEACYAFWALgAugBiADeAHoAP0AhgCJAEsAJoAUYArQBhgDKAGiANkAd4A9oB9gH7ARYBGACggFXALEAXMAvIBigDaAG4AOIAdQBF4CRAEyAJ2AUOAo8BTQCxQFsALgAXIAu0Bd4DDQGPAMkAZOAyqBlgGXAM5AaqA1gBt4DxwH1gQBIAHAAEABoAHOAWIBB4CPQE2gKTAVKAvIBqYDbAG3APKAfEA_YCB4EGAINgQrAimBGkCN8EkQSSAqmBWkCtsFcQVyIQIwAFgAUABcAFUALgAYgA3gB6AEcAO8AigBKQCggFXALmAYoA2gB1IFNAU2AqwBYoC0QFwALkAZOAzkBqoDxwH9gQtAh6BIoCSAFSgKvkoD4ACAAFgAUAA4ADwAIgATAAqgBcADFAIYAiQBHACjAFaANkAd4A_ACrgGKAOoAi8BIgCjwFigLYAZOAywBnIDWAG3gQPJADQALgDuAIAAVABHoCRQErAJtAUmAxYB5QD9wIIlIFwAC4AKAAqABwAEEAMgA0AB4AEQAJgAVQAxAB-gEMARIAowBWgDKAGiANkAd8A-wD9AIsARgAoIBVwC5gF5AMUAbQA3ACLwEiAJ2AUOApoBYoC2AFwALkAXaAw0BkgDJwGXAM5gawBrIDbwHjlADYAFwBHADnAHcAQAAkQBYgDXgHbAP-Aj0BIoCYgE2gKQAU-AvIBfQDFgGTANTAa8A8oB8UD9gP3AgYBA8.f_wACFwAAAAA", + "_EDGE_S": "SID=0E9A79052714638E1B996E1526C662EB", + "OptanonConsent": "isGpcEnabled=0&datestamp=Fri+Feb+27+2026+16%3A54%3A20+GMT%2B0800+(%E4%B8%AD%E5%9B%BD%E6%A0%87%E5%87%86%E6%97%B6%E9%97%B4)&version=202601.1.0&browserGpcFlag=0&isIABGlobal=false&hosts=&consentId=5002a581-af26-409b-9ddd-18c6fa715312&interactionCount=1&isAnonUser=1&landingPath=NotLandingPage&AwaitingReconsent=false&groups=C0001%3A1%2CC0002%3A1%2CC0003%3A1%2CC0004%3A1&intType=1&crTime=1770336044684&geolocation=CN%3BHN", + "MicrosoftApplicationsTelemetryDeviceId": "92b55e22-5935-460e-b130-7bed45666877", + "MSFPC": "GUID=710734b33f8e42ce9ac931a839e775f0&HASH=7107&LV=202510&V=4&LU=1760318000333", + "Serial_Num": "Y3NyZnxhOjI6e2k6MDtzOjIwOiJNVGMzTWpVeU5EY3pOaTQzT0RjeCI7aToxO047fQ%3A%3A", + "user_locale": "zh-CN", + "Hm_lvt_bcc7f8fe49b3eec09673ef49e4b33693": "1764053148", + "Hm_lvt_a7fe33f2f4184e3601e2e00b1c588945": "1765442032", + "Hm_lvt_c6fdddc87b51c079306b4a7874f12c44": "1765443136", + "abymg_id": "1_BE0919B54C29C232EF7E4637C5054A3460FA1FCE713D774DC9EC260AC783EA08", + "Hm_lvt_b4e4640430b8197fb9c1243e911d4245": "1769315064", + "Hm_lvt_5670e4c405b3d8c6e7c800094e7d5106": "1772248941", + "Hm_lvt_24f17767262929947cc3631f99bfd274": "1772248759,1772417392", + "Hm_lpvt_24f17767262929947cc3631f99bfd274": "1772417392", + "HMACCOUNT": "A5543FA0605C9B88", + "csrf_token": "jiKzVo3FVCj611BL5700JLQfM6noVYDHXqDgwk0Cv0ZNsnj9PNEIWdHFj8Hno9IDX3gORHh7ZAZ4tDMvl1qJkQ", + "gitee-session-n": "WGM4YS91UWpKTnVteUVPNXliR3gxcHQwWU5XY1JaZFVES1VPTlM0a3phSEU0SU8rUjVkejE0allFNzFYT2ZpVWkrS0g3YTJNcmxpdDJYRTRGOEl4OTlFdjgySERGMk9aOVFNdEtyd1lQUUwyUEVQOXZzaTFsRUdoOHZ0YVF0SlhEQi9vQWs1QTVOQnNlc2FyaW00UTB1d0pzRFd0dU93aWZ2OWxFRDFINzdERXM0RzlRdW9IdkRiM0x1b0MySDNILS0wc01jaDdYY2FINkZRc0VrWVpxNk93PT0%3D--58bbdae1c91004912640c84c963bd8ff39dd2979", + "oschina_new_user": "false", + "remote_way": "http", + "theme": "dark", + "Serve_State": "true", + "BEC": "8ddb6c1710618f9098bae11a2ceedd43", + "HMACCOUNT_BFESS": "A5543FA0605C9B88", + "w": "\"9KoC]^E=a0MuUe!@nvo6\"", + "SRCHD": "AF=ANNTA1", + "SRCHUID": "V=2&GUID=BFB3670E909644318B9002E310A98D3C&dmnchg=1", + "MUIDV": "NU=1", + "_tarLang": "default=zh-Hans", + "_TTSS_IN": "hist=WyJlbiIsImF1dG8tZGV0ZWN0Il0=&isADRU=0", + "_TTSS_OUT": "hist=WyJ6aC1IYW5zIl0=", + "_HPVN": "CS=eyJQbiI6eyJDbiI6MSwiU3QiOjAsIlFzIjowLCJQcm9kIjoiUCJ9LCJTYyI6eyJDbiI6MSwiU3QiOjAsIlFzIjowLCJQcm9kIjoiSCJ9LCJReiI6eyJDbiI6MSwiU3QiOjAsIlFzIjowLCJQcm9kIjoiVCJ9LCJBcCI6dHJ1ZSwiTXV0ZSI6dHJ1ZSwiTGFkIjoiMjAyNS0xMi0wM1QwMDowMDowMFoiLCJJb3RkIjowLCJHd2IiOjAsIlRucyI6MCwiRGZ0IjpudWxsLCJNdnMiOjAsIkZsdCI6MCwiSW1wIjo1LCJUb2JuIjowfQ==", + "_Rwho": "u=d&ts=2026-03-02", + "_SS": "PC=U531&SID=0E9A79052714638E1B996E1526C662EB&R=200&RB=0&GB=0&RG=200&RP=200", + "_clck": "16q1hg%5E2%5Eg3y%5E0%5E2250", + "SRCHHPGUSR": "SRCHLANG=zh-Hans&PV=10.0.0&BZA=0&PREFCOL=0&BRW=XW&BRH=M&CW=1912&CH=956&SCW=1897&SCH=2721&DPR=1.0&UTC=480&B=0&EXLTT=31&HV=1772513615&HVE=CfDJ8HAK7eZCYw5BifHFeUHnkJG5-y-KIWQt-NF_NMj7g1XTM1-_JG0BerkqmNlMA6aKg05rC8K2OStN3YDTyMImRVQF5L_6zrEgwK6ZcPtJ3gztJYslxiZ1TWc_xSfKw0DYQIgHOgNptd1LBakvWWLa1hicLJWteNn5q25s5xjn8jubB-w9Uiu1EejkHoi-32cY5A&PRVCW=1912&PRVCH=956&AV=14&ADV=14&RB=0&MB=0", + "GC": "QPiD6byfk27yxnUrhpFqxudo4c6Pg9q_h7cagC6f-zUvTCH6_w1OTEefjzYAM_yBVCS34dGzJwEwYAqrF3vdeg", + "_RwBf": "r=0&ilt=142&ihpd=0&ispd=2&rc=200&rb=0&rg=200&pc=200&mtu=0&rbb=0&clo=0&v=2&l=2026-03-03T08:00:00.0000000Z&lft=0001-01-01T00:00:00.0000000&aof=0&ard=0001-01-01T00:00:00.0000000&rwdbt=0&rwflt=0&rwaul2=0&g=&o=2&p=&c=&t=0&s=0001-01-01T00:00:00.0000000+00:00&ts=2026-03-03T08:34:46.0338286+00:00&rwred=0&wls=&wlb=&wle=&ccp=&cpt=&lka=0&lkt=0&aad=0&TH=&cid=0&gb=", + "dsc": "order=BingPages", + "SRCHUSR": "DOB=20250807&DS=1&POEX=W", + "_clsk": "jfg95q%5E1772526891301%5E2%5E0%5Eb.clarity.ms%2Fcollect", + "SRM_B": "048D92FAA90262ED311E84BBA8B46303", + "bcookie": "\"v=2&1dc84fe2-344c-4273-89b9-7f4c3c122d40\"", + "li_sugr": "e0fb56e0-21e4-4fdd-b43f-fb89f71cf2be", + "UserMatchHistory": "AQKBfWqe0n66KwAAAZyeSDycVPBDed8LhvZSAXGPSSKe5rGyV4fu_qTWR5307WPbfvyYOEQtrc2hpQ", + "AnalyticsSyncHistory": "AQJ4sQJBEiydVAAAAZyeSDycyJ1sdGtpRsuzCaoKt6_jH_Nm3B5BM2oYfFPZH6uSTjMrH1r9gs4w5xWYlSW8tg", + "uuid2": "7637048064474162103", + "anj": "dTM7k!M4/QDunaTF']wIg2Il^ts$vJNWBV:FGWY@!l0S`-99c1`*%j^=MxJ#RWKOt2Mi_dR-O^M'4UWu=YvYr2^$Q^R#*cPL7X^AE[uP'G3NJmmfU/ln" + } + ] +} \ No newline at end of file diff --git a/state.json b/state.json index 5f3b5ad..dbe4569 100644 --- a/state.json +++ b/state.json @@ -1,4 +1,4 @@ { "用户A_网站A": 0, - "用户B_网站A": 1 + "用户B_网站A": 0 } \ No newline at end of file diff --git a/test_cookie_import.py b/test_cookie_import.py new file mode 100644 index 0000000..0cac065 --- /dev/null +++ b/test_cookie_import.py @@ -0,0 +1,33 @@ +"""测试 cookie 导入功能""" +from browser_login import BrowserLogin +from applogger import setup_logging + +# 初始化日志 +setup_logging() + +# 创建浏览器实例 +browser = BrowserLogin(browser_type="edge", headless=False) + +# 模拟 cookie 数据 +test_cookies = [ + {"name": "test1", "value": "value1", "domain": "example.com", "path": "/", "secure": False, "httpOnly": False}, + {"name": "test2", "value": "value2", "domain": "example.com", "path": "/", "secure": True, "httpOnly": True}, + {"name": "test3", "value": "value3", "domain": "example.org", "path": "/", "secure": False, "httpOnly": False} +] + +print("测试 cookie 导入功能...") +print(f"准备导入 {len(test_cookies)} 个 cookie") + +# 测试导入功能 +result = browser.import_all_cookies(test_cookies) +print(f"导入结果: {'成功' if result else '失败'}") + +# 测试获取 cookie +get_cookies = browser.get_all_cookies() +print(f"获取到 {len(get_cookies)} 个 cookie") +for cookie in get_cookies: + print(f" - {cookie.get('name')}: {cookie.get('value')} (domain: {cookie.get('domain')})") + +# 关闭浏览器 +browser.close() +print("测试完成!")