53 lines
1.5 KiB
Python
53 lines
1.5 KiB
Python
"""抓取配置加载器。
|
|
|
|
从 YAML 文件读取 sources.yaml,并校验为 CrawlerConfig。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
from loguru import logger
|
|
|
|
from .models import CrawlerConfig
|
|
|
|
DEFAULT_CONFIG_PATH = Path("configs/sources.yaml")
|
|
|
|
|
|
def load_crawler_config(path: str | Path | None = None) -> CrawlerConfig:
|
|
"""加载并校验抓取配置。
|
|
|
|
参数:
|
|
path: YAML 配置路径,默认 configs/sources.yaml。
|
|
|
|
返回:
|
|
CrawlerConfig 实例。
|
|
|
|
异常:
|
|
FileNotFoundError: 配置文件不存在。
|
|
ValueError: YAML 顶层不是 mapping 或 sources 缺失。
|
|
pydantic.ValidationError: schema 校验失败。
|
|
"""
|
|
config_path = Path(path) if path else DEFAULT_CONFIG_PATH
|
|
if not config_path.is_file():
|
|
raise FileNotFoundError(f"抓取配置文件不存在: {config_path}")
|
|
|
|
with config_path.open("r", encoding="utf-8") as f:
|
|
raw: Any = yaml.safe_load(f)
|
|
|
|
if not isinstance(raw, dict):
|
|
raise ValueError(f"配置文件顶层必须是 mapping,实际类型: {type(raw).__name__}")
|
|
if "sources" not in raw:
|
|
raise ValueError("配置文件缺少 sources 字段")
|
|
|
|
config = CrawlerConfig.model_validate(raw)
|
|
logger.info(
|
|
"已加载抓取配置: 总 {} 个源, 启用 {} 个, 并发上限 {}",
|
|
len(config.sources),
|
|
len(config.enabled_sources()),
|
|
config.settings.concurrency,
|
|
)
|
|
return config
|