170 lines
6.5 KiB
Python
170 lines
6.5 KiB
Python
"""
|
||
自定义异常类定义
|
||
"""
|
||
|
||
from typing import Optional, Dict, Any
|
||
|
||
|
||
class SocialMediaError(Exception):
|
||
"""基础异常类"""
|
||
|
||
def __init__(self, message: str, error_code: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message)
|
||
self.message = message
|
||
self.error_code = error_code
|
||
self.details = details or {}
|
||
|
||
def to_dict(self) -> Dict[str, Any]:
|
||
"""转换为字典格式"""
|
||
return {
|
||
"error_type": self.__class__.__name__,
|
||
"message": self.message,
|
||
"error_code": self.error_code,
|
||
"details": self.details
|
||
}
|
||
|
||
|
||
class LoginFailedError(SocialMediaError):
|
||
"""登录失败异常"""
|
||
def __init__(self, message: str = "登录失败", platform: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "LOGIN_FAILED", details)
|
||
self.platform = platform
|
||
|
||
|
||
class UploadFailedError(SocialMediaError):
|
||
"""上传失败异常"""
|
||
def __init__(self, message: str = "文件上传失败", file_path: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "UPLOAD_FAILED", details)
|
||
self.file_path = file_path
|
||
|
||
|
||
class ContentRejectedError(SocialMediaError):
|
||
"""内容被拒绝异常"""
|
||
def __init__(self, message: str = "内容被平台拒绝", reason: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "CONTENT_REJECTED", details)
|
||
self.reason = reason
|
||
|
||
|
||
class RateLimitError(SocialMediaError):
|
||
"""频率限制异常"""
|
||
def __init__(self, message: str = "操作频率过高,请稍后再试", retry_after: Optional[int] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "RATE_LIMIT", details)
|
||
self.retry_after = retry_after
|
||
|
||
|
||
class ElementNotFoundError(SocialMediaError):
|
||
"""元素未找到异常"""
|
||
def __init__(self, message: str = "页面元素未找到", selector: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "ELEMENT_NOT_FOUND", details)
|
||
self.selector = selector
|
||
|
||
|
||
class TimeoutError(SocialMediaError):
|
||
"""超时异常"""
|
||
def __init__(self, message: str = "操作超时", timeout: Optional[float] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "TIMEOUT", details)
|
||
self.timeout = timeout
|
||
|
||
|
||
class AuthenticationError(SocialMediaError):
|
||
"""认证失败异常"""
|
||
def __init__(self, message: str = "认证失败", platform: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "AUTHENTICATION_FAILED", details)
|
||
self.platform = platform
|
||
|
||
|
||
class NetworkError(SocialMediaError):
|
||
"""网络错误异常"""
|
||
def __init__(self, message: str = "网络连接错误", url: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "NETWORK_ERROR", details)
|
||
self.url = url
|
||
|
||
|
||
class ValidationError(SocialMediaError):
|
||
"""数据验证错误异常"""
|
||
def __init__(self, message: str = "数据验证失败", field: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "VALIDATION_ERROR", details)
|
||
self.field = field
|
||
|
||
|
||
class PlatformNotSupportedError(SocialMediaError):
|
||
"""平台不支持异常"""
|
||
def __init__(self, message: str = "不支持的平台", platform: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "PLATFORM_NOT_SUPPORTED", details)
|
||
self.platform = platform
|
||
|
||
|
||
class BrowserError(SocialMediaError):
|
||
"""浏览器错误异常"""
|
||
def __init__(self, message: str = "浏览器操作错误", details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "BROWSER_ERROR", details)
|
||
|
||
|
||
class CookieExpiredError(AuthenticationError):
|
||
"""Cookie过期异常"""
|
||
def __init__(self, message: str = "Cookie已过期,请重新登录", platform: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, platform, details)
|
||
self.error_code = "COOKIE_EXPIRED"
|
||
|
||
|
||
class FileSizeExceededError(ValidationError):
|
||
"""文件大小超限异常"""
|
||
def __init__(self, message: str = "文件大小超出限制", file_size: Optional[int] = None, max_size: Optional[int] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "FILE_SIZE_EXCEEDED", details)
|
||
self.file_size = file_size
|
||
self.max_size = max_size
|
||
|
||
|
||
class UnsupportedFormatError(ValidationError):
|
||
"""不支持的文件格式异常"""
|
||
def __init__(self, message: str = "不支持的文件格式", file_format: Optional[str] = None, supported_formats: Optional[list] = None, details: Optional[Dict[str, Any]] = None):
|
||
super().__init__(message, "UNSUPPORTED_FORMAT", details)
|
||
self.file_format = file_format
|
||
self.supported_formats = supported_formats
|
||
|
||
|
||
# 异常处理装饰器
|
||
def handle_exceptions(platform: Optional[str] = None, default_message: str = "操作失败"):
|
||
"""异常处理装饰器"""
|
||
def decorator(func):
|
||
def wrapper(*args, **kwargs):
|
||
try:
|
||
return func(*args, **kwargs)
|
||
except SocialMediaError:
|
||
raise # 重新抛出自定义异常
|
||
except Exception as e:
|
||
# 将未知异常包装为SocialMediaError
|
||
raise SocialMediaError(
|
||
message=f"{default_message}: {str(e)}",
|
||
error_code="UNKNOWN_ERROR",
|
||
details={
|
||
"platform": platform,
|
||
"original_exception": str(e),
|
||
"function": func.__name__
|
||
}
|
||
)
|
||
return wrapper
|
||
return decorator
|
||
|
||
|
||
# 重试机制
|
||
class RetryStrategy:
|
||
"""重试策略类"""
|
||
|
||
def __init__(self, max_retries: int = 3, backoff_factor: float = 2.0):
|
||
self.max_retries = max_retries
|
||
self.backoff_factor = backoff_factor
|
||
self.retryable_exceptions = (
|
||
NetworkError,
|
||
TimeoutError,
|
||
ElementNotFoundError,
|
||
UploadFailedError
|
||
)
|
||
|
||
def should_retry(self, exception: Exception, attempt: int) -> bool:
|
||
"""判断是否应该重试"""
|
||
return attempt < self.max_retries and isinstance(exception, self.retryable_exceptions)
|
||
|
||
def get_delay(self, attempt: int) -> float:
|
||
"""获取重试延迟时间"""
|
||
return self.backoff_factor ** attempt |