"""Cookie 监控主程序""" import time from datetime import datetime from urllib.parse import urlparse from cookie_cloud import CookieCloud from notification import create_notification_manager from config_manager import ConfigManager, CookieDataManager from browser_manager import BrowserManager from logger import get_logger logger = get_logger(__name__) NOTIFY_TIMES = [6, 21] STATE_FILE = "notify_state.json" def load_notify_state() -> dict: """加载通知状态""" import json import os if os.path.exists(STATE_FILE): try: with open(STATE_FILE, 'r', encoding='utf-8') as f: return json.load(f) except: pass return {} def save_notify_state(state: dict): """保存通知状态""" import json try: with open(STATE_FILE, 'w', encoding='utf-8') as f: json.dump(state, f, indent=2, ensure_ascii=False) except Exception as e: logger.error(f"保存通知状态失败: {e}") def should_send_notification(user_name: str) -> bool: """判断是否应该发送通知""" # 去掉时间限制,每次都发送通知 return True def mark_notification_sent(user_name: str): """标记通知已发送""" now = datetime.now() state = load_notify_state() if user_name not in state: state[user_name] = {} state[user_name]['date'] = now.strftime('%Y-%m-%d') state[user_name]['hour'] = now.hour save_notify_state(state) class CookieMonitor: """Cookie 监控器""" def __init__(self, config_file: str = "config.json"): """ 初始化监控器 Args: config_file: 配置文件路径 """ self.config_manager = ConfigManager(config_file) self.cookie_data_manager = CookieDataManager() self.all_results = [] def process_user(self, user_config: dict): """ 处理单个用户:依次验证各网站登录状态 Args: user_config: 用户配置字典 """ user_name = user_config.get('name', '未知用户') logger.info(f"开始处理用户: {user_name}") websites = user_config.get('websites', []) if not websites: logger.info(f"用户 {user_name} 没有配置网站,跳过") return browser_config = user_config.get('browser', {}) browser = BrowserManager( browser_type=browser_config.get('type', 'edge'), headless=browser_config.get('headless', False) ) user_results = { 'user_name': user_name, 'notification_config': user_config.get('notification', {}), 'websites': [], 'success_count': 0, 'fail_count': 0 } try: local_cookies = self.cookie_data_manager.get_user_cookies(user_name) cookie_cloud_config = user_config.get('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', '') ) all_cookies = cookie_cloud.get_cookies() browser.init_browser() login_failed = False failed_website = None # 初始流程:逐个网站验证,使用本地cookie for website in websites: website_name = website.get('name', '未知网站') url = website.get('url', '') parsed = urlparse(url) domain = parsed.netloc domain_cookies = [] for cookie_domain, cookie_data in local_cookies.items(): clean_domain = cookie_domain.lstrip('.') if domain in clean_domain or clean_domain in domain: if isinstance(cookie_data, dict): cookies = cookie_data.get('cookies', []) elif isinstance(cookie_data, list): cookies = cookie_data else: cookies = [] domain_cookies.extend(cookies) if domain_cookies: success_count = browser.import_cookies(domain_cookies, domain) login_check_selector = website.get('login_check_selector', '') success_text = website.get('success_text', '') login_success = browser.verify_login( url=url, check_selector=login_check_selector, success_text=success_text ) if login_success: current_cookies = browser.get_cookies() if current_cookies: self.cookie_data_manager.save_user_cookies( user_name=user_name, cookies=current_cookies, url=url, website_name=website_name ) user_results['websites'].append({ 'name': website_name, 'url': url, 'success': True, 'error': '' }) user_results['success_count'] += 1 else: login_failed = True failed_website = website break # 错误处理机制:如果任何一个网站登录失败 if login_failed: browser.close() browser = BrowserManager( browser_type=browser_config.get('type', 'edge'), headless=browser_config.get('headless', False) ) browser.init_browser() relevant_cookies = [] target_domains = [] for website in websites: url = website.get('url', '') if url: parsed = urlparse(url) target_domains.append(parsed.netloc) for domain_cookies in all_cookies.values(): if isinstance(domain_cookies, dict): cookies = domain_cookies.get('cookies', []) elif isinstance(domain_cookies, list): cookies = domain_cookies else: cookies = [] for cookie in cookies: cookie_domain = cookie.get('domain', '') if cookie_domain: clean_cookie_domain = cookie_domain.lstrip('.') for target_domain in target_domains: clean_target_domain = target_domain.lstrip('.') if clean_cookie_domain in clean_target_domain or clean_target_domain in clean_cookie_domain: relevant_cookies.append(cookie) break if relevant_cookies: browser.import_cookies(relevant_cookies, domain='') user_results['websites'] = [] user_results['success_count'] = 0 user_results['fail_count'] = 0 for website in websites: website_name = website.get('name', '未知网站') url = website.get('url', '') login_check_selector = website.get('login_check_selector', '') success_text = website.get('success_text', '') login_success = browser.verify_login( url=url, check_selector=login_check_selector, success_text=success_text ) if login_success: current_cookies = browser.get_cookies() if current_cookies: self.cookie_data_manager.save_user_cookies( user_name=user_name, cookies=current_cookies, url=url, website_name=website_name ) user_results['websites'].append({ 'name': website_name, 'url': url, 'success': True, 'error': '' }) user_results['success_count'] += 1 else: user_results['websites'].append({ 'name': website_name, 'url': url, 'success': False, 'error': '登录状态验证失败' }) user_results['fail_count'] += 1 self.all_results.append(user_results) self._print_summary(user_name, user_results['websites']) if should_send_notification(user_name): self._send_user_notification(user_results) finally: browser.close() def process_website( self, user_name: str, website_config: dict, browser: BrowserManager, all_cookies: dict, local_cookies: dict ) -> dict: """ 验证网站登录状态 Args: user_name: 用户名 website_config: 网站配置 browser: 浏览器管理器 all_cookies: 所有cookies local_cookies: 本地cookies Returns: 验证结果字典 """ 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', '') logger.info(f"\n验证网站: {website_name}") logger.info(f" 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: parsed = urlparse(url) domain = parsed.netloc domain_cookies = [] for cookie_domain, cookie_data in local_cookies.items(): clean_domain = cookie_domain.lstrip('.') if domain in clean_domain or clean_domain in domain: if isinstance(cookie_data, dict): cookies = cookie_data.get('cookies', []) elif isinstance(cookie_data, list): cookies = cookie_data else: cookies = [] domain_cookies.extend(cookies) if domain_cookies: logger.info(f" 找到 {len(domain_cookies)} 个本地 cookie") success_count = browser.import_cookies(domain_cookies, domain) logger.info(f" 成功导入 {success_count} 个 cookie") else: logger.warning(f" 未找到本地 cookie") login_success = browser.verify_login( url=url, check_selector=check_selector, success_text=success_text ) if login_success: result['success'] = True logger.info(f" ✓ 使用本地 cookie 登录验证成功") if domain_cookies: logger.info(f" 保存 {len(domain_cookies)} 个 cookie 到本地文件") self.cookie_data_manager.save_user_cookies( user_name=user_name, cookies=domain_cookies, url=url, website_name=website_name ) else: logger.warning(f" 登录验证成功但 cookies 为空,跳过保存") else: logger.warning(f" ✗ 本地 cookie 登录失败,尝试使用服务器 cookie") domain_cookies = [] for cookie_domain, cookie_data in all_cookies.items(): clean_domain = cookie_domain.lstrip('.') if domain in clean_domain or clean_domain in domain: if isinstance(cookie_data, dict): cookies = cookie_data.get('cookies', []) elif isinstance(cookie_data, list): cookies = cookie_data else: cookies = [] domain_cookies.extend(cookies) if domain_cookies: logger.info(f" 找到 {len(domain_cookies)} 个服务器 cookie") success_count = browser.import_cookies(domain_cookies, domain) logger.info(f" 成功导入 {success_count} 个 cookie") else: logger.warning(f" 未找到服务器 cookie") login_success = browser.verify_login( url=url, check_selector=check_selector, success_text=success_text ) if login_success: result['success'] = True logger.info(f" ✓ 使用服务器 cookie 登录验证成功") if domain_cookies: logger.info(f" 保存 {len(domain_cookies)} 个 cookie 到本地文件") self.cookie_data_manager.save_user_cookies( user_name=user_name, cookies=domain_cookies, url=url, website_name=website_name ) else: logger.warning(f" 登录验证成功但 cookies 为空,跳过保存") else: result['error'] = '登录状态验证失败(本地和服务器 cookie 都无效)' logger.warning(f" ✗ {result['error']}") except Exception as e: 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 _send_user_notification(self, user_result: dict): """发送单个用户的通知""" user_name = user_result['user_name'] notification_config = user_result.get('notification_config', {}) notifier = create_notification_manager(notification_config) if not notifier: return success_count = user_result['success_count'] fail_count = user_result['fail_count'] title = f"Cookie登录" content_lines = [ f"**{user_name} Cookie登录报告**", f"", f"登录时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", f"成功: {success_count} 个网站", f"失败: {fail_count} 个网站", f"", ] for website in user_result['websites']: status = "成功" if website['success'] else f"失败: {website['error']}" content_lines.append(f"- {website['name']}: {status}") content = "\n".join(content_lines) if notifier.send(title, content): mark_notification_sent(user_name) else: logger.error(f"用户 {user_name} 通知发送失败") def run(self): """运行监控""" logger.info("Cookie 监控开始") users = self.config_manager.get_users() if not users: logger.error("未找到用户配置") return for user_config in users: try: self.process_user(user_config) except Exception as e: logger.error(f"处理用户失败: {e}") logger.info("Cookie 监控结束") def main(): """主函数""" from logger import setup_logging setup_logging() monitor = CookieMonitor() monitor.run() if __name__ == "__main__": main()