返回首页

异步漫画解析器:Python 中的架构

Python 中异步漫画解析器架构的详细分解。涵盖通过抽象类实现的契约、Pydantic 验证、SQLAlchemy ORM 以及向微服务的过渡。强调可扩展性和代码库的可维护性。

Python 漫画解析器:从契约到微服务
Advertisement 728x90

Python 异步漫画解析器:从架构到微服务

构建一个可扩展的漫画解析器是一项结合了异步编程、契约设计和状态管理的挑战性任务。Manga-Day 是一个从单体架构向微服务架构转型的实际案例,使用了 asyncio、Pydantic 和 SQLAlchemy。该项目最初构想为一个自动从数十个网站收集数据的工具,但如今已成为设计可扩展系统的教程。

架构基础:契约与异步性

系统的核心围绕抽象类 BaseSpider 构建。每个具体的解析器(例如,用于 multi-manga 的解析器)只需实现单一接口,即可动态添加新数据源,而无需修改核心代码。契约包括三个关键方法:

from abc import ABC, abstractmethod

class BaseSpider(ABC):
    BASE_URL = "https://example-manga.com"

    @abstractmethod
    async def get(self, url: str, **kwargs) -> Optional[MangaSchema]: ...

    @abstractmethod
    async def pages(
        self, start_page: int | None = None
    ) -> AsyncGenerator[list[BaseManga], Any]: ...

这种方法确保了:

Google AdInline article slot
  • 统一的错误和超时处理
  • 能够独立测试每个 spider
  • 通过异步生成器支持水平扩展

异步性在 asyncio 层面实现,能够高效处理数百个并发请求,而不会因 I/O 阻塞。这在处理缓慢或不稳定的数据源时尤为重要。

数据验证与 ORM 模型

Pydantic 用于严格的类型化和验证。系统基于三个层次的模型构建:

  • BaseManga — 最小字段集:标题、海报、URL、sku(SHA256 哈希)
  • MangaWithGallery — 添加图像 URL 列表
  • MangaSchema — 完整模型,包括类型、作者和语言(可选)

在 SQLAlchemy 管理的数据库中,实现了以下实体:

Google AdInline article slot
  • Manga、Author、Genre、Language — 核心表
  • GenreManga — 类型间的多对多关系
  • Gallery — 图像的独立表(避免随主查询加载)
  • GeneratedPdf — 已弃用的表,计划移除

将图库分离为独立实体,避免了加载漫画列表时的 N+1 问题——图像现仅在明确请求时加载。

管理器:数据之上的业务逻辑

管理器充当业务逻辑层——负责特定操作的类:

  • MangaManager:基于 SKU、URL、ID 的 CRUD 操作
  • RequestManager:带重试逻辑和超时的 HTTP 请求
  • AlertManager:通用通知系统(Telegram、Discord 等)
  • SpiderManager:所有 spider 的中央协调器

SpiderManager 因其模块化设计而特别有趣。它被拆分为四个文件:

Google AdInline article slot
  • _load.py — 通过 __all__ 动态加载 spider
  • _status.py — 状态模型和枚举
  • _starter.py — 启动和生命周期管理
  • _spider.py — 将组件组合成单一接口

这种拆分简化了测试,并允许变更隔离——例如,添加新 spider 仅需在 __init__.py 中注册,无需修改核心代码。

向微服务转型:痛点与解决方案

项目起初是单体架构,但两个服务成为变革的催化剂:

  • PDFService — 消耗过多 RAM,迁移到独立容器
  • Bot — 需要 WebSocket 和 JWT 认证,也迁移到隔离服务

迁移经历了几个阶段:

  • 前端与核心解耦——现仅通过 REST API 工作,Jinja 仅用于配置
  • Bot 使用 aiohttp 重写,支持 WebSocket 并通过 JWT 实现基于角色的访问控制
  • PDF 生成现作为后台任务运行,并限制内存使用

主要挑战:

  • 服务间复杂对象的序列化
  • 部分故障时的數據一致性
  • 设置健康检查和优雅关机

关键经验

  • 契约比实现更重要 — 抽象类实现了无需核心重构的扩展
  • 异步 ≠ 自动性能提升 — 控制并发任务数并使用信号量
  • ORM 并非万能 — 手动查询优化和反范式化(例如分离图库)对性能至关重要
  • 微服务增加复杂度但提供灵活性 — 将 PDFService 独立解决了内存问题,但提升了部署复杂度
  • 可测试性是架构成果 — SpiderManager 的模块化允许无需模拟外部依赖的单元测试

该项目已成为理解如何构建可长期演进系统的起点。代码库已扩展到数万行,但清晰的责任分离保持了其可维护性。下一步包括实现消息代理用于任务队列,并在每个拉取请求上运行完整的 CI/CD 和自动测试。

— Editorial Team

Advertisement 728x90

继续阅读