Add EasyEDA Std project source ingestion (10 boards backfilled)

打通 oshwhub origin=std 项目的工程源(schematic + PCB dataStr)抓取链路。原
plan.md §1.6 假设需要登录,实测 lceda.cn/api/documents/<doc>?uuid=<doc>&path=<doc>
对公开项目匿名可访问 —— 无需 cookie,无账号封禁风险。

调研:4 轮探测留痕在 data/state/std_probe[1-5]/(gitignored);翻 Std 编辑器
v6.5.51 的 main.min.js bundle 找到 ajaxDetail 端点;按 docType 区分两种
响应 shape(schematic 项目视图 vs PCB 文档视图)。

Crawler:
  - make_source_client() 用浏览器 UA + lceda.cn/editor Referer,因为
    oshwhub /api/project/<uuid> 端点拒绝 FacereDataset/0.1 UA(CLAUDE.md
    UA 例外条款:目标站主动封自定义 UA + 公开静态资源)
  - fetch_std_source(): 项目元 → version_documents → 逐文档 dataStr → 落
    source/<doc>.json + source/manifest.json
  - --with-source(爬新项目时一并抓源)/ --backfill-source(仅扫已有)
  - QPS ≤ 0.2 (SLEEP_SOURCE = 5s) 自律

Schema: 加 source_format / source_path / source_documents / editor_version
(前 3 进 enum 锁定,便于后续 Pro / KiCad 源对齐)。

回填结果:10/10 成功,45 个文档,33.2 MB;schema validate 全通。
docTypes 主要是 1 (schematic) 与 3 (pcb);USB 电压电流表只有 PCB 文档(4 个:
主板+盖板+底板+面板,作者未上传原理图源)。

完整调研:docs/sources/easyeda_std_source.md。
This commit is contained in:
2026-04-28 20:07:40 +08:00
parent b0d3afd2a9
commit d874278bc5
71 changed files with 4389 additions and 23 deletions

101
log.md
View File

