# FacereDataset 爬取与建设计划

**维护**：Charles
**最近更新**：2026-04-23
**状态**：Phase 0 已完成（仓库骨架），Phase 1 待启动

---

## 总体策略

**先广度后深度，先合规后规模。**

1. 每个数据源先做一份 "可行性调研"（一页纸，放 `docs/sources/<site>.md`），明确：访问形式、速率限制、许可证分布、ToS 摘要、数据字段覆盖。
2. 每个站点实现一个最小 MVP 爬虫，**单项目跑通** → 然后才全量化。
3. 全量化之前先对齐抽样结果与存储开销。
4. 所有站点输出统一到 `schemas/project.schema.json` 定义的结构，不要让下游消费者去适配 N 种 schema。

---

## Phase 0 — 仓库骨架 ✅

- [x] `README.md` / `CLAUDE.md` / `plan.md` / `log.md`
- [x] 目录骨架 `crawlers/ schemas/ scripts/ data/ docs/`
- [x] `.gitignore`（排除 derivative 目录）/ `.gitattributes`（LFS 规则）
- [x] 初始提交并推送

---

## Phase 0.5 — 基础设施 / 运行环境

**目标**：把爬取从本地 dev 机迁到专用云服务器（广州，已规划），集中管理登录凭据、磁盘和长跑任务。

### 0.5.1 云服务器初始化（待机器到位）

- [ ] 机器规格确认（CPU / 内存 / 磁盘初始容量；广州可用区）
- [ ] 基础环境：
  - [ ] 系统升级 + 防火墙
  - [ ] 安装：`git`, `git-lfs`, `uv`, `python 3.11+`, `jq`, `curl`
  - [ ] 创建非 root 用户 + SSH key（不允许密码登录）
- [ ] 克隆仓库：`git clone https://git.deepknow.site/Facere/FacereDataset.git ~/repo/FacereDataset`
- [ ] `git lfs install` + 配置 Gitea 带 token 的 remote
- [ ] `uv sync` 安装依赖
- [ ] 凭据目录：`~/.secrets/` (mode 700)，放 Gitea token、oshwhub cookie、其它登录态
- [ ] 写 `docs/infra.md` 记录主机 ID、用户、路径、端口开放情况（**不**含凭据值）

### 0.5.2 调度

- [ ] 单次长跑：`tmux` / `nohup` + 输出落 `~/logs/<site>-<date>.log`
- [ ] 定期增量：`systemd timer`（优先）或 `cron`，每周扫新增 / 更新
- [ ] 磁盘监控：` df -h | cron` 告警阈值 80%

### 0.5.3 登录态获取（按站点）

- [ ] oshwhub / u.lceda.cn：用浏览器登录后导出 cookie → 转 `~/.secrets/oshwhub-cookies.txt`，httpx 通过 `cookies=` 注入
- [ ] 换号 / 重登事件记到 `docs/secrets.md`（只写事件，不写值）

---

## Phase 1 — 立创开源平台（oshwhub.com）MVP ✅ 首批完成

**目标**：跑通 10 个项目的完整抓取，验证 schema。
**实际**：10/10 成功，52 附件，524 MB 入 LFS。

### 1.1 调研 ✅

- [x] 列表 API `/api/project?page=N&pageSize=M&sort=hot`（无鉴权）
- [x] 详情页 SSR HTML 嵌入 escaped JSON，含 attachments 数组与 license
- [x] 附件 CDN `image.lceda.cn/{src}` 直连
- [x] `docs/sources/oshwhub.md` 调研笔记

### 1.2 爬虫 MVP ✅

`crawlers/oshwhub/crawler.py`：

- [x] 列表分页 + 质量打分排序
- [x] HTML 解析：title / description / license / attachments
- [x] 每项目目录：metadata / description / cover / files / _urls
- [x] QPS ≤ 0.5，UA 真实声明

### 1.3 验收 ⏳

- [x] 10/10 成功，产出符合 `schemas/project.schema.json`
- [ ] **待人工**：随机抽查 2-3 条对照原站
- [ ] `scripts/validate.py` 自动 schema 校验（未写，后续补）

### 1.4 放量（待决策）

- [ ] 定目标规模：50 / 500 / 5000 / 全量 12493
- [x] 实测规模分布（见 `docs/sources/oshwhub.md` §5）：
  - median/proj 9 MB → 全量 **~110 GB**（合理预算）
  - p90 上界 **660 GB**
  - mp4+qt 视频占 54% → 加 `--skip-ext mp4,qt` 可省一半
