481 lines
17 KiB
Python
481 lines
17 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, 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()
|