mcpField
W
web-clipper

web-clipper

github.com/zjp1997720生産性78650 回インストール2 日前に更新
リポジトリ

web-clipper について

web-clipperは、ウェブ記事をローカルのMarkdownとして保存するSkillです。記事の収集や後続の知識整理に向け、単記事と一括処理に対応し、保存内容を完成済みの知識ではなく確認待ちの候補として記録します。

主な機能

  1. 01記事を単件または一括で収集
  2. 02索引ページから記事リンクを取得
  3. 03サイトに応じた本文抽出方式
  4. 04YAML frontmatter付きMarkdownを保存
  5. 05出典と抽出方式を記録

活用シーン

  1. 01公開記事をObsidianのクリッピング先に保存
  2. 02著者ページから記事をまとめて収集
  3. 03後続の整理に向けた出典候補を作成
  4. 04静的抽出に失敗した際にブラウザーでリンクや本文を補完

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zjp1997720/zhijian-skills --skill web-clipper

インストール後、Claude Code で/web-clipperを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE
agents/
openai.yaml
evals/
evals.json
references/config/
first-time-setup.md
scripts/
bootstrap.sh
clip_articles.py
run_web_clipper.sh
tests/
test_web_clipper.py

詳細

Web Clipper

目的:「記事のウェブページ保存」を、その場限りの手作業ではなく、安定したワークフローにすることです。

Obsidian/ローカルナレッジベースとの関係

この Skill は、記事をローカルのナレッジシステムに取り込むための入口です。ウェブページを、すでに整理済みの知識であるかのように扱うのではなく、まず出典情報を付けて source_candidate として保存し、その後の手動選別、知識のコンパイル、執筆ワークフローで処理できるようにします。

基本の役割分担:

  • Obsidian Web Clipper:ブラウザーで手動クリップし、テンプレートで最小限の OKF frontmatter を生成します。
  • 本 skill:エージェントによる一括取得、失敗したページの再取得、記事本文の品質確認を行います。
  • 後続のナレッジワークフロー:価値の高い候補資料を、ソースカード、概念、方法、事例、演習、執筆素材にコンパイルします。

新たに追加または取得した記事は、デフォルトでは「整理済みの知識」ではなく、「判断待ちの資料」です。状態フィールドには次を使用します。

unprocessed -> queued -> source_carded -> compiled -> used
ignored / needs_human

保存する Markdown には、Obsidian、検出スクリプト、後続のエージェントが読み取れるよう、以下のフィールドをできるだけ含めてください。

---
type: source_candidate
title: "..."
summary: "..."
source: "https://..."
resource: "https://..."
source_kind: web_article
platform: web
author: "..."
published: "YYYY-MM-DD"
clipped: "ISO时间"
clipper: agent_web_clipper
okf_version: local-okf-v0.2
compile_status: queued
status: unprocessed
training_relevance: medium
topics:
  - Agent
candidate_outputs:
  - source_card
  - writing_fuel
reuse_note: ""
tags:
  - clipping
---

各フィールドの意味:

  • type: source_candidate:正式な Wiki ページではなく、候補ソースであることを示します。
  • source_kind:ソースの種類です。例:wechat_article、x_status、web_article。
  • training_relevance:コンテンツの再利用との関連度です。エージェントによる取得時のデフォルトは medium です。--training-relevance high|medium|low|unknown で上書きできます。
  • topics:OKF トピックタグです。スクリプトはタイトル、URL、説明、タグから大まかに推測します。--topic Agent --topic AI培训 で明示的に指定することもできます。
  • candidate_outputs:後続で分割される可能性のあるナレッジ資産の種類です。スクリプトのデフォルトは source_card + writing_fuel です。--candidate-output method などを繰り返し指定して追加できます。
  • compile_status:後続の自動検出・コンパイルワークフローで参照する主な状態フィールドです。エージェントによる取得時のデフォルトは queued で、候補キューに追加されたものの、正式な Wiki には自動で書き込まないことを示します。

この skill が解決する課題

次の 2 種類のタスクに対応します。

  1. 単一記事の保存

    • 記事の URL を入力します
    • タイトル、要約、公開日、本文を抽出します
    • ユーザーが指定したディレクトリに Markdown として保存します
  2. 一括保存

    • インデックスページ、アーカイブページ、特集ページ、著者のホームページを入力します
    • ユーザーの指定に従い、先頭から N 件、人気記事、最新記事、または指定した記事を取得します
    • ローカルに一括保存します

