Files
FacereDataset/docs/sources/pro_crawl_vs_export.md
Knowit fc2a45f658 docs: explain per-doc .epro2 crawl vs web-export .epro2 ZIP
Colleague-facing explainer at docs/sources/pro_crawl_vs_export.md.
Addresses the "I see 278 .epro2 files but my browser only downloaded
one" confusion: web download is a ZIP container (extension is a UX
choice, not a format), our crawl produces per-doc message streams.
Both carry equivalent EPRO2 data; only real gap is IMAGE/ binary
previews which we don't fetch yet.

Why per-doc and not ZIP: the ZIP path has no public endpoint —
three HARs confirm the export button fires zero HTTP requests, it's
pure client-side JSZip on data already loaded by the editor. Our
crawler hits the same chain endpoints the editor uses internally,
which delivers per-doc streams.

Log entry references the 278 vs 266 doc-count delta for ESP-VoCat
(we walk full history chain, web export is a current snapshot).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 00:13:52 +08:00

167 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 为什么爬取产出 N 个 .epro2 文件,而网页端导出只有一个 .epro2
> 给同事的科普向解释。如果你看到我们仓库里某个 Pro 项目目录下躺着几十到上千个 `.epro2`
> 而你自己从网页端"下载工程包"只拿到一个 `.epro2`,你不是抓错了,它们也不是同一种文件,
> 只是名字撞了。
---
## 一句话结论
**网页端下载的那个 `.epro2` 是 ZIP 压缩包**(扩展名误导),里面其实有三样东西:
工程消息流 + 工程元数据 + 嵌入图片。
**我们爬取产出的 N 个 `.epro2` 是工程内每个"文档"各自的消息流**
一个组件一文件、一张原理图一文件、一块 PCB 一文件,没打包。
两者**承载的数据是等价的**,只是打包方式相反——一个是"全压一坨"
一个是"每文档一个文件"。
---
## 拿 ESP-VoCat 做实例
同一个项目(`ba64bd6f...`),两种获取方式得到的东西:
### 网页端"下载工程包" → `ProPrj_ESP-VoCat.epro2`1 个文件1.4 MB
文件名虽然是 `.epro2`**实际是 ZIP**。`unzip -l` 看里面:
```
IMAGE/ (目录)
IMAGE/38cc57d9...webp 60 KB ─┐
IMAGE/450927588f1f...webp 260 KB │
IMAGE/78404fce3de8...webp 134 KB │ 6 张嵌入图片
IMAGE/9904a7de7784...webp 48 KB │ (组件预览/3D 缩略图)
IMAGE/a20de4ce4ca4...webp 141 KB │
IMAGE/b3294b3234d6...webp 286 KB ─┘
project2.json 25 KB 工程元数据
ESP-VoCat 喵伴...epru 6.25 MB 全部 doc 拼成一坨的消息流
```
### 我们爬取产出 → `data/raw/oshwhub/ba64bd6f.../source/`278 个文件7.5 MB
每个 doc 一个独立的 `.epro2`
```
00184cbbad5a8d33.epro2 每个 SYMBOL 一个文件 × 105
0a29a31811039d37.epro2 每个 FOOTPRINT 一个 × 55
037c... .epro2 每个 DEVICE 一个 × 88
... 总共 278 个 .epro2 文件
manifest.json 索引(哪个文件对应哪个 docType
structure.json 工程结构树(哪些 sheet / pcb / board 属于哪些 board
```
按 docType 分布看:
| docType | 我们爬取 | 网页端导出 |
|---|---:|---:|
| SYMBOL原理图符号 | 105 | 105 |
| DEVICE元件 BOM 元数据) | 88 | 88 |
| FOOTPRINTPCB 封装) | 55 | 55 |
| SCH_PAGE原理图分页 | 9 | 6 |
| SCH原理图容器 | 6 | 3 |
| PCBPCB 容器) | 6 | 3 |
| BOARD板子顶层 | 6 | 3 |
| BLOB / FONT / CONFIG | 1 / 1 / 1 | 1 / 1 / 1 |
| **合计** | **278** | **266** |
---
## 那 N 个文件到底是啥?为什么这么多
EasyEDA Pro 是**文档式工程**——跟 KiCad「整个项目两个大文件」的思路不一样
- KiCad1 个 `.kicad_sch` + 1 个 `.kicad_pcb`,组件库走外部引用
- EasyEDA Pro**每用到一种组件,就把它的 symbol / footprint / device 各自快照成独立文档存进工程里**
外加多页原理图、容器层、全局资源……
ESP-VoCat 用了大约 100 种不同的元件ESP32-WROOM、各种规格的电阻、按键、LED、晶振、屏幕模组……
所以**自动产生 248 条都是元件库快照**105 SYMBOL + 55 FOOTPRINT + 88 DEVICE。
剩下 30 条才是工程"主体"9 张原理图 + 6 套 PCB/BOARD/SCH 容器 + FONT/BLOB/CONFIG 全局资源)。
> **直觉对照**:把 EPRO2 想象成**每个文档的 git history**,不是项目压缩包。
> 一个 SYMBOL 文件 ≈ 立创元件库里"这颗 0603 电阻"的快照 + 你在工程里对它的每次微调。
每个 EPRO2 文件内部是**事件流**event-sourced按行排
```
{"type":"DOCHEAD","ticket":4456}||{"docType":"FOOTPRINT","uuid":"a20de4ce..."}|
{"type":"OP","op":"ADD","id":"e123",...}||{...payload...}|
{"type":"OP","op":"UPDATE","id":"e123",...}||{...payload...}|
...
```
回放这些 event 就能拿到文档的当前状态。
---
## 为什么数量对不上278 vs 266
我们多 12 个,全部集中在**容器层文档**SCH_PAGE 多 3、SCH 多 3、PCB 多 3、BOARD 多 3。
原因很简单:
- **网页端导出**是当前快照——只导"这个项目此刻包含哪些 doc"
- **我们的爬虫**走完整 history chain——把工程历史上**演化路径**上出现过的 doc 都拉下来了
(比如项目历史里"加过一张图、又删了",那张图的 SCH_PAGE 在我们这里有,在网页导出里没有)
元件库部分248 条)完全一致,没有差异。
---
## 体积对比
| 形态 | 大小 | 说明 |
|---|---:|---|
| 网页 ZIP 压缩态 | **1.41 MB** | 适合用户下载 |
| 网页 ZIP 解压(.epru + json + 6 图) | 7.20 MB | |
| 我们爬取278 个独立 .epro2 | **7.85 MB** | 多 12 容器 + 缺 IMAGE/ |
> 我们多 0.65 MB 是那 12 个历史容器层;他们多的部分是 6 张 IMAGE/ 预览图(~0.93 MB
> 这是我们当前**确实缺的一块数据**——blob 引用爬到了,二进制图片本体没爬。
> 不影响 EPRO2 → KiCad 转换语料生成KiCad 端没对应字段),但如果要做"原貌可视化还原"会需要补。
---
## 为什么我们走 N 文件而不是 1 ZIP
简单说:**ZIP 这条路根本没有公开端点可爬**。
- 三份 HAR 反复抓过编辑器流量,**网页端"导出"按钮压根不发任何 HTTP 请求**
- 它是纯前端 JS 操作:编辑器把已经加载到内存的数据用 `JSZip` 在浏览器里现拼现压
- 所以服务端没有 `/export` 之类的 endpoint 给爬虫调用
我们走的是**官方编辑器加载工程时用的同一套 API**`/api/v4/projects/<P>/branches/<B>/histories/<H>` 拿 chain
逐段 AES-GCM 解密 + gunzip + 按 DOCHEAD 切分),所以拿到的是"原汁原味"的 per-doc EPRO2 流。
附带好处:
| | per-doc 爬取 | 网页 ZIP |
|---|---|---|
| 单文档 diff | ✅ 容易(每文件独立) | ❌ 全在一坨流里 |
| 增量更新 | ✅ 只重抓变动 doc | ❌ 整包重下 |
| LFS 友好 | ✅ 单文件可独立寻址 | ❌ 一个大 zip 改一字节 LFS 也得重传 |
| 历史完整性 | ✅ 全 chain | ❌ 只有当前快照 |
| 体积 | 7.5 MB 平铺 | 1.4 MB 压缩态 |
---
## 你应该用哪种
| 用途 | 选哪种 |
|---|---|
| 训练 LLM 做 EDA 任务、做 EPRO2 → KiCad 转换、做 BOM 抽取 | 我们爬的 per-doc |
| 给立创的人复刻你的工程(直接拿去用编辑器打开) | 网页端 ZIP |
| 想看项目历史演化、做版本 diff | 我们爬的 per-doc含 history |
| 想拿到组件预览图(原始 webp | 网页端 ZIPIMAGE/ 目录) |
---
## TL;DR
- "网页端 .epro2" = ZIP 容器(叫 .epro2 是 UX 决定,不是格式)
- "爬取的 .epro2" = 工程内每个文档自己的 EPRO2 消息流
- 两者**信息量基本等价**,包装方式相反
- 我们选 per-doc 是因为 ZIP 这条路根本没有服务端端点可爬,并且 per-doc 对下游处理更友好
- 唯一**真实差异**是 IMAGE/ 二进制图(我们暂未爬),其它都对得上