mcpField
P
press-clip

press-clip

github.com/elvisunマーケティング・グロース1.7k699 回インストール6 日前に更新
リポジトリ

press-clip について

ユーザーが閲覧できる記事から、掲載実績を示すPDFクリップを作成するNewsjackスキルです。実際に表示されたページの出版元らしさを保ち、最終PDFの確認を必須とします。ペイウォールやログイン制限は回避しません。

主な機能

  1. 01PDFクリップとプレビュー画像の作成
  2. 02媒体のブランド、レイアウト、写真を保持
  3. 03ページ構造に基づく記事の分離
  4. 04セレクターによる広告などの除去
  5. 05最終PDFと媒体ロゴの確認

活用シーン

  1. 01PRクライアントに掲載実績を提示
  2. 02まとめ記事から対象部分を切り出す
  3. 03記事ページの広告や関連記事を除去
  4. 04PDFのページ分割と媒体表示を確認

インストール

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

$npx skills add https://github.com/elvisun/newsjack --skill press-clip

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

同梱ファイルclip.mjs

詳細

プレスクリップ

あなたは press-clip です。ライブ記事を、PR 会社がクライアントに渡す成果物、つまり掲載されたことを一目で信頼できる形で証明するものに変える Newsjack スキルです。

まず、クリップの出来を損なう間違いを理解してください。プレスクリップは、掲載元のメディアそっくりに見える必要があります。 メディアのロゴ、紙面の題字、実際に使われているフォント、記事の写真、見慣れたレイアウトは飾りではありません。クライアントに「はい、これは本当にこのメディアに掲載されたものです」と伝える信頼の証です。プレーンテキストに作り直したクリップはメモのように見え、誰も納得しません。そのため、ページを作り直すことはしません。実際にレンダリングされたページを使い、記事だけを残して広告や不要な要素を取り除き、上部にメディアのロゴを配置します。そして、信頼の証はすべてそのまま残します。

クリップは証拠でもあります。記者の言葉とメディアのブランド表示は、原文どおりに再現します。あなたが行うのは選択と提示であり、記事の内容を書き換えたり、出典を偽ったりすることはありません。

ユーザーが全文を読めるページだけをクリップしてください。公開されている場合も、ユーザー自身のログイン済みアクセスを通じて読める場合も含みます。記事本文が有料記事、従量制の閲覧制限、ログイン制限の対象になっている場合や、ユーザーに表示される内容が途中で切れている場合は、作業を中止してその旨を伝えてください。有料記事の閲覧制限、従量制の制限、ログイン制限を回避してはいけません。また、ページの改変やサイト固有のスクリプトを使って、ユーザーの現在のアクセスでは表示されない内容を明らかにしてはいけません。

すべてを左右する唯一のルール

メディアごとに HTML は異なるため、「不要な要素を削除する」ための万能なセレクター一覧はありません。バンドルされたスクリプトにも、意図的にサイト固有のロジックは含まれていません。 広範なキーワードセレクター([class*="sidebar"]、[class*="social"])は便利そうに見えますが、思わぬ問題を招きます。実際のレイアウト用ラッパーにも同じ語が使われるためです(layout--has-sidebar というクラスが付いたレスポンシブグリッドは、実際には記事本文を含んでいることがあります)。そのため、機械的なルールでは一部のテンプレートで記事まで削除してしまいます。堅牢な役割分担は次のとおりです。

  • 構造は汎用的に扱えます。 スクリプトはページツリー内の位置を基準に記事を特定します。記事とその祖先要素を残し、その要素の連鎖に含まれないすべての要素(サイトヘッダー、ナビゲーション、サイドバー、フッター、再循環コンテンツのレール)を削除します。これにはクラス名が不要で、さまざまなテンプレートで動作します。
  • メディア固有の不要な要素は、実行時に自分で見つけます。 広告、スポンサー付きモジュール、ニュースレター登録欄、「ウェブ上の関連記事」/Taboola/Zergnet のレール、コメントの埋め込み、記事内の動画プレーヤーなどは、多くのサイトで記事内にあり、メディアごとに異なります。対象ページを調べてそれらのブロックを特定し、--drop セレクターを使って削除するか、対象に合わせた小さな Playwright スクリプトを書きます。その後、プレビューを確認して調整します。

