打通 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>
509 lines
25 KiB
Markdown
509 lines
25 KiB
Markdown
# FacereDataset 执行日志
|
||
|
||
时间倒序,最新在顶部。
|
||
|
||
---
|
||
|
||
## 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 / 无界 PLUS),3.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-VoCat(modern 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 轮换 / 多账号 pool(Pro 风控相对 Std 严)
|
||
|
||
---
|
||
|
||
## 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` 401(cookie 已过期,但和源抓取无关)
|
||
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 MB)grep `/api/`,找到 76 个端点。关键的 `ajaxDetail = '/api/documents/{uuid}'`
|
||
5. 命中:**`https://lceda.cn/api/documents/<doc>?uuid=<doc>&path=<doc>`** 匿名 200,body 是完整 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 锁定,后续新源好对齐)
|
||
|
||
### 跑批结果(dev1,QPS 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** 而不是 LFS(10 项目共 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 会话**
|
||
|
||
核心成果:**立创 EDA Pro 工程源的 API + 加密 + 格式三层全打通**。
|
||
|
||
### 完整链路
|
||
|
||
```
|
||
1. GET /api/v4/projects/<PROJ> → branch_uuid
|
||
2. GET /api/v4/projects/<PROJ>/branches/<BRANCH> → history_uuid
|
||
3. GET /api/v4/projects/<PROJ>/branches/<BRANCH>/histories/<HIST> → {key, iv, dataStrUrl}
|
||
4. GET <dataStrUrl> (modules.lceda.cn) → 417 KB 加密 blob
|
||
5. AES-128-GCM decrypt (tag=blob[-16:]) → 417 KB gzip
|
||
6. gunzip → 2.7 MB EPRO2 源流
|
||
```
|
||
|
||
关键 headers:`Editor-Version: 3.2.127` / `path: <PROJ_UUID>` / `Referer: https://pro.lceda.cn/editor` /
|
||
`Cookie: lceda_pro_session=...`(与 u.lceda.cn 的 session 不共享)
|
||
|
||
### 加密细节
|
||
|
||
- 算法: AES-128-GCM(从 `modules.lceda.cn/pro-mgr/.../project-worker.js` 里 `this.tool.decrypt({name:"AES-GCM",iv:this.iv,tagLength:128},...)` 反查确认)
|
||
- key / iv 都是 32 hex = 16 byte
|
||
- WebCrypto 约定:ciphertext || 16-byte-authTag(末尾附)
|
||
- 解密后 gzip magic `1f 8b 08`,gunzip 得最终源流
|
||
|
||
### EPRO2 格式
|
||
|
||
立创 EDA Pro 2 的**事件溯源**格式:消息流按 `\n` 分行,每行 `{"type":...,"ticket":N,"id":...}||{payload}||[extra]`。
|
||
示例样本(`无界PLUS` BOARD 文档)**8 357 条消息**,**40 种 type**:
|
||
- PART / COMPONENT / ATTR / PIN(零件与属性)
|
||
- PAD / VIA / WIRE / NET / PAD_NET(PCB 电气)
|
||
- LINE / POLY / RECT / ARC / CIRCLE / ELLIPSE / TEXT(几何)
|
||
- LAYER (1572) / LAYER_PHYS / ACTIVE_LAYER(层堆叠)
|
||
- FILL / POUR / POURED(铺铜)
|
||
- RULE / RULE_SELECTOR / RULE_TEMPLATE(设计规则)
|
||
|
||
### 与 Std 版对比
|
||
|
||
| | u.lceda.cn (Std) | pro.lceda.cn (Pro) |
|
||
|---|---|---|
|
||
| Cookie | `lceda_session` | `lceda_pro_session` |
|
||
| 源 API | 单一 `/api/projects/<uuid>` | 4 步 `/api/v4/...` 链 |
|
||
| 版本控制 | 无 | branches + histories |
|
||
| 加密 | 待验证 | AES-128-GCM |
|
||
| 源格式 | EasyEDA JSON(扁平) | EPRO2 消息流 |
|
||
| 工具 | `easyeda2kicad.py` 第三方 | **无**现成 KiCad 转换器 |
|
||
|
||
### 落地
|
||
|
||
- 新建 `docs/sources/easyeda_pro_source.md`(完整调研,见该文档附录 A 一键重跑)
|
||
- `pyproject.toml` 加 `pycryptodome>=3.23.0`
|
||
- 清理:dev1 上 `/tmp/source.blob` 与 `/tmp/source.json`(后者含 Charles 私人工程源 2.7 MB)
|
||
|
||
### 待验证 / 下一步
|
||
|
||
1. **他人公开 Pro 工程**能否同样 4 步通 —— 需 HAR
|
||
2. **SCHEMATIC docType** 的 API 入口(本次只解出 BOARD)
|
||
3. **多 document 枚举**(project → documents 列表端点)
|
||
4. Pro 编辑器"**导出 KiCad**"功能的 API 端点(若存在,能省自写转换器的工作)
|
||
5. 对齐 `OSHWHUB_INGEST_SPEC.md`(Forge 消费侧要求 `.kicad_sch` + 更严 license whitelist)
|
||
|
||
### ⚠️ 安全
|
||
|
||
Charles 在聊天里粘过两次 cookie(u.lceda.cn 一次 + pro.lceda.cn 一次),已写入 dev1 `~/.secrets/`。
|
||
当前会话 transcript 含明文 —— 本轮验证完 Charles 应登出再重登一次,让测试期间暴露过的 session invalidate。
|
||
|
||
---
|
||
|
||
## 2026-04-23 20:10 策略大调:登录内容入场 + 云服务器 + EDA→KiCad 转换
|
||
|
||
**Claude 会话**
|
||
|
||
四项变更落实到文档(暂不写代码,等云服务器到位):
|
||
|
||
### 1. 登录态内容纳入范围
|
||
|
||
原则(`CLAUDE.md`):
|
||
- 合法账号登录后抓,**禁止**盗号 / 共享号
|
||
- 凭据集中云服务器 `~/.secrets/` (mode 700),**不入** git / 日志 / metadata
|
||
- 仍不绕付费墙、不破 DRM、不抓站点明确禁抓的内容
|
||
- 换号 / 重登事件记 `docs/secrets.md`(只事件、不含值)
|
||
|
||
### 2. 云服务器(广州,待交付)
|
||
|
||
新增 plan.md §0.5 基础设施段:
|
||
- 0.5.1 机器初始化:git / git-lfs / uv / python 3.11+,非 root SSH,`~/.secrets/`
|
||
- 0.5.2 调度:tmux/nohup 长跑 + systemd timer 增量
|
||
- 0.5.3 登录态获取:cookie 导出流程
|
||
|
||
### 3. 存储分级演进
|
||
|
||
plan.md §1.4 改写:
|
||
- 前期 < 50 GB:云服务器磁盘 + Gitea LFS
|
||
- 中期 50–200 GB:评估 Gitea 容量压力;扩容 or 分仓
|
||
- 后期 > 200 GB:迁对象存储(OSS / COS / MinIO),Gitea 只存元数据 + 指针
|
||
- 50 GB 是决策评估点,**不**过早迁移
|
||
|
||
### 4. 立创 EDA → KiCad 转换
|
||
|
||
新增 plan.md §1.6(登录态工程源抓取)+ §1.7(EDA→KiCad 转换):
|
||
- §1.6 用登录账号抓 `u.lceda.cn/api/project/<uuid>` 工程源 JSON,存 `source.json`
|
||
- §1.7 写 `scripts/convert_to_kicad.py`,候选工具 `easyeda2kicad.py`(pypi,活跃维护)
|
||
- 批处理扫 `data/raw/oshwhub/` → 输出 `data/processed/oshwhub/<uuid>/kicad/`
|
||
- 跑 `kicad-cli sch erc / pcb drc` 做语法校验,失败样本记 `data/state/convert_failed.jsonl`
|
||
- 目的:打通 oshwhub (EasyEDA) 与 bshada/open-schematics (KiCad) 两个生态的训练语料
|
||
|
||
### 同步改动
|
||
|
||
- `docs/sources/oshwhub.md` §3.5 从"未开放"改为"需登录,纳入范围";R4 风险更新
|
||
- `README.md` 数据源表加「登录态」列,加运行环境说明
|
||
|
||
### 等待
|
||
|
||
- 广州云服务器到位 → 启动 Phase 0.5
|
||
- 账号登录凭据由 Charles 提供
|
||
|
||
---
|
||
|
||
## 2026-04-23 19:55 oshwhub.md 重写成完整调研文档
|
||
|
||
**Claude 会话**
|
||
|
||
Charles 要求把 12 493 总数验证、90 项目采样结果合进主调研文档。
|
||
|
||
`docs/sources/oshwhub.md` 重写为 9 节 + 2 附录的完整调研:
|
||
|
||
1. 一页纸 TL;DR 表
|
||
2. 站点架构
|
||
3. robots.txt 与合规
|
||
4. API 与抓取入口(列表 / SSR 详情 / 附件 CDN / 排除项 / 未开放端点)
|
||
5. **项目总数验证(新)**:三路 sort 一致 + 分页二分搜索(250 × 50 = 12 500 吻合)+ grade 覆盖抽样
|
||
6. **抽样语料特征(从 oshwhub_corpus_estimate.md 并入)**:体积 / 文件类型 / license 分布
|
||
7. Schema 映射
|
||
8. 速率与礼貌
|
||
9. 目录输出约定
|
||
10. 风险与未解决(7 条)
|
||
11. 附录:重跑命令、变更历史
|
||
|
||
删除重复文件 `oshwhub_corpus_estimate.md`(内容已并入 §5)。
|
||
|
||
---
|
||
|
||
## 2026-04-23 19:50 加入 HF bshada/open-schematics 计划
|
||
|
||
**Claude 会话**
|
||
|
||
Charles 点名把 https://huggingface.co/datasets/bshada/open-schematics 纳入第一批。
|
||
|
||
调研结论:
|
||
- 这是**已预处理**的 HF 数据集,非待爬网站
|
||
- 78 parquet shards **6.4 GB**;CC-BY-4.0(商用友好)
|
||
- 10K+ 条记录,每条含 `.kicad_sch` 源 / PNG / 组件列表 / JSON / YAML / name / description
|
||
- 与 oshwhub (EasyEDA) 互补,补 KiCad 生态
|
||
|
||
决定:
|
||
- **整包镜像**到 `data/external/huggingface/bshada--open-schematics/`,**不**拆 per-project 目录
|
||
- 用 `huggingface-cli download ... --repo-type dataset` 拉;parquet 走 LFS
|
||
- 维护单独的 `datasets.md`,不与 per-project 的 `projects.md` 混
|
||
|
||
改动:
|
||
- 新增 `docs/sources/hf_bshada_open_schematics.md` 完整调研
|
||
- `plan.md` 加 Phase 1.5
|
||
- `README.md` 数据源表加一行
|
||
|
||
**未下载**,等拍板 6.4 GB LFS 预算。
|
||
|
||
---
|
||
|
||
## 2026-04-23 19:30 Phase 1 MVP:10 个高质量 oshwhub 项目入库
|
||
|
||
**Claude 会话**:承接仓库初始化
|
||
|
||
### API 调研结论
|
||
|
||
- 列表 API:`GET https://oshwhub.com/api/project?page=N&pageSize=M&sort=hot`,无鉴权,返回 12493 个项目元数据(含 grade / likes / stars / views / forks)
|
||
- 详情:`GET https://oshwhub.com/<path>` 是 SSR HTML,嵌入 escaped JSON,含 `license` + `attachments[]`(每个带 name / src / size / md5 / ext / mime / download_count)
|
||
- 附件 CDN:`https://image.lceda.cn{src}` — 已验证无鉴权直接下载
|
||
- EasyEDA 工程源 JSON(`u.lceda.cn`)需登录,v0.1 不抓
|
||
- 详细调研见 `docs/sources/oshwhub.md`
|
||
|
||
### 选 10 个高质量项目
|
||
|
||
判据:`grade == 4`(平台精品徽章) + `likes ≥ 100` + 应用领域多样(避免同类堆叠)+ 排除 `_copy` 派生仓。
|
||
|
||
10 个项目覆盖:调试器、加热台、盖革计数器、可调电源、焊台、智能手表、USB 测电流、ZVS 感应加热、AI 开发板、红外热成像。
|
||
|
||
### MVP 爬虫
|
||
|
||
位置:`crawlers/oshwhub/crawler.py`
|
||
|
||
- `list_projects()` — 列表 API 分页
|
||
- `pick_top()` — 按 like×3 + star + fork×2 + views/100 + comments×2 + grade×50 排序
|
||
- `parse_detail_html()` — 从 SSR HTML 提取 title / license / description / attachments
|
||
- `crawl_one()` — 每项目产出:`metadata.json` / `description.md` / `cover.*` / `files/*` / `_urls.json`
|
||
- QPS ≤ 0.5(`SLEEP_BETWEEN = 2.0`),UA 显式声明 `FacereDataset/0.1`
|
||
|
||
### 抓取与入库
|
||
|
||
- 10/10 成功,52 个附件,**524 MB**
|
||
- Gitea LFS(v25.4.3 原生支持)+ 本地 `git-lfs 3.5.1`(用户态二进制装在 `~/.local/bin/`)
|
||
- `.gitattributes` 规则:`data/raw/**/files/**` 一律走 LFS;元数据(metadata.json / description.md / \_urls.json / cover.\*)走普通 git
|
||
- 每项目目录结构:
|
||
```
|
||
data/raw/oshwhub/<uuid>/
|
||
├── metadata.json # 按 schemas/project.schema.json
|
||
├── description.md
|
||
├── cover.{jpg,png,jpeg}
|
||
├── _urls.json # 所有原始 URL 清单
|
||
└── files/* # 原始附件(LFS)
|
||
```
|
||
|
||
### 改动汇总
|
||
|
||
- 新增:`crawlers/oshwhub/{__init__,__main__,crawler}.py`、`schemas/project.schema.json`、`docs/sources/oshwhub.md`、`pyproject.toml`
|
||
- 修改:`.gitattributes`(缩窄到 `data/raw/**/files/**`)、`.gitignore`(移除 `data/raw/*` 排除)
|
||
|
||
### 下一步建议
|
||
|
||
1. 验收 10 个项目元数据质量(随机抽 2-3 条对照原站)
|
||
2. 决定 Phase 1.4 放量目标(50?500?全量 12493?)
|
||
3. Phase 2 准备:GitHub KiCad repo 调研
|
||
|
||
---
|
||
|
||
## 2026-04-23 19:40 fs-web-stream 排查 + schema 自动校验
|
||
|
||
**Claude 会话**(自主推进)
|
||
|
||
### fs-web-stream.jlc.com 定性
|
||
|
||
重新抓 `/CYIIOT/ST_LINK-V2_1` 并看 13 个 `fs-web-stream.jlc.com` 链接的上下文:全部是嘉立创服务侧栏/推广图标(3D 打印、发热片、Ican、EDA 扩展广场、开源硬件平台 badge 等),**与项目本身无关**。`image.lceda.cn/attachments/` 就是项目附件的唯一入口,已确认闭环。`docs/sources/oshwhub.md` 对应章节已更新。
|
||
|
||
### scripts/validate.py
|
||
|
||
jsonschema 做两层校验:
|
||
- 默认:所有 `data/raw/**/metadata.json` 对 `schemas/project.schema.json` 的结构校验
|
||
- `--check-files`:另外验证每条 file 的本地 path 存在且 sha256 匹配
|
||
|
||
**结果**:10/10 项目两项全通过。
|
||
|
||
### 新增
|
||
|
||
- `scripts/validate.py`
|
||
- `pyproject.toml` 加 `jsonschema>=4.26`
|
||
|
||
### 待决策
|
||
|
||
- 放量规模 —— 已提供实测数据:**median ≈ 110 GB,p90 上界 ≈ 660 GB,建议预算 150–180 GB**(见 `docs/sources/oshwhub_corpus_estimate.md`)
|
||
- 是否需要抓 `u.lceda.cn` 的 EasyEDA 源 JSON(需登录,v0.1 跳过)
|
||
|
||
---
|
||
|
||
## 2026-04-23 19:45 全量规模实测 + License 分布
|
||
|
||
**Claude 会话**(自主推进)
|
||
|
||
写 `scripts/estimate_size.py`,只抓详情 HTML 解析 `attachments[].size`,不下载;采样 90 个 hot 项目(3 页 × 30)。
|
||
|
||
**关键发现**:
|
||
- 单项目 median 9 MB / mean 22 MB / p90 54 MB / max 204 MB;12493 全量 median 估算 **110 GB**,p90 上界 660 GB
|
||
- **视频 (.mp4 + .qt) 占 54% 存储**!如果训练只要 PCB/原理图/BOM,加 `--skip-ext mp4,qt` 存储直接砍半
|
||
- License 分布健康:GPL 3.0 占 49%,Public Domain 21%,CC 系列 ~20%,CERN/TAPR OHL 6%;样本内无闭源
|
||
- **NC (Non-Commercial) 占 ~11%**,商用场景必须过滤
|
||
|
||
结果固化到 `docs/sources/oshwhub_corpus_estimate.md`,可随时重跑验证。
|
||
|
||
### 建议
|
||
|
||
1. 存储预算定 **180 GB**(median + 15% buffer)
|
||
2. Phase 1.4 前给 crawler 加 `--skip-ext` 开关滤视频
|
||
3. 下游建立 license whitelist 过滤 NC / 未知
|
||
|
||
---
|
||
|
||
## 2026-04-23 18:50 仓库初始化 & 数据源调研
|
||
|
||
**Claude 会话**:初始化
|
||
|
||
完成:
|
||
- 从 `git.deepknow.site/Facere/FacereDataset` 克隆空仓到 `~/repo/FacereDataset`
|
||
- 调研立创开源平台(oshwhub.com)初步数据:
|
||
- `robots.txt` 仅 Disallow `/posts`,其他路径允许
|
||
- 存在 `sitemap.xml`(首页 + explore + activities + market 等入口已列出)
|
||
- 项目详情页路径为 `/detail/<uuid>`(示例 `f0652fd2ae3e40b8a0ecc8dc773e3512`)
|
||
- 图片 CDN:`image.lceda.cn/oshwhub/pullImage/...`
|
||
- 文件下载:`fs-web-stream.jlc.com/fs-web-stream/file-operation/download/<snowflake-id>`
|
||
- 页面是 Next.js SPA,首屏 HTML 800KB,但数据加载具体 API 入口需要浏览器 trace(留给 Phase 1.1)
|
||
- 创建项目骨架:
|
||
- `README.md` — 项目简介与数据源表
|
||
- `CLAUDE.md` — 项目级 Claude 指令(爬虫规约、合规红线、schema 要求)
|
||
- `plan.md` — 6 阶段建设计划(Phase 0 骨架 → Phase 5 数据清洗 → Phase 6 持续运营)
|
||
- `log.md` — 本文件
|
||
- `.gitignore` — 排除 `data/raw` `data/processed` `data/state` Python 缓存等
|
||
- 目录骨架 `crawlers/ schemas/ scripts/ data/{raw,processed,state} docs/{sources,}`
|
||
- 每个空目录放 `.gitkeep`
|
||
- 首次提交 & 推送到 `origin main`
|
||
|
||
**下一步建议**:
|
||
1. 拍板存储方案(本地盘 / Gitea LFS / 外部 OSS)—— 影响 Phase 1.4 放量时机
|
||
2. 目标规模(1 万 / 10 万 / 全量)
|
||
3. 决定是否保留二进制附件或只存 URL
|
||
4. 完成上述 3 项后启动 Phase 1.1(用 `chrome-devtools` MCP 录 oshwhub 的 network trace 定位真实 API)
|