Compare commits

..
6 Commits
Author SHA1 Message Date
bwstudio e2b23510a5 home1019 2025-10-18 22:31:17 +08:00
bwstudio 8db81de42a home1019 2025-10-18 22:26:14 +08:00
bwstudio c31031eb8f home1015d 2025-10-18 17:10:48 +08:00
bwstudio f2b99ab024 home1018c 2025-10-18 17:03:52 +08:00
bwstudio 6c31f3a729 home1018b 2025-10-18 16:53:51 +08:00
bwstudio 46fd695bf2 home1018a 2025-10-18 16:43:45 +08:00
6 changed files with 604 additions and 616 deletions
+20 -16
View File
@@ -6,12 +6,11 @@ autoLogon是一个自动化网站登录工具,可以帮助用户自动登录
## 主要功能 ## 主要功能
- 自动登录配置的多个网站 - 自动打开配置的多个网站并设置cookies
- 支持cookies管理,自动保存和更新会话信息 - 支持cookies管理,自动保存和更新会话信息
- 可自定义每个网站的保持登录时间 - 可自定义保持登录时间
- 支持自定义浏览器路径 - 支持自动退出浏览器功能
- 完整的日志记录系统 - 完整的日志记录系统
- 配置文件热更新
## 项目结构 ## 项目结构
@@ -49,12 +48,12 @@ autoLogon/
```json ```json
{ {
"browser_path": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", "duration": 30,
"AutoQuit": true,
"sites": [ "sites": [
{ {
"name": "网站名称", "name": "网站名称",
"url": "网站URL", "url": "网站URL",
"duration": 30,
"cookies": [ "cookies": [
{ {
"name": "cookie名称", "name": "cookie名称",
@@ -71,6 +70,14 @@ autoLogon/
} }
``` ```
**配置项说明**
- `duration`: 保持登录状态的时间(秒)
- `AutoQuit`: 是否在完成后自动退出浏览器(true/false)
- `sites`: 网站配置列表,每个网站包含:
- `name`: 网站名称(用于标识网站)
- `url`: 网站URL地址
- `cookies`: cookies列表,用于自动登录
## 安装依赖 ## 安装依赖
使用以下命令安装项目依赖: 使用以下命令安装项目依赖:
@@ -92,20 +99,17 @@ python main.py
## 工作流程 ## 工作流程
1. 加载配置文件 1. 加载配置文件
2. 遍历处理每个网站: 2. 为所有配置的网站创建标签页并访问URL
- 从配置中获取cookies(如果 3. 为每个网站设置cookies(如果配置了
- 启动浏览器并访问网站 4. 保持登录状态指定时间(根据配置的duration)
- 设置cookies(如果提供) 5. 获取所有页面更新后的cookies
- 保持登录状态指定时间 6. 保存更新后的cookies到配置文件
- 获取并更新最新cookies到配置 7. 根据AutoQuit配置决定是否自动关闭浏览器
- 关闭当前浏览器页面
3. 保存更新后的配置
4. 关闭浏览器
## 注意事项 ## 注意事项
- 确保浏览器路径正确配置,默认使用Edge浏览器 - 确保浏览器路径正确配置,默认使用Edge浏览器
- 配置文件中的`duration`参数表示网站打开后保持的时间(秒) - 配置文件中的`duration`参数表示处理每个网站时的延时时间(秒),默认30秒
- 首次运行时,应用会为没有cookies的网站创建空的cookies配置 - 首次运行时,应用会为没有cookies的网站创建空的cookies配置
- 日志文件保存在`log`目录下,按日期命名 - 日志文件保存在`log`目录下,按日期命名
+22 -205
View File
@@ -1,86 +1,14 @@
{ {
"browser_path": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", "duration": 30,
"AutoQuit": true,
"sites": [ "sites": [
{ {
"name": "百度", "name": "百度",
"url": "https://www.baidu.com", "url": "https://www.baidu.com",
"duration": 30,
"cookies": [ "cookies": [
{
"name": "BD_HOME",
"value": "1",
"domain": "www.baidu.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "BA_HECTOR",
"value": "20252k858l240g858hag848g2kcg811kf6cpe25",
"domain": ".baidu.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "PAD_BROWSER",
"value": "1",
"domain": "www.baidu.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "BIDUPSID",
"value": "118F20D8D3C3135F00559E5F3510FBB5",
"domain": ".baidu.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "BD_UPN",
"value": "12314753",
"domain": "www.baidu.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "PSTM",
"value": "1760768814",
"domain": ".baidu.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "ZFY",
"value": "R:BWN9Jj8RMAPiaPxY4bTL7jFZJ:AvWzWoS2wj:BdtPdNI:C",
"domain": ".baidu.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "H_PS_PSSID",
"value": "60275_64980_65216_65249_65311_65422_65456_65571_65596_65619_65598_65635_65664_65665_65682_65711_65733_65392_65759_65774_65791_65838_65866",
"domain": ".baidu.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{ {
"name": "BAIDUID_BFESS", "name": "BAIDUID_BFESS",
"value": "16F9B2349AAE73EDA898BA50E44AE46D:FG=1", "value": "07286BA0A030422D44083F3B4F2DAB27:FG=1",
"domain": ".baidu.com", "domain": ".baidu.com",
"path": "/", "path": "/",
"expires": 0, "expires": 0,
@@ -92,92 +20,19 @@
{ {
"name": "新浪", "name": "新浪",
"url": "https://www.sina.com.cn", "url": "https://www.sina.com.cn",
"duration": 30,
"cookies": [ "cookies": [
{
"name": "BAIDUID_BFESS",
"value": "07286BA0A030422D44083F3B4F2DAB27:FG=1",
"domain": ".baidu.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{ {
"name": "Hm_lpvt_90c40f528e0b2106bc03da5aadec190f", "name": "Hm_lpvt_90c40f528e0b2106bc03da5aadec190f",
"value": "1760771854", "value": "1760797352",
"domain": ".www.sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "NowDate",
"value": "Sat Oct 18 2025 15:17:33 GMT+0800 (中国标准时间)",
"domain": "www.sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "name",
"value": "sinaAds",
"domain": "www.sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "post",
"value": "massage",
"domain": "www.sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "Apache",
"value": "120.227.58.197_1760769194.496218",
"domain": ".sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "CLICK_ENHANCER_LAST_ACTIVATION",
"value": "1",
"domain": "www.sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "ULV",
"value": "1760769329201:4:4:4:120.227.58.197_1760769194.496218:1760769193685",
"domain": ".sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "UOR",
"value": "192.168.100.100,www.sina.com.cn,",
"domain": ".sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "SINAGLOBAL",
"value": "120.227.58.197_1760768783.259381",
"domain": ".sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "HMACCOUNT",
"value": "84FEB82BA2589EE5",
"domain": ".www.sina.com.cn", "domain": ".www.sina.com.cn",
"path": "/", "path": "/",
"expires": 0, "expires": 0,
@@ -186,60 +41,23 @@
}, },
{ {
"name": "Hm_lvt_90c40f528e0b2106bc03da5aadec190f", "name": "Hm_lvt_90c40f528e0b2106bc03da5aadec190f",
"value": "1760759893,1760768784,1760769195", "value": "1760794976,1760795033,1760795177,1760795343",
"domain": ".www.sina.com.cn", "domain": ".www.sina.com.cn",
"path": "/", "path": "/",
"expires": 0, "expires": 0,
"secure": false, "secure": false,
"httpOnly": false "httpOnly": false
},
{
"name": "SGUID",
"value": "1760768783361_32567590",
"domain": ".sina.com.cn",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
} }
] ]
}, },
{ {
"name": "示例网站1", "name": "示例网站5",
"url": "https://lmkbi.95155.com/bi-system/#/login", "url": "http://192.168.100.100:3000/#/login",
"duration": 30,
"cookies": [ "cookies": [
{ {
"name": "userType", "name": "MoviePilot",
"value": "2", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NjA3OTkxNTAsImlhdCI6MTc2MDc5NzM1MCwic3ViIjoiMSIsInVzZXJuYW1lIjoiYWRtaW4iLCJzdXBlcl91c2VyIjp0cnVlLCJsZXZlbCI6MiwicHVycG9zZSI6InJlc291cmNlIn0.hrce7pqwIUTzuYMSe4QXM80tepOvv5dKkDfLL8OuQo4",
"domain": "lmkbi.95155.com", "domain": "192.168.100.100",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "user",
"value": "13548569666",
"domain": "lmkbi.95155.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "edentoken",
"value": "13548569666",
"domain": "lmkbi.95155.com",
"path": "/",
"expires": 0,
"secure": false,
"httpOnly": false
},
{
"name": "LMKBIUSS",
"value": "eyJhY2NvdW50SWQiOjIzMzk0OTQ3NTAwMjA0OSwicGhvbmUiOiIxMzU0ODU2OTY2NiIsInRpbWVzdGFtcCI6MTc2MDY4Mzg5MzIwOCwidG9rZW4iOiJlMmJhMTE1Yi05YmZiLTQ5MDYtYTA0OS1iMzlmMjkwYTFmODUifQ==",
"domain": "lmkbi.95155.com",
"path": "/", "path": "/",
"expires": 0, "expires": 0,
"secure": false, "secure": false,
@@ -248,13 +66,12 @@
] ]
}, },
{ {
"name": "示例网站2", "name": "示例网站6",
"url": "http://192.168.100.1/", "url": "http://192.168.100.1",
"duration": 30,
"cookies": [ "cookies": [
{ {
"name": "sysauth_http", "name": "sysauth_http",
"value": "b05d9c8feea4a5a931e8ef687ac119de", "value": "788d6c33e71fbe7dd24947876759ac71",
"domain": "192.168.100.1", "domain": "192.168.100.1",
"path": "/", "path": "/",
"expires": 0, "expires": 0,
+84 -16
View File
@@ -17,12 +17,18 @@ class ConfigManager:
""" """
self.config_file = config_file self.config_file = config_file
self.default_config = { self.default_config = {
'sites': [] 'duration': 30,
'sites': [
{'name': '百度', 'url': 'https://www.baidu.com'},
{'name': '新浪', 'url': 'https://www.sina.com.cn'}
]
} }
# 在初始化时加载配置并保存到实例属性
self._config = self._load_config_from_file()
def load_config(self) -> Dict: def _load_config_from_file(self) -> Dict:
""" """
加载配置文件 从文件加载配置的内部方法
Returns: Returns:
dict: 配置数据 dict: 配置数据
@@ -32,23 +38,68 @@ class ConfigManager:
with open(self.config_file, 'r', encoding='utf-8') as f: with open(self.config_file, 'r', encoding='utf-8') as f:
config = json.load(f) config = json.load(f)
logger.info(f"成功加载配置文件: {self.config_file}") logger.info(f"成功加载配置文件: {self.config_file}")
# 确保配置中包含duration字段
if 'duration' not in config:
logger.info("配置中没有duration字段,使用默认值30秒")
config['duration'] = self.default_config['duration']
# 检查是否存在网站配置,如果不存在则使用默认示例网站并保存
sites = config.get('sites', [])
if not sites:
logger.warning("配置中没有设置任何网站,使用默认示例网站")
config['sites'] = self.default_config['sites']
# 保存默认网站到配置中
try:
self._save_config_to_file(config)
logger.info("已保存默认网站配置")
except Exception as e:
logger.error(f"保存默认网站配置失败: {e}")
return config return config
else: else:
logger.warning(f"配置文件不存在: {self.config_file}") logger.warning(f"配置文件不存在: {self.config_file}")
logger.info("使用默认配置") logger.info("使用默认配置")
return self.default_config.copy()
# 创建并保存默认配置
default_config = self.default_config.copy()
try:
self._save_config_to_file(default_config)
logger.info("已创建默认配置文件")
except Exception as e:
logger.error(f"保存默认配置文件失败: {e}")
return default_config
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
logger.error(f"配置文件格式错误: {e}") logger.error(f"配置文件格式错误: {e}")
logger.info("使用默认配置") logger.info("使用默认配置")
return self.default_config.copy()
# 使用默认配置并保存
default_config = self.default_config.copy()
try:
self._save_config_to_file(default_config)
logger.info("已覆盖错误配置文件")
except Exception as e:
logger.error(f"保存默认配置文件失败: {e}")
return default_config
except Exception as e: except Exception as e:
logger.error(f"加载配置文件时发生错误: {e}") logger.error(f"加载配置文件时发生错误: {e}")
logger.info("使用默认配置") logger.info("使用默认配置")
return self.default_config.copy() return self.default_config.copy()
def save_config(self, config: Dict) -> bool: def load_config(self) -> Dict:
""" """
保存配置到文件 获取当前配置(从实例属性中返回)
Returns:
dict: 配置数据
"""
return self._config.copy() # 返回配置的副本,避免外部直接修改
def _save_config_to_file(self, config: Dict) -> bool:
"""
保存配置到文件的内部方法
Args: Args:
config (dict): 要保存的配置数据 config (dict): 要保存的配置数据
@@ -70,6 +121,22 @@ class ConfigManager:
logger.error(f"保存配置文件时发生错误: {e}") logger.error(f"保存配置文件时发生错误: {e}")
return False return False
def save_config(self, config: Dict) -> bool:
"""
保存配置并更新实例属性
Args:
config (dict): 要保存的配置数据
Returns:
bool: 保存是否成功
"""
if self._save_config_to_file(config):
# 保存成功后更新实例属性
self._config = config
return True
return False
def get_sites(self) -> List[Dict]: def get_sites(self) -> List[Dict]:
""" """
获取所有网站配置 获取所有网站配置
@@ -77,10 +144,9 @@ class ConfigManager:
Returns: Returns:
list: 网站配置列表 list: 网站配置列表
""" """
config = self.load_config() sites = self._config.get('sites', [])
sites = config.get('sites', [])
logger.info(f"获取到 {len(sites)} 个网站配置") logger.info(f"获取到 {len(sites)} 个网站配置")
return sites return sites.copy() # 返回副本以避免直接修改内部数据
def add_site(self, site_config: Dict) -> bool: def add_site(self, site_config: Dict) -> bool:
""" """
@@ -96,15 +162,15 @@ class ConfigManager:
logger.error("网站配置格式错误,必须包含name和url字段") logger.error("网站配置格式错误,必须包含name和url字段")
return False return False
config = self.load_config()
sites = config.get('sites', [])
# 检查是否已存在同名网站 # 检查是否已存在同名网站
for site in sites: for site in self._config.get('sites', []):
if site.get('name') == site_config.get('name'): if site.get('name') == site_config.get('name'):
logger.warning(f"网站 '{site_config.get('name')}' 已存在") logger.warning(f"网站 '{site_config.get('name')}' 已存在")
return False return False
# 创建配置副本并添加新网站
config = self._config.copy()
sites = config.get('sites', [])
sites.append(site_config) sites.append(site_config)
config['sites'] = sites config['sites'] = sites
return self.save_config(config) return self.save_config(config)
@@ -120,7 +186,8 @@ class ConfigManager:
Returns: Returns:
bool: 更新是否成功 bool: 更新是否成功
""" """
config = self.load_config() # 创建配置副本
config = self._config.copy()
sites = config.get('sites', []) sites = config.get('sites', [])
for i, site in enumerate(sites): for i, site in enumerate(sites):
@@ -145,7 +212,8 @@ class ConfigManager:
Returns: Returns:
bool: 删除是否成功 bool: 删除是否成功
""" """
config = self.load_config() # 创建配置副本
config = self._config.copy()
sites = config.get('sites', []) sites = config.get('sites', [])
new_sites = [site for site in sites if site.get('name') != site_name] new_sites = [site for site in sites if site.get('name') != site_name]
+348 -239
View File
@@ -1,7 +1,7 @@
import os import os
import time import time
from typing import Dict, List, Any from typing import Dict, List, Any, Optional
from DrissionPage import ChromiumPage, ChromiumOptions from DrissionPage import ChromiumPage, ChromiumOptions, Chromium
from logger_config import global_logger as logger from logger_config import global_logger as logger
from config import ConfigManager from config import ConfigManager
@@ -13,287 +13,396 @@ class LoginManager:
def __init__(self): def __init__(self):
""" """
初始化登录管理器 初始化登录管理器,创建浏览器对象
""" """
self.page = None self.browser = None
self.config_manager = ConfigManager() self.config_manager = ConfigManager()
self.sites = [] # 存储包含网站和页面信息的字典列表
def login(self, site_url: str, cookies: List[Dict[str, Any]] = None) -> bool: # 初始化浏览器对象
"""
登录网站
Args:
site_url (str): 网站URL
cookies (List[Dict[str, Any]], optional): 预先设置的cookies记录列表
Returns:
bool: 登录是否成功
"""
logger.info(f"开始登录网站: {site_url}")
try: try:
# 根据DrissionPage 4.x文档,使用ChromiumOptions配置浏览器
logger.info("正在配置浏览器...")
# 创建浏览器配置对象 # 创建浏览器配置对象
co = ChromiumOptions() co = ChromiumOptions()
# 从配置文件中读取浏览器路径,如果不存在则使用默认路径 # 从配置文件中读取浏览器路径
config = self.config_manager.load_config() config = self.config_manager.load_config()
edge_path = config.get('browser_path', r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe') edge_path = config.get('browser_path', r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe')
if os.path.exists(edge_path): if os.path.exists(edge_path):
# 根据文档,使用set_browser_path方法设置浏览器路径 # 设置浏览器路径
co.set_browser_path(edge_path) co.set_browser_path(edge_path)
logger.info(f"已配置Edge浏览器路径: {edge_path}") logger.info(f"已配置浏览器路径: {edge_path}")
else: else:
logger.warning(f"Edge浏览器路径不存在: {edge_path}") logger.warning(f"浏览器路径不存在: {edge_path}")
logger.info("将使用默认配置,让DrissionPage自动查找浏览器") logger.info("将使用默认配置,让DrissionPage自动查找浏览器")
# 使用配置创建ChromiumPage实例 # 用配置创建浏览器对象
# 根据文档,在DrissionPage 4.x中,应该使用正确的方式初始化 self.browser = Chromium(addr_or_opts=co)
self.page = ChromiumPage(co) logger.info("浏览器对象初始化成功")
except Exception as e:
logger.error(f"初始化浏览器失败: {e}")
self.browser = None
# 访问网站
logger.info(f"正在加载网站: {site_url}")
self.page.get(site_url)
# 如果提供了cookies,设置它们
if cookies:
logger.info(f"设置 {len(cookies)} 条cookies记录")
# 检查cookies类型,支持列表格式和字典格式
if isinstance(cookies, dict):
# 兼容旧的字典格式,转换为列表格式
cookies_list = [] def save_cookies(self) -> List[Dict[str, Any]]:
for key, value in cookies.items(): """
cookies_list.append({ 保存所有打开网站的cookies到配置文件
'name': key,
'value': value, Returns:
'domain': '', List[Dict[str, Any]]: 包含所有网站cookies的列表
'path': '/', """
'expires': 0, logger.info("开始保存所有网站的cookies到配置文件")
'secure': False,
'httpOnly': False all_sites_cookies = []
if not self.sites:
logger.warning("没有打开的网站,无法获取cookies")
return all_sites_cookies
try:
# 加载配置文件
config = self.config_manager.load_config()
# 遍历所有网站获取cookies
for index, site_info in enumerate(self.sites):
try:
page = site_info['page']
site_name = site_info.get('name', f'网站_{index+1}')
site_url = getattr(page, 'url', site_info.get('url', f'网站_{index+1}'))
page_title = getattr(page, 'title', f'网站_{index+1}')
logger.info(f"获取网站 {index+1}/{len(self.sites)} 的cookies: {site_name} - {site_url}")
# 获取页面的cookies
cookies_list = self._get_page_cookies(page, site_name, site_url)
# 将网站信息和cookies添加到结果列表
if cookies_list:
all_sites_cookies.append({
'url': site_url,
'title': page_title,
'cookies': cookies_list
}) })
cookies = cookies_list logger.info(f"成功获取网站 {site_url}{len(cookies_list)} 条cookies记录")
logger.info(f"已将字典格式cookies转换为列表格式")
# 尝试多种方式设置cookies # 更新配置文件中的cookies - 使用name属性作为匹配条件
try: for config_site in config.get('sites', []):
# 首先尝试使用set.cookies()方法(DrissionPage 4.x推荐方式) if config_site.get('name') == site_name:
if hasattr(self.page, 'set') and hasattr(self.page.set, 'cookies'): config_site['cookies'] = cookies_list
if hasattr(self.page.set.cookies, 'clear'): logger.info(f"已更新配置文件中网站 {site_name} 的cookies")
self.page.set.cookies.clear() break
self.page.set.cookies(cookies)
logger.info(f"成功使用set.cookies()方法设置cookies")
# 备选方案1:使用set_cookies方法
elif hasattr(self.page, 'set_cookies'):
self.page.set_cookies(cookies)
logger.info("成功使用set_cookies方法设置cookies")
# 备选方案2:使用page.cookies属性
elif hasattr(self.page, 'cookies'):
self.page.cookies = cookies
logger.info("成功使用page.cookies属性设置cookies")
else: else:
logger.error("无法找到设置cookies的有效方法") logger.warning(f"未能获取网站 {site_name} - {site_url}cookies")
except Exception as e:
logger.error(f"设置cookies失败: {e}")
# 刷新页面以应用cookies except Exception as e:
logger.error(f"处理网站时发生错误: {e}")
continue
# 使用ConfigManager保存更新后的配置
if self.config_manager.save_config(config):
logger.info("已将更新后的配置保存到配置文件")
else:
logger.error("保存配置文件失败")
except Exception as e:
logger.error(f"保存cookies到配置文件时发生错误: {e}")
logger.info(f"成功获取并保存 {len(all_sites_cookies)} 个网站的cookies")
return all_sites_cookies
def close(self, quit_browser: bool = None) -> None:
"""
关闭浏览器页面,可选择是否同时关闭浏览器对象
Args:
quit_browser (bool): 是否关闭浏览器对象,None表示根据配置决定
"""
# 关闭所有页面
if self.sites:
for page_info in reversed(self.sites):
try: try:
self.page.refresh() page = page_info['page']
if hasattr(page, 'close'):
page.close()
logger.info("一个标签页已关闭")
except Exception as e: except Exception as e:
logger.warning(f"刷新页面时出错: {e}") logger.error(f"关闭浏览器页面时发生错误: {e}")
# 清空sites列表
self.sites = []
else:
logger.warning("没有活动的浏览器页面需要关闭")
# 等待页面加载完成 # 决定是否关闭浏览器对象
time.sleep(2) should_quit = quit_browser
# 验证是否登录成功 # 只有当调用者没有明确指定时,才从配置中读取
current_url = self.page.url if should_quit is None:
logger.info(f"当前URL: {current_url}") try:
config = self.config_manager.load_config()
should_quit = config.get('AutoQuit', False)
except Exception as e:
logger.error(f"读取配置时出错: {e}")
should_quit = False
# 如果能成功加载页面,暂时认为登录成功 # 如果需要关闭浏览器对象
if should_quit and self.browser:
try:
self.browser.quit()
logger.info("浏览器对象已关闭")
self.browser = None
except Exception as e:
logger.error(f"关闭浏览器对象时发生错误: {e}")
def _add_page_metadata(self, page: Any, name: str, url: str, cookies: Optional[List[Dict[str, Any]]] = None) -> None:
"""
添加页面元数据到sites列表
Args:
page: 页面对象
name: 网站名称
url: 网站URL
cookies: cookies列表
"""
self.sites.append({
'page': page,
'name': name,
'url': url,
'original_cookies': cookies if cookies else []
})
def _set_cookies_to_page(self, page: Any, cookies: List[Dict[str, Any]] or Dict[str, str], site_name: str) -> bool:
"""
为页面对象设置cookies
Args:
page: 页面对象
cookies: cookies列表或字典
site_name: 网站名称
Returns:
bool: 设置是否成功
"""
logger.info(f"为网站 '{site_name}' 设置 {len(cookies)} 条cookies记录")
try:
# 检查cookies类型,支持列表格式和字典格式
if isinstance(cookies, dict):
# 兼容旧的字典格式,转换为列表格式
cookies_list = []
for key, value in cookies.items():
cookies_list.append({
'name': key,
'value': value,
'domain': '',
'path': '/',
'expires': 0,
'secure': False,
'httpOnly': False
})
cookies = cookies_list
logger.info(f"已将字典格式cookies转换为列表格式")
# 尝试多种方式设置cookies
if hasattr(page, 'set') and hasattr(page.set, 'cookies'):
if hasattr(page.set.cookies, 'clear'):
page.set.cookies.clear()
page.set.cookies(cookies)
logger.info(f"成功使用set.cookies()方法设置cookies")
elif hasattr(page, 'set_cookies'):
page.set_cookies(cookies)
logger.info("成功使用set_cookies方法设置cookies")
elif hasattr(page, 'cookies'):
page.cookies = cookies
logger.info("成功使用page.cookies属性设置cookies")
else:
logger.error("无法找到设置cookies的有效方法")
return False
# 刷新页面以应用cookies
page.refresh()
logger.info(f"网站 '{site_name}' 页面已刷新以应用cookies")
return True return True
except Exception as e: except Exception as e:
error_msg = str(e) logger.error(f"为网站 '{site_name}' 设置cookies失败: {e}")
logger.error(f"登录网站时发生错误: {error_msg}")
# 针对浏览器路径错误提供详细指导
if "无法找到浏览器可执行文件路径" in error_msg:
logger.warning("===== 浏览器配置错误指导 =====")
logger.warning("DrissionPage无法找到系统中的浏览器")
logger.warning("请尝试以下解决方法:")
logger.warning("1. 确保Microsoft Edge浏览器已正确安装")
logger.warning("2. Edge浏览器默认安装路径: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe")
logger.warning("3. 检查Edge浏览器是否在系统PATH环境变量中")
logger.warning("4. 或者尝试安装Chrome浏览器")
logger.warning("5. 确保用户有足够的权限运行浏览器")
logger.warning("==========================")
# 安全关闭浏览器
if self.page:
try:
self.page.close()
except:
pass
self.page = None
return False return False
def maintain_login(self, duration: int = 120) -> None: def _get_page_cookies(self, page: Any, site_name: str, page_url: Optional[str] = None) -> List[Dict[str, Any]]:
""" """
保持登录状态 获取指定页面的cookies
Args: Args:
duration (int): 保持时间(秒) page: 页面对象
""" site_name: 网站名称
if not self.page: page_url: 页面URL(可选)
logger.warning("没有活动的浏览器页面,无法保持登录状态")
return
logger.info(f"保持登录状态 {duration} 秒...")
try:
# 定期刷新页面以保持会话活跃
interval = min(30, duration) # 最多每30秒刷新一次
elapsed = 0
while elapsed < duration:
time.sleep(interval)
elapsed += interval
# 刷新页面
try:
self.page.refresh()
logger.info(f"页面已刷新,已保持登录 {elapsed}")
except Exception as e:
logger.error(f"刷新页面时发生错误: {e}")
break
except KeyboardInterrupt:
logger.info("保持登录状态被用户中断")
except Exception as e:
logger.error(f"保持登录状态时发生错误: {e}")
def get_cookies(self) -> List[Dict[str, Any]]:
"""
获取当前页面的cookies
Returns: Returns:
List[Dict[str, Any]]: cookies记录列表 List[Dict[str, Any]]: cookies列表
""" """
if not self.page: cookies_list = []
logger.warning("没有活动的浏览器页面,无法获取cookies") cookies = None
return []
# 构建日志标识
log_id = f"网站 '{site_name}'" if not page_url else f"页面 {site_name} - {page_url}"
# 尝试多种方式获取cookies
try:
if hasattr(page, 'get_cookies'):
cookies = page.get_cookies()
elif hasattr(page, 'cookies'):
if callable(page.cookies):
cookies = page.cookies()
else:
cookies = page.cookies
except Exception as api_e:
logger.warning(f"获取{log_id}的cookies时出错: {api_e}")
# 处理获取到的cookies
if cookies is not None:
if isinstance(cookies, list):
for cookie in cookies:
if 'name' in cookie and 'value' in cookie:
standard_cookie = {
'name': cookie.get('name'),
'value': cookie.get('value'),
'domain': cookie.get('domain', ''),
'path': cookie.get('path', '/'),
'expires': cookie.get('expires', 0),
'secure': cookie.get('secure', False),
'httpOnly': cookie.get('httpOnly', False)
}
cookies_list.append(standard_cookie)
elif isinstance(cookies, dict):
for key, value in cookies.items():
cookies_list.append({
'name': key,
'value': value,
'domain': '',
'path': '/',
'expires': 0,
'secure': False,
'httpOnly': False
})
# 如果还是没有获取到cookies,尝试使用JavaScript
if not cookies_list:
try:
if hasattr(page, 'run_js'):
js_cookies = page.run_js('return document.cookie')
elif hasattr(page, 'execute_script'):
js_cookies = page.execute_script('return document.cookie')
else:
js_cookies = None
if js_cookies:
cookie_pairs = js_cookies.split(';')
for pair in cookie_pairs:
pair = pair.strip()
if '=' in pair:
try:
key, value = pair.split('=', 1)
cookies_list.append({
'name': key.strip(),
'value': value.strip(),
'domain': '',
'path': '/',
'expires': 0,
'secure': False,
'httpOnly': False
})
except Exception as parse_e:
logger.warning(f"解析cookie对失败: {pair}, 错误: {parse_e}")
except Exception as js_e:
logger.warning(f"使用JavaScript获取{log_id}的cookies时出错: {js_e}")
return cookies_list
def get_duration(self) -> int:
"""
获取配置中的延时时间
Returns:
int: 延时秒数
"""
try:
return self.config_manager.load_config().get('duration', 30)
except Exception as e:
logger.error(f"获取duration配置时发生错误: {e}")
return 30 # 返回默认值
def run(self) -> None:
"""
从配置文件中读取网站信息,为每个网站新建标签页并加载cookies
"""
logger.info("开始运行自动登录流程")
# 检查浏览器对象是否初始化
if not self.browser:
logger.error("浏览器对象未初始化,无法运行自动登录流程")
return
try: try:
cookies_list = [] # 从配置文件中读取网站信息
config = self.config_manager.load_config()
sites = config.get('sites', [])
# 根据DrissionPage文档,尝试多种方式获取cookies logger.info(f"获取到 {len(sites)} 个网站配置")
cookies = None
# 首先尝试使用标准API获取cookies if not sites:
try: logger.warning("配置文件中没有网站信息")
# 尝试使用get_cookies方法 return
if hasattr(self.page, 'get_cookies'):
logger.info("尝试使用page.get_cookies()方法获取cookies")
cookies = self.page.get_cookies()
# 尝试使用page.cookies属性
elif hasattr(self.page, 'cookies'):
logger.info("尝试使用page.cookies属性获取cookies")
# 检查是否是可调用对象
if callable(self.page.cookies):
cookies = self.page.cookies()
else:
cookies = self.page.cookies
else:
logger.error("无法找到获取cookies的有效方法")
return []
except Exception as api_e:
logger.warning(f"使用标准API获取cookies失败: {api_e},尝试其他方法")
# 处理获取到的cookies logger.info(f"找到 {len(sites)} 个网站需要登录")
if cookies is not None:
if isinstance(cookies, list):
# 如果已经是列表格式,确保每条记录包含必要字段
for cookie in cookies:
# 确保cookie记录包含必要的字段
if 'name' in cookie and 'value' in cookie:
# 标准化cookie记录格式
standard_cookie = {
'name': cookie.get('name'),
'value': cookie.get('value'),
'domain': cookie.get('domain', ''),
'path': cookie.get('path', '/'),
'expires': cookie.get('expires', 0),
'secure': cookie.get('secure', False),
'httpOnly': cookie.get('httpOnly', False)
}
cookies_list.append(standard_cookie)
elif isinstance(cookies, dict):
# 如果是字典格式,转换为列表格式
for key, value in cookies.items():
cookies_list.append({
'name': key,
'value': value,
'domain': '',
'path': '/',
'expires': 0,
'secure': False,
'httpOnly': False
})
# 如果还是没有获取到cookies,尝试使用execute_script方法 # 存储所有创建的标签页
if not cookies_list: tabs = []
# 为每个网站创建标签页并设置cookies
for site in sites:
try: try:
logger.info("尝试使用JavaScript获取cookies") site_name = site.get('name', '未命名网站')
if hasattr(self.page, 'run_js'): site_url = site.get('url', '')
js_cookies = self.page.run_js('return document.cookie') site_cookies = site.get('cookies', [])
elif hasattr(self.page, 'execute_script'):
js_cookies = self.page.execute_script('return document.cookie')
else:
logger.warning("无法找到执行JavaScript的方法")
js_cookies = None
if js_cookies: if not site_url:
# 解析JavaScript返回的cookie字符串 logger.warning(f"网站 '{site_name}' 缺少URL,跳过")
cookie_pairs = js_cookies.split(';') continue
for pair in cookie_pairs:
pair = pair.strip() logger.info(f"开始处理网站: {site_name} ({site_url})")
if '=' in pair:
try: # 创建新标签页
key, value = pair.split('=', 1) try:
cookies_list.append({ new_tab = self.browser.new_tab(site_url)
'name': key.strip(), logger.info(f"为网站 '{site_name}' 创建了新标签页")
'value': value.strip(), tabs.append(new_tab)
'domain': '', # 添加网站元数据
'path': '/', self._add_page_metadata(new_tab, site_name, site_url, site_cookies)
'expires': 0, except Exception as e:
'secure': False, logger.error(f"为网站 '{site_name}' 创建标签页失败: {e}")
'httpOnly': False continue
})
except Exception as parse_e: # 设置cookies
logger.warning(f"解析cookie对失败: {pair}, 错误: {parse_e}") if site_cookies:
except Exception as js_e: self._set_cookies_to_page(new_tab, site_cookies, site_name)
logger.warning(f"使用JavaScript获取cookies失败: {js_e}")
# 等待页面加载完成
logger.info("页面加载中...")
time.sleep(2) # 仅保留短暂延时确保页面加载完成
logger.info(f"网站 '{site_name}' 处理完成")
except Exception as e:
logger.error(f"处理网站时发生错误: {e}")
continue
logger.info(f"所有网站处理完成,共创建了 {len(tabs)} 个标签页")
# 所有标签页已通过_add_page_metadata添加到sites列表中
if tabs:
logger.info("已创建并记录所有标签页")
logger.info(f"成功获取 {len(cookies_list)} 条cookies记录")
return cookies_list
except Exception as e: except Exception as e:
logger.error(f"获取cookies时发生错误: {e}") logger.error(f"运行自动登录流程时发生错误: {e}")
return []
def close(self) -> None:
"""
关闭浏览器页面
"""
if self.page:
try:
self.page.browser.quit()
# self.page.close()
# self.page = None
logger.info("浏览器页面已关闭")
except Exception as e:
logger.error(f"关闭浏览器页面时发生错误: {e}")
else:
logger.warning("没有活动的浏览器页面需要关闭")
+23 -75
View File
@@ -1,5 +1,4 @@
import time import time
import json
from typing import Dict, List, Any from typing import Dict, List, Any
from config import ConfigManager from config import ConfigManager
from login_manager import LoginManager from login_manager import LoginManager
@@ -18,91 +17,43 @@ class AutoLoginApp:
self.config_manager = ConfigManager() self.config_manager = ConfigManager()
self.login_manager = LoginManager() self.login_manager = LoginManager()
def run(self): def run(self):
""" """
运行自动登录应用 运行自动登录应用
""" """
logger.info("===== 自动登录应用启动 =====") logger.info("===== 自动登录应用启动 =====")
# 加载配置 # 直接调用LoginManager的run函数处理所有网站
config = self.config_manager.load_config() self.login_manager.run()
sites = config.get('sites', [])
if not sites: # 从配置管理器直接获取duration参数
logger.warning("配置中没有设置任何网站,使用默认示例网站") duration = self.login_manager.get_duration()
# 添加默认示例网站
sites = [
{'name': '百度', 'url': 'https://www.baidu.com'},
{'name': '新浪', 'url': 'https://www.sina.com.cn'}
]
# 处理每个网站 logger.info(f"延时 {duration} 秒后获取所有页面cookies")
for site in sites: time.sleep(duration)
site_name = site.get('name', '未知网站')
site_url = site.get('url', '')
if not site_url: # 调用save_cookies函数获取并保存所有网站的cookies到config.json
logger.warning(f"网站 '{site_name}' 的URL为空,跳过")
continue
logger.info(f"处理网站: {site_name} ({site_url})")
# 获取cookies(从配置中)
cookies = []
if 'cookies' in site:
config_cookies = site['cookies']
# 确保cookies是列表格式
if isinstance(config_cookies, dict):
# 直接将字典转换为列表格式
cookies = []
for key, value in config_cookies.items():
cookies.append({
'name': key,
'value': value,
'domain': '',
'path': '/',
'expires': 0,
'secure': False,
'httpOnly': False
})
else:
cookies = config_cookies
logger.info(f"使用配置文件中的 {len(cookies)} 条cookies记录")
# 登录网站
login_success = self.login_manager.login(site_url, cookies)
if login_success:
logger.info(f"登录网站 '{site_name}' 成功")
# 保持登录状态一段时间,从配置中获取duration值,默认30秒
duration = site.get('duration', 30)
self.login_manager.maintain_login(duration=duration) # 保持{duration}秒
# 保持登录状态后获取并更新到配置中的cookies
new_cookies = self.login_manager.get_cookies()
if new_cookies:
# 更新当前site对象的cookies
site['cookies'] = new_cookies
logger.info(f"已更新网站 '{site_name}' 的cookies到配置中,共 {len(new_cookies)} 条记录")
else:
logger.error(f"登录网站 '{site_name}' 失败")
# 关闭当前浏览器页面,准备下一个网站
self.login_manager.close()
time.sleep(2) # 间隔2秒再处理下一个网站
# 保存更新后的配置到config.json
try: try:
self.config_manager.save_config(config) all_cookies = self.login_manager.save_cookies()
logger.info("已将更新后的cookies保存到config.json文件") logger.info(f"成功获取并保存 {len(all_cookies)} 个网站的cookies到config.json文件")
except Exception as e: except Exception as e:
logger.error(f"保存配置文件时发生错误: {e}") logger.error(f"获取或保存cookies时发生错误: {e}")
logger.info("===== 所有网站处理完成 =====") logger.info("===== 所有网站处理完成 =====")
# 从配置管理器直接获取AutoQuit配置并关闭浏览器
auto_quit = self.config_manager.load_config().get('AutoQuit', False)
if auto_quit:
try:
self.login_manager.close(True) # 直接传入True表示关闭浏览器
logger.info("已关闭浏览器")
except Exception as e:
logger.error(f"关闭浏览器时发生错误: {e}")
else:
logger.info("浏览器保持打开状态")
# 不再需要返回auto_quit值,因为它已经在方法内部使用
if __name__ == "__main__": if __name__ == "__main__":
app = AutoLoginApp() app = AutoLoginApp()
try: try:
@@ -111,6 +62,3 @@ if __name__ == "__main__":
logger.info("程序被用户中断") logger.info("程序被用户中断")
except Exception as e: except Exception as e:
logger.error(f"程序运行时发生错误: {e}") logger.error(f"程序运行时发生错误: {e}")
finally:
# 确保关闭浏览器
app.login_manager.close()
+107 -65
View File
@@ -2,131 +2,173 @@
## 1. 项目概述 ## 1. 项目概述
本项目使用Python语言和DrissionPage库开发一个自动化脚本,用于按顺序登录多个网站,保持登录状态一段时间后保存更新的cookies,并关闭网站。 本项目使用Python语言和DrissionPage库开发一个自动化脚本,用于按顺序登录多个网站,保持登录状态一段时间后保存更新的cookies,并关闭网站。该应用支持配置多个网站、自定义保持登录时间、自动管理cookies以及完整的日志记录系统。
## 2. 功能需求 ## 2. 功能需求
- 从配置文件读取网站地址和对应的cookies信息 - 从配置文件读取网站地址和对应的cookies信息
- 按顺序登录每个网站 - 按顺序登录每个网站
- 登录成功后保持登录状态2分钟 - 登录成功后依次打开多个网页(支持全局duration配置)
- 保存更新后的cookies信息 - 保存更新后的cookies信息到配置文件
- 关闭网站 - 关闭网站浏览器实例
- 完整的日志记录功能
- 支持自定义浏览器路径配置
## 3. 技术栈 ## 3. 技术栈
- Python 3.8+ - Python 3.8+
- DrissionPage库 - DrissionPage库(用于浏览器自动化)
- JSON/YAML用于配置文件格式 - JSON用于配置文件格式
- Python标准库logging(用于日志记录)
## 4. 项目结构 ## 4. 项目结构
``` ```
autoLogon/ autoLogon/
├── config.py # 配置文件处理模块 ├── main.py # 应用主入口
├── login_manager.py # 登录管理模块 ├── login_manager.py # 登录管理
├── cookie_handler.py # Cookies处理模块 ├── config.py # 配置管理器
├── main.py # 主程序入口 ├── logger_config.py # 日志配置
├── config.json # 配置文件(存储网站和cookies信息) ├── config.json # 配置文件
├── requirements.txt # 依赖列表 ├── requirements.txt # 依赖列表
── README.md # 项目说明文档 ── README.md # 项目说明文档
└── log/ # 日志文件夹(自动创建)
``` ```
## 5. 模块设计 ## 5. 模块设计
### 5.1 配置文件处理模块 (config.py) ### 5.1 配置管理器 (config.py)
**功能**:负责读取和写入配置文件中的网站地址和cookies信息 **功能**:负责加载、保存和管理应用配置,包括网站列表、浏览器路径等信息
**主要函数** **主要类和方法**
- `load_config(file_path)`: 加载配置文件 - `ConfigManager`: 配置管理类
- `save_config(config_data, file_path)`: 保存配置文件 - `__init__(config_file='config.json')`: 初始化配置管理器
- `load_config()`: 加载配置文件,处理文件不存在或格式错误的情况
- `save_config(config)`: 保存配置到文件
- `get_sites()`: 获取所有网站配置
- `add_site(site_config)`: 添加网站配置
- `update_site(site_name, updated_config)`: 更新网站配置
- `delete_site(site_name)`: 删除网站配置
### 5.2 Cookies处理模块 (cookie_handler.py) ### 5.2 登录管理器 (login_manager.py)
**功能**:负责cookies管理,包括解析、转换和保存 **功能**:负责浏览器的初始化、网站访问、cookies管理和会话维护。
**主要函数** **主要类和方法**
- `parse_cookies(cookie_str)`: 解析cookies字符串为字典格式 - `LoginManager`: 登录管理类
- `cookies_to_str(cookies_dict)`: 将cookies字典转换为字符串 - `__init__()`: 初始化登录管理器
- `save_cookies(site_url, cookies, config_manager)`: 保存网站的cookies到配置文件 - `run()`: 从配置文件读取网站信息,为每个网站新建标签页并加载cookies
- `save_cookies()`: 获取所有页面的cookies并保存到配置文件
- `get_duration()`: 获取配置的持续时间
- `close(quit_browser=None)`: 关闭浏览器页面和实例
- `_add_page_metadata(page, name, url, cookies=None)`: 添加页面元数据
- `_set_cookies_to_page(page, cookies, site_name)`: 设置cookies到页面
- `_get_page_cookies(page, site_name, page_url=None)`: 获取页面cookies
### 5.3 登录管理模块 (login_manager.py) ### 5.3 日志配置器 (logger_config.py)
**功能**负责网站的登录和维护登录状态 **功能**设置全局日志记录器,支持文件和控制台双重输出。
**主要函数** **主要类和方法**
- `login_to_site(browser, site_url, cookies)`: 使用提供的cookies登录网站 - `LoggerConfig`: 日志配置类
- `verify_login(browser)`: 验证是否登录成功 - `setup_logger(log_level=logging.INFO)`: 设置日志记录器
- `maintain_session(browser, duration=120)`: 保持登录状态指定时间 - `global_logger`: 全局日志记录器实例
### 5.4 主程序模块 (main.py) ### 5.4 主程序模块 (main.py)
**功能**程序入口,协调各模块工作 **功能**应用主入口,协调各模块工作流程。
**主要类和方法**
- `AutoLoginApp`: 自动登录应用主类
- `__init__()`: 初始化自动登录应用
- `run()`: 运行自动登录应用,执行完整的登录流程
**主要流程** **主要流程**
1. 初始化配置管理器 1. 初始化配置管理器和登录管理器
2. 加载配置文件 2. 加载配置文件
3. 初始化浏览器 3. 调用login_manager.run()方法处理所有网站
4. 遍历每个网站配置 - 为每个网站创建标签页并访问URL
5. 调用登录管理模块登录网站 - 设置cookies(如果有)
6. 保持登录状态 - 等待页面加载完成
7. 更新并保存cookies 4. 获取配置的持续时间并等待指定时间
8. 关闭浏览器 5. 获取并保存所有页面更新后的cookies
6. 根据配置决定是否自动关闭浏览器
## 6. 配置文件格式 (JSON) ## 6. 配置文件格式 (JSON)
```json ```json
{ {
"sites": [ "duration": 30,
"AutoQuit": true,
"sites": [
{
"name": "网站名称",
"url": "网站URL",
"cookies": [
{ {
"name": "网站A", "name": "cookie名称",
"url": "https://example.com", "value": "cookie值",
"cookies": { "domain": "域名",
"cookie1": "value1", "path": "/",
"cookie2": "value2" "expires": 0,
} "secure": false,
}, "httpOnly": false
{
"name": "网站B",
"url": "https://example2.com",
"cookies": {
"cookie3": "value3",
"cookie4": "value4"
}
} }
] ]
}
]
} }
``` ```
**配置项说明**
- `duration`: 保持登录状态的时间(秒)
- `AutoQuit`: 是否在完成后自动退出浏览器(true/false)
- `sites`: 网站配置列表
- `name`: 网站名称(用于标识网站)
- `url`: 网站URL地址
- `cookies`: cookies列表,用于自动登录
```
## 7. 依赖安装 ## 7. 依赖安装
```bash ```bash
pip install drissionpage pip install -r requirements.txt
```
requirements.txt内容:
```
drissionpage
``` ```
## 8. 实现步骤 ## 8. 实现步骤
1. 创建项目目录结构 1. 创建项目目录结构
2. 编写配置文件处理模块 2. 编写日志配置模块 (logger_config.py)
3. 编写Cookies处理模块 3. 编写配置管理器模块 (config.py)
4. 编写登录管理模块 4. 编写登录管理模块 (login_manager.py)
5. 编写主程序模块 5. 编写主程序模块 (main.py)
6. 创建配置文件示例 6. 创建配置文件示例 (config.json)
7. 测试各个模块 7. 测试各个模块
8. 整合测试 8. 整合测试
## 9. 注意事项 ## 9. 注意事项
- 确保使用正确的cookies格式 - 确保使用正确的cookies格式,支持列表格式
- 处理可能的登录失败情况 - 处理可能的登录失败情况,程序有完整的异常处理
- 考虑网站的反爬机制 - 考虑网站的反爬机制,避免频繁操作
- 妥善保存配置文件,避免敏感信息泄露 - 妥善保存配置文件,cookies可能包含敏感信息
- 处理网络异常和超时情况 - 处理网络异常和超时情况
- 确保正确配置浏览器路径,默认为Edge浏览器
- 程序运行时需要有足够权限启动浏览器
## 10. 扩展功能建议 ## 10. 扩展功能建议
- 添加日志记录功能
- 实现登录失败重试机制 - 实现登录失败重试机制
- 添加多线程或异步支持以提高效率 - 添加多线程或异步支持以提高效率
- 实现定时任务功能 - 实现定时任务功能
- 添加GUI界面便于操作 - 添加GUI界面便于操作
- 添加cookies加密存储功能
- 实现更智能的登录验证机制
- 添加多浏览器支持
- 实现命令行参数解析功能