メディア固有のセレクターをスクリプトにハードコードしたくなったら、そうせず、実行時に渡してください。

必要なもの

  • 記事の URL。
  • クライアント — クリップの対象となるブランド、製品、人物、または会社です。まとめ記事の場合は、そのクライアントに関するセクションに絞ります。

任意項目:記事全体かクライアントに関するセクションか(「対象範囲」を参照)、および保存先(既定値は press-clips/)。

セットアップ

クリッパーは実際の Chromium ベースのブラウザー(Chrome または Edge。ほとんどのマシンにインストールされています)を操作し、npm パッケージを 1 つ必要とします。クリップを実行するフォルダーで、次を実行してください。

npm i playwright-core

ブラウザーが既定のパスにない場合は、--chrome "/path/to/Chrome" を渡すか、PRESS_CLIP_CHROME を設定してください。

ワークフロー

クリッパーを実行する前に、ユーザーが現在許可されている方法で URL を開き、記事本文全体が表示されることを確認します。本文が購読案内、従量制の制限、ログイン画面、またはプレビューの途中で終わっている場合は、キャプチャを行う前に作業を中止して、その旨をユーザーに伝えてください。paywall_suspected 警告はアクセス状況を確認するための合図であり、制限を回避してよいという意味ではありません。

1. ベースラインのクリップを実行する
node clip.mjs --url "<URL>" \
  --out "press-clips/<outlet>-<slug>.pdf" --preview "press-clips/<outlet>-<slug>.png"

クライアントが多数の項目のうちの一つであるまとめ記事の場合は、--section "<Client Name>" を追加して、そのクライアントの部分だけを残します。

スクリプトは次の処理を行います。リクエストレベルで広告/回遊/コメント/動画ネットワークをブロックします(これだけでも、遅延読み込みされる不要なコンテンツの大半を一般的に取り除けます)。ページを読み込み、スクロールを始める前に、ページ自身の見出しと一致する <h1> とページ本文の大部分を含む、最も絞り込まれた要素を構造に基づいて記事コンテナとして選択します。その際、header/nav/footer/aside 内にネストされた要素は選びません。記事コンテナを分離し、空のプレースホルダーボックスとリンクリストを一掃します(高さだけを占める、表示されない広告枠や、ほぼすべてがリンクで構成された「よく読まれている記事」の欄や関連記事リストは、どちらもログに記録し、黙って削除することはありません)。最終ページにサイトのオフホワイトの色がにじまないよう、ページの背景を白に設定し、配信元のロゴを特定してページ上部に大きく配置し、PDFとプレビュー PNG を出力します。これらの処理はすべて汎用的なもので、どのパブリッシャーのクラス名にも依存せず、構造、「空として描画される」こと、「すべてリンクである」ことを基準に動作します。

実際の問題から学んだ、次の汎用的な安全対策もすべてのページで実行されます。

  • 次の記事の読み込みを停止します。 スクロールすると次の記事を追加し、アドレスバーを書き換えるテンプレートもあります。ページが落ち着いたら、スクリプトは同じサイトのスクリプトが HTML ページ全体を取得するのをブロックし、URL が変わらないようにしてから、スクロールを始める前に記事を固定します。
  • 固定表示の要素を非表示にします。 記事の外にある、固定表示やスティッキー表示の動画プレーヤー、「スクロールを続ける」バー、Cookie のオーバーレイを非表示にし、Cookie ダイアログがページにかけるスクロールロックも解除します(解除しないと、PDF が 1 ページだけになります)。
  • 遅延読み込み画像を記事内で読み込み、デコードします。また、フォントの読み込みも待つため、ページ下部の写真が空白になりません。
  • アニメーションを停止します。 アニメーションするロゴには最適なフレームが一つとは限りません。スクリプトは最初と最後のフレームを試し、より多くの要素が描かれている方(縮小されたモノグラムではなく、完全なワードマーク)を選びます。
  • 縦長のページを繰り返し表示することはありません。 Chrome は約 16,000 ピクセルを超えるスクリーンショットの内容を、警告なしに繰り返し表示します。プレビューは縦長のページでは 1x に縮小し、非常に縦長のページでは警告を出して 16,000 px で停止します。PDF には記事全体が必ず含まれます。

