237 lines
7.7 KiB
Python
237 lines
7.7 KiB
Python
|
|
"""
|
||
|
|
系统配置设置
|
||
|
|
包含系统级别的基础配置。
|
||
|
|
"""
|
||
|
|
|
||
|
|
import os
|
||
|
|
from dataclasses import dataclass
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Optional, Tuple
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class BrowserConfig:
|
||
|
|
"""浏览器配置"""
|
||
|
|
headless: bool = False
|
||
|
|
timeout: int = 30000 # 30秒
|
||
|
|
viewport_width: int = 1920
|
||
|
|
viewport_height: int = 1080
|
||
|
|
user_agent: Optional[str] = None
|
||
|
|
locale: str = "zh-CN"
|
||
|
|
timezone: str = "Asia/Shanghai"
|
||
|
|
proxy: Optional[str] = None
|
||
|
|
executable_path: Optional[str] = None
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class HumanBehaviorConfig:
|
||
|
|
"""人类行为配置"""
|
||
|
|
typing_speed: Tuple[int, int] = (80, 150) # 打字速度范围(毫秒/字符)
|
||
|
|
pause_probability: float = 0.15 # 随机暂停概率
|
||
|
|
random_delay_range: Tuple[float, float] = (0.3, 0.8) # 随机延迟范围(秒)
|
||
|
|
click_delay_range: Tuple[float, float] = (0.1, 0.3) # 点击延迟范围
|
||
|
|
scroll_delay_range: Tuple[float, float] = (0.2, 0.5) # 滚动延迟范围
|
||
|
|
page_load_wait: Tuple[float, float] = (1.0, 3.0) # 页面加载等待时间
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class ConcurrencyConfig:
|
||
|
|
"""并发配置"""
|
||
|
|
max_concurrent_tasks: int = 3
|
||
|
|
task_retry_count: int = 3
|
||
|
|
retry_backoff_factor: float = 2.0
|
||
|
|
task_timeout: int = 300 # 5分钟
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class FileConfig:
|
||
|
|
"""文件配置"""
|
||
|
|
max_image_size: int = 10 * 1024 * 1024 # 10MB
|
||
|
|
max_video_size: int = 500 * 1024 * 1024 # 500MB
|
||
|
|
supported_image_formats: list = None
|
||
|
|
supported_video_formats: list = None
|
||
|
|
temp_dir: str = "temp"
|
||
|
|
upload_timeout: int = 600 # 10分钟
|
||
|
|
|
||
|
|
def __post_init__(self):
|
||
|
|
if self.supported_image_formats is None:
|
||
|
|
self.supported_image_formats = ["jpg", "jpeg", "png", "webp"]
|
||
|
|
if self.supported_video_formats is None:
|
||
|
|
self.supported_video_formats = ["mp4", "mov", "avi", "mkv"]
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class LogConfig:
|
||
|
|
"""日志配置"""
|
||
|
|
level: str = "INFO"
|
||
|
|
format: str = (
|
||
|
|
"<green>{time:YYYY-MM-DD HH:mm:ss}</green> | "
|
||
|
|
"<level>{level: <8}</level> | "
|
||
|
|
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
|
||
|
|
"<level>{message}</level>"
|
||
|
|
)
|
||
|
|
log_dir: str = "logs"
|
||
|
|
rotation: str = "1 day"
|
||
|
|
retention: str = "30 days"
|
||
|
|
compression: str = "zip"
|
||
|
|
enable_colors: bool = True
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class SecurityConfig:
|
||
|
|
"""安全配置"""
|
||
|
|
encrypt_cookies: bool = True
|
||
|
|
cookie_expiry_days: int = 30
|
||
|
|
max_login_attempts: int = 3
|
||
|
|
session_timeout: int = 7200 # 2小时
|
||
|
|
enable_rate_limit: bool = True
|
||
|
|
rate_limit_per_minute: int = 10
|
||
|
|
|
||
|
|
|
||
|
|
class Settings:
|
||
|
|
"""系统主配置类"""
|
||
|
|
|
||
|
|
def __init__(self):
|
||
|
|
# 项目基础路径
|
||
|
|
self.BASE_DIR = Path(__file__).resolve().parent.parent
|
||
|
|
|
||
|
|
# 环境变量
|
||
|
|
self.ENV = os.getenv("SMP_ENV", "development")
|
||
|
|
self.DEBUG = os.getenv("SMP_DEBUG", "false").lower() == "true"
|
||
|
|
|
||
|
|
# 初始化各个配置模块
|
||
|
|
self.browser = BrowserConfig()
|
||
|
|
self.human_behavior = HumanBehaviorConfig()
|
||
|
|
self.concurrency = ConcurrencyConfig()
|
||
|
|
self.file = FileConfig()
|
||
|
|
self.log = LogConfig()
|
||
|
|
self.security = SecurityConfig()
|
||
|
|
|
||
|
|
# 加载环境变量配置
|
||
|
|
self._load_env_config()
|
||
|
|
|
||
|
|
# 根据环境调整配置
|
||
|
|
self._adjust_for_environment()
|
||
|
|
|
||
|
|
def _load_env_config(self):
|
||
|
|
"""加载环境变量配置"""
|
||
|
|
# 浏览器配置
|
||
|
|
if os.getenv("SMP_BROWSER_HEADLESS"):
|
||
|
|
self.browser.headless = os.getenv("SMP_BROWSER_HEADLESS").lower() == "true"
|
||
|
|
if os.getenv("SMP_BROWSER_TIMEOUT"):
|
||
|
|
self.browser.timeout = int(os.getenv("SMP_BROWSER_TIMEOUT"))
|
||
|
|
if os.getenv("SMP_BROWSER_USER_AGENT"):
|
||
|
|
self.browser.user_agent = os.getenv("SMP_BROWSER_USER_AGENT")
|
||
|
|
if os.getenv("SMP_BROWSER_PROXY"):
|
||
|
|
self.browser.proxy = os.getenv("SMP_BROWSER_PROXY")
|
||
|
|
|
||
|
|
# 并发配置
|
||
|
|
if os.getenv("SMP_MAX_CONCURRENT_TASKS"):
|
||
|
|
self.concurrency.max_concurrent_tasks = int(os.getenv("SMP_MAX_CONCURRENT_TASKS"))
|
||
|
|
if os.getenv("SMP_TASK_RETRY_COUNT"):
|
||
|
|
self.concurrency.task_retry_count = int(os.getenv("SMP_TASK_RETRY_COUNT"))
|
||
|
|
|
||
|
|
# 文件配置
|
||
|
|
if os.getenv("SMP_MAX_IMAGE_SIZE"):
|
||
|
|
self.file.max_image_size = int(os.getenv("SMP_MAX_IMAGE_SIZE"))
|
||
|
|
if os.getenv("SMP_MAX_VIDEO_SIZE"):
|
||
|
|
self.file.max_video_size = int(os.getenv("SMP_MAX_VIDEO_SIZE"))
|
||
|
|
|
||
|
|
# 日志配置
|
||
|
|
if os.getenv("SMP_LOG_LEVEL"):
|
||
|
|
self.log.level = os.getenv("SMP_LOG_LEVEL")
|
||
|
|
if os.getenv("SMP_LOG_DIR"):
|
||
|
|
self.log.log_dir = os.getenv("SMP_LOG_DIR")
|
||
|
|
|
||
|
|
def _adjust_for_environment(self):
|
||
|
|
"""根据环境调整配置"""
|
||
|
|
if self.ENV == "production":
|
||
|
|
# 生产环境配置
|
||
|
|
self.browser.headless = True
|
||
|
|
self.log.level = "WARNING"
|
||
|
|
self.concurrency.max_concurrent_tasks = 2 # 降低并发
|
||
|
|
self.human_behavior.pause_probability = 0.25 # 增加暂停频率
|
||
|
|
elif self.ENV == "testing":
|
||
|
|
# 测试环境配置
|
||
|
|
self.browser.headless = True
|
||
|
|
self.concurrency.max_concurrent_tasks = 1
|
||
|
|
self.concurrency.task_retry_count = 1
|
||
|
|
self.log.level = "DEBUG"
|
||
|
|
|
||
|
|
@property
|
||
|
|
def cookies_dir(self) -> Path:
|
||
|
|
"""Cookie目录路径"""
|
||
|
|
return self.BASE_DIR / "auth" / "cookies"
|
||
|
|
|
||
|
|
@property
|
||
|
|
def logs_dir(self) -> Path:
|
||
|
|
"""日志目录路径"""
|
||
|
|
return self.BASE_DIR / self.log.log_dir
|
||
|
|
|
||
|
|
@property
|
||
|
|
def temp_dir(self) -> Path:
|
||
|
|
"""临时目录路径"""
|
||
|
|
return self.BASE_DIR / self.file.temp_dir
|
||
|
|
|
||
|
|
@property
|
||
|
|
def media_dir(self) -> Path:
|
||
|
|
"""媒体文件目录路径"""
|
||
|
|
return self.BASE_DIR / "media"
|
||
|
|
|
||
|
|
def ensure_directories(self):
|
||
|
|
"""确保所有必要的目录存在"""
|
||
|
|
directories = [
|
||
|
|
self.cookies_dir,
|
||
|
|
self.logs_dir,
|
||
|
|
self.temp_dir,
|
||
|
|
self.media_dir / "images",
|
||
|
|
self.media_dir / "videos"
|
||
|
|
]
|
||
|
|
|
||
|
|
for directory in directories:
|
||
|
|
directory.mkdir(parents=True, exist_ok=True)
|
||
|
|
|
||
|
|
def to_dict(self) -> dict:
|
||
|
|
"""转换为字典格式"""
|
||
|
|
return {
|
||
|
|
"ENV": self.ENV,
|
||
|
|
"DEBUG": self.DEBUG,
|
||
|
|
"BASE_DIR": str(self.BASE_DIR),
|
||
|
|
"browser": {
|
||
|
|
"headless": self.browser.headless,
|
||
|
|
"timeout": self.browser.timeout,
|
||
|
|
"viewport_width": self.browser.viewport_width,
|
||
|
|
"viewport_height": self.browser.viewport_height,
|
||
|
|
"user_agent": self.browser.user_agent,
|
||
|
|
"proxy": self.browser.proxy
|
||
|
|
},
|
||
|
|
"human_behavior": {
|
||
|
|
"typing_speed": self.human_behavior.typing_speed,
|
||
|
|
"pause_probability": self.human_behavior.pause_probability,
|
||
|
|
"random_delay_range": self.human_behavior.random_delay_range
|
||
|
|
},
|
||
|
|
"concurrency": {
|
||
|
|
"max_concurrent_tasks": self.concurrency.max_concurrent_tasks,
|
||
|
|
"task_retry_count": self.concurrency.task_retry_count,
|
||
|
|
"retry_backoff_factor": self.concurrency.retry_backoff_factor
|
||
|
|
},
|
||
|
|
"file": {
|
||
|
|
"max_image_size": self.file.max_image_size,
|
||
|
|
"max_video_size": self.file.max_video_size,
|
||
|
|
"supported_image_formats": self.file.supported_image_formats,
|
||
|
|
"supported_video_formats": self.file.supported_video_formats
|
||
|
|
},
|
||
|
|
"log": {
|
||
|
|
"level": self.log.level,
|
||
|
|
"log_dir": self.log.log_dir,
|
||
|
|
"rotation": self.log.rotation,
|
||
|
|
"retention": self.log.retention
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# 全局配置实例
|
||
|
|
settings = Settings()
|
||
|
|
|
||
|
|
# 确保目录存在
|
||
|
|
settings.ensure_directories()
|