第31章:工具类实现
31.1 概述
工具类是剪映小助手的基础功能模块,提供了一系列通用的辅助函数,包括文件下载、URL参数解析、唯一ID生成、文件遍历等功能。这些工具函数被广泛应用于各个服务模块中,为整个系统提供稳定可靠的基础支持。
31.2 核心工具函数
31.2.1 URL参数提取函数
get_url_param 函数用于从URL中提取指定的查询参数:
def get_url_param(url: str, key: str, default=None):
"""
从 URL 中提取指定查询参数的值(返回第一个值)。
若参数不存在,返回 default。
"""
query = parse_qs(urlparse(url).query)
return query.get(key, [default])[0]
该函数使用Python标准库的urlparse和parse_qs来解析URL查询字符串,支持提取多个相同参数名的第一个值。
31.2.2 文件下载函数
download 函数是核心的文件下载工具,支持多种文件类型和大小限制:
def download(url, save_dir, limit=30*1024*1024, timeout=180) -> str:
"""
下载文件并根据Content-Type判断文件类型
Args:
url: 文件的URL地址
save_dir: 文件保存目录
limit: 文件大小限制(字节),默认30MB
timeout: 整体下载超时时间(秒),默认3分钟
Returns:
完整的文件路径
Raises:
CustomException: 自定义异常
"""
# 1. 生成文件名
save_path = os.path.join(save_dir, gen_unique_id())
try:
# 2. 发送GET请求下载文件
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36',
'Referer': 'https://www.jcaigc.cn/',
'Accept': 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
}
response = requests.get(url, stream=True, timeout=timeout, headers=headers)
response.raise_for_status()
# 3. 获取Content-Type,判断文件类型
content_type = response.headers.get('Content-Type', '').split(';')[0].strip()
# 4. 根据Content-Type猜测扩展名
extension = mimetypes.guess_extension(content_type)
if extension:
save_path += extension
# 5. 下载文件并实时检查大小
downloaded_size = 0
with open(save_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
downloaded_size += len(chunk)
# 检查文件大小是否超过限制
if downloaded_size > limit:
# 删除部分下载的文件
f.close()
os.remove(save_path)
logger.info(f"Download failed, url: {url}, error: File size exceeds the limit of {limit/1024/1024:.2f}MB")
raise CustomException(err=CustomError.FILE_SIZE_LIMIT_EXCEEDED, detail=f"{limit/1024/1024:.2f} MB")
# 6. 验证下载完整性
content_length = response.headers.get('Content-Length')
if content_length and os.path.getsize(save_path) != int(content_length):
os.remove(save_path)
logger.warning(f"Download failed, url: {url}, error: File download incomplete")
raise CustomException(err=CustomError.DOWNLOAD_FILE_FAILED)
logger.info(f"Download success, url: {url}, save_path: {save_path}")
return save_path
except Exception as e:
# 清理可能已部分下载的文件
if os.path.exists(save_path):
os.remove(save_path)
logger.warning(f"Download failed, url: {url}, error: {str(e)}")
raise CustomException(err=CustomError.DOWNLOAD_FILE_FAILED)
31.2.3 唯一ID生成函数
gen_unique_id 函数生成基于时间戳和UUID的唯一标识符:
def gen_unique_id() -> str:
"""
生成唯一ID
"""
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
unique_id = uuid.uuid4().hex[:8]
return f"{timestamp}{unique_id}"
该函数结合时间戳(精确到秒)和UUID的前8位字符,确保生成的ID具有唯一性和可读性。
31.2.4 文件遍历函数
get_all_files 函数递归获取目录下所有文件的路径列表:
def get_all_files(dir: str) -> list:
"""
使用 pathlib.Path.rglob() 递归获取目录下所有文件的路径列表。
参数:
dir (str): 要遍历的目录路径。
返回:
list: 包含所有文件完整路径的列表。
"""
path_obj = Path(dir)
# 检查目录是否存在
if not path_obj.exists():
return []
# 使用 rglob('*') 递归匹配所有条目,并用 is_file() 过滤出文件
file_list = [str(file_path) for file_path in path_obj.rglob('*') if file_path.is_file()]
return file_list
该函数使用pathlib.Path.rglob()方法递归遍历目录,自动过滤出文件类型的条目,忽略子目录。
31.3 错误处理机制
工具类中的函数都实现了完善的错误处理机制:
31.3.1 下载错误处理
文件下载函数包含多重错误检查:
- 网络错误处理:捕获
requests库抛出的网络异常 - 文件大小限制:实时监控下载文件大小,超出限制时立即终止
- 完整性验证:对比
Content-Length头与实际下载文件大小 - 清理机制:在任何错误情况下都会清理部分下载的文件
31.3.2 自定义异常抛出
工具函数使用统一的自定义异常体系:
# 文件大小超出限制
raise CustomException(err=CustomError.FILE_SIZE_LIMIT_EXCEEDED, detail=f"{limit/1024/1024:.2f} MB")
# 下载失败
raise CustomException(err=CustomError.DOWNLOAD_FILE_FAILED)
31.4 性能优化特性
31.4.1 流式下载
文件下载采用流式处理,避免大文件占用过多内存:
response = requests.get(url, stream=True, timeout=timeout, headers=headers)
# ...
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
31.4.2 实时大小检查
在下载过程中实时检查文件大小,避免下载完成后才发现超出限制:
downloaded_size += len(chunk)
if downloaded_size > limit:
# 立即终止并清理
31.4.3 智能文件类型检测
通过HTTP响应头的Content-Type自动确定文件扩展名:
content_type = response.headers.get('Content-Type', '').split(';')[0].strip()
extension = mimetypes.guess_extension(content_type)
31.5 使用示例
31.5.1 URL参数提取
url = "https://example.com/api?draft_id=12345&user=abc"
draft_id = get_url_param(url, "draft_id") # 返回 "12345"
user = get_url_param(url, "user") # 返回 "abc"
31.5.2 文件下载
try:
save_path = download(
url="https://example.com/video.mp4",
save_dir="/tmp/downloads",
limit=50*1024*1024, # 50MB限制
timeout=300 # 5分钟超时
)
print(f"文件下载成功: {save_path}")
except CustomException as e:
print(f"下载失败: {e.err.cn_message}")
31.5.3 唯一ID生成
unique_id = gen_unique_id() # 例如: "20240115143025a1b2c3d4"
31.5.4 文件遍历
files = get_all_files("/path/to/directory")
print(f"找到 {len(files)} 个文件")
for file_path in files:
print(file_path)
31.6 扩展性设计
工具类的设计具有良好的扩展性:
- 模块化设计:每个函数功能单一,便于维护和扩展
- 参数化配置:支持通过参数调整函数行为
- 异常统一:使用统一的异常体系,便于错误处理
- 日志集成:集成了日志记录功能,便于调试和监控
附录
代码仓库地址:
- GitHub:
https://github.com/Hommy-master/capcut-mate - Gitee:
https://gitee.com/taohongmin-gitee/capcut-mate
接口文档地址:
- API文档地址:
https://docs.jcaigc.cn