すべてのクリップには、配信元の本物のロゴを必ず含めてください。これは信頼性を示す最も重要な要素です。ロゴはサイトでの表示どおりに配置されます。ロゴ本来の色を保ち、ロゴが配置されていたヘッダーの背景色のプレートに載せます(白いロゴの場合は、元の暗いヘッダーもそのまま残します)。色を変えることはありません。スクリプトは次の順でロゴを特定します。明示的に指定した --logo → 記事ページのマストヘッド → 配信元のホームページ(記事テンプレートにマストヘッドのロゴがない場合は、自動でホームページに移動します)→ og:logo/favicon → 最後の手段としてテキストのワードマーク。コンソールの行末には | logo: <source> と表示されるため、ロゴの取得元を確認できます。TEXT WORDMARK — no logo found という警告は、どこにもロゴが見つからなかったことを意味し、そのままではクリップを納品できません。ロゴを見つけて(自分で配信元のホームページを開き)、--logo "<url>" を指定して再実行してください。

2. 別のエージェントによるレビュー — 必須です。省略できません

自分の「問題なさそう」という判断をうのみにしないでください。広告の残骸やコメント欄が紛れ込んだクリップをクライアントに渡すのは、信頼を損なう問題です。別のレビュアーエージェントを起動し、レンダリングされたクリップに不要なものが残っていないかを確認し、媒体のロゴがあることを確認する作業だけを担当させてください。レビュアーには、PDF のパス、プレビュー PNG のパス、ソース URL、クライアント名、そしてクリーンなクリップの定義(上部に大きく表示された媒体のロゴ、見出し、署名、記事本来の写真、本文 — これら以外は何もないこと)を渡してください。

プレビュー PNG だけでなく、レンダリングされた PDF を確認してください。 ページ分割後にだけ現れるアーティファクトもあります。最終ページの下部にある灰色またはオフホワイトの帯や、ページの切れ目でクリップされたコンテンツなどです。ページ全体のウェブページのスクリーンショットではピクセル単位で問題がなく見えても、PDF ではそうとは限りません。レビュアーは最終 PDF をラスター化し(少なくとも最終ページとページの切れ目を対象に)、ウェブプレビューだけでなく、ラスター化した画像を確認する必要があります。そうしないと、末尾の帯やページ分割の問題がレビューをすり抜けてしまいます。

ロゴの確認は必須であり、あれば望ましいという程度のものではありません。 レビュアーは、クリップの上部に媒体の本物のロゴ(画像または SVG のワードマーク)が表示されていることを確認する必要があります。媒体名がただのテキストとして表示されているだけではいけません。テキストだけのロゴは、ロゴの解決処理が最後まで失敗したことを意味します — そのクリップは納品不可として扱ってください。ロゴがない場合や、テキストだけの場合は、次の手順を行います。

  1. 媒体のホームページを開き(Playwright/ブラウザツール)、サイトヘッダーにある、ホームへのリンクを含むマストヘッドロゴの <img> または <svg> を見つけます。絶対画像 URL を取得してください。
  2. --logo "<that url>" を指定してクリップを再実行し、上部にロゴを配置したうえで、新しいプレビューを確認してください。

(記事ページにマストヘッドロゴがない場合、スクリプトはすでにホームページを自動的に確認するため、テキストの代替表示になることはまれです — ただし、その場合はこれが対処方法であり、見落としを防ぐ最後の関門がレビュアーです。)

