This commit is contained in:
2026-03-03 08:53:50 +08:00
parent f8a14a3e2e
commit 0fbbbce2ee
4 changed files with 390 additions and 274 deletions
+106 -145
View File
@@ -1,7 +1,5 @@
"""Cookie 监控主程序"""
import json
import os
import logging
from datetime import datetime
from cookie_cloud import CookieCloud
from notifier import IYUUNotifier, FailureTracker
@@ -15,237 +13,200 @@ class CookieMonitor:
"""Cookie 监控器"""
def __init__(self, config_file: str = "config.json"):
"""
初始化 Cookie 监控器
Args:
config_file: 配置文件路径
"""
self.config_file = config_file
self.config = self._load_config()
self.cookie_manager = CookieManager("cookies.json")
self.failure_tracker = FailureTracker("state.json")
def _load_config(self) -> dict:
"""加载配置文件"""
try:
with open(self.config_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"加载配置文件失败: {e}")
logger.error(f"加载配置文件失败: {e}")
return {}
def _log(self, message: str):
"""记录日志"""
logger.info(message)
def _get_domain_from_url(self, url: str) -> str:
"""从 URL 中提取域名"""
from urllib.parse import urlparse
parsed = urlparse(url)
return parsed.netloc
return urlparse(url).netloc
def process_user(self, user_config: dict):
"""
处理单个用户的所有网站
Args:
user_config: 用户配置
处理单个用户:一次性导入所有cookies,然后验证各网站登录状态
"""
user_name = user_config.get('name', '未知用户')
self._log(f"开始处理用户: {user_name}")
logger.info(f"{'='*20} 开始处理用户: {user_name} {'='*20}")
# 获取用户配置
cookie_cloud_config = user_config.get('cookie_cloud', {})
notification_config = user_config.get('notification', {})
browser_config = user_config.get('browser', {})
websites = user_config.get('websites', [])
# 初始化爱语飞飞通知
if not websites:
logger.info(f"用户 {user_name} 没有配置网站,跳过")
return
iyuu_token = notification_config.get('iyuu_token', '')
max_fail_count = notification_config.get('max_fail_count', 3)
notifier = IYUUNotifier(iyuu_token) if iyuu_token else None
# 初始化 Cookie Cloud
cookie_cloud = CookieCloud(
api_url=cookie_cloud_config.get('api_url', ''),
uuid=cookie_cloud_config.get('uuid', ''),
password=cookie_cloud_config.get('password', '')
)
# 初始化浏览器
logger.info(f"步骤1: 从 Cookie Cloud 获取所有 cookies")
all_cookies = cookie_cloud.get_cookies()
total_domains = len(all_cookies)
total_cookies = sum(len(c) for c in all_cookies.values())
logger.info(f"获取到 {total_domains} 个域名,共 {total_cookies} 个 cookie")
browser = BrowserLogin(
browser_type=browser_config.get('type', 'edge'),
headless=browser_config.get('headless', False)
)
results = []
try:
# 处理每个网站
logger.info(f"步骤2: 一次性导入所有 cookies 到浏览器")
all_cookies_list = []
for cookies in all_cookies.values():
all_cookies_list.extend(cookies)
import_success = browser.import_all_cookies(all_cookies_list)
if import_success:
logger.info(f"成功导入 {len(all_cookies_list)} 个 cookie")
else:
logger.warning(f"部分 cookie 导入失败")
logger.info(f"步骤3: 依次验证各网站登录状态")
for website in websites:
self.process_website(
result = self.process_website(
user_name=user_name,
website_config=website,
cookie_cloud=cookie_cloud,
notifier=notifier,
max_fail_count=max_fail_count,
browser=browser
)
finally:
# 关闭浏览器
browser.close()
results.append(result)
self._log(f"用户 {user_name} 处理完成")
if not result['success']:
self.failure_tracker.check_and_notify(
user_name=user_name,
website_name=result['name'],
max_fail_count=max_fail_count,
notifier=notifier,
error_msg=result['error']
)
else:
self.failure_tracker.reset_fail_count(user_name, result['name'])
self._print_summary(user_name, results)
finally:
browser.close()
def process_website(
self,
user_name: str,
website_config: dict,
cookie_cloud: CookieCloud,
notifier: IYUUNotifier,
max_fail_count: int,
browser: BrowserLogin
):
) -> dict:
"""
处理单个网站
Args:
user_name: 用户名
website_config: 网站配置
cookie_cloud: Cookie Cloud 客户端
notifier: 爱语飞飞通知客户端
max_fail_count: 最大失败次数
browser: 浏览器客户端
验证网站登录状态(cookies已预先导入)
Returns:
dict: {'name': 网站名, 'url': URL, 'success': 是否成功, 'error': 错误信息}
"""
website_name = website_config.get('name', '未知网站')
url = website_config.get('url', '')
check_selector = website_config.get('login_check_selector', '')
success_text = website_config.get('success_text', '')
self._log(f"处理网站: {user_name} - {website_name}")
logger.info(f"\n验证网站: {website_name}")
logger.info(f" URL: {url}")
# 获取域名
domain = self._get_domain_from_url(url)
result = {
'name': website_name,
'url': url,
'success': False,
'error': ''
}
if not url:
result['error'] = 'URL 未配置'
logger.error(f" 失败: {result['error']}")
return result
try:
# 第一步:使用本地 cookie 登录
self._log(f"尝试使用本地 cookie 登录: {website_name}")
local_cookies = self.cookie_manager.get_cookies(user_name, website_name)
if local_cookies:
login_success = browser.login_with_cookies(
url=url,
cookies=local_cookies,
check_selector=check_selector,
success_text=success_text
)
if login_success:
self._log(f"本地 cookie 登录成功: {website_name}")
# 刷新页面并保存新的 cookie
new_cookies = browser.refresh_and_save_cookies(url)
if new_cookies:
self.cookie_manager.save_cookies(user_name, website_name, new_cookies)
self._log(f"已更新 cookie: {website_name}")
# 重置失败计数
self.failure_tracker.reset_fail_count(user_name, website_name)
return
self._log(f"本地 cookie 登录失败: {website_name}")
# 第二步:从 Cookie Cloud 获取 cookie 并重试
self._log(f"从 Cookie Cloud 获取 cookie: {website_name}")
cloud_cookies = cookie_cloud.get_cookies_for_domain(domain)
if cloud_cookies:
login_success = browser.login_with_cookies(
url=url,
cookies=cloud_cookies,
check_selector=check_selector,
success_text=success_text
)
if login_success:
self._log(f"Cookie Cloud 登录成功: {website_name}")
# 刷新页面并保存新的 cookie
new_cookies = browser.refresh_and_save_cookies(url)
if new_cookies:
self.cookie_manager.save_cookies(user_name, website_name, new_cookies)
self._log(f"已更新 cookie: {website_name}")
# 重置失败计数
self.failure_tracker.reset_fail_count(user_name, website_name)
return
self._log(f"Cookie Cloud 登录失败: {website_name}")
else:
self._log(f"未从 Cookie Cloud 获取到 cookie: {website_name}")
# 第三步:登录失败,增加失败计数并检查是否需要通知
self._log(f"登录失败: {website_name}")
error_msg = f"{website_name} 登录失败,请检查 Cookie Cloud 是否有最新的 cookie"
should_stop = self.failure_tracker.check_and_notify(
user_name=user_name,
website_name=website_name,
max_fail_count=max_fail_count,
notifier=notifier,
error_msg=error_msg
login_success = browser.verify_login(
url=url,
check_selector=check_selector,
success_text=success_text
)
if should_stop:
self._log(f"已达到最大失败次数,已发送通知并重置计数: {website_name}")
if login_success:
result['success'] = True
logger.info(f" ✓ 登录验证成功")
new_cookies = browser.refresh_and_save_cookies(url)
if new_cookies:
self.cookie_manager.save_cookies(user_name, website_name, new_cookies)
logger.info(f" 已保存 {len(new_cookies)} 个新 cookie")
else:
fail_count = self.failure_tracker.get_fail_count(user_name, website_name)
self._log(f"当前失败次数: {fail_count}/{max_fail_count}")
result['error'] = '登录状态验证失败(cookies可能已过期或选择器配置错误)'
logger.warning(f"{result['error']}")
except Exception as e:
self._log(f"处理网站 {website_name} 时发生异常: {e}")
error_msg = f"{website_name} 处理异常: {str(e)}"
should_stop = self.failure_tracker.check_and_notify(
user_name=user_name,
website_name=website_name,
max_fail_count=max_fail_count,
notifier=notifier,
error_msg=error_msg
)
result['error'] = f'处理异常: {str(e)}'
logger.error(f" 异常: {e}")
return result
def _print_summary(self, user_name: str, results: list):
"""打印处理结果汇总"""
success_count = sum(1 for r in results if r['success'])
fail_count = len(results) - success_count
logger.info(f"\n{'='*20} 用户 {user_name} 处理结果汇总 {'='*20}")
logger.info(f"总网站数: {len(results)}")
logger.info(f"成功: {success_count}, 失败: {fail_count}")
if fail_count > 0:
logger.info("\n失败详情:")
for r in results:
if not r['success']:
logger.info(f" - {r['name']}: {r['error']}")
def run(self):
"""运行监控"""
self._log("===== Cookie 监控开始 =====")
logger.info("="*50)
logger.info("Cookie 监控开始")
logger.info(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
logger.info("="*50)
users = self.config.get('users', [])
if not users:
self._log("未找到用户配置")
logger.error("未找到用户配置")
return
success_count = 0
fail_count = 0
for user_config in users:
try:
self.process_user(user_config)
success_count += 1
except Exception as e:
self._log(f"处理用户失败: {e}")
fail_count += 1
logger.error(f"处理用户失败: {e}")
self._log(f"===== Cookie 监控结束 =====")
self._log(f"成功处理: {success_count} 个用户,失败: {fail_count} 个用户")
logger.info("\n" + "="*50)
logger.info("Cookie 监控结束")
logger.info("="*50)
def main():
"""主函数"""
# 配置日志
setup_logging()
monitor = CookieMonitor()
monitor.run()
if __name__ == "__main__":
main()
main()