- [ ] **存储分级**（按规模演进）：
  - **Phase 1.x 前期（< 50 GB）**：直接落云服务器磁盘，`git-lfs push` 到 Gitea
  - **放量中期（50 – 200 GB）**：Gitea LFS 容量压力评估；可选方案 (a) 服务器挂载大盘扩容，(b) 分批 push 分仓（按月 / 按 grade 档位切仓库）
  - **放量后期（> 200 GB）**：迁移到**网盘 / 对象存储**（候选：阿里云 OSS、腾讯 COS、MinIO 自建），Gitea 只存 metadata + 指针
  - [ ] 选型决策点：达到 50 GB 时评估，**不**过早迁移
- [ ] 增量更新：`updated_at` 变动检测 + LFS prune 策略（未实现）
- [ ] 登录态工程源（u.lceda.cn EasyEDA JSON）现在纳入范围，见 §1.6

### 1.6 登录态工程源抓取（u.lceda.cn）

**目标**：拿到立创 EDA 的**真正工程源 JSON**（含原理图、PCB、组件数据），而不只是用户附件。是训练数据质量的关键升级。

- [ ] 在广州云服务器上用合法账号登录 oshwhub / EasyEDA，导出 cookie
- [ ] 探明 `u.lceda.cn/api/...` 的项目源下载端点：
  - `/api/projects` 返回 401（需 session）——登录后试
  - 可能的端点：`/api/project/<uuid>`、`/api/document/<uuid>/source`
- [ ] 扩展 `crawlers/oshwhub/crawler.py`：
  - `--with-source` 开关触发登录态抓取
  - 把工程源 JSON 存到 `data/raw/oshwhub/<uuid>/source.json`（LFS）
  - schema 加 `source_format: "easyeda"` 字段
- [ ] 账号速率更保守：登录态 QPS ≤ 0.2，避免被封号

### 1.7 立创 EDA → KiCad 格式转换

**目标**：把 `source.json`（立创 EDA / EasyEDA 格式）批量转成 KiCad 原生格式（`.kicad_sch` + `.kicad_pcb` + 可选 `.pretty` 库），打通 oshwhub（EasyEDA 生态）与 `bshada/open-schematics`（KiCad 生态）的统一训练语料。