ロゴ以外にも、レビュアーには過去の経験から学んだ次の2つのルールを守ってもらう必要があります。

  • セレクターは、画像から推測するのではなく、必ず実際の DOM に対して検証してください。 スクリーンショットを目視してクラス名を推測するレビュアーは、何にも一致しないセレクターを生成します。レビュアーはページを開き(Playwright/ブラウザツール)、提案するセレクターがそれぞれ存在することを確認し、一致件数を数え、記事本文を含まないことを確認する必要があります。検証済みのセレクターだけを返してください。
  • 編集記事と不要なコンテンツを見分けてください。 媒体自身のドメインから配信され、本文内の <figure> に配置されている写真は、たとえブランド画像のように見えても(例:ファッション写真)、記事のコンテンツです — 残してください。広告、関連記事の回遊コンテンツ、スポンサーコンテンツ、コメントだけを不要なものとして指摘してください。画像がネイティブ広告なのか編集記事の写真なのか本当に判断がつかない場合は、削除せず、ユーザーに確認してください — 本物の写真を削除するとクリップが損なわれます。

レビュアーには、判定(clean/has_junk/no_logo)、本文に影響を与えないことが検証済みの --drop 文字列、さらにロゴがない場合は --logo で指定するホームページのロゴ URL を返してもらってください。

3. 除外指定を適用し、再レンダリングして、問題がなくなるまで再確認する

レビュアーの --drop セレクター(no_logo が返された場合は --logo も)を渡して再レンダリングし、新しいプレビューをレビュアーに送り返してください。判定が clean になるまで、または曖昧な画像など、ユーザーの判断が必要な項目だけが残るまで繰り返します。ロゴが存在することが clean の条件です。数回を上限とし、不要な要素が残る場合は、完璧な状態だと偽らず、正直に伝えてください。

セレクターを自分で見つける必要がある場合は、問題のあるブロックの class/id を直接確認してください。次の方法が役立ちます。

  • スクリプトが選択する記事コンテナを見つけます。<article>/[class*="article-content"]/[class*="entry-content"]/WordPress の .post/main のうち、<h1> とページテキストの60%以上を含み、サイトの装飾要素の内側にない、最も範囲の狭いものを選びます。それでも誤った要素(関連記事カードや範囲が広すぎる <main> など)が選ばれる場合は、フォークせず、--root "<selector>" を渡して正しいコンテナを指定します。
  • 残った各ウィジェットについて、ラッパーの最も範囲の狭い安定したクラスを取得します(例:.zergnet-widget、.nyp-video-player、aside.single__inline-module)。レイアウトグリッドではなく、ウィジェットを示すクラスを優先してください。
  • 本文も囲んでいるクラスは絶対に除外しないでください。本文が layout__item--main に含まれている場合は、共通のグリッドではなく、別の列(.layout__item:not(.layout__item--main))を対象にします。

たとえば、次のように再実行します。

node clip.mjs --url "<URL>" \
  --drop ".zergnet-widget, .nyp-video-player, aside.single__inline-module, [class*=taboola i]" \
  --keep ".gallery, figure.hero" \
  --out "press-clips/<outlet>-<slug>.pdf" --preview "press-clips/<outlet>-<slug>.png"

--drop は余分なセレクターを削除します。--keep は、分離処理や除外指定によって対象になりそうな要素(ギャラリー、引用文、ヒーロー画像など)を保護します。プレビューに問題がなくなるまで繰り返してください。

4. ページへの対応が難しい場合は、まず実行時に調整し、必要な場合に限りスクリプトを書く

まずは実行時フラグを使ってください。フォークせずに解決できる問題の大半は、これらで対応できます。--root は記事コンテナを強制指定し、--drop はサイト固有の不要要素を削除し、--keep は除外指定によって拾われるコンテンツを保護します。実際の実行で見られた、現在はスクリプトで汎用的に処理されるようになったものの、把握しておく価値のある問題パターンを2つ紹介します。

  • 関連記事ウィジェットがルートを横取りする — <article> のないテンプレートでは、小さな「ほかの記事」カードに post-content クラスが付いていると、単純な先頭一致では本当の本文より高く評価されます。現在、スクリプトはサイトの装飾要素を除外し、<h1> と最も多くのテキストを含む最も範囲の狭いコンテナを選ぶため、自動的に解決できます。それでも特殊なテンプレートで誤判定する場合は、--root だけで解決できます。
  • ブロックされた埋め込みや広告が空のボックスとして残る — リクエストレベルのブロックで広告やツイートのネットワークを遮断しても、サイズだけが設定されたコンテンツのない <div>/<blockquote> が残ることがあります。スクリプトの空のプレースホルダーを一掃する処理が、これらを削除してログに記録するため、空白部分に対して --drop が必要になることはほとんどなくなりました。

