Files
cookie/monitor.py
T

373 lines
13 KiB
Python

"""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, 22]
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 False
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"{'='*20} 开始处理用户: {user_name} {'='*20}")
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:
logger.info(f"步骤1: 从本地 cookie_data.json 读取用户 cookies")
local_cookies = self.cookie_data_manager.get_user_cookies(user_name)
logger.info(f"步骤1.5: 从 Cookie Cloud 获取所有 cookies")
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()
total_domains = len(all_cookies)
total_cookies = sum(len(c) for c in all_cookies.values())
logger.info(f"获取到 {total_domains} 个域名,共 {total_cookies} 个 cookie")
logger.info(f"步骤2: 初始化浏览器")
browser.init_browser()
logger.info(f"步骤3: 依次验证各网站登录状态")
for website in websites:
result = self.process_website(
user_name=user_name,
website_config=website,
browser=browser,
all_cookies=all_cookies,
local_cookies=local_cookies
)
user_results['websites'].append(result)
if result['success']:
user_results['success_count'] += 1
else:
user_results['fail_count'] += 1
self.all_results.append(user_results)
self._print_summary(user_name, user_results['websites'])
logger.info(f"\n检查用户 {user_name} 是否需要发送通知")
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:
logger.warning(f"用户 {user_name} 未配置通知")
return
success_count = user_result['success_count']
fail_count = user_result['fail_count']
title = f"【Cookie监控】{user_name} - 成功{success_count} 失败{fail_count}"
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)
logger.info(f"\n发送用户通知: {user_name}")
logger.info(f"Title: {title}")
if notifier.send(title, content):
logger.info(f"✓ 用户 {user_name} 通知发送成功")
mark_notification_sent(user_name)
else:
logger.error(f"✗ 用户 {user_name} 通知发送失败")
def run(self):
"""运行监控"""
logger.info("="*50)
logger.info("Cookie 监控开始")
logger.info(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
logger.info("="*50)
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("\n" + "="*50)
logger.info("Cookie 监控结束")
logger.info("="*50)
def main():
"""主函数"""
from logger import setup_logging
setup_logging()
monitor = CookieMonitor()
monitor.run()
if __name__ == "__main__":
main()