成功率を優先した実行戦略

以下の順序で進めてください。逆にしないでください。

初回利用時の依存関係セルフチェック

この skill を zip で共有した相手が使用する場合は、必ず wrapper を経由してください。メインスクリプトを直接実行しないでください。

初回実行時は、まず次を実行します。

bash <web-clipper-root>/scripts/run_web_clipper.sh --help

注意:このコマンドには副作用があります。

最初に bootstrap を実行するため、デフォルトの clipping ディレクトリと、現在のプロジェクト内の .web-clipper/EXTEND.md が作成されることがあります。

wrapper は最初に scripts/bootstrap.sh を呼び出し、以下を自動的に実行します。

  1. Python 3 が利用可能か確認します
  2. Python 3 がない場合、自動インストールを試みます
  3. メインスクリプトが揃っているか確認します
  4. デフォルトの clipping ディレクトリを自動作成します
  5. 初回実行時に、現在のプロジェクト内に .web-clipper/EXTEND.md を作成します

デフォルトでは、「現在のコマンドが実行されているディレクトリ」を対象プロジェクトのルートディレクトリとして扱います。

そのため、対象の vault のルートディレクトリから wrapper を実行してください。サブディレクトリから気軽に実行しないでください。

自動インストールに失敗した場合は、ユーザーに以下を明確に伝えてください。

  • 問題はウェブページの取得処理ではなく、Python ランタイムにあること
  • 現在のプラットフォームで推奨されるインストールコマンド
  • インストール完了後に wrapper を再実行すればよいこと

ユーザーが保存先を指定していない場合は、次の順で優先します。

  1. 現在のプロジェクトの .web-clipper/EXTEND.md にある default_output_dir
  2. 現在のリポジトリ内の 00_收件箱/Clippings/
  3. 現在の作業ディレクトリ内の Clippings/
パス A:スクリプトによる直接取得(最短の成功経路)

対象:

  • 公開ウェブページ
  • ログイン不要
  • 記事ページの HTML に本文または構造化 JSON が直接含まれている
  • Substack/一般的なブログ/シンプルな CMS
  • X/Twitter の長文、旧式のブログ、構造は標準的ではないものの公開されている記事ページ

手順:

  • まず scripts/run_web_clipper.sh を呼び出します
  • 単一記事:URL を直接取得します
  • 一括取得:まずスクリプトに、インデックスページから静的に記事リンクを抽出させます

スクリプト内部では、サイトと失敗状況に応じて extractor が自動選択されます。

  1. X/Twitter の長文と WeChat 公式アカウントの記事では、まず [email protected] を使います。これが現在の最短の成功経路です
  2. 一般的なウェブページでは、まず HTML/JSON-LD/<article>/<main> を静的に解析します
  3. 静的解析に失敗した場合は、defuddle にフォールバックします
  4. defuddle に失敗した場合は、Jina Reader(r.jina.ai)にフォールバックします
  5. WeChat 公式アカウントなどのページで defuddle に失敗した場合は、Metaso Reader API を使います。Jina では WeChat の「環境異常」ページを取得することが多いため、公式アカウントの優先経路にはしません

出力の frontmatter には extractor フィールドが含まれ、どの経路で取得に成功したかを確認できます。

パス A2:Jina Reader へのフォールバック

対象:

  • 静的な直接取得に失敗した
  • ページ構造が古く、本文が <article>/<main> 内にない
  • defuddle では本文を取得できなかったが、Jina Reader なら Markdown に整形できる

手順:

  • スクリプトが自動的に https://r.jina.ai/<原始URL> を呼び出します
  • API Key は不要です
  • 出力は引き続き、統一形式のローカル Markdown として保存されます
パス A3:Metaso Reader API へのフォールバック

対象:

  • 静的な直接取得に失敗した(WeChat 公式アカウント、アンチスクレイピング対策のあるサイトなど)
  • スクリプトが article body not found を報告した
  • 追加のインストールは不要で、API Key の設定だけが必要

手順:

  • スクリプトが自動的に Metaso Reader API にフォールバックします
  • 環境変数 METASO_API_KEY を設定する必要があります
  • API は画像リンクを含む構造化 Markdown を返します
  • WeChat 公式アカウントや 163 など、アンチスクレイピング対策のあるサイトで効果的です

