add-files
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,248 @@
|
||||
# CookieCloud Client
|
||||
|
||||
一个独立的、可复用的CookieCloud服务器客户端Python模块。
|
||||
|
||||
## 特性
|
||||
|
||||
- ✅ **完全独立** - 无外部依赖,仅使用Python标准库
|
||||
- ✅ **类型安全** - 完整的类型提示支持
|
||||
- ✅ **异常处理** - 完善的异常体系
|
||||
- ✅ **易于使用** - 简洁的API设计
|
||||
- ✅ **可扩展** - 支持自定义配置
|
||||
- ✅ **文档完善** - 详细的使用文档和示例
|
||||
|
||||
## 安装
|
||||
|
||||
将 `cookiecloud_client` 目录复制到您的项目中即可使用。
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 基本使用
|
||||
|
||||
```python
|
||||
from cookiecloud_client import CookieCloudClient, CookieConfig
|
||||
|
||||
# 创建配置
|
||||
config = CookieConfig(
|
||||
server="https://cookiecloud.example.com",
|
||||
username="your_username",
|
||||
password="your_password"
|
||||
)
|
||||
|
||||
# 创建客户端
|
||||
client = CookieCloudClient(config)
|
||||
|
||||
# 下载所有cookies
|
||||
result = client.download()
|
||||
|
||||
if result.success:
|
||||
print(f"下载成功!")
|
||||
print(f"总域名数: {result.total_domains}")
|
||||
print(f"总Cookie数: {result.total_cookies}")
|
||||
print(f"下载耗时: {result.download_time:.2f}秒")
|
||||
|
||||
# 获取指定域名的cookie
|
||||
cookie_str = result.get_cookie_string("example.com")
|
||||
print(f"example.com的cookie: {cookie_str}")
|
||||
else:
|
||||
print(f"下载失败: {result.error_message}")
|
||||
```
|
||||
|
||||
### 下载指定域名的Cookie
|
||||
|
||||
```python
|
||||
# 下载单个域名
|
||||
cookie_str = client.download_for_domain("baidu.com")
|
||||
if cookie_str:
|
||||
print(f"baidu.com的cookie: {cookie_str}")
|
||||
|
||||
# 批量下载多个域名
|
||||
domains = ["baidu.com", "google.com", "github.com"]
|
||||
cookies = client.download_for_domains(domains)
|
||||
for domain, cookie in cookies.items():
|
||||
print(f"{domain}: {cookie}")
|
||||
```
|
||||
|
||||
### 测试连接
|
||||
|
||||
```python
|
||||
success, message = client.test_connection()
|
||||
if success:
|
||||
print("连接成功!")
|
||||
else:
|
||||
print(f"连接失败: {message}")
|
||||
```
|
||||
|
||||
## 高级用法
|
||||
|
||||
### 自定义配置
|
||||
|
||||
```python
|
||||
config = CookieConfig(
|
||||
server="https://cookiecloud.example.com",
|
||||
username="your_username",
|
||||
password="your_password",
|
||||
timeout=60, # 超时时间(秒)
|
||||
verify_ssl=False, # 是否验证SSL证书
|
||||
ignore_cookies=[ # 忽略的cookie名称
|
||||
"CookieAutoDeleteBrowsingDataCleanup",
|
||||
"CookieAutoDeleteCleaningDiscarded"
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
### 异常处理
|
||||
|
||||
```python
|
||||
from cookiecloud_client import (
|
||||
CookieCloudClient,
|
||||
CookieConfig,
|
||||
CookieCloudError,
|
||||
ConnectionError,
|
||||
AuthenticationError,
|
||||
DataParseError,
|
||||
NetworkError
|
||||
)
|
||||
|
||||
try:
|
||||
client = CookieCloudClient(config)
|
||||
result = client.download()
|
||||
|
||||
except AuthenticationError as e:
|
||||
print(f"认证失败: {e.message}")
|
||||
print(f"用户名: {e.details.get('username')}")
|
||||
|
||||
except ConnectionError as e:
|
||||
print(f"连接失败: {e.message}")
|
||||
print(f"服务器: {e.details.get('server')}")
|
||||
print(f"状态码: {e.details.get('status_code')}")
|
||||
|
||||
except DataParseError as e:
|
||||
print(f"数据解析失败: {e.message}")
|
||||
|
||||
except NetworkError as e:
|
||||
print(f"网络错误: {e.message}")
|
||||
print(f"原始错误: {e.details.get('original_error')}")
|
||||
|
||||
except CookieCloudError as e:
|
||||
print(f"CookieCloud错误: {e.message}")
|
||||
```
|
||||
|
||||
### 使用Cookie数据对象
|
||||
|
||||
```python
|
||||
result = client.download()
|
||||
|
||||
# 获取所有域名
|
||||
domains = result.get_domains()
|
||||
print(f"所有域名: {domains}")
|
||||
|
||||
# 遍历所有cookie
|
||||
for domain, collection in result.cookies.items():
|
||||
print(f"\n域名: {domain}")
|
||||
for cookie in collection.cookies:
|
||||
print(f" - {cookie.name}={cookie.value[:20]}...")
|
||||
print(f" 路径: {cookie.path}")
|
||||
print(f" 安全: {cookie.secure}")
|
||||
print(f" HttpOnly: {cookie.http_only}")
|
||||
```
|
||||
|
||||
## API文档
|
||||
|
||||
### CookieConfig
|
||||
|
||||
配置类,用于存储CookieCloud服务器配置。
|
||||
|
||||
**参数:**
|
||||
- `server` (str): CookieCloud服务器地址
|
||||
- `username` (str): 用户名
|
||||
- `password` (str): 密码
|
||||
- `timeout` (int): 请求超时时间(秒),默认30
|
||||
- `verify_ssl` (bool): 是否验证SSL证书,默认True
|
||||
- `ignore_cookies` (List[str]): 忽略的cookie名称列表
|
||||
|
||||
### CookieCloudClient
|
||||
|
||||
客户端类,用于与CookieCloud服务器交互。
|
||||
|
||||
**方法:**
|
||||
|
||||
#### `download() -> DownloadResult`
|
||||
下载所有cookies
|
||||
|
||||
**返回:** DownloadResult对象
|
||||
|
||||
#### `download_for_domain(domain: str) -> Optional[str]`
|
||||
下载指定域名的cookie字符串
|
||||
|
||||
**参数:**
|
||||
- `domain` (str): 目标域名
|
||||
|
||||
**返回:** cookie字符串或None
|
||||
|
||||
#### `download_for_domains(domains: List[str]) -> Dict[str, Optional[str]]`
|
||||
批量下载多个域名的cookie字符串
|
||||
|
||||
**参数:**
|
||||
- `domains` (List[str]): 目标域名列表
|
||||
|
||||
**返回:** {domain: cookie_string}字典
|
||||
|
||||
#### `test_connection() -> Tuple[bool, str]`
|
||||
测试与CookieCloud服务器的连接
|
||||
|
||||
**返回:** (是否成功, 消息)元组
|
||||
|
||||
### DownloadResult
|
||||
|
||||
下载结果类。
|
||||
|
||||
**属性:**
|
||||
- `success` (bool): 是否成功
|
||||
- `cookies` (Dict[str, CookieCollection]): cookie集合字典
|
||||
- `error_message` (str): 错误信息
|
||||
- `total_domains` (int): 总域名数
|
||||
- `total_cookies` (int): 总cookie数
|
||||
- `download_time` (float): 下载耗时(秒)
|
||||
|
||||
**方法:**
|
||||
- `get_cookie_string(domain: str) -> Optional[str]`: 获取指定域名的cookie字符串
|
||||
- `get_domains() -> List[str]`: 获取所有域名列表
|
||||
|
||||
## 异常类
|
||||
|
||||
### CookieCloudError
|
||||
基础异常类,所有其他异常都继承自此类。
|
||||
|
||||
### ConfigurationError
|
||||
配置错误异常
|
||||
|
||||
### ConnectionError
|
||||
连接错误异常
|
||||
|
||||
### AuthenticationError
|
||||
认证错误异常
|
||||
|
||||
### DataParseError
|
||||
数据解析错误异常
|
||||
|
||||
### NetworkError
|
||||
网络错误异常
|
||||
|
||||
## 依赖
|
||||
|
||||
- Python 3.7+
|
||||
- 仅使用Python标准库
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT License
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.0 (2026-03-02)
|
||||
- 初始版本发布
|
||||
- 完整的CookieCloud客户端功能
|
||||
- 独立模块,无外部依赖
|
||||
- 完善的异常处理
|
||||
- 详细的文档和示例
|
||||
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
CookieCloud客户端模块
|
||||
一个独立的、可复用的CookieCloud服务器客户端
|
||||
|
||||
作者: CookieManager Team
|
||||
版本: 1.0.0
|
||||
许可证: MIT
|
||||
"""
|
||||
|
||||
from .client import CookieCloudClient
|
||||
from .exceptions import (
|
||||
CookieCloudError,
|
||||
ConnectionError,
|
||||
AuthenticationError,
|
||||
DataParseError,
|
||||
ConfigurationError,
|
||||
NetworkError
|
||||
)
|
||||
from .models import CookieData, CookieConfig
|
||||
from .version import __version__
|
||||
|
||||
__all__ = [
|
||||
'CookieCloudClient',
|
||||
'CookieCloudError',
|
||||
'ConnectionError',
|
||||
'AuthenticationError',
|
||||
'DataParseError',
|
||||
'ConfigurationError',
|
||||
'NetworkError',
|
||||
'CookieData',
|
||||
'CookieConfig',
|
||||
'__version__'
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,347 @@
|
||||
"""
|
||||
CookieCloud客户端核心实现
|
||||
"""
|
||||
import json
|
||||
import time
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from .models import CookieConfig, CookieData, CookieCollection, DownloadResult
|
||||
from .exceptions import (
|
||||
CookieCloudError,
|
||||
ConfigurationError,
|
||||
ConnectionError,
|
||||
AuthenticationError,
|
||||
DataParseError,
|
||||
NetworkError
|
||||
)
|
||||
|
||||
|
||||
class CookieCloudClient:
|
||||
"""
|
||||
CookieCloud客户端
|
||||
|
||||
用于从CookieCloud服务器下载和管理cookies的独立客户端
|
||||
|
||||
示例:
|
||||
>>> config = CookieConfig(
|
||||
... server="https://cookiecloud.example.com",
|
||||
... username="your_username",
|
||||
... password="your_password"
|
||||
... )
|
||||
>>> client = CookieCloudClient(config)
|
||||
>>> result = client.download()
|
||||
>>> if result.success:
|
||||
... print(f"下载成功,共{result.total_domains}个域名")
|
||||
... cookie_str = result.get_cookie_string("example.com")
|
||||
"""
|
||||
|
||||
def __init__(self, config: CookieConfig):
|
||||
"""
|
||||
初始化客户端
|
||||
|
||||
Args:
|
||||
config: CookieCloud配置对象
|
||||
|
||||
Raises:
|
||||
ConfigurationError: 配置验证失败
|
||||
"""
|
||||
if not isinstance(config, CookieConfig):
|
||||
raise ConfigurationError("配置参数必须是CookieConfig类型")
|
||||
|
||||
self.config = config
|
||||
self._last_download_time = None
|
||||
self._download_count = 0
|
||||
|
||||
def download(self) -> DownloadResult:
|
||||
"""
|
||||
从CookieCloud服务器下载所有cookies
|
||||
|
||||
Returns:
|
||||
DownloadResult: 下载结果对象
|
||||
|
||||
Raises:
|
||||
ConnectionError: 连接服务器失败
|
||||
AuthenticationError: 认证失败
|
||||
DataParseError: 数据解析失败
|
||||
NetworkError: 网络错误
|
||||
"""
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
raw_data = self._fetch_data()
|
||||
cookies = self._parse_cookies(raw_data)
|
||||
|
||||
download_time = time.time() - start_time
|
||||
self._last_download_time = time.time()
|
||||
self._download_count += 1
|
||||
|
||||
total_cookies = sum(len(c.cookies) for c in cookies.values())
|
||||
|
||||
return DownloadResult(
|
||||
success=True,
|
||||
cookies=cookies,
|
||||
total_domains=len(cookies),
|
||||
total_cookies=total_cookies,
|
||||
download_time=download_time
|
||||
)
|
||||
|
||||
except CookieCloudError:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise CookieCloudError(f"下载cookies失败: {str(e)}")
|
||||
|
||||
def download_for_domain(self, domain: str) -> Optional[str]:
|
||||
"""
|
||||
下载指定域名的cookie字符串
|
||||
|
||||
Args:
|
||||
domain: 目标域名
|
||||
|
||||
Returns:
|
||||
Optional[str]: cookie字符串,如果不存在则返回None
|
||||
|
||||
Raises:
|
||||
ConnectionError: 连接服务器失败
|
||||
AuthenticationError: 认证失败
|
||||
DataParseError: 数据解析失败
|
||||
"""
|
||||
result = self.download()
|
||||
return result.get_cookie_string(domain)
|
||||
|
||||
def download_for_domains(self, domains: List[str]) -> Dict[str, Optional[str]]:
|
||||
"""
|
||||
批量下载多个域名的cookie字符串
|
||||
|
||||
Args:
|
||||
domains: 目标域名列表
|
||||
|
||||
Returns:
|
||||
Dict[str, Optional[str]]: {domain: cookie_string}
|
||||
"""
|
||||
result = self.download()
|
||||
return {domain: result.get_cookie_string(domain) for domain in domains}
|
||||
|
||||
def test_connection(self) -> Tuple[bool, str]:
|
||||
"""
|
||||
测试与CookieCloud服务器的连接
|
||||
|
||||
Returns:
|
||||
Tuple[bool, str]: (是否成功, 消息)
|
||||
"""
|
||||
try:
|
||||
self._fetch_data()
|
||||
return True, "连接成功"
|
||||
except AuthenticationError as e:
|
||||
return False, f"认证失败: {e.message}"
|
||||
except ConnectionError as e:
|
||||
return False, f"连接失败: {e.message}"
|
||||
except Exception as e:
|
||||
return False, f"测试失败: {str(e)}"
|
||||
|
||||
def _fetch_data(self) -> Dict:
|
||||
"""
|
||||
从服务器获取原始数据
|
||||
|
||||
Returns:
|
||||
Dict: 原始JSON数据
|
||||
|
||||
Raises:
|
||||
ConnectionError: 连接失败
|
||||
AuthenticationError: 认证失败
|
||||
NetworkError: 网络错误
|
||||
"""
|
||||
url = f"{self.config.server}/get/{self.config.username}"
|
||||
|
||||
try:
|
||||
data = json.dumps({"password": self.config.password}).encode('utf-8')
|
||||
|
||||
request = urllib.request.Request(
|
||||
url,
|
||||
data=data,
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'CookieCloudClient/1.0'
|
||||
},
|
||||
method='POST'
|
||||
)
|
||||
|
||||
response = urllib.request.urlopen(
|
||||
request,
|
||||
timeout=self.config.timeout
|
||||
)
|
||||
|
||||
if response.status != 200:
|
||||
if response.status == 401:
|
||||
raise AuthenticationError(
|
||||
"认证失败,请检查用户名和密码",
|
||||
username=self.config.username
|
||||
)
|
||||
elif response.status == 404:
|
||||
raise ConnectionError(
|
||||
"用户不存在,请检查用户名",
|
||||
server=self.config.server,
|
||||
status_code=response.status
|
||||
)
|
||||
else:
|
||||
raise ConnectionError(
|
||||
f"服务器返回错误状态码: {response.status}",
|
||||
server=self.config.server,
|
||||
status_code=response.status
|
||||
)
|
||||
|
||||
result = json.loads(response.read().decode('utf-8'))
|
||||
|
||||
if not result:
|
||||
raise DataParseError("服务器返回数据为空")
|
||||
|
||||
return result
|
||||
|
||||
except urllib.error.HTTPError as e:
|
||||
if e.code == 401:
|
||||
raise AuthenticationError(
|
||||
"认证失败,请检查用户名和密码",
|
||||
username=self.config.username
|
||||
)
|
||||
else:
|
||||
raise ConnectionError(
|
||||
f"HTTP错误: {e.code} {e.reason}",
|
||||
server=self.config.server,
|
||||
status_code=e.code
|
||||
)
|
||||
except urllib.error.URLError as e:
|
||||
raise NetworkError(
|
||||
f"网络连接失败: {e.reason}",
|
||||
original_error=e
|
||||
)
|
||||
except json.JSONDecodeError as e:
|
||||
raise DataParseError(
|
||||
f"JSON解析失败: {str(e)}"
|
||||
)
|
||||
except Exception as e:
|
||||
if isinstance(e, CookieCloudError):
|
||||
raise
|
||||
raise NetworkError(
|
||||
f"请求失败: {str(e)}",
|
||||
original_error=e
|
||||
)
|
||||
|
||||
def _parse_cookies(self, raw_data: Dict) -> Dict[str, CookieCollection]:
|
||||
"""
|
||||
解析原始cookie数据
|
||||
|
||||
Args:
|
||||
raw_data: 原始JSON数据
|
||||
|
||||
Returns:
|
||||
Dict[str, CookieCollection]: {domain: CookieCollection}
|
||||
"""
|
||||
if raw_data.get("cookie_data"):
|
||||
contents = raw_data.get("cookie_data")
|
||||
else:
|
||||
contents = raw_data
|
||||
|
||||
domain_groups = self._group_by_domain(contents)
|
||||
|
||||
cookies = {}
|
||||
for domain, cookie_list in domain_groups.items():
|
||||
if not cookie_list:
|
||||
continue
|
||||
|
||||
if self._is_cloudflare_only(cookie_list):
|
||||
continue
|
||||
|
||||
collection = CookieCollection(domain=domain)
|
||||
|
||||
for cookie_data in cookie_list:
|
||||
cookie = CookieData(
|
||||
domain=cookie_data.get('domain', ''),
|
||||
name=cookie_data.get('name', ''),
|
||||
value=cookie_data.get('value', ''),
|
||||
path=cookie_data.get('path', '/'),
|
||||
secure=cookie_data.get('secure', False),
|
||||
http_only=cookie_data.get('httpOnly', False)
|
||||
)
|
||||
collection.add_cookie(cookie)
|
||||
|
||||
cookies[domain] = collection
|
||||
|
||||
return cookies
|
||||
|
||||
def _group_by_domain(self, contents: Dict) -> Dict[str, List[Dict]]:
|
||||
"""
|
||||
按域名分组cookies
|
||||
|
||||
Args:
|
||||
contents: 原始cookie内容
|
||||
|
||||
Returns:
|
||||
Dict[str, List[Dict]]: {domain: [cookie_data]}
|
||||
"""
|
||||
domain_groups = {}
|
||||
|
||||
for site, cookies in contents.items():
|
||||
for cookie in cookies:
|
||||
domain = cookie.get("domain", "")
|
||||
if not domain:
|
||||
continue
|
||||
|
||||
domain_key = self._extract_domain(domain)
|
||||
if not domain_key:
|
||||
continue
|
||||
|
||||
if domain_key not in domain_groups:
|
||||
domain_groups[domain_key] = []
|
||||
|
||||
domain_groups[domain_key].append(cookie)
|
||||
|
||||
return domain_groups
|
||||
|
||||
def _extract_domain(self, domain: str) -> Optional[str]:
|
||||
"""
|
||||
提取主域名
|
||||
|
||||
Args:
|
||||
domain: 原始域名
|
||||
|
||||
Returns:
|
||||
Optional[str]: 主域名
|
||||
"""
|
||||
if not domain:
|
||||
return None
|
||||
|
||||
domain = domain.lstrip('.')
|
||||
|
||||
parts = domain.split('.')
|
||||
if len(parts) < 2:
|
||||
return domain
|
||||
|
||||
if len(parts) == 2:
|
||||
return domain
|
||||
|
||||
return '.'.join(parts[-2:])
|
||||
|
||||
def _is_cloudflare_only(self, cookie_list: List[Dict]) -> bool:
|
||||
"""
|
||||
检查是否仅包含Cloudflare验证cookie
|
||||
|
||||
Args:
|
||||
cookie_list: cookie列表
|
||||
|
||||
Returns:
|
||||
bool: 是否仅包含cf_clearance
|
||||
"""
|
||||
for cookie in cookie_list:
|
||||
if cookie.get("name") != "cf_clearance":
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def last_download_time(self) -> Optional[float]:
|
||||
"""获取最后下载时间"""
|
||||
return self._last_download_time
|
||||
|
||||
@property
|
||||
def download_count(self) -> int:
|
||||
"""获取下载次数"""
|
||||
return self._download_count
|
||||
@@ -0,0 +1,259 @@
|
||||
"""
|
||||
CookieCloud客户端使用示例
|
||||
演示如何使用cookiecloud_client模块
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加父目录到路径
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
# 示例1: 基本使用
|
||||
def example_basic_usage():
|
||||
"""基本使用示例"""
|
||||
from cookiecloud_client import CookieCloudClient, CookieConfig
|
||||
|
||||
print("=" * 60)
|
||||
print("示例1: 基本使用")
|
||||
print("=" * 60)
|
||||
|
||||
# 创建配置
|
||||
config = CookieConfig(
|
||||
server="https://movie-pilot.org/cookiecloud",
|
||||
username="hu6n2vcUmzpu7mqUN2rVCg",
|
||||
password="jtDM5dV9AyqXkZdQVeA9f6"
|
||||
)
|
||||
|
||||
# 创建客户端
|
||||
client = CookieCloudClient(config)
|
||||
|
||||
# 测试连接
|
||||
success, message = client.test_connection()
|
||||
print(f"连接测试: {message}")
|
||||
|
||||
if success:
|
||||
# 下载所有cookies
|
||||
result = client.download()
|
||||
|
||||
if result.success:
|
||||
print(f"\n✓ 下载成功!")
|
||||
print(f" 总域名数: {result.total_domains}")
|
||||
print(f" 总Cookie数: {result.total_cookies}")
|
||||
print(f" 下载耗时: {result.download_time:.2f}秒")
|
||||
|
||||
# 显示前5个域名
|
||||
domains = result.get_domains()[:5]
|
||||
print(f"\n前5个域名:")
|
||||
for idx, domain in enumerate(domains, 1):
|
||||
cookie_str = result.get_cookie_string(domain)
|
||||
preview = cookie_str[:50] + "..." if len(cookie_str) > 50 else cookie_str
|
||||
print(f" {idx}. {domain}: {preview}")
|
||||
else:
|
||||
print(f"\n✗ 下载失败: {result.error_message}")
|
||||
|
||||
|
||||
# 示例2: 下载指定域名的Cookie
|
||||
def example_download_specific_domain():
|
||||
"""下载指定域名示例"""
|
||||
from cookiecloud_client import CookieCloudClient, CookieConfig
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("示例2: 下载指定域名的Cookie")
|
||||
print("=" * 60)
|
||||
|
||||
config = CookieConfig(
|
||||
server="https://movie-pilot.org/cookiecloud",
|
||||
username="hu6n2vcUmzpu7mqUN2rVCg",
|
||||
password="jtDM5dV9AyqXkZdQVeA9f6"
|
||||
)
|
||||
|
||||
client = CookieCloudClient(config)
|
||||
|
||||
# 下载单个域名
|
||||
domain = "baidu.com"
|
||||
cookie_str = client.download_for_domain(domain)
|
||||
|
||||
if cookie_str:
|
||||
print(f"✓ {domain}的Cookie:")
|
||||
print(f" {cookie_str[:100]}...")
|
||||
else:
|
||||
print(f"✗ 未找到{domain}的Cookie")
|
||||
|
||||
|
||||
# 示例3: 批量下载多个域名
|
||||
def example_download_multiple_domains():
|
||||
"""批量下载示例"""
|
||||
from cookiecloud_client import CookieCloudClient, CookieConfig
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("示例3: 批量下载多个域名")
|
||||
print("=" * 60)
|
||||
|
||||
config = CookieConfig(
|
||||
server="https://movie-pilot.org/cookiecloud",
|
||||
username="hu6n2vcUmzpu7mqUN2rVCg",
|
||||
password="jtDM5dV9AyqXkZdQVeA9f6"
|
||||
)
|
||||
|
||||
client = CookieCloudClient(config)
|
||||
|
||||
# 批量下载
|
||||
domains = ["baidu.com", "github.com", "google.com", "bing.com"]
|
||||
cookies = client.download_for_domains(domains)
|
||||
|
||||
print("批量下载结果:")
|
||||
for domain, cookie_str in cookies.items():
|
||||
if cookie_str:
|
||||
preview = cookie_str[:50] + "..."
|
||||
print(f" ✓ {domain}: {preview}")
|
||||
else:
|
||||
print(f" ✗ {domain}: 未找到Cookie")
|
||||
|
||||
|
||||
# 示例4: 异常处理
|
||||
def example_error_handling():
|
||||
"""异常处理示例"""
|
||||
from cookiecloud_client import (
|
||||
CookieCloudClient,
|
||||
CookieConfig,
|
||||
CookieCloudError,
|
||||
ConnectionError,
|
||||
AuthenticationError,
|
||||
NetworkError
|
||||
)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("示例4: 异常处理")
|
||||
print("=" * 60)
|
||||
|
||||
try:
|
||||
# 使用错误的凭据
|
||||
config = CookieConfig(
|
||||
server="https://movie-pilot.org/cookiecloud",
|
||||
username="wrong_user",
|
||||
password="wrong_pass"
|
||||
)
|
||||
|
||||
client = CookieCloudClient(config)
|
||||
result = client.download()
|
||||
|
||||
except AuthenticationError as e:
|
||||
print(f"✗ 认证失败: {e.message}")
|
||||
print(f" 用户名: {e.details.get('username')}")
|
||||
|
||||
except ConnectionError as e:
|
||||
print(f"✗ 连接失败: {e.message}")
|
||||
print(f" 服务器: {e.details.get('server')}")
|
||||
print(f" 状态码: {e.details.get('status_code')}")
|
||||
|
||||
except NetworkError as e:
|
||||
print(f"✗ 网络错误: {e.message}")
|
||||
print(f" 原始错误: {e.details.get('original_error')}")
|
||||
|
||||
except CookieCloudError as e:
|
||||
print(f"✗ CookieCloud错误: {e.message}")
|
||||
|
||||
|
||||
# 示例5: 自定义配置
|
||||
def example_custom_config():
|
||||
"""自定义配置示例"""
|
||||
from cookiecloud_client import CookieCloudClient, CookieConfig
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("示例5: 自定义配置")
|
||||
print("=" * 60)
|
||||
|
||||
# 自定义配置
|
||||
config = CookieConfig(
|
||||
server="https://movie-pilot.org/cookiecloud",
|
||||
username="hu6n2vcUmzpu7mqUN2rVCg",
|
||||
password="jtDM5dV9AyqXkZdQVeA9f6",
|
||||
timeout=60, # 60秒超时
|
||||
verify_ssl=False, # 不验证SSL证书
|
||||
ignore_cookies=[ # 忽略的cookie
|
||||
"CookieAutoDeleteBrowsingDataCleanup",
|
||||
"CookieAutoDeleteCleaningDiscarded",
|
||||
"_ga", # 忽略Google Analytics
|
||||
]
|
||||
)
|
||||
|
||||
client = CookieCloudClient(config)
|
||||
|
||||
print(f"配置信息:")
|
||||
print(f" 服务器: {config.server}")
|
||||
print(f" 用户名: {config.username}")
|
||||
print(f" 超时时间: {config.timeout}秒")
|
||||
print(f" 验证SSL: {config.verify_ssl}")
|
||||
print(f" 忽略Cookie: {len(config.ignore_cookies)}个")
|
||||
|
||||
result = client.download()
|
||||
|
||||
if result.success:
|
||||
print(f"\n✓ 下载成功")
|
||||
print(f" 总域名数: {result.total_domains}")
|
||||
print(f" 总Cookie数: {result.total_cookies}")
|
||||
|
||||
|
||||
# 示例6: 使用Cookie数据对象
|
||||
def example_cookie_data_objects():
|
||||
"""使用Cookie数据对象示例"""
|
||||
from cookiecloud_client import CookieCloudClient, CookieConfig
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("示例6: 使用Cookie数据对象")
|
||||
print("=" * 60)
|
||||
|
||||
config = CookieConfig(
|
||||
server="https://movie-pilot.org/cookiecloud",
|
||||
username="hu6n2vcUmzpu7mqUN2rVCg",
|
||||
password="jtDM5dV9AyqXkZdQVeA9f6"
|
||||
)
|
||||
|
||||
client = CookieCloudClient(config)
|
||||
result = client.download()
|
||||
|
||||
if result.success:
|
||||
# 获取第一个域名的详细信息
|
||||
first_domain = result.get_domains()[0]
|
||||
collection = result.cookies.get(first_domain)
|
||||
|
||||
if collection:
|
||||
print(f"域名: {collection.domain}")
|
||||
print(f"Cookie数量: {len(collection.cookies)}")
|
||||
print(f"\nCookie详情:")
|
||||
|
||||
for idx, cookie in enumerate(collection.cookies[:3], 1):
|
||||
print(f" {idx}. {cookie.name}")
|
||||
print(f" 值: {cookie.value[:30]}...")
|
||||
print(f" 路径: {cookie.path}")
|
||||
print(f" 安全: {cookie.secure}")
|
||||
print(f" HttpOnly: {cookie.http_only}")
|
||||
print()
|
||||
|
||||
|
||||
# 主函数
|
||||
def main():
|
||||
"""运行所有示例"""
|
||||
print("\n")
|
||||
print("╔" + "=" * 58 + "╗")
|
||||
print("║" + " " * 15 + "CookieCloud客户端使用示例" + " " * 17 + "║")
|
||||
print("╚" + "=" * 58 + "╝")
|
||||
|
||||
try:
|
||||
example_basic_usage()
|
||||
example_download_specific_domain()
|
||||
example_download_multiple_domains()
|
||||
example_error_handling()
|
||||
example_custom_config()
|
||||
example_cookie_data_objects()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("所有示例执行完成!")
|
||||
print("=" * 60)
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n示例执行出错: {str(e)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
CookieCloud客户端异常类
|
||||
"""
|
||||
|
||||
|
||||
class CookieCloudError(Exception):
|
||||
"""CookieCloud基础异常类"""
|
||||
|
||||
def __init__(self, message: str, details: dict = None):
|
||||
self.message = message
|
||||
self.details = details or {}
|
||||
super().__init__(self.message)
|
||||
|
||||
def __str__(self):
|
||||
if self.details:
|
||||
return f"{self.message} - 详情: {self.details}"
|
||||
return self.message
|
||||
|
||||
|
||||
class ConfigurationError(CookieCloudError):
|
||||
"""配置错误异常"""
|
||||
|
||||
def __init__(self, message: str, config_key: str = None):
|
||||
details = {'config_key': config_key} if config_key else {}
|
||||
super().__init__(message, details)
|
||||
|
||||
|
||||
class ConnectionError(CookieCloudError):
|
||||
"""连接错误异常"""
|
||||
|
||||
def __init__(self, message: str, server: str = None, status_code: int = None):
|
||||
details = {}
|
||||
if server:
|
||||
details['server'] = server
|
||||
if status_code:
|
||||
details['status_code'] = status_code
|
||||
super().__init__(message, details)
|
||||
|
||||
|
||||
class AuthenticationError(CookieCloudError):
|
||||
"""认证错误异常"""
|
||||
|
||||
def __init__(self, message: str, username: str = None):
|
||||
details = {'username': username} if username else {}
|
||||
super().__init__(message, details)
|
||||
|
||||
|
||||
class DataParseError(CookieCloudError):
|
||||
"""数据解析错误异常"""
|
||||
|
||||
def __init__(self, message: str, raw_data: str = None):
|
||||
details = {}
|
||||
if raw_data:
|
||||
details['raw_data_length'] = len(raw_data)
|
||||
super().__init__(message, details)
|
||||
|
||||
|
||||
class NetworkError(CookieCloudError):
|
||||
"""网络错误异常"""
|
||||
|
||||
def __init__(self, message: str, original_error: Exception = None):
|
||||
details = {}
|
||||
if original_error:
|
||||
details['original_error'] = str(original_error)
|
||||
super().__init__(message, details)
|
||||
@@ -0,0 +1,126 @@
|
||||
"""
|
||||
CookieCloud数据模型
|
||||
"""
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional, Dict, List
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
class CookieConfig:
|
||||
"""CookieCloud配置"""
|
||||
server: str
|
||||
username: str
|
||||
password: str
|
||||
timeout: int = 30
|
||||
verify_ssl: bool = True
|
||||
ignore_cookies: List[str] = field(default_factory=lambda: [
|
||||
"CookieAutoDeleteBrowsingDataCleanup",
|
||||
"CookieAutoDeleteCleaningDiscarded"
|
||||
])
|
||||
|
||||
def __post_init__(self):
|
||||
"""验证配置参数"""
|
||||
if not self.server:
|
||||
raise ValueError("服务器地址不能为空")
|
||||
if not self.username:
|
||||
raise ValueError("用户名不能为空")
|
||||
if not self.password:
|
||||
raise ValueError("密码不能为空")
|
||||
if not self.server.startswith(('http://', 'https://')):
|
||||
self.server = f"https://{self.server}"
|
||||
|
||||
|
||||
@dataclass
|
||||
class CookieData:
|
||||
"""Cookie数据"""
|
||||
domain: str
|
||||
name: str
|
||||
value: str
|
||||
path: str = "/"
|
||||
secure: bool = False
|
||||
http_only: bool = False
|
||||
expiry: Optional[datetime] = None
|
||||
|
||||
def to_dict(self) -> Dict:
|
||||
"""转换为字典"""
|
||||
return {
|
||||
'domain': self.domain,
|
||||
'name': self.name,
|
||||
'value': self.value,
|
||||
'path': self.path,
|
||||
'secure': self.secure,
|
||||
'httpOnly': self.http_only,
|
||||
'expiry': self.expiry.isoformat() if self.expiry else None
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict) -> 'CookieData':
|
||||
"""从字典创建"""
|
||||
expiry = None
|
||||
if data.get('expiry'):
|
||||
try:
|
||||
expiry = datetime.fromisoformat(data['expiry'])
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
return cls(
|
||||
domain=data.get('domain', ''),
|
||||
name=data.get('name', ''),
|
||||
value=data.get('value', ''),
|
||||
path=data.get('path', '/'),
|
||||
secure=data.get('secure', False),
|
||||
http_only=data.get('httpOnly', False),
|
||||
expiry=expiry
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class CookieCollection:
|
||||
"""Cookie集合"""
|
||||
domain: str
|
||||
cookies: List[CookieData] = field(default_factory=list)
|
||||
|
||||
def to_cookie_string(self, ignore_list: List[str] = None) -> str:
|
||||
"""转换为cookie字符串"""
|
||||
ignore_list = ignore_list or []
|
||||
cookie_parts = []
|
||||
|
||||
for cookie in self.cookies:
|
||||
if cookie.name not in ignore_list:
|
||||
cookie_parts.append(f"{cookie.name}={cookie.value}")
|
||||
|
||||
return ";".join(cookie_parts)
|
||||
|
||||
def add_cookie(self, cookie: CookieData):
|
||||
"""添加cookie"""
|
||||
self.cookies.append(cookie)
|
||||
|
||||
def get_cookie_by_name(self, name: str) -> Optional[CookieData]:
|
||||
"""根据名称获取cookie"""
|
||||
for cookie in self.cookies:
|
||||
if cookie.name == name:
|
||||
return cookie
|
||||
return None
|
||||
|
||||
|
||||
@dataclass
|
||||
class DownloadResult:
|
||||
"""下载结果"""
|
||||
success: bool
|
||||
cookies: Dict[str, CookieCollection] = field(default_factory=dict)
|
||||
error_message: str = ""
|
||||
total_domains: int = 0
|
||||
total_cookies: int = 0
|
||||
download_time: float = 0.0
|
||||
|
||||
def get_cookie_string(self, domain: str) -> Optional[str]:
|
||||
"""获取指定域名的cookie字符串"""
|
||||
collection = self.cookies.get(domain)
|
||||
if collection:
|
||||
return collection.to_cookie_string()
|
||||
return None
|
||||
|
||||
def get_domains(self) -> List[str]:
|
||||
"""获取所有域名列表"""
|
||||
return list(self.cookies.keys())
|
||||
@@ -0,0 +1,14 @@
|
||||
# CookieCloud客户端依赖项
|
||||
# 此模块完全独立,仅使用Python标准库
|
||||
|
||||
# Python版本要求
|
||||
Python>=3.7
|
||||
|
||||
# 无外部依赖
|
||||
# 仅使用Python标准库模块:
|
||||
# - json
|
||||
# - urllib
|
||||
# - dataclasses
|
||||
# - typing
|
||||
# - datetime
|
||||
# - unittest (用于测试)
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
CookieCloud客户端安装脚本
|
||||
"""
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
with open("README.md", "r", encoding="utf-8") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
setup(
|
||||
name="cookiecloud-client",
|
||||
version="1.0.0",
|
||||
author="CookieManager Team",
|
||||
author_email="support@example.com",
|
||||
description="一个独立的、可复用的CookieCloud服务器客户端",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
url="https://github.com/example/cookiecloud-client",
|
||||
packages=find_packages(),
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
],
|
||||
python_requires=">=3.7",
|
||||
install_requires=[
|
||||
# 无外部依赖,仅使用Python标准库
|
||||
],
|
||||
extras_require={
|
||||
"dev": [
|
||||
"pytest>=6.0",
|
||||
"pytest-cov>=2.0",
|
||||
"black>=21.0",
|
||||
"flake8>=3.9",
|
||||
],
|
||||
},
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
"cookiecloud-client=cookiecloud_client.cli:main",
|
||||
],
|
||||
},
|
||||
project_urls={
|
||||
"Bug Reports": "https://github.com/example/cookiecloud-client/issues",
|
||||
"Source": "https://github.com/example/cookiecloud-client",
|
||||
"Documentation": "https://github.com/example/cookiecloud-client#readme",
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,295 @@
|
||||
"""
|
||||
CookieCloud客户端单元测试
|
||||
"""
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch, MagicMock
|
||||
import json
|
||||
from cookiecloud_client import (
|
||||
CookieCloudClient,
|
||||
CookieConfig,
|
||||
CookieCloudError,
|
||||
ConfigurationError,
|
||||
ConnectionError,
|
||||
AuthenticationError,
|
||||
DataParseError,
|
||||
NetworkError
|
||||
)
|
||||
|
||||
|
||||
class TestCookieConfig(unittest.TestCase):
|
||||
"""测试CookieConfig配置类"""
|
||||
|
||||
def test_valid_config(self):
|
||||
"""测试有效配置"""
|
||||
config = CookieConfig(
|
||||
server="https://example.com",
|
||||
username="user",
|
||||
password="pass"
|
||||
)
|
||||
self.assertEqual(config.server, "https://example.com")
|
||||
self.assertEqual(config.username, "user")
|
||||
self.assertEqual(config.password, "pass")
|
||||
self.assertEqual(config.timeout, 30)
|
||||
self.assertTrue(config.verify_ssl)
|
||||
|
||||
def test_config_with_custom_params(self):
|
||||
"""测试自定义参数配置"""
|
||||
config = CookieConfig(
|
||||
server="https://example.com",
|
||||
username="user",
|
||||
password="pass",
|
||||
timeout=60,
|
||||
verify_ssl=False,
|
||||
ignore_cookies=["test_cookie"]
|
||||
)
|
||||
self.assertEqual(config.timeout, 60)
|
||||
self.assertFalse(config.verify_ssl)
|
||||
self.assertEqual(config.ignore_cookies, ["test_cookie"])
|
||||
|
||||
def test_config_auto_add_protocol(self):
|
||||
"""测试自动添加协议"""
|
||||
config = CookieConfig(
|
||||
server="example.com",
|
||||
username="user",
|
||||
password="pass"
|
||||
)
|
||||
self.assertTrue(config.server.startswith("https://"))
|
||||
|
||||
def test_config_empty_server(self):
|
||||
"""测试空服务器地址"""
|
||||
with self.assertRaises(ValueError):
|
||||
CookieConfig(server="", username="user", password="pass")
|
||||
|
||||
def test_config_empty_username(self):
|
||||
"""测试空用户名"""
|
||||
with self.assertRaises(ValueError):
|
||||
CookieConfig(server="https://example.com", username="", password="pass")
|
||||
|
||||
def test_config_empty_password(self):
|
||||
"""测试空密码"""
|
||||
with self.assertRaises(ValueError):
|
||||
CookieConfig(server="https://example.com", username="user", password="")
|
||||
|
||||
|
||||
class TestCookieCloudClient(unittest.TestCase):
|
||||
"""测试CookieCloudClient客户端类"""
|
||||
|
||||
def setUp(self):
|
||||
"""测试前准备"""
|
||||
self.config = CookieConfig(
|
||||
server="https://test.example.com",
|
||||
username="testuser",
|
||||
password="testpass"
|
||||
)
|
||||
self.client = CookieCloudClient(self.config)
|
||||
|
||||
def test_client_initialization(self):
|
||||
"""测试客户端初始化"""
|
||||
self.assertIsInstance(self.client.config, CookieConfig)
|
||||
self.assertIsNone(self.client.last_download_time)
|
||||
self.assertEqual(self.client.download_count, 0)
|
||||
|
||||
def test_client_invalid_config(self):
|
||||
"""测试无效配置"""
|
||||
with self.assertRaises(ConfigurationError):
|
||||
CookieCloudClient("invalid_config")
|
||||
|
||||
@patch('urllib.request.urlopen')
|
||||
def test_download_success(self, mock_urlopen):
|
||||
"""测试成功下载"""
|
||||
mock_response = Mock()
|
||||
mock_response.status = 200
|
||||
mock_response.read.return_value = json.dumps({
|
||||
"cookie_data": {
|
||||
"test.com": [
|
||||
{
|
||||
"domain": "test.com",
|
||||
"name": "session",
|
||||
"value": "test_value",
|
||||
"path": "/",
|
||||
"secure": False,
|
||||
"httpOnly": False
|
||||
}
|
||||
]
|
||||
}
|
||||
}).encode('utf-8')
|
||||
mock_urlopen.return_value = mock_response
|
||||
|
||||
result = self.client.download()
|
||||
|
||||
self.assertTrue(result.success)
|
||||
self.assertEqual(result.total_domains, 1)
|
||||
self.assertEqual(result.total_cookies, 1)
|
||||
self.assertIsNotNone(self.client.last_download_time)
|
||||
self.assertEqual(self.client.download_count, 1)
|
||||
|
||||
@patch('urllib.request.urlopen')
|
||||
def test_download_authentication_error(self, mock_urlopen):
|
||||
"""测试认证失败"""
|
||||
import urllib.error
|
||||
|
||||
mock_urlopen.side_effect = urllib.error.HTTPError(
|
||||
url="https://test.example.com/get/testuser",
|
||||
code=401,
|
||||
msg="Unauthorized",
|
||||
hdrs={},
|
||||
fp=None
|
||||
)
|
||||
|
||||
with self.assertRaises(AuthenticationError):
|
||||
self.client.download()
|
||||
|
||||
@patch('urllib.request.urlopen')
|
||||
def test_download_connection_error(self, mock_urlopen):
|
||||
"""测试连接错误"""
|
||||
import urllib.error
|
||||
|
||||
mock_urlopen.side_effect = urllib.error.HTTPError(
|
||||
url="https://test.example.com/get/testuser",
|
||||
code=404,
|
||||
msg="Not Found",
|
||||
hdrs={},
|
||||
fp=None
|
||||
)
|
||||
|
||||
with self.assertRaises(ConnectionError):
|
||||
self.client.download()
|
||||
|
||||
@patch('urllib.request.urlopen')
|
||||
def test_download_network_error(self, mock_urlopen):
|
||||
"""测试网络错误"""
|
||||
import urllib.error
|
||||
|
||||
mock_urlopen.side_effect = urllib.error.URLError("Connection refused")
|
||||
|
||||
with self.assertRaises(NetworkError):
|
||||
self.client.download()
|
||||
|
||||
@patch('urllib.request.urlopen')
|
||||
def test_download_empty_data(self, mock_urlopen):
|
||||
"""测试空数据"""
|
||||
mock_response = Mock()
|
||||
mock_response.status = 200
|
||||
mock_response.read.return_value = json.dumps({}).encode('utf-8')
|
||||
mock_urlopen.return_value = mock_response
|
||||
|
||||
with self.assertRaises(DataParseError):
|
||||
self.client.download()
|
||||
|
||||
@patch('urllib.request.urlopen')
|
||||
def test_test_connection_success(self, mock_urlopen):
|
||||
"""测试连接测试成功"""
|
||||
mock_response = Mock()
|
||||
mock_response.status = 200
|
||||
mock_response.read.return_value = json.dumps({
|
||||
"cookie_data": {}
|
||||
}).encode('utf-8')
|
||||
mock_urlopen.return_value = mock_response
|
||||
|
||||
success, message = self.client.test_connection()
|
||||
|
||||
self.assertTrue(success)
|
||||
self.assertEqual(message, "连接成功")
|
||||
|
||||
@patch('urllib.request.urlopen')
|
||||
def test_test_connection_failure(self, mock_urlopen):
|
||||
"""测试连接测试失败"""
|
||||
import urllib.error
|
||||
|
||||
mock_urlopen.side_effect = urllib.error.HTTPError(
|
||||
url="https://test.example.com/get/testuser",
|
||||
code=401,
|
||||
msg="Unauthorized",
|
||||
hdrs={},
|
||||
fp=None
|
||||
)
|
||||
|
||||
success, message = self.client.test_connection()
|
||||
|
||||
self.assertFalse(success)
|
||||
self.assertIn("认证失败", message)
|
||||
|
||||
@patch('urllib.request.urlopen')
|
||||
def test_download_for_domain(self, mock_urlopen):
|
||||
"""测试下载指定域名"""
|
||||
mock_response = Mock()
|
||||
mock_response.status = 200
|
||||
mock_response.read.return_value = json.dumps({
|
||||
"cookie_data": {
|
||||
"test.com": [
|
||||
{
|
||||
"domain": "test.com",
|
||||
"name": "session",
|
||||
"value": "test_value",
|
||||
"path": "/",
|
||||
"secure": False,
|
||||
"httpOnly": False
|
||||
}
|
||||
]
|
||||
}
|
||||
}).encode('utf-8')
|
||||
mock_urlopen.return_value = mock_response
|
||||
|
||||
cookie_str = self.client.download_for_domain("test.com")
|
||||
|
||||
self.assertIsNotNone(cookie_str)
|
||||
self.assertIn("session=test_value", cookie_str)
|
||||
|
||||
@patch('urllib.request.urlopen')
|
||||
def test_download_for_domains(self, mock_urlopen):
|
||||
"""测试批量下载多个域名"""
|
||||
mock_response = Mock()
|
||||
mock_response.status = 200
|
||||
mock_response.read.return_value = json.dumps({
|
||||
"cookie_data": {
|
||||
"test1.com": [
|
||||
{"domain": "test1.com", "name": "cookie1", "value": "value1", "path": "/"}
|
||||
],
|
||||
"test2.com": [
|
||||
{"domain": "test2.com", "name": "cookie2", "value": "value2", "path": "/"}
|
||||
]
|
||||
}
|
||||
}).encode('utf-8')
|
||||
mock_urlopen.return_value = mock_response
|
||||
|
||||
domains = ["test1.com", "test2.com", "test3.com"]
|
||||
cookies = self.client.download_for_domains(domains)
|
||||
|
||||
self.assertEqual(len(cookies), 3)
|
||||
self.assertIn("cookie1=value1", cookies["test1.com"])
|
||||
self.assertIn("cookie2=value2", cookies["test2.com"])
|
||||
self.assertIsNone(cookies["test3.com"])
|
||||
|
||||
|
||||
class TestExceptions(unittest.TestCase):
|
||||
"""测试异常类"""
|
||||
|
||||
def test_cookie_cloud_error(self):
|
||||
"""测试基础异常"""
|
||||
error = CookieCloudError("测试错误", {"key": "value"})
|
||||
self.assertEqual(error.message, "测试错误")
|
||||
self.assertEqual(error.details, {"key": "value"})
|
||||
self.assertIn("测试错误", str(error))
|
||||
|
||||
def test_configuration_error(self):
|
||||
"""测试配置错误"""
|
||||
error = ConfigurationError("配置错误", config_key="server")
|
||||
self.assertEqual(error.message, "配置错误")
|
||||
self.assertEqual(error.details["config_key"], "server")
|
||||
|
||||
def test_connection_error(self):
|
||||
"""测试连接错误"""
|
||||
error = ConnectionError("连接失败", server="example.com", status_code=404)
|
||||
self.assertEqual(error.message, "连接失败")
|
||||
self.assertEqual(error.details["server"], "example.com")
|
||||
self.assertEqual(error.details["status_code"], 404)
|
||||
|
||||
def test_authentication_error(self):
|
||||
"""测试认证错误"""
|
||||
error = AuthenticationError("认证失败", username="testuser")
|
||||
self.assertEqual(error.message, "认证失败")
|
||||
self.assertEqual(error.details["username"], "testuser")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
版本信息
|
||||
"""
|
||||
|
||||
__version__ = '1.0.0'
|
||||
__author__ = 'CookieManager Team'
|
||||
__email__ = 'support@example.com'
|
||||
__license__ = 'MIT'
|
||||
+647
@@ -343,3 +343,650 @@
|
||||
2026-03-02 16:38:22,061 - INFO - 用户 用户A 处理完成
|
||||
2026-03-02 16:38:22,075 - INFO - ===== Cookie 监控结束 =====
|
||||
2026-03-02 16:38:22,102 - INFO - 成功处理: 1 个用户,失败: 0 个用户
|
||||
2026-03-02 18:56:27,278 - INFO - ===== Cookie 监控开始 =====
|
||||
2026-03-02 18:56:27,279 - INFO - 开始处理用户: 用户A
|
||||
2026-03-02 18:56:27,279 - INFO - 处理网站: 用户A - 网站A
|
||||
2026-03-02 18:56:27,280 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 18:56:27,280 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 18:56:54,215 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 18:56:54,216 - INFO - 登录失败: 网站A
|
||||
2026-03-02 18:56:54,435 - INFO - 已发送失败通知: 用户A - 网站A
|
||||
2026-03-02 18:56:54,508 - INFO - 已达到最大失败次数,已发送通知并重置计数: 网站A
|
||||
2026-03-02 18:56:55,613 - INFO - 用户 用户A 处理完成
|
||||
2026-03-02 18:56:55,615 - INFO - ===== Cookie 监控结束 =====
|
||||
2026-03-02 18:56:55,616 - INFO - 成功处理: 1 个用户,失败: 0 个用户
|
||||
2026-03-02 18:57:16,772 - INFO - ===== Cookie 监控开始 =====
|
||||
2026-03-02 18:57:16,772 - INFO - 开始处理用户: 用户A
|
||||
2026-03-02 18:57:16,773 - INFO - 处理网站: 用户A - 网站A
|
||||
2026-03-02 18:57:16,773 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 18:57:16,774 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 18:57:38,432 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 18:57:38,433 - INFO - 登录失败: 网站A
|
||||
2026-03-02 18:57:38,434 - INFO - 当前失败次数: 1/3
|
||||
2026-03-02 18:57:39,475 - INFO - 用户 用户A 处理完成
|
||||
2026-03-02 18:57:39,479 - INFO - ===== Cookie 监控结束 =====
|
||||
2026-03-02 18:57:39,480 - INFO - 成功处理: 1 个用户,失败: 0 个用户
|
||||
2026-03-02 19:06:12,869 - INFO - ===== Cookie 监控开始 =====
|
||||
2026-03-02 19:06:12,870 - INFO - 开始处理用户: 用户A
|
||||
2026-03-02 19:06:12,871 - INFO - 处理网站: 用户A - 网站A
|
||||
2026-03-02 19:06:12,871 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:06:12,872 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:06:13,899 - INFO - 获取到 4 个 cookie:
|
||||
2026-03-02 19:06:13,900 - INFO - - LMKBIUSS: eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOi...
|
||||
2026-03-02 19:06:13,902 - INFO - - edentoken: 13548569666
|
||||
2026-03-02 19:06:13,903 - INFO - - user: 13548569666
|
||||
2026-03-02 19:06:13,904 - INFO - - userType: 2
|
||||
2026-03-02 19:08:41,909 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:08:41,910 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:08:41,913 - INFO - 当前失败次数: 2/3
|
||||
2026-03-02 19:08:43,011 - INFO - 用户 用户A 处理完成
|
||||
2026-03-02 19:08:43,019 - INFO - ===== Cookie 监控结束 =====
|
||||
2026-03-02 19:08:43,020 - INFO - 成功处理: 1 个用户,失败: 0 个用户
|
||||
2026-03-02 19:09:07,392 - INFO - ===== Cookie 监控开始 =====
|
||||
2026-03-02 19:09:07,393 - INFO - 开始处理用户: 用户A
|
||||
2026-03-02 19:09:07,393 - INFO - 处理网站: 用户A - 网站A
|
||||
2026-03-02 19:09:07,393 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:09:07,394 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:09:08,548 - INFO - 获取到 4 个 cookie:
|
||||
2026-03-02 19:09:08,549 - INFO - - LMKBIUSS: eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOi...
|
||||
2026-03-02 19:09:08,549 - INFO - - edentoken: 13548569666
|
||||
2026-03-02 19:09:08,549 - INFO - - user: 13548569666
|
||||
2026-03-02 19:09:08,550 - INFO - - userType: 2
|
||||
2026-03-02 19:09:24,826 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:09:24,827 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:09:24,974 - INFO - 已发送失败通知: 用户A - 网站A
|
||||
2026-03-02 19:09:24,975 - INFO - 已达到最大失败次数,已发送通知并重置计数: 网站A
|
||||
2026-03-02 19:09:26,021 - INFO - 用户 用户A 处理完成
|
||||
2026-03-02 19:09:26,022 - INFO - ===== Cookie 监控结束 =====
|
||||
2026-03-02 19:09:26,023 - INFO - 成功处理: 1 个用户,失败: 0 个用户
|
||||
2026-03-02 19:18:24,406 - INFO - ===== Cookie 监控开始 =====
|
||||
2026-03-02 19:18:24,408 - INFO - 开始处理用户: 用户A
|
||||
2026-03-02 19:18:24,408 - INFO - 处理网站: 用户A - 网站A
|
||||
2026-03-02 19:18:24,409 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:18:24,409 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:18:25,149 - INFO - 获取到 4 个 cookie:
|
||||
2026-03-02 19:18:25,149 - INFO - - LMKBIUSS: eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOi...
|
||||
2026-03-02 19:18:25,150 - INFO - - edentoken: 13548569666
|
||||
2026-03-02 19:18:25,150 - INFO - - user: 13548569666
|
||||
2026-03-02 19:18:25,151 - INFO - - userType: 2
|
||||
2026-03-02 19:19:20,811 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:19:20,812 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:19:20,826 - INFO - 当前失败次数: 1/3
|
||||
2026-03-02 19:19:21,868 - INFO - 用户 用户A 处理完成
|
||||
2026-03-02 19:19:21,875 - INFO - 开始处理用户: 用户B
|
||||
2026-03-02 19:19:21,876 - INFO - 处理网站: 用户B - 网站A
|
||||
2026-03-02 19:19:21,879 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:19:21,883 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:19:22,305 - INFO - 获取到 6 个 cookie:
|
||||
2026-03-02 19:19:22,306 - INFO - - _qimei_uuid42: 1a302130f16100ca18af370a47cb8afce807c4a076
|
||||
2026-03-02 19:19:22,306 - INFO - - _qimei_fingerprint: 50aa79f919511142818459f44ac38dee
|
||||
2026-03-02 19:19:22,307 - INFO - - _qimei_i_3: 64c844d0c35e05dc9796fc355d8470e5a3eba5f0410e00d3e7...
|
||||
2026-03-02 19:19:22,307 - INFO - - _qimei_h38: f8e0750618af370a47cb8afc0200000c91a302
|
||||
2026-03-02 19:19:22,308 - INFO - - merchantType: web
|
||||
2026-03-02 19:19:22,308 - INFO - - _qimei_i_1: 63f25ad49d0f50dcc497f83153d525e3f0eef5f51508518ae5...
|
||||
2026-03-02 19:19:42,892 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:19:42,893 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:19:42,897 - INFO - 当前失败次数: 1/3
|
||||
2026-03-02 19:19:43,952 - INFO - 用户 用户B 处理完成
|
||||
2026-03-02 19:19:43,953 - INFO - ===== Cookie 监控结束 =====
|
||||
2026-03-02 19:19:43,956 - INFO - 成功处理: 2 个用户,失败: 0 个用户
|
||||
2026-03-02 19:28:58,190 - INFO - ===== Cookie 监控开始 =====
|
||||
2026-03-02 19:28:58,195 - INFO - 开始处理用户: 用户A
|
||||
2026-03-02 19:28:58,196 - INFO - 处理网站: 用户A - 网站A
|
||||
2026-03-02 19:28:58,197 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:28:58,198 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:28:58,934 - INFO - 获取到 4 个 cookie:
|
||||
2026-03-02 19:28:58,934 - INFO - - LMKBIUSS: eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOi...
|
||||
2026-03-02 19:28:58,935 - INFO - - edentoken: 13548569666
|
||||
2026-03-02 19:28:58,936 - INFO - - user: 13548569666
|
||||
2026-03-02 19:28:58,936 - INFO - - userType: 2
|
||||
2026-03-02 19:29:09,680 - INFO - 开始设置 4 个 cookie
|
||||
2026-03-02 19:29:10,559 - INFO - 设置 cookie: LMKBIUSS
|
||||
2026-03-02 19:29:10,589 - INFO - 设置 cookie: edentoken
|
||||
2026-03-02 19:29:10,616 - INFO - 设置 cookie: user
|
||||
2026-03-02 19:29:10,649 - INFO - 设置 cookie: userType
|
||||
2026-03-02 19:31:57,850 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:31:57,874 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:31:57,908 - INFO - 当前失败次数: 2/3
|
||||
2026-03-02 19:31:59,017 - INFO - 用户 用户A 处理完成
|
||||
2026-03-02 19:31:59,026 - INFO - 开始处理用户: 用户B
|
||||
2026-03-02 19:31:59,034 - INFO - 处理网站: 用户B - 网站A
|
||||
2026-03-02 19:31:59,049 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:31:59,057 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:31:59,548 - INFO - 获取到 6 个 cookie:
|
||||
2026-03-02 19:31:59,549 - INFO - - _qimei_uuid42: 1a302130f16100ca18af370a47cb8afce807c4a076
|
||||
2026-03-02 19:31:59,549 - INFO - - _qimei_fingerprint: 50aa79f919511142818459f44ac38dee
|
||||
2026-03-02 19:31:59,550 - INFO - - _qimei_i_3: 64c844d0c35e05dc9796fc355d8470e5a3eba5f0410e00d3e7...
|
||||
2026-03-02 19:31:59,551 - INFO - - _qimei_h38: f8e0750618af370a47cb8afc0200000c91a302
|
||||
2026-03-02 19:31:59,555 - INFO - - merchantType: web
|
||||
2026-03-02 19:31:59,557 - INFO - - _qimei_i_1: 63f25ad49d0f50dcc497f83153d525e3f0eef5f51508518ae5...
|
||||
2026-03-02 19:32:04,579 - INFO - 开始设置 6 个 cookie
|
||||
2026-03-02 19:32:05,108 - INFO - 设置 cookie: _qimei_uuid42
|
||||
2026-03-02 19:32:05,123 - INFO - 设置 cookie: _qimei_fingerprint
|
||||
2026-03-02 19:32:05,134 - INFO - 设置 cookie: _qimei_i_3
|
||||
2026-03-02 19:32:05,152 - INFO - 设置 cookie: _qimei_h38
|
||||
2026-03-02 19:32:05,176 - INFO - 设置 cookie: merchantType
|
||||
2026-03-02 19:32:05,191 - INFO - 设置 cookie: _qimei_i_1
|
||||
2026-03-02 19:32:20,855 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:32:20,856 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:32:20,861 - INFO - 当前失败次数: 2/3
|
||||
2026-03-02 19:32:21,948 - INFO - 用户 用户B 处理完成
|
||||
2026-03-02 19:32:21,953 - INFO - ===== Cookie 监控结束 =====
|
||||
2026-03-02 19:32:21,970 - INFO - 成功处理: 2 个用户,失败: 0 个用户
|
||||
2026-03-02 19:41:26,080 - INFO - ===== Cookie 监控开始 =====
|
||||
2026-03-02 19:41:26,081 - INFO - 开始处理用户: 用户A
|
||||
2026-03-02 19:41:26,082 - INFO - 处理网站: 用户A - 网站A
|
||||
2026-03-02 19:41:26,082 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:41:26,082 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:41:27,131 - INFO - 获取到 4 个 cookie:
|
||||
2026-03-02 19:41:27,132 - INFO - - LMKBIUSS: eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOi...
|
||||
2026-03-02 19:41:27,134 - INFO - - edentoken: 13548569666
|
||||
2026-03-02 19:41:27,135 - INFO - - user: 13548569666
|
||||
2026-03-02 19:41:27,137 - INFO - - userType: 2
|
||||
2026-03-02 19:41:32,196 - INFO - 开始设置 4 个 cookie
|
||||
2026-03-02 19:41:32,218 - INFO - 设置 cookie: LMKBIUSS
|
||||
2026-03-02 19:41:32,256 - INFO - 设置 cookie: edentoken
|
||||
2026-03-02 19:41:32,291 - INFO - 设置 cookie: user
|
||||
2026-03-02 19:41:32,315 - INFO - 设置 cookie: userType
|
||||
2026-03-02 19:41:47,436 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:41:47,436 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:41:47,804 - INFO - 已发送失败通知: 用户A - 网站A
|
||||
2026-03-02 19:41:47,828 - INFO - 已达到最大失败次数,已发送通知并重置计数: 网站A
|
||||
2026-03-02 19:41:48,879 - INFO - 用户 用户A 处理完成
|
||||
2026-03-02 19:41:48,880 - INFO - 开始处理用户: 用户B
|
||||
2026-03-02 19:41:48,881 - INFO - 处理网站: 用户B - 网站A
|
||||
2026-03-02 19:41:48,882 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:41:48,882 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:41:49,422 - INFO - 获取到 17 个 cookie:
|
||||
2026-03-02 19:41:49,426 - INFO - - _qimei_uuid42: 1a302130f16100ca18af370a47cb8afce807c4a076
|
||||
2026-03-02 19:41:49,435 - INFO - - _qimei_fingerprint: 50aa79f919511142818459f44ac38dee
|
||||
2026-03-02 19:41:49,481 - INFO - - _qimei_i_3: 64c844d0c35e05dc9796fc355d8470e5a3eba5f0410e00d3e7...
|
||||
2026-03-02 19:41:49,561 - INFO - - _qimei_h38: f8e0750618af370a47cb8afc0200000c91a302
|
||||
2026-03-02 19:41:49,583 - INFO - - merchantType: web
|
||||
2026-03-02 19:41:49,596 - INFO - - _qimei_i_1: 63f25ad49d0f50dcc497f83153d525e3f0eef5f51508518ae5...
|
||||
2026-03-02 19:41:49,609 - INFO - - JSESSIONID: B93CC37376EFC653A59B550FE761CC72
|
||||
2026-03-02 19:41:49,612 - INFO - - _qimei_i_1: 0
|
||||
2026-03-02 19:41:49,662 - INFO - - merchantType: 0
|
||||
2026-03-02 19:41:49,665 - INFO - - _qimei_h38: 0
|
||||
2026-03-02 19:41:49,666 - INFO - - _qimei_i_3: 0
|
||||
2026-03-02 19:41:49,668 - INFO - - _qimei_fingerprint: 0
|
||||
2026-03-02 19:41:49,672 - INFO - - _qimei_uuid42: 0
|
||||
2026-03-02 19:41:49,672 - INFO - - LMKBIUSS: eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOi...
|
||||
2026-03-02 19:41:49,674 - INFO - - edentoken: 13548569666
|
||||
2026-03-02 19:41:49,675 - INFO - - user: 13548569666
|
||||
2026-03-02 19:41:49,676 - INFO - - userType: 2
|
||||
2026-03-02 19:41:53,678 - INFO - 开始设置 17 个 cookie
|
||||
2026-03-02 19:41:54,168 - INFO - 设置 cookie: _qimei_uuid42
|
||||
2026-03-02 19:41:54,177 - INFO - 设置 cookie: _qimei_fingerprint
|
||||
2026-03-02 19:41:54,191 - INFO - 设置 cookie: _qimei_i_3
|
||||
2026-03-02 19:41:54,205 - INFO - 设置 cookie: _qimei_h38
|
||||
2026-03-02 19:41:54,218 - INFO - 设置 cookie: merchantType
|
||||
2026-03-02 19:41:54,228 - INFO - 设置 cookie: _qimei_i_1
|
||||
2026-03-02 19:41:54,240 - INFO - 设置 cookie: JSESSIONID
|
||||
2026-03-02 19:41:54,250 - INFO - 设置 cookie: _qimei_i_1
|
||||
2026-03-02 19:41:54,263 - INFO - 设置 cookie: merchantType
|
||||
2026-03-02 19:41:54,277 - INFO - 设置 cookie: _qimei_h38
|
||||
2026-03-02 19:41:54,290 - INFO - 设置 cookie: _qimei_i_3
|
||||
2026-03-02 19:41:54,302 - INFO - 设置 cookie: _qimei_fingerprint
|
||||
2026-03-02 19:41:54,315 - INFO - 设置 cookie: _qimei_uuid42
|
||||
2026-03-02 19:41:54,328 - INFO - 设置 cookie: LMKBIUSS
|
||||
2026-03-02 19:41:54,339 - INFO - 设置 cookie: edentoken
|
||||
2026-03-02 19:41:54,350 - INFO - 设置 cookie: user
|
||||
2026-03-02 19:41:54,362 - INFO - 设置 cookie: userType
|
||||
2026-03-02 19:44:10,871 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:44:10,872 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:44:11,050 - INFO - 已发送失败通知: 用户B - 网站A
|
||||
2026-03-02 19:44:11,111 - INFO - 已达到最大失败次数,已发送通知并重置计数: 网站A
|
||||
2026-03-02 19:44:12,178 - INFO - 用户 用户B 处理完成
|
||||
2026-03-02 19:44:12,181 - INFO - ===== Cookie 监控结束 =====
|
||||
2026-03-02 19:44:12,187 - INFO - 成功处理: 2 个用户,失败: 0 个用户
|
||||
2026-03-02 19:44:29,316 - INFO - ===== Cookie 监控开始 =====
|
||||
2026-03-02 19:44:29,316 - INFO - 开始处理用户: 用户A
|
||||
2026-03-02 19:44:29,317 - INFO - 处理网站: 用户A - 网站A
|
||||
2026-03-02 19:44:29,317 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:44:29,318 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:44:31,320 - INFO - 获取到 4 个 cookie:
|
||||
2026-03-02 19:44:31,321 - INFO - - LMKBIUSS: eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOi...
|
||||
2026-03-02 19:44:31,324 - INFO - - edentoken: 13548569666
|
||||
2026-03-02 19:44:31,325 - INFO - - user: 13548569666
|
||||
2026-03-02 19:44:31,326 - INFO - - userType: 2
|
||||
2026-03-02 19:44:34,631 - INFO - 开始设置 4 个 cookie
|
||||
2026-03-02 19:44:34,649 - INFO - 设置 cookie: LMKBIUSS
|
||||
2026-03-02 19:44:34,666 - INFO - 设置 cookie: edentoken
|
||||
2026-03-02 19:44:34,684 - INFO - 设置 cookie: user
|
||||
2026-03-02 19:44:34,709 - INFO - 设置 cookie: userType
|
||||
2026-03-02 19:44:49,463 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:44:49,465 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:44:49,466 - INFO - 当前失败次数: 1/3
|
||||
2026-03-02 19:44:50,505 - INFO - 用户 用户A 处理完成
|
||||
2026-03-02 19:44:50,506 - INFO - 开始处理用户: 用户B
|
||||
2026-03-02 19:44:50,506 - INFO - 处理网站: 用户B - 网站A
|
||||
2026-03-02 19:44:50,507 - INFO - 尝试使用本地 cookie 登录: 网站A
|
||||
2026-03-02 19:44:50,508 - INFO - 从 Cookie Cloud 获取 cookie: 网站A
|
||||
2026-03-02 19:44:50,863 - INFO - 获取到 17 个 cookie:
|
||||
2026-03-02 19:44:50,864 - INFO - - _qimei_uuid42: 1a302130f16100ca18af370a47cb8afce807c4a076
|
||||
2026-03-02 19:44:50,865 - INFO - - _qimei_fingerprint: 50aa79f919511142818459f44ac38dee
|
||||
2026-03-02 19:44:50,865 - INFO - - _qimei_i_3: 64c844d0c35e05dc9796fc355d8470e5a3eba5f0410e00d3e7...
|
||||
2026-03-02 19:44:50,866 - INFO - - _qimei_h38: f8e0750618af370a47cb8afc0200000c91a302
|
||||
2026-03-02 19:44:50,866 - INFO - - merchantType: web
|
||||
2026-03-02 19:44:50,867 - INFO - - _qimei_i_1: 63f25ad49d0f50dcc497f83153d525e3f0eef5f51508518ae5...
|
||||
2026-03-02 19:44:50,868 - INFO - - JSESSIONID: B93CC37376EFC653A59B550FE761CC72
|
||||
2026-03-02 19:44:50,868 - INFO - - _qimei_i_1: 0
|
||||
2026-03-02 19:44:50,868 - INFO - - merchantType: 0
|
||||
2026-03-02 19:44:50,869 - INFO - - _qimei_h38: 0
|
||||
2026-03-02 19:44:50,870 - INFO - - _qimei_i_3: 0
|
||||
2026-03-02 19:44:50,870 - INFO - - _qimei_fingerprint: 0
|
||||
2026-03-02 19:44:50,871 - INFO - - _qimei_uuid42: 0
|
||||
2026-03-02 19:44:50,872 - INFO - - LMKBIUSS: eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOi...
|
||||
2026-03-02 19:44:50,872 - INFO - - edentoken: 13548569666
|
||||
2026-03-02 19:44:50,873 - INFO - - user: 13548569666
|
||||
2026-03-02 19:44:50,873 - INFO - - userType: 2
|
||||
2026-03-02 19:44:54,212 - INFO - 开始设置 17 个 cookie
|
||||
2026-03-02 19:44:54,239 - INFO - 设置 cookie: _qimei_uuid42
|
||||
2026-03-02 19:44:54,258 - INFO - 设置 cookie: _qimei_fingerprint
|
||||
2026-03-02 19:44:54,286 - INFO - 设置 cookie: _qimei_i_3
|
||||
2026-03-02 19:44:54,306 - INFO - 设置 cookie: _qimei_h38
|
||||
2026-03-02 19:44:54,323 - INFO - 设置 cookie: merchantType
|
||||
2026-03-02 19:44:54,344 - INFO - 设置 cookie: _qimei_i_1
|
||||
2026-03-02 19:44:54,366 - INFO - 设置 cookie: JSESSIONID
|
||||
2026-03-02 19:44:54,391 - INFO - 设置 cookie: _qimei_i_1
|
||||
2026-03-02 19:44:54,414 - INFO - 设置 cookie: merchantType
|
||||
2026-03-02 19:44:54,436 - INFO - 设置 cookie: _qimei_h38
|
||||
2026-03-02 19:44:54,456 - INFO - 设置 cookie: _qimei_i_3
|
||||
2026-03-02 19:44:54,474 - INFO - 设置 cookie: _qimei_fingerprint
|
||||
2026-03-02 19:44:54,503 - INFO - 设置 cookie: _qimei_uuid42
|
||||
2026-03-02 19:44:54,529 - INFO - 设置 cookie: LMKBIUSS
|
||||
2026-03-02 19:44:54,554 - INFO - 设置 cookie: edentoken
|
||||
2026-03-02 19:44:54,571 - INFO - 设置 cookie: user
|
||||
2026-03-02 19:44:54,590 - INFO - 设置 cookie: userType
|
||||
2026-03-02 19:45:10,024 - INFO - Cookie Cloud 登录失败: 网站A
|
||||
2026-03-02 19:45:10,025 - INFO - 登录失败: 网站A
|
||||
2026-03-02 19:45:10,026 - INFO - 当前失败次数: 1/3
|
||||
2026-03-02 19:45:11,099 - INFO - 用户 用户B 处理完成
|
||||
2026-03-02 19:45:11,100 - INFO - ===== Cookie 监控结束 =====
|
||||
2026-03-02 19:45:11,100 - INFO - 成功处理: 2 个用户,失败: 0 个用户
|
||||
2026-03-02 19:47:06,309 - INFO - ==================================================
|
||||
2026-03-02 19:47:06,310 - INFO - Cookie 监控开始
|
||||
2026-03-02 19:47:06,310 - INFO - 时间: 2026-03-02 19:47:06
|
||||
2026-03-02 19:47:06,311 - INFO - ==================================================
|
||||
2026-03-02 19:47:06,311 - INFO - ==================== 开始处理用户: 用户A ====================
|
||||
2026-03-02 19:47:06,312 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 19:47:08,398 - INFO - 获取到 278 个域名,共 803 个 cookie
|
||||
2026-03-02 19:47:08,399 - INFO -
|
||||
处理网站: 网站A
|
||||
2026-03-02 19:47:08,399 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 19:47:08,400 - INFO - 找到 4 个 cookie
|
||||
2026-03-02 19:47:19,291 - INFO - 开始设置 4 个 cookie
|
||||
2026-03-02 19:47:19,316 - INFO - 设置 cookie: LMKBIUSS
|
||||
2026-03-02 19:47:19,336 - INFO - 设置 cookie: edentoken
|
||||
2026-03-02 19:47:19,351 - INFO - 设置 cookie: user
|
||||
2026-03-02 19:47:19,367 - INFO - 设置 cookie: userType
|
||||
2026-03-02 19:49:03,692 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 19:49:03,700 - INFO -
|
||||
==================== 用户 用户A 处理结果汇总 ====================
|
||||
2026-03-02 19:49:03,703 - INFO - 总网站数: 1
|
||||
2026-03-02 19:49:03,704 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 19:49:03,705 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 19:49:03,706 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 19:49:04,751 - INFO - ==================== 开始处理用户: 用户B ====================
|
||||
2026-03-02 19:49:04,790 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 19:49:05,278 - INFO - 获取到 814 个域名,共 2941 个 cookie
|
||||
2026-03-02 19:49:05,282 - INFO -
|
||||
处理网站: 网站A
|
||||
2026-03-02 19:49:05,299 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 19:49:05,303 - INFO - 找到 17 个 cookie
|
||||
2026-03-02 19:49:19,363 - INFO - 开始设置 17 个 cookie
|
||||
2026-03-02 19:49:19,378 - INFO - 设置 cookie: _qimei_uuid42
|
||||
2026-03-02 19:49:19,392 - INFO - 设置 cookie: _qimei_fingerprint
|
||||
2026-03-02 19:49:19,408 - INFO - 设置 cookie: _qimei_i_3
|
||||
2026-03-02 19:49:19,426 - INFO - 设置 cookie: _qimei_h38
|
||||
2026-03-02 19:49:19,443 - INFO - 设置 cookie: merchantType
|
||||
2026-03-02 19:49:19,459 - INFO - 设置 cookie: _qimei_i_1
|
||||
2026-03-02 19:49:19,475 - INFO - 设置 cookie: JSESSIONID
|
||||
2026-03-02 19:49:19,490 - INFO - 设置 cookie: _qimei_i_1
|
||||
2026-03-02 19:49:19,506 - INFO - 设置 cookie: merchantType
|
||||
2026-03-02 19:49:19,521 - INFO - 设置 cookie: _qimei_h38
|
||||
2026-03-02 19:49:19,534 - INFO - 设置 cookie: _qimei_i_3
|
||||
2026-03-02 19:49:19,549 - INFO - 设置 cookie: _qimei_fingerprint
|
||||
2026-03-02 19:49:19,562 - INFO - 设置 cookie: _qimei_uuid42
|
||||
2026-03-02 19:49:19,578 - INFO - 设置 cookie: LMKBIUSS
|
||||
2026-03-02 19:49:19,592 - INFO - 设置 cookie: edentoken
|
||||
2026-03-02 19:49:19,601 - INFO - 设置 cookie: user
|
||||
2026-03-02 19:49:19,615 - INFO - 设置 cookie: userType
|
||||
2026-03-02 19:51:34,896 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 19:51:34,902 - INFO -
|
||||
==================== 用户 用户B 处理结果汇总 ====================
|
||||
2026-03-02 19:51:34,904 - INFO - 总网站数: 1
|
||||
2026-03-02 19:51:34,905 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 19:51:34,906 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 19:51:34,907 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 19:51:35,961 - INFO -
|
||||
==================================================
|
||||
2026-03-02 19:51:35,976 - INFO - Cookie 监控结束
|
||||
2026-03-02 19:51:35,988 - INFO - ==================================================
|
||||
2026-03-02 19:52:33,025 - INFO - ==================================================
|
||||
2026-03-02 19:52:33,026 - INFO - Cookie 监控开始
|
||||
2026-03-02 19:52:33,026 - INFO - 时间: 2026-03-02 19:52:33
|
||||
2026-03-02 19:52:33,027 - INFO - ==================================================
|
||||
2026-03-02 19:52:33,027 - INFO - ==================== 开始处理用户: 用户A ====================
|
||||
2026-03-02 19:52:33,028 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 19:52:35,067 - INFO - 获取到 278 个域名,共 801 个 cookie
|
||||
2026-03-02 19:52:35,069 - INFO -
|
||||
处理网站: 网站A
|
||||
2026-03-02 19:52:35,070 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 19:52:35,071 - INFO - 找到 4 个 cookie
|
||||
2026-03-02 19:52:37,975 - INFO - 开始设置 4 个 cookie
|
||||
2026-03-02 19:52:37,997 - INFO - 设置 cookie: LMKBIUSS
|
||||
2026-03-02 19:52:38,014 - INFO - 设置 cookie: edentoken
|
||||
2026-03-02 19:52:38,032 - INFO - 设置 cookie: user
|
||||
2026-03-02 19:52:38,056 - INFO - 设置 cookie: userType
|
||||
2026-03-02 19:52:53,369 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 19:52:53,618 - INFO - 已发送失败通知: 用户A - 网站A
|
||||
2026-03-02 19:52:53,621 - INFO -
|
||||
==================== 用户 用户A 处理结果汇总 ====================
|
||||
2026-03-02 19:52:53,623 - INFO - 总网站数: 1
|
||||
2026-03-02 19:52:53,628 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 19:52:53,630 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 19:52:53,632 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 19:52:54,675 - INFO - ==================== 开始处理用户: 用户B ====================
|
||||
2026-03-02 19:52:54,676 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 19:52:55,007 - INFO - 获取到 814 个域名,共 2940 个 cookie
|
||||
2026-03-02 19:52:55,009 - INFO -
|
||||
处理网站: 网站A
|
||||
2026-03-02 19:52:55,011 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 19:52:55,012 - INFO - 找到 17 个 cookie
|
||||
2026-03-02 19:52:58,102 - INFO - 开始设置 17 个 cookie
|
||||
2026-03-02 19:52:58,116 - INFO - 设置 cookie: _qimei_uuid42
|
||||
2026-03-02 19:52:58,131 - INFO - 设置 cookie: _qimei_fingerprint
|
||||
2026-03-02 19:52:58,145 - INFO - 设置 cookie: _qimei_i_3
|
||||
2026-03-02 19:52:58,161 - INFO - 设置 cookie: _qimei_h38
|
||||
2026-03-02 19:52:58,178 - INFO - 设置 cookie: merchantType
|
||||
2026-03-02 19:52:58,191 - INFO - 设置 cookie: _qimei_i_1
|
||||
2026-03-02 19:52:58,206 - INFO - 设置 cookie: JSESSIONID
|
||||
2026-03-02 19:52:58,221 - INFO - 设置 cookie: _qimei_i_1
|
||||
2026-03-02 19:52:58,236 - INFO - 设置 cookie: merchantType
|
||||
2026-03-02 19:52:58,251 - INFO - 设置 cookie: _qimei_h38
|
||||
2026-03-02 19:52:58,266 - INFO - 设置 cookie: _qimei_i_3
|
||||
2026-03-02 19:52:58,283 - INFO - 设置 cookie: _qimei_fingerprint
|
||||
2026-03-02 19:52:58,299 - INFO - 设置 cookie: _qimei_uuid42
|
||||
2026-03-02 19:52:58,316 - INFO - 设置 cookie: LMKBIUSS
|
||||
2026-03-02 19:52:58,332 - INFO - 设置 cookie: edentoken
|
||||
2026-03-02 19:52:58,348 - INFO - 设置 cookie: user
|
||||
2026-03-02 19:52:58,368 - INFO - 设置 cookie: userType
|
||||
2026-03-02 19:53:12,951 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 19:53:13,096 - INFO - 已发送失败通知: 用户B - 网站A
|
||||
2026-03-02 19:53:13,102 - INFO -
|
||||
==================== 用户 用户B 处理结果汇总 ====================
|
||||
2026-03-02 19:53:13,104 - INFO - 总网站数: 1
|
||||
2026-03-02 19:53:13,107 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 19:53:13,109 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 19:53:13,110 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 19:53:14,193 - INFO -
|
||||
==================================================
|
||||
2026-03-02 19:53:14,194 - INFO - Cookie 监控结束
|
||||
2026-03-02 19:53:14,194 - INFO - ==================================================
|
||||
2026-03-02 19:57:38,356 - INFO - ==================================================
|
||||
2026-03-02 19:57:38,357 - INFO - Cookie 监控开始
|
||||
2026-03-02 19:57:38,357 - INFO - 时间: 2026-03-02 19:57:38
|
||||
2026-03-02 19:57:38,358 - INFO - ==================================================
|
||||
2026-03-02 19:57:38,358 - INFO - ==================== 开始处理用户: 用户A ====================
|
||||
2026-03-02 19:57:38,359 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 19:57:39,474 - INFO - 获取到 278 个域名,共 801 个 cookie
|
||||
2026-03-02 19:57:39,475 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-02 19:57:50,386 - INFO - 开始导入 801 个 cookie
|
||||
2026-03-02 19:59:53,803 - INFO - Cookie 导入完成: 成功 801, 失败 0
|
||||
2026-03-02 19:59:53,805 - INFO - 成功导入 801 个 cookie
|
||||
2026-03-02 19:59:53,805 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-02 19:59:53,806 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-02 19:59:53,806 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 20:00:09,296 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 20:00:09,298 - INFO -
|
||||
==================== 用户 用户A 处理结果汇总 ====================
|
||||
2026-03-02 20:00:09,299 - INFO - 总网站数: 1
|
||||
2026-03-02 20:00:09,299 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 20:00:09,300 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 20:00:09,301 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 20:00:10,370 - INFO - ==================== 开始处理用户: 用户B ====================
|
||||
2026-03-02 20:00:10,374 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 20:00:10,940 - INFO - 获取到 814 个域名,共 2947 个 cookie
|
||||
2026-03-02 20:00:10,948 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-02 20:00:14,614 - INFO - 开始导入 2947 个 cookie
|
||||
2026-03-02 20:16:17,328 - INFO - ==================================================
|
||||
2026-03-02 20:16:17,331 - INFO - Cookie 监控开始
|
||||
2026-03-02 20:16:17,331 - INFO - 时间: 2026-03-02 20:16:17
|
||||
2026-03-02 20:16:17,332 - INFO - ==================================================
|
||||
2026-03-02 20:16:17,332 - INFO - ==================== 开始处理用户: 用户A ====================
|
||||
2026-03-02 20:16:17,332 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 20:16:19,422 - INFO - 获取到 278 个域名,共 801 个 cookie
|
||||
2026-03-02 20:16:19,423 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-02 20:16:33,797 - INFO - 开始导入 801 个 cookie
|
||||
2026-03-02 20:30:29,314 - INFO - Cookie 导入完成: 成功 801, 失败 0
|
||||
2026-03-02 20:30:29,347 - INFO - 成功导入 801 个 cookie
|
||||
2026-03-02 20:30:29,349 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-02 20:30:29,351 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-02 20:30:29,352 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 20:31:15,938 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 20:31:16,156 - INFO -
|
||||
==================== 用户 用户A 处理结果汇总 ====================
|
||||
2026-03-02 20:31:16,174 - INFO - 总网站数: 1
|
||||
2026-03-02 20:31:16,188 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 20:31:16,195 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 20:31:16,204 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 20:31:17,772 - INFO - ==================== 开始处理用户: 用户B ====================
|
||||
2026-03-02 20:31:17,832 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 20:31:19,351 - INFO - 获取到 814 个域名,共 2946 个 cookie
|
||||
2026-03-02 20:31:19,469 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-02 20:31:40,232 - INFO - 开始导入 2946 个 cookie
|
||||
2026-03-02 23:12:19,893 - INFO - ==================================================
|
||||
2026-03-02 23:12:19,894 - INFO - Cookie 监控开始
|
||||
2026-03-02 23:12:19,894 - INFO - 时间: 2026-03-02 23:12:19
|
||||
2026-03-02 23:12:19,894 - INFO - ==================================================
|
||||
2026-03-02 23:12:19,895 - INFO - ==================== 开始处理用户: 用户A ====================
|
||||
2026-03-02 23:12:19,895 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 23:12:21,973 - INFO - 获取到 278 个域名,共 801 个 cookie
|
||||
2026-03-02 23:12:21,973 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-02 23:12:26,570 - INFO - 开始导入 801 个 cookie
|
||||
2026-03-02 23:14:33,586 - INFO - Cookie 导入完成: 成功 801, 失败 0
|
||||
2026-03-02 23:14:33,587 - INFO - 成功导入 801 个 cookie
|
||||
2026-03-02 23:14:33,587 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-02 23:14:33,588 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-02 23:14:33,588 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 23:14:52,444 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 23:14:52,659 - INFO - 已发送失败通知: 用户A - 网站A
|
||||
2026-03-02 23:14:52,660 - INFO -
|
||||
==================== 用户 用户A 处理结果汇总 ====================
|
||||
2026-03-02 23:14:52,661 - INFO - 总网站数: 1
|
||||
2026-03-02 23:14:52,661 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 23:14:52,662 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 23:14:52,662 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 23:14:53,782 - INFO - ==================== 开始处理用户: 用户B ====================
|
||||
2026-03-02 23:14:53,782 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 23:14:54,433 - INFO - 获取到 814 个域名,共 2950 个 cookie
|
||||
2026-03-02 23:14:54,433 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-02 23:14:58,023 - INFO - 开始导入 2950 个 cookie
|
||||
2026-03-02 23:22:13,589 - INFO - Cookie 导入完成: 成功 2949, 失败 1
|
||||
2026-03-02 23:22:13,690 - WARNING - 部分 cookie 导入失败
|
||||
2026-03-02 23:22:13,701 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-02 23:22:13,704 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-02 23:22:13,706 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 23:22:13,709 - ERROR - 验证登录状态失败:
|
||||
与页面的连接已断开。
|
||||
版本: 4.1.0.18
|
||||
2026-03-02 23:22:13,710 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 23:22:13,720 - INFO -
|
||||
==================== 用户 用户B 处理结果汇总 ====================
|
||||
2026-03-02 23:22:13,732 - INFO - 总网站数: 1
|
||||
2026-03-02 23:22:13,748 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 23:22:13,755 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 23:22:13,759 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 23:22:14,205 - INFO -
|
||||
==================================================
|
||||
2026-03-02 23:22:14,206 - INFO - Cookie 监控结束
|
||||
2026-03-02 23:22:14,206 - INFO - ==================================================
|
||||
2026-03-02 23:24:45,469 - INFO - ==================================================
|
||||
2026-03-02 23:24:45,470 - INFO - Cookie 监控开始
|
||||
2026-03-02 23:24:45,470 - INFO - 时间: 2026-03-02 23:24:45
|
||||
2026-03-02 23:24:45,471 - INFO - ==================================================
|
||||
2026-03-02 23:24:45,471 - INFO - ==================== 开始处理用户: 用户A ====================
|
||||
2026-03-02 23:24:45,472 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 23:24:51,705 - INFO - 获取到 278 个域名,共 801 个 cookie
|
||||
2026-03-02 23:24:51,705 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-02 23:25:00,772 - INFO - 开始导入 801 个 cookie
|
||||
2026-03-02 23:26:59,941 - INFO - Cookie 导入完成: 成功 801, 失败 0
|
||||
2026-03-02 23:26:59,942 - INFO - 成功导入 801 个 cookie
|
||||
2026-03-02 23:26:59,942 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-02 23:26:59,943 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-02 23:26:59,943 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 23:27:14,779 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 23:27:14,783 - INFO -
|
||||
==================== 用户 用户A 处理结果汇总 ====================
|
||||
2026-03-02 23:27:14,785 - INFO - 总网站数: 1
|
||||
2026-03-02 23:27:14,786 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 23:27:14,787 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 23:27:14,788 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 23:27:15,886 - INFO - ==================== 开始处理用户: 用户B ====================
|
||||
2026-03-02 23:27:15,889 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-02 23:27:16,629 - INFO - 获取到 814 个域名,共 2948 个 cookie
|
||||
2026-03-02 23:27:16,631 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-02 23:27:18,380 - INFO - 开始导入 2948 个 cookie
|
||||
2026-03-02 23:31:37,244 - INFO - Cookie 导入完成: 成功 2947, 失败 1
|
||||
2026-03-02 23:31:37,246 - WARNING - 部分 cookie 导入失败
|
||||
2026-03-02 23:31:37,247 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-02 23:31:37,248 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-02 23:31:37,248 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-02 23:31:37,254 - ERROR - 验证登录状态失败:
|
||||
与页面的连接已断开。
|
||||
版本: 4.1.0.18
|
||||
2026-03-02 23:31:37,256 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 23:31:37,260 - INFO -
|
||||
==================== 用户 用户B 处理结果汇总 ====================
|
||||
2026-03-02 23:31:37,263 - INFO - 总网站数: 1
|
||||
2026-03-02 23:31:37,264 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-02 23:31:37,264 - INFO -
|
||||
失败详情:
|
||||
2026-03-02 23:31:37,265 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-02 23:31:38,233 - INFO -
|
||||
==================================================
|
||||
2026-03-02 23:31:38,235 - INFO - Cookie 监控结束
|
||||
2026-03-02 23:31:38,236 - INFO - ==================================================
|
||||
2026-03-03 08:29:26,844 - INFO - ==================================================
|
||||
2026-03-03 08:29:26,845 - INFO - Cookie 监控开始
|
||||
2026-03-03 08:29:26,845 - INFO - 时间: 2026-03-03 08:29:26
|
||||
2026-03-03 08:29:26,846 - INFO - ==================================================
|
||||
2026-03-03 08:29:26,846 - INFO - ==================== 开始处理用户: 用户A ====================
|
||||
2026-03-03 08:29:26,846 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-03 08:29:33,515 - INFO - 获取到 278 个域名,共 801 个 cookie
|
||||
2026-03-03 08:29:33,515 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-03 08:29:34,818 - INFO - 开始导入 801 个 cookie
|
||||
2026-03-03 08:34:05,206 - INFO - Cookie 导入完成: 成功 800, 失败 1
|
||||
2026-03-03 08:34:05,227 - WARNING - 部分 cookie 导入失败
|
||||
2026-03-03 08:34:05,228 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-03 08:34:05,234 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-03 08:34:05,236 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-03 08:34:05,239 - ERROR - 验证登录状态失败:
|
||||
与页面的连接已断开。
|
||||
版本: 4.1.0.18
|
||||
2026-03-03 08:34:05,240 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-03 08:34:05,255 - INFO -
|
||||
==================== 用户 用户A 处理结果汇总 ====================
|
||||
2026-03-03 08:34:05,259 - INFO - 总网站数: 1
|
||||
2026-03-03 08:34:05,261 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-03 08:34:05,270 - INFO -
|
||||
失败详情:
|
||||
2026-03-03 08:34:05,271 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-03 08:34:05,974 - INFO - ==================== 开始处理用户: 用户B ====================
|
||||
2026-03-03 08:34:05,976 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-03 08:34:06,647 - INFO - 获取到 813 个域名,共 2940 个 cookie
|
||||
2026-03-03 08:34:06,648 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-03 08:34:09,040 - INFO - 开始导入 2940 个 cookie
|
||||
2026-03-03 08:47:28,987 - INFO - Cookie 导入完成: 成功 2939, 失败 1
|
||||
2026-03-03 08:47:29,120 - WARNING - 部分 cookie 导入失败
|
||||
2026-03-03 08:47:29,235 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-03 08:47:29,271 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-03 08:47:29,313 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-03 08:47:29,334 - ERROR - 验证登录状态失败:
|
||||
与页面的连接已断开。
|
||||
版本: 4.1.0.18
|
||||
2026-03-03 08:47:29,359 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-03 08:47:30,226 - INFO - 已发送失败通知: 用户B - 网站A
|
||||
2026-03-03 08:47:30,227 - INFO -
|
||||
==================== 用户 用户B 处理结果汇总 ====================
|
||||
2026-03-03 08:47:30,229 - INFO - 总网站数: 1
|
||||
2026-03-03 08:47:30,230 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-03 08:47:30,231 - INFO -
|
||||
失败详情:
|
||||
2026-03-03 08:47:30,234 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-03 08:47:30,235 - INFO -
|
||||
==================================================
|
||||
2026-03-03 08:47:30,236 - INFO - Cookie 监控结束
|
||||
2026-03-03 08:47:30,237 - INFO - ==================================================
|
||||
2026-03-03 08:47:50,074 - INFO - ==================================================
|
||||
2026-03-03 08:47:50,075 - INFO - Cookie 监控开始
|
||||
2026-03-03 08:47:50,076 - INFO - 时间: 2026-03-03 08:47:50
|
||||
2026-03-03 08:47:50,076 - INFO - ==================================================
|
||||
2026-03-03 08:47:50,077 - INFO - ==================== 开始处理用户: 用户A ====================
|
||||
2026-03-03 08:47:50,077 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-03 08:47:56,370 - INFO - 获取到 278 个域名,共 801 个 cookie
|
||||
2026-03-03 08:47:56,371 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-03 08:48:03,542 - INFO - 开始导入 801 个 cookie
|
||||
2026-03-03 08:49:19,995 - INFO - Cookie 导入完成: 成功 800, 失败 1
|
||||
2026-03-03 08:49:19,995 - WARNING - 部分 cookie 导入失败
|
||||
2026-03-03 08:49:19,996 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-03 08:49:19,996 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-03 08:49:19,997 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-03 08:49:20,040 - ERROR - 验证登录状态失败:
|
||||
与页面的连接已断开。
|
||||
版本: 4.1.0.18
|
||||
2026-03-03 08:49:20,042 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-03 08:49:22,005 - INFO - 已发送失败通知: 用户A - 网站A
|
||||
2026-03-03 08:49:22,007 - INFO -
|
||||
==================== 用户 用户A 处理结果汇总 ====================
|
||||
2026-03-03 08:49:22,007 - INFO - 总网站数: 1
|
||||
2026-03-03 08:49:22,008 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-03 08:49:22,008 - INFO -
|
||||
失败详情:
|
||||
2026-03-03 08:49:22,009 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-03 08:49:22,009 - INFO - ==================== 开始处理用户: 用户B ====================
|
||||
2026-03-03 08:49:22,009 - INFO - 步骤1: 从 Cookie Cloud 获取所有 cookies
|
||||
2026-03-03 08:49:22,809 - INFO - 获取到 813 个域名,共 2940 个 cookie
|
||||
2026-03-03 08:49:22,819 - INFO - 步骤2: 一次性导入所有 cookies 到浏览器
|
||||
2026-03-03 08:49:30,875 - INFO - 开始导入 2940 个 cookie
|
||||
2026-03-03 08:49:43,208 - INFO - Cookie 导入完成: 成功 2939, 失败 1
|
||||
2026-03-03 08:49:43,209 - WARNING - 部分 cookie 导入失败
|
||||
2026-03-03 08:49:43,209 - INFO - 步骤3: 依次验证各网站登录状态
|
||||
2026-03-03 08:49:43,209 - INFO -
|
||||
验证网站: 网站A
|
||||
2026-03-03 08:49:43,210 - INFO - URL: https://lmkbi.95155.com/bi-system/#/carUnpetrifiedComAll
|
||||
2026-03-03 08:49:43,212 - ERROR - 验证登录状态失败:
|
||||
与页面的连接已断开。
|
||||
版本: 4.1.0.18
|
||||
2026-03-03 08:49:43,214 - WARNING - ✗ 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-03 08:49:43,219 - INFO -
|
||||
==================== 用户 用户B 处理结果汇总 ====================
|
||||
2026-03-03 08:49:43,223 - INFO - 总网站数: 1
|
||||
2026-03-03 08:49:43,227 - INFO - 成功: 0, 失败: 1
|
||||
2026-03-03 08:49:43,236 - INFO -
|
||||
失败详情:
|
||||
2026-03-03 08:49:43,236 - INFO - - 网站A: 登录状态验证失败(cookies可能已过期或选择器配置错误)
|
||||
2026-03-03 08:49:43,691 - INFO -
|
||||
==================================================
|
||||
2026-03-03 08:49:43,692 - INFO - Cookie 监控结束
|
||||
2026-03-03 08:49:43,692 - INFO - ==================================================
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
"""
|
||||
MoviePilot Cookie功能示例程序
|
||||
从CookieCloud下载数据并注入浏览器访问网站
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
import hashlib
|
||||
import base64
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from dataclasses import dataclass
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
|
||||
@dataclass
|
||||
class CookieCloudConfig:
|
||||
"""CookieCloud配置"""
|
||||
server: str
|
||||
username: str
|
||||
password: str
|
||||
timeout: int = 30
|
||||
|
||||
|
||||
class CookieCloudDownloader:
|
||||
"""从CookieCloud服务器下载cookie数据"""
|
||||
|
||||
def __init__(self, config: CookieCloudConfig):
|
||||
self.config = config
|
||||
|
||||
def _get_crypt_key(self) -> bytes:
|
||||
combined_string = f"{self.config.username}-{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:
|
||||
assert len(salt) == 8, len(salt)
|
||||
data += salt
|
||||
key = hashlib.md5(data).digest()
|
||||
final_key = key
|
||||
while len(final_key) < output:
|
||||
key = hashlib.md5(key + data).digest()
|
||||
final_key += key
|
||||
return final_key[:output]
|
||||
|
||||
def _decrypt(self, encrypted: str, passphrase: bytes) -> bytes:
|
||||
encrypted_bytes = base64.b64decode(encrypted)
|
||||
assert encrypted_bytes.startswith(b"Salted__"), "Invalid encrypted data format"
|
||||
salt = encrypted_bytes[8:16]
|
||||
key_iv = self._bytes_to_key(passphrase, salt, 32 + 16)
|
||||
key = key_iv[:32]
|
||||
iv = key_iv[32:]
|
||||
aes = AES.new(key, AES.MODE_CBC, iv)
|
||||
decrypted_padded = aes.decrypt(encrypted_bytes[16:])
|
||||
padding_length = decrypted_padded[-1]
|
||||
if isinstance(padding_length, str):
|
||||
padding_length = ord(padding_length)
|
||||
return decrypted_padded[:-padding_length]
|
||||
|
||||
def _get_url_domain(self, domain: str) -> str:
|
||||
if not domain:
|
||||
return ""
|
||||
domain = domain.lstrip('.')
|
||||
if ":" in domain:
|
||||
domain = domain.split(":")[0]
|
||||
parts = domain.split(".")
|
||||
if all(part.isdigit() for part in parts):
|
||||
return domain
|
||||
if len(parts) >= 2:
|
||||
return ".".join(parts[-2:])
|
||||
return domain
|
||||
|
||||
def download_all(self) -> Tuple[Optional[Dict], str]:
|
||||
"""下载所有cookie和local storage数据"""
|
||||
try:
|
||||
url = f"{self.config.server}/get/{self.config.username}"
|
||||
request = urllib.request.Request(
|
||||
url,
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'MoviePilot-Cookie-Client/1.0'
|
||||
},
|
||||
method='GET'
|
||||
)
|
||||
|
||||
response = urllib.request.urlopen(request, timeout=self.config.timeout)
|
||||
|
||||
if response.status != 200:
|
||||
return None, f"服务器返回错误状态码: {response.status}"
|
||||
|
||||
result = json.loads(response.read().decode('utf-8'))
|
||||
|
||||
if not result:
|
||||
return None, "服务器返回数据为空"
|
||||
|
||||
encrypted = result.get("encrypted")
|
||||
if not encrypted:
|
||||
return None, "未获取到cookie密文"
|
||||
|
||||
crypt_key = self._get_crypt_key()
|
||||
try:
|
||||
decrypted_data = self._decrypt(encrypted, crypt_key)
|
||||
result = json.loads(decrypted_data.decode("utf-8"))
|
||||
except Exception as e:
|
||||
return None, f"cookie解密失败: {str(e)}"
|
||||
|
||||
if not result:
|
||||
return None, "cookie解密为空"
|
||||
|
||||
cookie_data = result.get("cookie_data", {})
|
||||
local_storage_data = result.get("local_storage_data", {})
|
||||
|
||||
total_cookies = sum(len(v) for v in cookie_data.values())
|
||||
total_ls = sum(len(v) for v in local_storage_data.values())
|
||||
print(f" 下载完成: {len(cookie_data)} 个域名的Cookie({total_cookies}个), {len(local_storage_data)} 个域名的Local Storage({total_ls}个)")
|
||||
|
||||
return {"cookies": cookie_data, "local_storage": local_storage_data}, ""
|
||||
|
||||
except urllib.error.HTTPError as e:
|
||||
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:
|
||||
return None, f"下载失败: {str(e)}"
|
||||
|
||||
|
||||
class BrowserController:
|
||||
"""使用Playwright控制浏览器"""
|
||||
|
||||
def __init__(self, headless: bool = False, use_edge: bool = False):
|
||||
self.headless = headless
|
||||
self.use_edge = use_edge
|
||||
self.browser = None
|
||||
self.context = None
|
||||
self.page = None
|
||||
self.playwright = None
|
||||
|
||||
def start(self) -> bool:
|
||||
try:
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
self.playwright = sync_playwright().start()
|
||||
|
||||
if self.use_edge:
|
||||
self.browser = self.playwright.chromium.launch(
|
||||
channel="msedge",
|
||||
headless=self.headless,
|
||||
args=['--disable-blink-features=AutomationControlled', '--disable-dev-shm-usage', '--no-sandbox']
|
||||
)
|
||||
else:
|
||||
self.browser = self.playwright.chromium.launch(
|
||||
headless=self.headless,
|
||||
args=['--disable-blink-features=AutomationControlled', '--disable-dev-shm-usage', '--no-sandbox']
|
||||
)
|
||||
|
||||
self.context = self.browser.new_context(
|
||||
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
||||
)
|
||||
|
||||
self.page = self.context.new_page()
|
||||
|
||||
print(f"✓ 浏览器启动成功 ({'Edge' if self.use_edge else 'Chromium'})")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 浏览器启动失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def inject_cookies(self, cookies: Dict):
|
||||
"""注入cookie到浏览器"""
|
||||
if not self.context or not cookies:
|
||||
return
|
||||
|
||||
try:
|
||||
playwright_cookies = []
|
||||
for domain_key, cookie_list in cookies.items():
|
||||
for cookie in cookie_list:
|
||||
cookie_domain = cookie.get("domain", "").lstrip('.')
|
||||
if not cookie_domain:
|
||||
cookie_domain = domain_key.lstrip('.')
|
||||
|
||||
pw_cookie = {
|
||||
"name": cookie.get("name", ""),
|
||||
"value": cookie.get("value", ""),
|
||||
"domain": cookie_domain,
|
||||
"path": cookie.get("path", "/"),
|
||||
}
|
||||
if cookie.get("secure"):
|
||||
pw_cookie["secure"] = True
|
||||
if cookie.get("httpOnly"):
|
||||
pw_cookie["httpOnly"] = True
|
||||
if cookie.get("expirationDate"):
|
||||
pw_cookie["expires"] = int(cookie.get("expirationDate"))
|
||||
playwright_cookies.append(pw_cookie)
|
||||
|
||||
self.context.add_cookies(playwright_cookies)
|
||||
print(f"✓ Cookie注入成功 ({len(playwright_cookies)} 个)")
|
||||
except Exception as e:
|
||||
print(f"✗ Cookie注入失败: {str(e)}")
|
||||
|
||||
def navigate(self, url: str, wait_time: int = 5, timeout: int = 60) -> bool:
|
||||
if not self.page:
|
||||
return False
|
||||
|
||||
try:
|
||||
print(f"正在访问: {url}")
|
||||
|
||||
self.page.goto(url, timeout=timeout * 1000)
|
||||
|
||||
try:
|
||||
self.page.wait_for_load_state("networkidle", timeout=timeout * 1000)
|
||||
except Exception:
|
||||
print(" networkidle超时,尝试load状态...")
|
||||
try:
|
||||
self.page.wait_for_load_state("load", timeout=30000)
|
||||
except Exception:
|
||||
print(" load超时,尝试domcontentloaded状态...")
|
||||
self.page.wait_for_load_state("domcontentloaded", timeout=10000)
|
||||
|
||||
time.sleep(wait_time)
|
||||
|
||||
print(f"✓ 页面加载完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 页面访问失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def check_login_status(self, login_indicator: str) -> bool:
|
||||
if not self.page:
|
||||
return False
|
||||
|
||||
try:
|
||||
html_content = self.page.content()
|
||||
|
||||
if login_indicator:
|
||||
if login_indicator in html_content:
|
||||
print(f"✓ 检测到登录指示器: {login_indicator}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 未检测到登录指示器: {login_indicator}")
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 登录状态检查失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def take_screenshot(self, filepath: str):
|
||||
if not self.page:
|
||||
return
|
||||
|
||||
try:
|
||||
self.page.screenshot(path=filepath)
|
||||
print(f"✓ 截图已保存: {filepath}")
|
||||
except Exception as e:
|
||||
print(f"✗ 截图失败: {str(e)}")
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
if self.browser:
|
||||
self.browser.close()
|
||||
|
||||
if self.playwright:
|
||||
self.playwright.stop()
|
||||
|
||||
print("✓ 浏览器已关闭")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 关闭浏览器失败: {str(e)}")
|
||||
|
||||
|
||||
class CookieDemo:
|
||||
"""Cookie功能示例"""
|
||||
|
||||
def __init__(self, cookiecloud_config: CookieCloudConfig):
|
||||
self.downloader = CookieCloudDownloader(cookiecloud_config)
|
||||
self.browser = None
|
||||
|
||||
def run_sites(self, sites: list, headless: bool = False, use_edge: bool = False):
|
||||
"""下载一次数据,依次访问多个网站"""
|
||||
# 下载数据
|
||||
print("=" * 60)
|
||||
print("从CookieCloud下载数据")
|
||||
print("=" * 60)
|
||||
|
||||
data, error = self.downloader.download_all()
|
||||
|
||||
if error:
|
||||
print(f"✗ 数据下载失败: {error}")
|
||||
return
|
||||
|
||||
# 启动浏览器
|
||||
print(f"\n启动浏览器")
|
||||
print("-" * 60)
|
||||
|
||||
self.browser = BrowserController(headless=headless, use_edge=use_edge)
|
||||
|
||||
if not self.browser.start():
|
||||
return
|
||||
|
||||
# 注入所有cookie
|
||||
if data and data.get("cookies"):
|
||||
print(f"\n注入所有cookie到浏览器")
|
||||
print("-" * 60)
|
||||
self.browser.inject_cookies(data["cookies"])
|
||||
|
||||
# 依次访问每个网站
|
||||
for idx, site in enumerate(sites, 1):
|
||||
print(f"\n\n{'=' * 60}")
|
||||
print(f"访问网站 {idx}/{len(sites)}: {site['name']}")
|
||||
print(f"URL: {site['url']}")
|
||||
print("=" * 60)
|
||||
|
||||
if not self.browser.navigate(site['url']):
|
||||
print(f"✗ 页面访问失败")
|
||||
continue
|
||||
|
||||
# 验证登录状态
|
||||
from urllib.parse import urlparse
|
||||
parsed = urlparse(site['url'])
|
||||
target_domain = parsed.netloc
|
||||
|
||||
login_indicator = site.get('login_indicator')
|
||||
is_logged_in = self.browser.check_login_status(login_indicator)
|
||||
|
||||
if is_logged_in:
|
||||
print("✓ Cookie验证成功:已登录状态")
|
||||
else:
|
||||
print("⚠ Cookie验证失败:未检测到登录状态")
|
||||
|
||||
# 截图
|
||||
screenshot_path = f"{target_domain.replace('.', '_').replace(':', '_')}_screenshot.png"
|
||||
self.browser.take_screenshot(screenshot_path)
|
||||
|
||||
if idx < len(sites):
|
||||
print("\n等待3秒后继续下一个网站...")
|
||||
time.sleep(3)
|
||||
|
||||
# 关闭浏览器
|
||||
print(f"\n关闭浏览器")
|
||||
print("-" * 60)
|
||||
self.browser.close()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("所有网站访问完成")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
def main():
|
||||
# 配置CookieCloud
|
||||
config = CookieCloudConfig(
|
||||
server="http://192.168.1.100:3000/cookiecloud",
|
||||
username="qyZpTrgiP5mVwiRZwfBhjz",
|
||||
password="iGn1B4FnWftp3oj4Ko3jxA",
|
||||
timeout=30
|
||||
)
|
||||
|
||||
# 创建示例程序
|
||||
demo = CookieDemo(config)
|
||||
|
||||
# 测试网站列表
|
||||
test_sites = [
|
||||
{
|
||||
"url": "https://lmkbi.95155.com/bi-system/#/login",
|
||||
"name": "BI系统",
|
||||
"login_indicator": "彭峰"
|
||||
},
|
||||
{
|
||||
"url": "http://192.168.1.100:3000/#/subscribe/movie",
|
||||
"name": "MoviePilot订阅",
|
||||
"login_indicator": "搜索"
|
||||
},
|
||||
{
|
||||
"url": "http://192.168.1.102:8418/bwadmin/QueryCarInfo2",
|
||||
"name": "QueryCarInfo2",
|
||||
"login_indicator": "工单管理"
|
||||
}
|
||||
]
|
||||
|
||||
# 下载一次数据,依次访问所有网站
|
||||
demo.run_sites(
|
||||
sites=test_sites,
|
||||
headless=False,
|
||||
use_edge=True
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"用户A_网站A": 2
|
||||
"用户A_网站A": 0,
|
||||
"用户B_网站A": 1
|
||||
}
|
||||
Reference in New Issue
Block a user