Doc-Scraper 是一个解耦化、可扩展的离线文档抓取与 HTML 转 Markdown 格式化系统。 支持双后端并发调度、令牌桶 QPS 限流、API 熔断自动降级、原子化断点续抓以及多格式索引解析。
- 多引擎抓取:抽象统一
Fetcher接口,内置HttpxFetcher(HTTP 直接抓取)与FirecrawlFetcher(CLI + JS 动态渲染)。 - 可配置解析器:通过
ParserConfig支持任意站点的 CSS 正文选择器、指定 class/id/tag DOM 节点剔除、正则二次文本清洗等。 - 多格式索引与锚点去重:
EntryParser支持解析多格式索引,并根据唯一页面 URL (base_url) 自动去重聚合,保持网页原汁原味的完整排版 Markdown,消除 Fragment 锚点拆分产生的碎片文件与多余子目录。
- 生命周期状态机:任务经历
PENDING → QUEUED → FETCHING → PARSING → DONE / FAILED / WAITING。 - 指数退避重试:针对网络波动、429 限流、5xx 错误自动计算指数退避,区分不可重试错误。
- 原子检查点 (Atomic Checkpoints):定时原子化(
write -> rename)持久化已完成状态_state.json,防止中断损害数据完整性。 - 优雅关停 (Graceful Shutdown):捕获
SIGINT (Ctrl+C),优先完成正在执行的请求后退出,支持断点续抓。
- 双协程组协同:Firecrawl 组(低 QPS / 额度控制)与 HTTP 组(高并发 / 免额度)同时消费全局统一任务队列。
- 自动熔断降级:若 Firecrawl API 额度耗尽,触发熔断器(Circuit Breaker),Firecrawl 组自动退出,剩余所有任务由 HTTP 组接管。
.
├── pyproject.toml # 项目构建与依赖配置
├── README.md # 项目文档
├── path.md # 示例入口文件
├── SKILL.md # AI Agent 接入技能定义
├── configs/ # 解析器预设配置文件目录
│ ├── wechat_miniprogram.json # 微信小程序文档解析预设
│ └── generic_article.json # 通用文章/文档解析预设
├── src/
│ └── doc_scraper/ # 核心 Python 包
│ ├── __init__.py
│ ├── cli.py # CLI 命令行接口与子命令入口
│ ├── config.py # 配置模型 (ParserConfig, SchedulerConfig)
│ ├── state.py # 状态机与持久化 (TaskState, PersistentState)
│ ├── entries.py # 入口索引文件解析器 (TXT, JSON, CSV)
│ ├── fetchers/ # 抓取引擎模块
│ │ ├── base.py # Fetcher 接口与 FetchResult 容器
│ │ ├── httpx_fetcher.py # HTTP 直接抓取器
│ │ ├── firecrawl_fetcher.py # Firecrawl CLI 抓取器
│ │ └── fallback_fetcher.py # 降级编排器
│ ├── parsers/ # 内容提取与转换模块
│ │ ├── content_parser.py # DOM 选择器、节点清理与 Markdown 转换器
│ │ └── path_builder.py # 目录层级映射与主页面文档生成
│ └── schedulers/ # 调度与控速模块
│ ├── rate_limiter.py # 令牌桶 TokenBucket 限速器与退避策略
│ ├── base_scheduler.py # 单后端调度器
│ └── hybrid_scheduler.py # 双后端并发协同与熔断调度器
└── scrape_wxdoc.py # 兼容入口脚本
- Python >= 3.10
- uv (推荐)
# 测试模式 (处理前 5 个 URL)
uv run scrape_wxdoc.py --test
# 全量并发抓取 (默认双后端协同)
uv run scrape_wxdoc.py
# 使用 HTTP 模式抓取
uv run scrape_wxdoc.py --backend httpx --concurrency 10 --qps 10使用 doc-scraper 命令或 scrape_wxdoc.py 脚本:
doc-scraper [子命令] [选项]
# 或
uv run scrape_wxdoc.py [子命令] [选项]| 参数 | 默认值 | 说明 |
|---|---|---|
--path-file |
path.md |
入口索引文件路径 (支持 .md, .txt, .json, .csv) |
--output |
doc |
输出 Markdown 文档根目录 |
--backend |
hybrid |
抓取模式: hybrid(双后端协同), auto(串行降级), httpx(HTTP模式), firecrawl |
--config |
None |
解析器 JSON 配置文件路径 |
--selector |
#docContent |
提取目标正文的 CSS 选择器 |
--delimiter |
- |
标题层级路径分隔符 (例如 开发-指南-起步) |
--concurrency |
8 |
通用 / HTTP 协程组并发数 |
--qps |
8.0 |
通用 / HTTP 协程组 QPS 限速 |
--firecrawl-concurrency |
2 |
Hybrid 模式下 Firecrawl 协程组并发数 |
--firecrawl-qps |
1.0 |
Hybrid 模式下 Firecrawl 协程组 QPS 限速 |
--test |
False |
测试模式 (仅处理前 5 个页面) |
--limit |
0 |
限制处理页面数量 (0 = 不限) |
--force |
False |
强制重新抓取所有页面 (忽略历史记录) |
uv run scrape_wxdoc.py init-config -o site_config.jsonuv run scrape_wxdoc.py status --output docuv run scrape_wxdoc.py repair-links --output doc --path-file path.md功能:清理目标文档目录中由于锚点拆分产生的多余碎片文件及空目录,仅保留完整网页的主 Markdown 文件。
抓取其他网站时,配置对应的正文 CSS 选择器与节点清洗规则。
uv run scrape_wxdoc.py \
--path-file my_urls.json \
--selector "article" \
--delimiter "/" \
--backend httpx创建 custom_config.json:
{
"selector": "main.article-content",
"remove_classes": ["sidebar", "navigation", "ads"],
"remove_ids": ["comments", "footer-banner"],
"remove_tags": ["script", "style", "nav", "footer"],
"clean_patterns": [
"Edit on GitHub"
],
"heading_style": "atx",
"path_delimiter": "/"
}执行抓取:
uv run scrape_wxdoc.py --config custom_config.json --path-file urls.csvPYTHONUNBUFFERED=1 nohup uv run scrape_wxdoc.py --backend hybrid > scrape.log 2>&1 &
tail -f scrape.logMIT License