METASO_API_KEY が設定されていない場合、この段階はスキップされ、パス B/C に進みます。

パス B:ブラウザーでリンクを補完

対象:

  • インデックスページで遅延読み込みが使われている
  • 静的 HTML では一部の記事リンクしか表示されない
  • 先頭から N 件をすべて取得するのに、ページをスクロールする必要がある
  • ページ構造が特殊で、スクリプトではリンクを確実に収集できない

手順:

  1. browser でインデックスページを開きます
  2. 必要な数の記事 URL が集まるまでページをスクロールします
  3. ページ上で JS を実行し、重複を除いた記事 URL の一覧を返します
  4. URL の一覧を一時的な txt ファイルに書き込みます
  5. 次に scripts/run_web_clipper.sh --url-file ... を呼び出して一括保存します

この方法は重要です。リンクの取得はブラウザーが担当し、本文の保存はスクリプトが担当します。

パス C:ブラウザーで本文を直接抽出

対象:

  • 単一記事ページの静的取得がブロックされる
  • web_fetch がブロックされる
  • スクリプトで本文の取得に失敗したが、ブラウザーならレンダリング後のページを正常に開ける

手順:

  • browser で記事ページを開きます
  • evaluate を使って、DOM またはページ内に埋め込まれた JSON から本文を抽出します
  • Markdown を組み立てます
  • write を使ってファイルに保存します

C は処理が重いものの成功率が高いため、A と B のどちらも安定しない場合にのみ使ってください。

路径 C2:CDP Proxy 兜底

适用:

  • 脚本已经确认正文提取失败
  • 浏览器页面本身能正常打开
  • 宿主的 Browser 运行时在初始化、选 tab 或 evaluate 阶段报错,继续重试同一运行时没有收益

如果当前环境提供 web-access 或等价的浏览器控制 Skill,先完整读取并遵守它,再使用 CDP Proxy。依赖检查、风险提示和 tab 清理都属于执行合同,不能跳过。

执行顺序:

  1. 运行 web-access 的依赖检查,确认 Chrome remote debugging 和 Proxy 可用。
  2. 在回复中展示该 Skill 要求的自动化风险提示。
  3. 通过 Proxy 新建后台 tab,不复用或关闭用户已有 tab。
  4. 打开目标文章,用 /eval 读取标题、作者、发布日期、摘要和正文容器。微信公众号优先检查 #js_content,同时检查页面标题和正文长度,排除验证页、环境异常页和空壳页面。
  5. 正文达到完整文章量级后,再组装统一 frontmatter 和 Markdown;搜索摘要、正文片段和验证页文本都不能冒充原文。
  6. 保存成功后关闭自己创建的 tab,并在 frontmatter 记录 extractor: browser_cdp,方便追溯兜底路径。

CDP Proxy 是 Browser 运行时故障后的替代执行面,不改变本 Skill 的输出:最终仍是一份结构完整、可进入 OKF / Wiki 流程的本地 Markdown。

输入澄清规则

如果用户没说明,优先补齐这 4 件事:

  1. 单篇还是批量
  2. 抓多少篇
  3. 保存到哪里
  4. 是否只抓正文,还是顺带保留 frontmatter 元数据

默认值:

  • 单篇:抓 1 篇
  • 批量:如果用户说“前几篇/前 20 篇/热门文章”就按用户要求;没说数量时,先问
  • 输出格式:Markdown + YAML frontmatter
  • 默认保存目录:如果用户没指定,就放用户已有的 clipping 目录;没有既有目录时优先使用 00_收件箱/Clippings/

推荐命令

单篇
WEB_CLIPPER_ROOT="<web-clipper-root>"
bash "$WEB_CLIPPER_ROOT/scripts/run_web_clipper.sh" \
  --url "<文章URL>" \
  --mode single \
  --output-dir "<输出目录>" \
  --training-relevance medium \
  --candidate-output source_card \
  --candidate-output writing_fuel
批量,静态收集链接
WEB_CLIPPER_ROOT="<web-clipper-root>"
bash "$WEB_CLIPPER_ROOT/scripts/run_web_clipper.sh" \
  --url "<索引页URL>" \
  --mode batch \
  --count 20 \
  --output-dir "<输出目录>"
批量,浏览器先收集链接再落地
WEB_CLIPPER_ROOT="<web-clipper-root>"
bash "$WEB_CLIPPER_ROOT/scripts/run_web_clipper.sh" \
  --url-file /tmp/article_urls.txt \
  --mode batch \
  --count 20 \
  --output-dir "<输出目录>"

