Add EasyEDA Pro EPRO2 source ingestion (3/5 batch test)

打通 oshwhub origin=pro 现代 Pro 3.x 工程的 EPRO2 源抓取链路。3/5
modern Pro 项目完整解出(共 8423 docs / 542 MB plain):

- X86 主板        7374 docs / 481 MB plain (chain=85, editor=3.2.15)
- 220V 桌面电源     771 docs /  26 MB plain (chain=28, editor=3.2.69)
- ESP-VoCat       278 docs / 7.5 MB plain (chain=12, editor=3.2.91)

剩余 2/5 是 legacy Pro 2.x(立创泰山派 RK3566、梁山派),项目 meta
返回 branch_uuid=null + editorVersion="2.1.40",没有 git-style chain
模型,文档直接挂在 boards[].sch/pcb 字段上,访问端点暂未挖通;元
数据落库 metadata.json,source/ 留空。

实现要点:
- fetch_pro_source(): 4 步流程(project → branch HEAD → structures
  → /branches/<B>/histories/<HEAD> 即返完整 chain,无需 ?limit 批量
  端点)+ 逐 history 走 AES-128-GCM 解密(16 字节 IV,pycryptodome
  原生支持)+ gunzip + 按 DOCHEAD 切 per-doc EPRO2 流
- EPRO2 解析坑:行末单 `|` 是行终止符不是字段分隔符,必须先
  rstrip("|") 再 split("||"),否则 payload JSON 解析失败 silently
  swallow 导致 cur_doc 不设 → 第一轮 X86 板 7374 docs 抽出来只剩 2 个
- docType 实测远不止 BOARD/PCB/SCH/SCH_PAGE,还含 SYMBOL /
  FOOTPRINT / DEVICE / BLOB / FONT / CONFIG —— Pro 把组件库快照也
  随项目存到 history,下游做 EPRO2→KiCad 转换时必须先把这些 lib
  doc 加载进 symbol cache
- Pro 2.x vs 3.x 是不同存储模型 —— 3.x 走 branch 模型(已打通),
  2.x 走 boards[] 直链(未打通);判别条件:project meta 的
  branch_uuid 是否为 null

CLI 新增 --with-pro-source / --backfill-pro-source / --pro-cookie /
--origin(按 origin 字段服务端过滤 listing API),crawl_one() 按
origin=pro 自动 dispatch 到 Pro fetcher。

schema:docType 类型从 integer 放宽到 [integer, string, null]
(兼容 Std 的 1/3 + Pro 的 BOARD/SCH 等),新增 message_count 字段。

License 注意:本批 5 个项目全是 NC-SA / GPL,未达 Pro source doc
§4.2 Forge 白名单(MIT/BSD/Apache/CC0/CC-BY/CERN-OHL-P/Unlicense)。
按 CLAUDE.md "研究用、不再分发" 原则 raw 入库无碍;Forge 投影时
另过白名单。

详细技术细节见 docs/sources/easyeda_pro_source.md rev 3 + log.md。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-28 21:45:52 +08:00
parent d874278bc5
commit 3282a028c4
8455 changed files with 2275248 additions and 36 deletions

97
log.md
View File