@@ -4,6 +4,107 @@
---
## 2026-04-28 19:50 Std 工程源链路打通 + 10 板子 schematic/PCB 全部回填
**Claude 会话**
承接计划:把已抓 10 个板子的"需登录才能下载的原理图 + PCB"补齐。
### 关键发现:根本不需要登录
10 个板子全是 `origin: "std"`EasyEDA 标准版)。原 `plan.md §1.6` 假设源数据要登录 — 实际**公开项目的 `dataStr` 匿名可访**。
调研路径4 轮探测,留痕在 `data/state/std_probe[1-5]/`
1. `/api/user``/api/projects` 401cookie 已过期,但和源抓取无关)
2. **`oshwhub.com/api/project/<uuid>` 浏览器 UA 匿名 200**,返回 `version_documents[]`(含 doc uuid + master + history chain
3. `modules.lceda.cn/histories/<hash>.json` 仍 403与 Pro 同结构,但 Std 不走这条路)
4. 翻 Std 编辑器 `/editor/6.5.51/js/main.min.js`5 MBgrep `/api/`,找到 76 个端点。关键的 `ajaxDetail = '/api/documents/{uuid}'`
5. 命中:**`https://lceda.cn/api/documents/<doc>?uuid=<doc>&path=<doc>`** 匿名 200body 是完整 EasyEDA JSON`dataStr.{head,canvas,shape,BBox,colors[layers,objects,DRCRULE,...]}`
**两种响应 shape**(按 docType 区分):
- docType=1 (Schematic):返"项目视图"`result.schematics[0].dataStr`
- docType=3 (PCB):返"文档视图"`result.dataStr` 直接在顶层
### 与 Pro 的差异
| 维度 | Std (本轮) | Pro (`docs/sources/easyeda_pro_source.md`) |
|---|---|---|
| 鉴权 | **无需** | `lceda_pro_session` 必须 |
| 加密 | **无** | AES-128-GCM + gzip |
| 源格式 | 扁平 EasyEDA JSON`shape[]` | EPRO2 消息流(事件溯源) |
| 多 doc | `version_documents[]` 逐个 GET | `/structures` + history chain 重放 |
### 实施
- `docs/sources/easyeda_std_source.md`:完整调研(含 dataStr 字段、抓取伪代码、附录重跑脚本)
- `crawlers/oshwhub/crawler.py`
- 新增 `make_source_client()` —— 浏览器 UA + Referer规避 oshwhub `/api/project/<uuid>` 端点对 `FacereDataset/0.1` UA 的 reject在 commit message 注明 UA 例外原因)
- 新增 `fetch_std_source()`:项目 → version_documents → 逐文档 dataStr → 落 `source/<doc>.json` + `source/manifest.json`
- 新增 `--with-source` 标志(爬新项目时一并抓源)和 `--backfill-source`(仅扫已有项目补源)
- QPS ≤ 0.2`SLEEP_SOURCE = 5.0s`
- `schemas/project.schema.json`:加 `source_format`/`source_path`/`source_documents`/`editor_version` 字段(前 3 个进 enum 锁定,后续新源好对齐)
### 跑批结果dev1QPS 0.2
10/10 全成功schema 验证 10/10 pass
| 项目 | docs | docTypes | 大小 | editor |
|---|---|---|---|---|
| ST-LINK V2-1 | 2 | [1,3] | 682 KB | 6.5.39 |
| USB 电压电流表 | **4** | **[3]** | 1.2 MB | 6.5.15 |
| 红外热成像 | 2 | [1,3] | 1.6 MB | 6.5.22 |
| t12-858d 焊台 | **11** | [1,3] | 6.1 MB | 6.5.15 |
| 加热台量产计划 | 6 | [1,3] | **12.0 MB** | 6.5.43 |
| ESP32-S3 智能手表 | 4 | [1,3] | 1.4 MB | 6.5.41 |
| RT300-MKV 可调电源 | 3 | [1,3] | 3.3 MB | 6.5.23 |
| YuzuMaix V831 | 4 | [1,3] | 5.4 MB | 6.5.37 |
| 盖革计数器 | 6 | [1,3] | 1.2 MB | 6.5.47 |
| ZVS 感应加热 | 3 | [1,3] | 990 KB | 6.5.40 |
**合计**45 个文档 / 33.2 MB中位 ~1.5 MB / 项目,附件主体约为附件主流量的 6%
观察:
- USB 电压电流表只有 PCB 文档4 个:主板 + 盖板 + 底板 + 面板,作者未上传原理图源)
- t12 焊台 11 个文档(拆得碎,估计含多个独立模块)
- editor 版本散布在 6.5.15 - 6.5.47(取决于作者上一次保存项目时的客户端版本)
### 落盘结构per project
```
data/raw/oshwhub/<uuid>/
├── metadata.json # ★ 新增字段source_format/source_path/source_documents/editor_version
├── description.md
├── cover.*
├── _urls.json
├── files/ # 用户附件已存在LFS
└── source/ # ★ 新EasyEDA Std 工程源
├── manifest.json # 文档清单 + 抓取时间 + upstream version_documents 留档
└── <doc_uuid>.json # 完整 dataStr 响应(普通 git文件 1-5 MB 量级)
```
`source/*.json` **走普通 git** 而不是 LFS10 项目共 33 MB 完全够用;放量时再考虑加 LFS 规则)。
### 安全 / 合规
- 无登录态、无凭据使用 → 无账号封禁风险,无 cookie 泄漏顾虑
- UA 例外:源抓取使用浏览器 UA 而非 `FacereDataset/0.1`,原因写入 `docs/sources/easyeda_std_source.md §3` 与本 commit message
- License与原项目附件相同的 license 字段已在 metadata下游 whitelist 过滤逻辑不变
### 未决 / 下一步
1. dev1 上的 `~/.secrets/lceda.json` cookie 已过期XSRF 4-22 失效,今天 4-28但**本任务已不依赖**它。是否保留待定 —— Pro 流程可能仍要
2. `easyeda2kicad.py` 转换:现有 45 个 dataStr 是关键测试样本,可立刻跑(`plan.md §1.7`
3. 放量决策:从 10 → 50 → 全量 12,493 时,按 33 MB / 10 ≈ 3.3 MB/proj 估算,全量源 ~40 GB不含附件本体
4. 多账号轮询、Pro 链路打通仍是 `plan.md §1.6` 的开放项(仅当遇到 Pro 项目时才用得上)
### 改动清单
- 新增:`docs/sources/easyeda_std_source.md``scripts/probe_std_api[1-5].py``data/raw/oshwhub/<uuid>/source/`10 项目)
- 修改:`crawlers/oshwhub/crawler.py``schemas/project.schema.json`、10 项目的 `metadata.json`
- 待人工:`projects.md` 重生成(脚本未跑);`plan.md §1.6` 状态从 ⏳ → ✅§1.7 unblocked
---
## 2026-04-24 00:25 打通 pro.lceda.cn 工程源完整链 + EPRO2 格式解析
**Claude 会话**