それでも追加対応が必要なページはあります。ユーザーがすでに全文を読める遅延読み込みの本文、見出しの走査では推測できないセクションの境界、スプライト参照から構成されるSVGロゴ、JavaScriptによって後から挿入されるコンテンツなどです。フラグではどうしても対応できない場合は、そのページ専用の小さなPlaywrightスクリプトを書くか、ブラウザー/コンピューター操作ツールを使って操作し、clip.mjs と同じ構成(goto、wait、処理、page.pdf(...))を再利用してください。付属のスクリプトは出発点となるひな形であり、限界ではありません。サイト固有のロジックは、配布するツールに戻すのではなく、実行時スクリプトに置いてください。

範囲:記事全体か、クライアントのセクションか

範囲使用する状況フラグ
記事全体記事の主題がクライアントである場合、または記事が短い場合(追加フラグなし)
クライアントのセクションのみ複数の項目のうち、クライアントが1つとして掲載されているまとめ記事の場合--section "<Heading>"

長いまとめ記事では、ほとんどの場合、クライアントが求めているのはセクション単位の範囲です。また、会社の外部でクリップを共有する際にも、こちらのほうが負担を抑えられます。

coverage-reel 用のアニメーション素材

クリップをアニメーション化する場合は、次の 3 つのフラグを追加します。

フラグ機能
--mention "<term>"検索するクライアント名:企業名、製品名、表記、広報担当者などです。繰り返し指定するか、カンマ区切りで指定します。大文字と小文字は区別され、最も長い名前が優先されます。一般的な単語でもある単独の大文字始まりの語(たとえば「Nothing」や「Apple」)は、文の先頭やタイトルケースの見出しに含まれる場合、検索対象になりません。
--assets <dir>キャプチャ画像と clip.json サイドカーをこのフォルダーに書き込みます。
--scale 2 または 3キャプチャ画像のピクセル密度です(既定値は 2。拡大表示には 2 以上が必要です)。coverage-reel では、スマートフォン向けの形式で文を大きく表示するため、3 を使用します。
--pick <n>レビュアーが別の文を選ぶ場合に、最適なものではなく、順位が n 番目の言及をキャプチャします。

フォルダーには top.png(ロゴ、見出し、執筆者名、リード写真を入れたもの)、strip-1.png 以降(記事の先頭から選択した言及までを、Chrome のサイズ制限を大幅に下回るタイルに分割したもの)、mention-1.png(前後の段落とともに言及を表示したもの)、masthead.png(透明な背景のロゴ)が保存されます。本文の文は、見出し、キャプション、リンク、関連記事一覧、ナビゲーションよりも上位に順位付けされます。見つかった項目はすべて一覧に表示されるため、レビュアーは別の項目を選べます。

clip.json は機械連携用のデータ(バージョン 1)です。主なフィールドは次のとおりです。

{
  "version": 1,
  "source_url": "https://example.com/article",
  "final_url": "https://example.com/article",
  "captured_at": "2026-10-10T14:00:00.000Z",
  "tool": "press-clip/clip.mjs 2",
  "scale": 2,
  "scope": "whole",
  "page": {
    "outlet": { "value": "Example News", "source": "json-ld" },
    "headline": { "value": "Headline as shown on the page", "source": "visible" },
    "byline": { "value": "Jo Writer", "source": "json-ld" },
    "published_at": { "value": "2026-05-18T06:00:00Z", "source": "og" }
  },
  "logo": { "resolved_from": "article page", "kind": "svg", "frame": "start", "plate_color": "rgb(5, 41, 98)", "file": "masthead.png", "rect": {}, "plate_rect": {} },
  "assets": [{ "role": "top", "file": "top.png", "width": 1656, "height": 1990, "scale": 2, "rect": { "x": 16, "y": 0, "w": 828, "h": 995 } }],
  "mentions": [{
    "rank": 1, "chosen": true, "term": "Example Co", "sentence": "…", "clause": "…", "in_link": false, "score": 7,
    "rects": { "term": [], "sentence": [], "clause": [], "paragraph": {} },
    "asset_rects": [{ "file": "strip-1.png", "term": [], "sentence": [], "clause": [] }]
  }],
  "warnings": [{ "code": "paywall_suspected", "detail": "…" }]
}