**预选工具**：[`easyeda2kicad`](https://github.com/uPesy/easyeda2kicad.py)（pypi 包，活跃维护）
- 支持 EasyEDA → KiCad 6/7/8 symbol / footprint / 3D model 转换
- 可能需要扩展以支持整个 project JSON → `.kicad_pro` + 关联文件

- [ ] 调研 `easyeda2kicad.py` 的整工程转换能力；若只支持单符号 / 封装，评估是否需要自写 orchestrator
- [ ] 写 `scripts/convert_to_kicad.py`：
  - 输入：`data/raw/oshwhub/<uuid>/source.json`
  - 输出：`data/processed/oshwhub/<uuid>/kicad/` 下的 `.kicad_sch`、`.kicad_pcb` 等
  - 支持批处理：`--input data/raw/oshwhub/ --output data/processed/oshwhub/` 扫全目录
  - 失败样本落 `data/state/convert_failed.jsonl`（记 uuid + 原因）
  - 转换后跑 KiCad CLI `kicad-cli sch erc` / `pcb drc` 做语法校验
- [ ] 产出统计：转换成功率、常见失败模式，反馈到工具选型
- [ ] 运行：云服务器定期批处理（每次爬完新项目后跑）

### 1.5 纳入第三方预处理数据集 `bshada/open-schematics`

**性质**：Hugging Face 已发布的 KiCad schematics 数据集（非待爬网站），镜像导入即可。

**目标**：补 KiCad 原生生态，与 oshwhub (EasyEDA) 互补。

- [x] 调研（见 `docs/sources/hf_bshada_open_schematics.md`）
- [ ] **待拍板** 6.4 GB LFS 预算
- [ ] 目录：`data/external/huggingface/bshada--open-schematics/`
  - 整包镜像，**不**拆成 per-project 目录（10K+ 条记录）
  - 78 parquet shards + README + 封面 + 追加 `ATTRIBUTION.md`
- [ ] `.gitattributes`：`data/external/**/*.{parquet,png}` 走 LFS
- [ ] 下载：`huggingface-cli download bshada/open-schematics --repo-type dataset --local-dir data/external/huggingface/bshada--open-schematics`
- [ ] 单独维护 `datasets.md`（per-project 索引 `projects.md` 不适合整包数据集）

---

## Phase 2 — GitHub 开源硬件 repo

**目标**：抓 KiCad / EasyEDA / Eagle 格式的公开 repo。

- [ ] 用 GitHub Code Search API 查 `extension:kicad_pcb` / `extension:sch` / `filename:*.epro` 等
- [ ] 过滤 star ≥ N（降噪，可调）
- [ ] 抓 repo 元数据 + 文件树 + 关键文件，**不 clone 全仓**（省带宽）
- [ ] License 从 repo `LICENSE` 文件 + GitHub API `license` 字段双取
- [ ] MCP：优先 `mcp__github__*` 工具；大规模批量可切 `gh api` + `gitingest`

预计工期：3-5 天。

---

## Phase 3 — Hackaday.io

- [ ] 探测是否有公开 API（`/api/v1/` 曾经存在，需 key）
- [ ] 若无 API：解析 explore 列表 + project/log 页面
- [ ] 重点抓项目叙事（README / build log）——这是 LLM 语料的高价值部分

预计工期：3 天。

---

## Phase 4 — 长尾站点

并列小项目，每个 0.5-1 天：

- [ ] CERN OHR（`ohwr.org`）—— 高质量、CERN-OHL 许可清晰
- [ ] Wikifactory
- [ ] Open Hardware Park
- [ ] Tindie（仅商品元数据，文件多半不公开）
- [ ] Instructables 硬件类目（文本叙事为主）

---

## Phase 5 — 数据清洗与派生

- [ ] 去重：`sha256(files)` + `(title, author)` 模糊匹配
- [ ] 质量打分：字段完整度 + 文件大小合理性 + license 有效性
- [ ] 派生数据集：
  - `components.jsonl`：从 BOM 汇总常见元件 → 成本曲线
  - `subcircuits.jsonl`：常见子电路模板（电源、USB、MCU 最小系统）
  - `narratives.jsonl`：项目叙事文本语料（给 LLM 预训练）
- [ ] 生成 README 级统计：项目总数、许可证分布、站点覆盖

---

## Phase 6 — 持续运营

- [ ] 增量爬取 cron：每站点每周扫一次新增/更新
- [ ] 数据发布：版本化 snapshot（v0.1, v0.2, ...），Release tag 到 Gitea
- [ ] 反馈回路：模型训练团队发现脏数据 → issue → 过滤规则下沉到 `scripts/`

---

## 风险与未决项

| 风险 | 影响 | 缓解 |
|-----|-----|-----|
| oshwhub 反爬加强 | 卡住 Phase 1 | 切 lightpanda/真 Chrome；降速；部分内容弃 |
| 许可证字段缺失 / 模糊 | 下游训练合规风险 | 默认剔除 `license: unknown`；建 whitelist |
| 单个项目附件过大（>100MB） | 存储爆炸 | 实测 p90=54MB 可接受；大于阈值走外部 OSS、只存 URL |
| GitHub API rate limit | Phase 2 慢 | 使用已登录 `gh` token；必要时换 fine-grained PAT |
| 站点改版 | 爬虫失效 | 爬虫带 schema 自检，HTML 结构变化时告警 |
| **登录态账号被封** | §1.6 登录态工程源卡住 | 账号 QPS ≤ 0.2；多账号轮询；凭据泄露应急计划（见 `docs/infra.md`） |
| **EDA→KiCad 转换缺失字段** | §1.7 产物不可用 | 每轮记录失败样本；扩展工具 or 保留原始 JSON 作 fallback |
| **云服务器单点故障** | 长跑任务中断 | 数据及时 push 到 Gitea；定时快照云盘；抓取进度存 `data/state/` |

**未决**：
- 数据规模目标：第一版想要 1 万 / 10 万 / 全量？
- 存储分级切换阈值：什么时机从 Gitea LFS 迁到对象存储？（当前提议 200 GB）
- 对象存储选型：阿里云 OSS / 腾讯 COS / MinIO 自建？
- 是否保留视频（mp4/qt 占 54% 存储）：加 `--skip-ext` 还是全保？
