Install
openclaw skills install @wufengsheng/url-to-obsidian通过网址获取网页内容并创建为 Obsidian 笔记。支持技术文档、博客文章、GitHub README 等类型网页。 支持可选的中文翻译(代码块、命令、包名、URL 保持不变),排版结构清晰简洁。 优先使用 opencli web read 抓取,不可用时自动降级到 Firecrawl、fetchWebContent、fetch。 使用前会主动收集信息:链接地址、笔记名称、存储位置、是否翻译 —— 信息不明确时提供选项让用户选择, 用户也可一键确认默认建议。自动生成 frontmatter、标签和来源信息。 Triggers on: 保存网址到obsidian、网页转obsidian笔记、url to obsidian、抓取网页到 obsidian、 save url to obsidian、fetch and save to obsidian、把这个网页保存到 obsidian、 收藏到 obsidian、保存到 obsidian 知识库、存档页面到 obsidian
openclaw skills install @wufengsheng/url-to-obsidian将任意网址的内容抓取、清理并保存为 Obsidian 笔记。专为技术文档类内容优化(安装指南、使用说明、API 文档、README 等)。
预检查工具链 → 信息收集(URL+名称+位置+翻译) → 智能抓取 → 清理格式化 → 写入笔记 → 验证输出
每步完成后验证结果再进入下一步。关键原则:先检查再执行,避免无效等待;信息不明确时主动询问用户并提供选项。
在抓取前先检测各工具的可用性,直接选择最高优先级可用工具,避免等待超时后再降级。
opencli 检测:
opencli web read --help >/dev/null 2>&1 && echo "AVAIL" || echo "UNAVAIL"
如果返回 "AVAIL",直接使用 opencli(优先级 1)。
如果 opencli 不可用:跳过 opencli,直接尝试 MCP 工具。MCP 工具通过 ToolSearch 检测:
mcp__firecrawl-mcp__firecrawl_scrape → 优先级 2mcp__web-search__fetchWebContent → 优先级 3mcp__fetch__fetch → 优先级 4告知用户当前使用的工具和原因:
使用 opencli 抓取(已检测可用)opencli daemon 未运行,降级使用 Firecrawl报告可用工具检测结果,请用户手动粘贴网页内容或检查工具安装状态。
从用户消息中提取关键信息:链接地址、笔记名称、存储位置、翻译偏好。信息不完整时主动询问用户,提供合理选项供选择。
从用户消息中解析已提供的信息:
| 信息项 | 提取规则 | 示例 |
|---|---|---|
| 链接地址 (URL) | 匹配 https?:// 开头的链接 | https://example.com/doc |
| 笔记名称 | "命名为XXX"、"标题用XXX"、"叫XXX"、引号包裹的名称 | 命名为 React 指南 |
| 存储位置 | "保存到XXX"、"存到XXX目录"、"放在XXX"、路径格式 | 保存到 ~/Obsidian/React/ |
| 标签 | "标签:a, b, c" 或 "#tag1 #tag2" | 标签:docker, tutorial |
快速路径判断:如果用户消息中同时明确提供了 URL + 笔记名称 + 存储位置,直接跳到步骤 2 执行抓取,不进行询问。
URL 已提供 → 进入阶段二。
URL 未提供 → 反问用户:
请提供要保存的网页链接地址。例如:
• 一篇技术文档的 URL
• 一个 GitHub 仓库地址
• 一篇博客文章链接
多个 URL → 逐个处理,每个 URL 独立走完整流程(独立询问名称和位置)。
当用户未同时提供"笔记名称"和"存储位置"时,先做准备工作:
预抓取标题(不做完整翻译和格式化,仅提取标题):
# 标题(Markdown H1)<title> 标签提取 | Example Site)、去除多余空格索引导航页检测: 在预抓取后,判断当前页面是否为索引导航页(即页面主要内容为子页面链接列表,而非详细文档正文)。满足以下 任意 2 项 即判定为索引导航页:
索引导航页处理:
存储位置选项生成:
~/Obsidian/ 根目录(默认)~/Obsidian/技术文档/~/Obsidian/收藏/obsidian_list_files_in_vault 探查目录结构使用 AskUserQuestion 工具一次性询问用户。根据阶段二的探测结果动态生成选项。
问题 1:笔记名称(如果用户未指定名称)
| 选项 | 内容 | 说明 |
|---|---|---|
| 选项 1(推荐) | 从网页标题生成的名称 | 阶段二预抓取的标题,干净简洁 |
| 选项 2 | 从 URL 路径推断的名称 | 如 URL 为 react.dev/learn/installation,建议 React 安装指南 |
| 选项 3 | "自定义名称" | 用户选择后在 Other 中输入自定义名称 |
问题 2:存储位置(如果用户未指定位置)
| 选项 | 内容 | 说明 |
|---|---|---|
| 选项 1(默认) | ~/Obsidian/ 根目录 | 直接保存在 vault 根目录 |
| 选项 2-N | vault 中已有的子目录 | 从阶段二探测结果中选取,如 ~/Obsidian/技术文档/ |
| 最后选项 | "自定义目录" | 用户选择后在 Other 中输入自定义路径 |
问题 3:是否翻译为中文(始终询问,除非用户在消息中已明确指示)
| 选项 | 内容 | 说明 |
|---|---|---|
| 选项 1(默认) | "保留原文不翻译" | 保持网页原始语言,不做翻译处理 |
| 选项 2 | "翻译为简体中文" | 将正文翻译为简体中文(代码块、命令、URL保持原样) |
问题 4:子页面处理(仅在步骤 1.3 检测到索引导航页时询问)
当预抓取判定为索引导航页时,列出检测到的子页面链接数量,询问用户如何处理:
| 选项 | 内容 | 说明 |
|---|---|---|
| 选项 1(推荐) | "合并到同一笔记" | 抓取所有子页面内容,合并到主笔记中,用 --- 分隔线区分各方式 |
| 选项 2 | "保存为独立笔记" | 每个子页面单独保存为一个笔记文件 |
| 选项 3 | "仅保存当前页面" | 只保存索引导航页的概览索引,不抓取子页面 |
选项 1「合并到同一笔记」的后续流程:
AskUserQuestion(multiSelect)让用户勾选要抓取的子页面选项 2「保存为独立笔记」的后续流程:
AskUserQuestion 调用示例(含索引导航页检测):
问题1 header: "笔记名称"
- "React 18 安装与使用指南"(根据网页标题生成,推荐)
- "react-installation-guide"(根据 URL 路径推断)
- "自定义名称..."
问题2 header: "存储位置"
- "~/Obsidian/ 根目录"(默认)
- "~/Obsidian/React 文档/"(已有目录)
- "自定义目录..."
问题3 header: "翻译选项"
- "保留原文不翻译"(默认)
- "翻译为简体中文"
--- 以下仅在检测到索引导航页时出现 ---
问题4 header: "子页面处理"
- "合并到同一笔记"(推荐)-- 子页面内容追加到主笔记
- "保存为独立笔记" -- 每个子页面单独一个文件
- "仅保存当前页面" -- 只保存概览索引
--- 选择合并或独立后,进一步勾选子页面 ---
问题5 header: "选择子页面"(multiSelect)
- "全部子页面 (5个)"(推荐)
- "命令行方式"
- "Docker 方式"
- "Maven 方式"
- "Gradle 方式"
- "Desktop 方式"
注意:
询问完成后,向用户展示确认摘要:
确认信息:
🔗 链接:https://example.com/doc
📝 笔记名称:React 18 安装指南
📁 存储位置:~/Obsidian/React 文档/
🌐 翻译:保留原文 / 翻译为简体中文
📑 子页面:合并到同一笔记(3个子页面) / 独立笔记(3个) / 不抓取
然后进入步骤 2 开始抓取。
按预检查结果选择工具。以下为完整优先级表:
opencli web read --url "<url>" --stdout
opencli doctor 绿色)--wait <秒> — 页面加载后额外等待(默认 3 秒,内容多的页面可设为 5-8 秒)--wait-for "<CSS选择器>" — 等待特定元素出现后再抓取--wait-until networkidle — 等待网络空闲opencli daemon 未运行,自动降级到 Firecrawl使用 ToolSearch 加载 mcp__firecrawl-mcp__firecrawl_scrape,然后调用:
url: "<url>"
formats: ["markdown"]
onlyMainContent: true
使用 ToolSearch 加载 mcp__web-search__fetchWebContent,然后调用:
url: "<url>"
readability: true
maxChars: 50000
使用 ToolSearch 加载 mcp__fetch__fetch,然后调用:
url: "<url>"
max_length: 10000
如果 URL 匹配 github.com/*/*(仓库 README 页面),跳过降级链,直接使用:
使用 ToolSearch 加载 mcp__web-search__fetchGithubReadme,然后调用。
如果 fetchGithubReadme 不可用,再走正常降级链。
仅在步骤 1 中用户选择了「合并到同一笔记」或「保存为独立笔记」时执行此步骤。
对用户勾选的所有子页面,使用与主页面相同的工具链并行抓取。所有子页面抓取命令使用相同工具参数,并行发起以节省时间。
注意:
对每个子页面的抓取内容进行与步骤 3 相同的清理:
Page last updated、版权信息、论坛链接等)当用户选择「合并到同一笔记」时:
---
## 子页面标题
> 来源:[原始子页面标题](子页面URL)
子页面正文内容...
> 引用块标注子页面原始链接--- 分隔线区分合并模式示例结构:
# 主标题
> [!note]- 来源信息
> - **URL**: 主页面URL
## 概述
主页面的概览内容...
---
## 命令行方式
> 来源:[Quickstart - Command-line](子页面URL)
子页面正文内容...
---
## Docker 方式
> 来源:[Quickstart - Docker](子页面URL)
子页面正文内容...
当用户选择「保存为独立笔记」时:
[[子页面笔记名称]]独立笔记模式下的主页面优化: 主页面笔记中的链接列表替换为 Obsidian wikilink 格式,方便 Obsidian 内跳转:
## 快速开始指南
- [[Flyway 命令行快速开始]]
- [[Flyway Docker 快速开始]]
- [[Flyway Maven 快速开始]]
如果部分子页面抓取失败:
> [!warning] 子页面抓取失败:[URL]按优先级尝试:
# 标题(Markdown H1)<title> 标签文本标题清理规则:
| Example Site、 - Blog Name)®、™)# 站点名\n> 作者: ...\n> 原文链接: ... 块)Copy link、复制链接 等复制按钮文字Terminal、bash、text、css、tsx 等单独成行的代码块标签(保留代码块内的语言标记如 ```bash)``` 代码块完整,语法高亮标记不丢失对大内容按边界截断,避免破坏 Markdown 结构:
| 内容大小 | 处理方式 |
|---|---|
| ≤ 80KB | 完整保存 |
| 80KB-200KB | 在最近的双换行(段落边界)处截断,优先保证完整段落 |
| > 200KB | 在最近的 H2 标题边界处截断,优先保证章节完整性 |
截断后添加标记:
> [!warning] 内容过长已截断
> 原始约 X KB,保存约 Y KB。完整内容请访问原始 URL: <url>
禁止在以下位置截断:代码块内部、表格中间、列表中间。
识别到技术文档特征时(包含代码块、命令行示例、API 端点等):
bash、shell、json、yaml 等代码块语言标记正确npm install、pip install、brew install、git clone 等)仅在步骤 1 中用户选择了"翻译为简体中文"时才执行此步骤。默认保留原文不翻译。
翻译原则:
| 需要翻译 | 保持原样 |
|---|---|
| 标题和章节名 | 代码块内容(含注释) |
| 描述性段落和说明文字 | 命令行和终端命令 |
| 表格中的文字说明 | 包名、库名(如 @astryxdesign/core) |
| 列表项的描述文字 | URL 链接地址 |
| Callout/提示框中的文字 | 文件名和路径(如 app/page.tsx) |
| 表格列头 | API 名称、组件名、函数名 |
| 技术术语的解释 | 语言/框架名称(React、Next.js、StyleX 等) |
翻译质量标准:
globals.css、app/page.tsx)保留原样,下方的说明文字翻译直接使用步骤 1 中用户确认的笔记名称作为文件名。
安全处理(对用户输入做基本清理):
/ : \ * ? " < > |未命名-<时间戳>命名风格:保留中文和英文混合,不强制翻译。尊重用户的选择。
直接使用步骤 1 中用户选择的存储位置:
默认:~/Obsidian/<用户指定名称>.md
指定目录:~/Obsidian/<用户选择的目录>/<用户指定名称>.md
自定义路径:~/Obsidian/<用户自定义路径>/<用户指定名称>.md
mkdir -p).raw/articles/<文件名>-<YYYY-MM-DD>.md如果目标文件已存在:
--- 分隔-2、-3 后缀.raw/articles/<slug>-<日期>.md,原文件不动标准技术文档模板(翻译状态取决于用户选择):
---
title: "<中文标题>"
source: "<原始URL>"
created: <YYYY-MM-DD>
fetch_tool: "<opencli | firecrawl | fetchWebContent | fetch | fetchGithubReadme>"
tags:
- web-clip
- <域名标签>
- <内容标签1>
- <内容标签2>
---
# <中文标题>
> [!note]- 来源信息
> - **URL**: <原始URL>
> - **抓取时间**: <YYYY-MM-DD>
> - **抓取工具**: <工具名>
<中文正文内容>
GitHub README 模板(fetch_tool 为 fetchGithubReadme 时):
---
title: "<仓库名> - <描述(翻译为中文)>"
source: "<GitHub URL>"
created: <YYYY-MM-DD>
fetch_tool: "fetchGithubReadme"
tags:
- web-clip
- github
- readme
- <语言标签>
---
# <仓库名>
> [!note]- 来源信息
> - **仓库**: <GitHub URL>
> - **抓取时间**: <YYYY-MM-DD>
> - **抓取工具**: fetchGithubReadme
<README 正文(翻译为中文)>
排版简洁原则:
[!note]-),默认收起减少视觉干扰web-clip| 域名特征 | 标签 |
|---|---|
github.com | github |
npmjs.com / nodejs.org | nodejs |
pypi.org | python |
docs.rs / crates.io | rust |
docker.com / hub.docker.com | docker |
medium.com / dev.to | blog |
*.readthedocs.io / docs.* | documentation |
react、api、docker、cli、kubernetestutorial、installation、guide、reference、readme、changelogjavascript、python、rust、go、typescript严格遵循 Obsidian YAML frontmatter 格式,这是不可协商的规则:
tags:
- web-clip
- docker
tags: [web-clip, docker] ← 绝对不会使用YYYY-MM-DD(如 2026-07-02)2026-07-02T00:00:00Z ← 错误格式title: "包含:冒号的标题"写入:使用 Write 工具直接写入绝对路径:
Write: ~/Obsidian/<目录>/<文件名>.md
写入后验证(必须执行):
Read 回读文件的前 20 行,检查:
tags: 字段是否使用了多行列表格式(绝对不能是 inline [a, b])created: 日期格式是否为 YYYY-MM-DDsource: 和 fetch_tool: 字段是否存在Edit 工具修正格式,再次验证完成后向用户报告:
✅ 笔记已创建:~/Obsidian/<目录>/<文件名>.md
- 标题:<标题>
- 来源:<URL>
- 抓取工具:<工具名><降级说明>
- 内容大小:<约 X>KB
多 URL 时汇总报告所有结果(成功/失败/跳过的数量和详情)。
| 场景 | 处理方式 |
|---|---|
| 预检查:所有工具不可用 | 报告检测结果,请用户手动粘贴内容 |
| obsidian MCP 工具不可用 | 使用固定常用路径列表( |
| AskUserQuestion 超时/取消 | 使用默认名称(网页标题)和默认位置(~/Obsidian/ 根目录),告知用户可按需调整 |
| 子页面抓取部分失败 | 合并模式下跳过错题子页面并标注;独立模式下不创建失败笔记。报告中列出成功/失败数 |
| 子页面全部抓取失败 | 保留主页面笔记(不追加子页面内容),报告所有失败的子页面 URL 和原因 |
| 用户选择的自定义路径不存在 | 自动创建目录(mkdir -p),然后继续保存 |
| opencli daemon 未运行 | 自动降级到 Firecrawl,告知原因 |
| Firecrawl API 不可用 | 降级到 fetchWebContent,告知原因 |
| 所有抓取工具都失败 | 报告错误,列出失败的 URL 和原因,不创建空笔记 |
| URL 返回 404/403 | 告知用户该 URL 无法访问,不重试 |
| 需要登录才能访问 | 告知用户该页面需要登录,建议手动复制内容后保存 |
| 网页内容为空/仅导航 | 告知用户内容质量差,询问是否仍保存 |
| 内容超过 80KB | 按边界感知截断策略处理,标注截断位置 |
| 磁盘空间不足 | 报告错误,不创建笔记 |
| frontmatter 格式验证失败 | 用 Edit 修正,重新验证直到通过 |
url-to-obsidianurl-to-obsidian 保存到 .raw/articles/,再 wiki-ingest 处理defuddle-cli 已安装,可在步骤 3 可选使用tags: [a, b]),始终用多行格式> 来源:[原标题](URL))--- 分隔不同子页面内容