@@ -4,6 +4,103 @@
---
## 2026-04-28 21:35 Pro 工程源EPRO2批量抓取打通3/5 modern Pro 项目 ✅2/5 legacy 2.x ❌
**Claude 会话**
承接刚做完 Std 链路;用户给了浏览器 HAR (`tmp/prodownload.har`174 请求,目标 = 立创·泰山派 RK3576 现代 Pro 项目) 验证 endpoint 形态,要求"找 5 个专业版项目,看能不能批量抓 EPRO2"。
### 5 个候选
`oshwhub /api/project?origin=pro&sort=hot` 取前 5详情 API 拿 license
| # | UUID | License | 项目 | 结果 |
|---|---|---|---|---|
| 1 | `b77840665e2e...` | GPL 3.0 | 【全网首发】X86电脑主板 | ✅ |
| 2 | `7360e73de5dd...` | GPL 3.0 | 立创·泰山派 RK3566 开发板 | ❌ legacy 2.x |
| 3 | `0c4675983733...` | GPL 3.0 | 立创·梁山派开发板 | ❌ legacy 2.x |
| 4 | `dc91a91e6693...` | CC BY-NC-SA 4.0 | 高颜值220V 300W 桌面电源 | ✅ |
| 5 | `ba64bd6f1c9c...` | GPL 3.0 | ESP-VoCat 喵伴 AI 萌宠 | ✅ |
License 全是限制性CC-NC-SA / GPL— Pro 用户群是立创团队/教育机构,默认上 NC-SA。和用户对齐本仓库为研究用、不再分发license 字段忠实落库;下游 Forge 投影时再用白名单过滤。
### 关键发现Pro 2.x ≠ Pro 3.x重要
立创开发板的旗舰板RK3566 / 梁山派)抓 `/api/v4/projects/<uuid>` 返回 **`branch_uuid: null`** + `editorVersion: "2.1.40"`
这是 **Pro 编辑器旧版2.x**:没有 git-style branch/history 模型,文档直接通过 `boards: [{sch, name, pcb}]` 字段定位。我们之前调研的全是 3.x泰山派 RK3576 / 无界 PLUS3.x 才有 `/branches/<B>/structures` + `/histories/<H>` 全套。
旧版的访问端点暂未挖通:`/api/v4/documents/<doc>` 404`/api/documents/<doc>` 401`/api/v4/projects/<P>/snapshots` 200 但响应体是 project meta 不是 doc。需要录一份"在 pro.lceda.cn 编辑器里打开 RK3566"的 HAR 才能继续。已记入 `docs/sources/easyeda_pro_source.md §1.1`
### EPRO2 解析坑:行末单 `|`(找了 2 轮才看到)
第一轮跑 5 个项目结果X86 board 7374 docs 抽出来只剩 **2 个**220V 电源和 ESP-VoCat 都是 **0 docs**
定位过程:
1. 直接 dump 一条 history 的 lines看到 DOCHEAD payload **行末有单个 `|`**,例如 `{"docType":"BOARD",...,"version":"..."}|`
2. 我的解析 `json.loads(ln.split(b"||")[1])` 拿到带尾随 `|` 的字符串 → `Extra data: line 1 column 127`
3. silently swallow exception → `cur_doc` 没设 → 全 chain 的 message 被丢弃。
4. 修复:解析前先 `ln.rstrip(b"|").split(b"||")`。已在 `docs/sources/easyeda_pro_source.md §3.1` 记录"行末单 `|` 是行终止符不是字段分隔符"。
### 修复后批量结果
3 个 modern Pro 项目完整解出来:
| 项目 | chain | docs | plain | blob | editor |
|---|---|---|---|---|---|
| ESP-VoCat | 12 | 278 | 7.5 MB | 1.1 MB | 3.2.91 |
| 220V 电源 | 28 | 771 | 26.3 MB | 7.4 MB | 3.2.69 |
| X86 主板 | 85 | 7374 | **481 MB** | 61 MB | 3.2.15 |
X86 主板5123 FOOTPRINT + 1243 DEVICE + 837 SYMBOL = 7203 个组件库 doc数据量惊人是个超复杂工程。
### docType 取值表(实测扩展)
之前 doc 只列了 `BOARD/PCB/SCHEMATIC/SHEET`。实测 EPRO2 流里 docType 实际取值更细:
- 用户级文档:`BOARD`(板物理边框)+ `PCB`(板内容)+ `SCH`(原理图)+ `SCH_PAGE`(子图)。一个完整 PCB 板 = 一对 `BOARD` + `PCB`,不是命名变化。
- 组件库 / 资源:`SYMBOL` / `FOOTPRINT` / `DEVICE` / `BLOB` / `FONT` / `CONFIG`。每个独特组件 / 字体 / 项目配置都是独立 doc。
- 抓 EPRO2 = 抓项目 + **完整的局部组件库快照**。下游做 EPRO2 → KiCad 转换时必须先把 lib doc 加载进 symbol cache。
已更新到 `docs/sources/easyeda_pro_source.md §3.4`
### 代码改动
- `crawlers/oshwhub/crawler.py`
- 新增 `make_pro_source_client()` —— 加载 `~/.secrets/pro-lceda-cookie-header.txt`,自动配 `Editor-Version` / `Referer` / per-request `path` header
- 新增 `fetch_pro_source(client, project_uuid, proj_dir, sleep)` —— 4 步流程project meta → branch HEAD → structures → history chain然后逐 history 解密AES-128-GCM, 16 字节 IV+ gunzip + 按 DOCHEAD 切 per-doc
- 新增 `_order_history_chain()` —— 沿 parent 链从 root 到 HEAD 排序
- 新增 `_pro_get_json()` —— 包装 `/api/v4` GET 调用,自动加 `path` header + 校验 success
- 扩展 `crawl_one()``pro_source_client` 参数,按 `list_item.origin` 自动 dispatch
- 新增 CLI flag `--with-pro-source` / `--backfill-pro-source` / `--pro-cookie` / `--origin`
- 新增 `_run_backfill_pro_source()`filter on `raw_fields.origin == "pro"`
- `schemas/project.schema.json``docType` 类型从 `integer` 放宽到 `["integer","string","null"]`(兼容 Std 的 1/3 + Pro 的 BOARD/PCB/SCH 等字符串),新增 `message_count` 字段
- `docs/sources/easyeda_pro_source.md` rev 3加 §1.1 Pro 2.x vs 3.x、§3.1 行末 `|` 警告、§3.4 docType 实测表、§2.2 单 history endpoint 即返完整 chain
### 数据落地
```
data/raw/oshwhub/
b77840665e2e48148c1b04ce84b5f7e7/ # X86 主板modern Pro 3.2.15
source/
manifest.json # 7374 docs index
structure.json # 项目树boards/schematics/sheets/pcbs
<doc_uuid>.epro2 # 7374 个 EPRO2 文件
dc91a91e669349898d709a5ba02f5b5f/ # 220V 电源modern Pro 3.2.69
ba64bd6f1c9c467ba3b674a54943557d/ # ESP-VoCatmodern Pro 3.2.91
7360e73de5dd428e9f29e10573f2d8ac/ # legacy Pro 2.x无 source/
0c46759837334318aa4882d6d37f96fa/ # legacy Pro 2.x无 source/
```
### 下一步
1. 重要legacy Pro 2.x 抓取链:录 HAR 看 RK3566 / 梁山派 在 pro.lceda.cn 编辑器打开时走什么 endpoint
2. 想跑量到 50 / 500 项目时,先做风控测试:阶梯放量,监控 403 / 429 / 1111111
3. EPRO2 → KiCad 转换器是 Forge 投影前置硬门槛
4. 可考虑 cookie 轮换 / 多账号 poolPro 风控相对 Std 严)
---
## 2026-04-28 19:50 Std 工程源链路打通 + 10 板子 schematic/PCB 全部回填
**Claude 会话**