# 豆瓣图书 Obsidian Web Clipper 模板项目 - 完整总结 ## 项目概述 **项目名称**:豆瓣图书 Obsidian Web Clipper 模板 **开始日期**:2025-01-22 **完成日期**:2025-01-22 **总迭代次数**:14 次(v1 → v14) **总耗时**:约 2 小时 **最终成功率**:71%(10/14 个字段自动提取) --- ## 第一部分:流程优化 ### 1.1 初始流程的问题 **问题 1:缺乏目标明确的阶段划分** - 没有明确的需求分析阶段 - 直接进入编码,导致多次返工 - 缺乏测试驱动开发的思路 **问题 2:缺乏系统性的调试方法** - 遇到问题就尝试新方案,缺乏分析 - 没有建立失败原因分类体系 - 缺乏版本回滚机制 **问题 3:信息收集不足** - 没有深入了解工具的限制 - 没有收集官方文档和社区经验 - 没有查看类似模板的实现方式 --- ### 1.2 优化后的流程(推荐) #### 阶段 1:需求分析和信息收集(30% 时间) **目标**:明确需求,收集信息,了解工具限制 **步骤:** 1. **需求分析** - [ ] 明确需要提取的字段列表 - [ ] 确定字段的格式要求(text, number, multitext, date) - [ ] 确定数据来源(Preset, Schema.org, Selector, Content) - [ ] 确定输出格式(YAML frontmatter) 2. **工具研究** - [ ] 阅读官方文档: - [Obsidian Web Clipper Variables](https://help.obsidian.md/web-clipper/variables) - [Obsidian Web Clipper Filters](https://help.obsidian.md/web-clipper/filters) - [ ] 研究类似项目: - [kepano/clipper-templates](https://github.com/kepano/clipper-templates) - [ ] 收集社区经验: - GitHub Issues - Reddit / Discord / 论坛讨论 3. **目标页面分析** - [ ] 使用浏览器开发者工具分析 HTML 结构 - [ ] 查看页面源代码,查找 Schema.org JSON-LD 数据 - [ ] 检查 meta tags - [ ] 截图保存关键部分的 HTML **输出物:** - 需求文档(字段列表、格式要求) - 工具研究文档(支持的方法、不支持的方法) - 目标页面分析报告(HTML 结构、可用数据源) --- #### 阶段 2:方案设计(20% 时间) **目标**:设计多个备选方案,评估优劣势 **步骤:** 1. **方案设计** - [ ] 根据需求文档,设计 3-5 个不同的提取方案 - [ ] 每个方案明确: - 字段提取方法(Preset/Schema/Selector/Content) - 过滤器链设计 - 备选方案(如果某个方法失败) 2. **方案评估** - [ ] 使用评估矩阵比较方案: - 可靠性(基于工具支持情况) - 复杂度(过滤器链的长度) - 性能(提取速度) - 维护性(页面结构变化的敏感度) | 方案 | 可靠性 | 复杂度 | 性能 | 维护性 | 总分 | |------|--------|--------|------|--------|------| | 方案 A | 高 | 低 | 高 | 中 | ⭐⭐⭐ | | 方案 B | 中 | 中 | 中 | 高 | ⭐⭐ | | 方案 C | 低 | 高 | 低 | 低 | ⭐ | 3. **方案选择** - [ ] 选择总分最高的方案作为主要方案 - [ ] 选择第二高的方案作为备选方案 - [ ] 记录选择理由和风险 **输出物:** - 方案设计文档 - 评估矩阵 - 方案选择决策记录 --- #### 阶段 3:原型开发(30% 时间) **目标**:快速验证方案可行性,收集反馈 **步骤:** 1. **最小可行产品(MVP)** - [ ] 实现最核心的字段(如 3-5 个) - [ ] 使用最简单的提取方法 - [ ] 不考虑边缘情况 2. **快速测试** - [ ] 在 1-2 个目标页面上测试 - [ ] 记录测试结果 - [ ] 收集问题反馈 3. **迭代优化** - [ ] 根据反馈调整方案 - [ ] 如果主要方案失败,切换到备选方案 - [ ] 继续测试,直到核心功能稳定 **关键原则:** - 快速失败(Fail Fast) - 频繁测试 - 保持记录 **输出物:** - MVP 版本模板 - 测试报告 - 问题记录表 --- #### 阶段 4:全面开发(15% 时间) **目标**:实现所有字段,处理边缘情况 **步骤:** 1. **字段实现** - [ ] 按优先级实现所有字段 - [ ] 为每个字段设计提取方法 - [ ] 考虑边缘情况(空值、多值、格式异常) 2. **集成测试** - [ ] 在多个不同类型的页面上测试 - [ ] 验证字段之间的关联性 - [ ] 测试模板的稳定性 3. **问题修复** - [ ] 根据测试结果修复问题 - [ ] 每次修复后重新测试 - [ ] 保持版本记录 **输出物:** - 完整的模板文件 - 集成测试报告 - 问题修复记录 --- #### 阶段 5:验证和文档化(5% 时间) **目标**:确保模板稳定可用,提供完整文档 **步骤:** 1. **最终验证** - [ ] 按照测试清单进行完整测试 - [ ] 在多个浏览器/页面上测试 - [ ] 验证所有功能正常 2. **文档编写** - [ ] 编写使用指南 - [ ] 编写维护文档 - [ ] 编写故障排查指南 3. **发布和分享** - [ ] 分享到社区 - [ ] 收集用户反馈 - [ ] 根据反馈持续改进 **输出物:** - 使用指南 - 维护文档 - 故障排查指南 - 用户反馈记录 --- ### 1.3 流程对比 | 阶段 | 初始流程 | 优化后流程 | 改进 | | ---- | ------ | ------------- | ---------- | | 需求分析 | ❌ 无 | ✅ 30% 时间,明确需求 | 明确目标,减少返工 | | 工具研究 | ⚠️ 部分 | ✅ 全面收集文档和经验 | 避免踩坑,提高效率 | | 方案设计 | ❌ 直接开发 | ✅ 设计多方案,评估选择 | 降低风险,提高成功率 | | 原型开发 | ❌ 无 | ✅ MVP + 迭代开发 | 快速验证,快速调整 | | 全面开发 | ❌ 无序迭代 | ✅ 按优先级实现 | 提高效率,减少混乱 | | 验证测试 | ⚠️ 不充分 | ✅ 完整测试清单 | 确保质量 | --- ### 1.4 流程优化效果 | 指标 | 初始流程 | 优化后流程 | 改进 | |------|---------|-----------|------| | 迭代次数 | 14 次 | 预计 5-8 次 | 减少 40% | | 总耗时 | 2 小时 | 预计 1-1.5 小时 | 减少 25% | | 成功率 | 71% | 预计 85-90% | 提高 14-19% | | 返工率 | 50% | 预计 10-20% | 减少 60-75% | | 代码质量 | 不稳定 | 稳定 | 提高 | --- ## 第二部分:Obsidian Web Clipper 模板设计指南 ### 2.1 模板设计原则 #### 原则 1:简单优先(Keep It Simple) **说明**:优先使用简单、可靠的方法,避免过度设计 **实践:** ```json // ✅ 好:简单的 Preset variable "author": "{{author}}" // ❌ 差:复杂的选择器 + 过滤器链 "author": "{{selector:div#info a:first-of-type|trim|split:","}}" // ❌ 差:正则表达式(Web Clipper 不支持) "pages": "{{content|regex:\"页数:\\s*(\\d+)\"}}" ``` **经验:** - Preset variables(`{{author}}`, `{{title}}`, `{{date}}`)最可靠 - Schema.org variables(`{{schema:@Book:isbn}}`)次之 - CSS selectors 再次 - 复杂的过滤器链最后考虑 --- #### 原则 2:防御性设计(Fail Gracefully) **说明**:假设某些方法可能失败,提供备选方案 **实践:** ```json // ✅ 好:多层备选 // 方案 1: Preset variable // 方案 2: Schema.org variable // 方案 3: CSS selector // 方案 4: 留空(用户手动输入) "author": "{{author}}" // ❌ 差:单点故障 "author": "{{selector:div#info a:first-of-type|trim}}" ``` **经验:** - 每个字段至少有一个备选方案 - 如果所有自动提取方法都失败,允许手动输入 - 使用条件逻辑或默认值 --- #### 原则 3:渐进式增强(Progressive Enhancement) **说明**:先实现核心功能,再逐步增强 **实践:** ```json // MVP: 只提取最核心的 3 个字段 { "name": "Douban Books MVP", "properties": [ { "name": "title", "value": "{{title}}", "type": "text" }, { "name": "isbn", "value": "{{schema:@Book:isbn}}", "type": "text" }, { "name": "url", "value": "{{url}}", "type": "text" } ] } // v1: 增加更多字段 { "name": "Douban Books v1", "properties": [ { "name": "title", "value": "{{title}}", "type": "text" }, { "name": "author", "value": "{{author}}", "type": "multitext" }, { "name": "isbn", "value": "{{schema:@Book:isbn}}", "type": "text" }, { "name": "scoreGr", "value": "{{selector:.rating_num|trim|number}}", "type": "number" }, { "name": "url", "value": "{{url}}", "type": "text" } ] } // v2: 完整功能 { "name": "Douban Books v2", "properties": [ ... all 14 fields ... ] } ``` **经验:** - 不要一开始就追求完美 - 先确保核心功能稳定 - 逐步添加辅助功能 - 每个版本都可以独立使用 --- #### 原则 4:数据一致性(Data Consistency) **说明**:确保提取的数据格式一致,便于后处理 **实践:** ```json // ✅ 好:一致的数据类型 { "name": "pages", "type": "number", "value": "{{...}}" } // ❌ 差:混合的数据类型 { "name": "pages", "type": "text", "value": "264" } // ✅ 好:一致的数组格式(即使单元素) { "name": "author", "type": "multitext", "value": "{{author}}" } // ❌ 差:有时是字符串,有时是数组 { "name": "author", "type": "text", "value": "{{selector:...}}" } ``` **经验:** - 选择器可能输出数组格式,应将类型设为 `multitext` - 数值字段使用 `number` 类型,确保输出为数字 - 日期字段使用 `date` 类型,确保输出为标准格式 --- #### 原则 5:性能优先(Performance First) **说明**:优先考虑性能,避免复杂的操作 **实践:** ```json // ✅ 好:简单的提取 "isbn": "{{schema:@Book:isbn}}" // ❌ 差:复杂的过滤器链 "isbn": "{{content|split:\"ISBN: \"|slice:1|split:\"\\n\"|slice:0|trim}}" // ✅ 好:直接提取 "author": "{{author}}" // ❌ 差:正则表达式搜索 "author": "{{content|regex:\"author:\\s*([^\n]+)\"}}" ``` **经验:** - Preset variables 和 Schema.org variables 最快 - CSS selectors 次之 - Content + split 最慢 - 避免正则表达式(如果支持的话) --- ### 2.2 变量选择指南 #### 变量类型优先级 | 优先级 | 变量类型 | 可靠性 | 速度 | 复杂度 | 适用场景 | |--------|---------|--------|------|--------|---------| | 1 | Preset Variables | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐ | 页面级信息(author, title, date, description) | | 2 | Schema.org Variables | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | 结构化数据(isbn, name, url, author, datePublished) | | 3 | CSS Selectors | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | HTML 元素(rating, votes, specific fields) | | 4 | Content Variable | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 页面内容的纯文本,需要 split 提取 | --- #### Preset Variables 最佳实践 **支持的 Preset Variables:** - `{{author}}` - 页面作者 - `{{title}}` - 页面标题 - `{{date}}` - 当前日期 - `{{description}}` - 页面描述或摘要 - `{{content}}` - 页面内容、高亮或选择 - `{{url}}` - 当前 URL - `{{image}}` - Social share 图片 URL **最佳实践:** ```json // ✅ 适用:作者名、标题、日期、描述 "author": "{{author}}" "title": "{{title}}" "created": "{{date}}" // ⚠️ 谨慎:image 可能不是预期内容 "cover": "{{image}}" // 可能不是图书封面 // ✅ 适用:URL(通常很可靠) "url": "{{url}}" ``` **经验:** - `{{author}}` 对于豆瓣读书页面,提取的是图书作者,不是页面作者 - `{{title}}` 对于豆瓣读书页面,提取的是图书标题 - `{{date}}` 提取的是当前日期(不是图书出版日期) - `{{content}}` 包含页面上的所有内容,可用于提取其他字段 --- #### Schema.org Variables 最佳实践 **豆瓣图书页面包含的 Schema.org 数据:** ```html ``` **最佳实践:** ```json // ✅ 可用:ISBN, 图书名称 "isbn": "{{schema:@Book:isbn}}" "name": "{{schema:@Book:name}}" // ⚠️ 可用但冗余:使用 Preset variables 更简单 "author": "{{schema:@Book:author}}" "title": "{{schema:@Book:name}}" "url": "{{schema:@Book:url}}" // ❌ 不可用:豆瓣页面不包含 "pages": "{{schema:@Book:numberOfPages}}" "year": "{{schema:@Book:datePublished}}" ``` **经验:** - 先检查页面是否包含所需的 Schema.org 数据 - 使用浏览器开发者工具查看 `