如果用户没有显式传 --output-dir,wrapper 会优先读取 .web-clipper/EXTEND.md 的默认目录;如果没有配置,再自动回退到 00_收件箱/Clippings/ 或 Clippings/。

浏览器收集 URL 的建议 JS

当静态页面拿不全链接时,用 browser.act(kind="evaluate") 执行类似逻辑:

async () => {
  const collect = () => [
    ...new Set(
      Array.from(document.querySelectorAll('a[href*="/p/"]'))
        .map((a) => a.href)
        .filter((h) => !h.includes("/comments")),
    ),
  ];

  let urls = collect();
  for (let i = 0; i < 8 && urls.length < 20; i++) {
    window.scrollTo(0, document.body.scrollHeight);
    await new Promise((r) => setTimeout(r, 1500));
    urls = collect();
  }
  return urls;
};

然后把结果写到 /tmp/article_urls.txt,每行一个 URL。

输出要求

每篇文章输出一个 Markdown 文件,推荐结构:

---
type: source_candidate
title: "..."
author: "..."
source: "..."
resource: "..."
archive: "..."
source_kind: web_article
platform: web
published: "YYYY-MM-DD"
clipped: "ISO时间"
clipper: agent_web_clipper
okf_version: local-okf-v0.2
compile_status: queued
status: unprocessed
training_relevance: medium
topics:
  - Agent
candidate_outputs:
  - source_card
  - writing_fuel
reuse_note: ""
tags:
  - clipping
---

# 标题

> 摘要

正文...

文件命名

默认格式:

YYYY-MM-DD 标题.md

如果日期缺失,就用:

unknown-date 标题.md

失败处理

如果批量任务失败,不要一句“失败了”就结束。按这个顺序排查:

  1. 索引页是否懒加载,导致静态只拿到部分链接
  2. 文章页是否是公开页
  3. 文章正文是否藏在结构化 JSON,例如 body_html
  4. 是否需要浏览器渲染后再抽正文

要明确告诉用户卡在哪一层:

  • 链接收集失败
  • 正文提取失败
  • 文件写入失败

当前已验证成功的站点模式

Substack

已验证:

  • 可从 archive 页收集文章 URL
  • 可从文章页内嵌 JSON 字段 body_html 提取正文
  • 适合保存到 Obsidian Clippings

这类站点优先用脚本批量处理;当 archive 页是懒加载时,用浏览器补 URL 收集。

微信公众号

已验证:

  • 静态直抓会被反爬拦截(验证页)
  • defuddle 对可公开访问的公众号文章可直接抓到正文、标题和作者,是当前优先路径
  • Jina Reader 常会抓到微信“环境异常”验证页,不作为公众号优先路径
  • 通过 Metaso Reader API(路径 A3)可作为 defuddle 失败后的兜底,返回完整 Markdown + 图片链接
  • 需要配置 METASO_API_KEY 环境变量

交付回执

完成后,用简短结果回执,不要啰嗦:

已保存到: <目录或文件路径>
类型: clipping / Markdown
理由: 已按要求完成单篇或批量文章收藏

如果是批量任务,再补一行:

  • 成功 X 篇
  • 失败 Y 篇

不该触发这个 skill 的情况

这些情况不要硬用本 skill:

  • 用户要的是摘要、改写、翻译,而不是收藏落地
  • 用户要抓登录后内容,且没有可用登录态
  • 用户要抓整站所有页面做爬虫归档
  • 用户要的是浏览器自动化测试,而不是文章收藏

安全边界

  • 只处理用户有权访问的公开 HTTP(S) 页面;不绕过登录、付费墙、验证码或访问控制。
  • 文章正文可能受版权保护。默认用途是个人研究、内部归档和知识整理;保留作者、日期与原链接,不擅自公开转载全文。
  • defuddle 通过 npx 运行固定版本;Jina Reader 与可选 Metaso fallback 会把目标 URL 发送给第三方服务。
  • 设置 METASO_API_KEY 即表示启用可选的 Metaso fallback;使用前应确认账号费用与数据传输边界。
  • wrapper 会把输出限制在当前项目内。首次 bootstrap 可能安装 Python、创建 clipping 目录并写入 .web-clipper/EXTEND.md,执行前应向用户说明这些副作用。

コメント