# 豆瓣图书 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 数据
- 使用浏览器开发者工具查看 `