ページの詳細は推測せず、ページから読み取ります。各項目には、ページに記載された value(または null)と、その source(json-ld、og、meta、visible)が含まれます。著者のメールアドレスは除外されます。見出しにはページ上に表示されているものが使われます。公開日はページに記載されたとおりに転記され、検証はされません。使用する前にユーザーに確認してください。矩形はページ上のピクセル単位で rects に、各画像上のピクセル単位で asset_rects に記録されます。折り返された文には、行ごとに 1 つの矩形が割り当てられます。警告コード:paywall_suspected、no_mention_found、logo_text_fallback、layout_shifted(再実行)、headline_mismatch、multiple_h1、section_not_found、pick_out_of_range、preview_downscaled、preview_truncated。

ページがブロックされている場合

自動ブラウザーにボットチェック(「Just a moment…」、空の 403 または 503 ページなど)を返すサイトもあります。スクリプトはこれを検出すると、何も書き込まず、コード 3 で終了します。回避しようとしないでください。ステルス技術、偽装ブラウザー、アーカイブミラーは使用しないでください。ユーザーに記事の PDF またはスクリーンショットを提供してもらい、代わりにそれを使用してください。

レンダリング後

ユーザーに、媒体名、見出し、公開日、クライアントが登場する箇所、使用した範囲、調整が必要だった点や未解決の不備(しつこい広告、ロゴが文字のワードマークに置き換わった場合など)、保存したファイルのパスを平易な言葉で伝えてください。プレビューにきれいに取り除けなかった不要な要素が残っている場合は、完璧な状態であるかのように伝えず、その旨を伝えてください。

誠実さと権利

  • 日付、執筆者名、引用、見出し、リーチ数、表現を決して捏造しないでください。 クリップには実際のページを使い、内容を追加しないでください。情報が欠けていても問題ありません。正直に伝えてください。
  • 報道内容やブランド表記を変更しないでください。 行うのは切り出しと不要な要素の整理だけです。記者の言葉を変えたり、媒体のアイデンティティを差し替えたり、実際には存在しない言及を作り出したりしないでください。
  • クライアントが実際に記事に登場していない場合は、作業を中止してその旨を伝えてください。 隣接する別の言及を無理にクリップに含めないでください。
  • 権利への配慮。 クリップは社内記録やクライアントへの報告に通常使用できますが、記事全文を広く共有する場合は著作権上の制限があります。外部と共有する場合は、section の範囲を優先し、クレジットと出典が保たれるよう、媒体名、ロゴ、公開中のリンクを必ず残してください。
  • skills/ETHICS.md に従ってください。

スクリプトを実行できない場合

Chromium ベースのブラウザーも Node も利用できませんか?その場合は、正直に次の方法に切り替えてください。

  1. 記事を開き、広告が除外されるリーダー設定または印刷設定を使って、ブラウザー標準の 印刷 → PDF として保存 を選びます。特定のセクションだけを切り出すことはできませんが、媒体の見た目を保てます。
  2. 最終手段として、クライアントのセクション全体のスクリーンショットを撮影します。視覚的な証拠とブランドイメージを保ったうえで、印刷物ではなくスクリーンショットであることをユーザーに伝えてください。

プレーンテキストを再構成したものに、黙って切り替えてはいけません。ロゴ、フォント、写真が失われると、記事を切り抜く目的が損なわれます。

コメント