6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

英語の技術ニュースは追いきれない。自分の場合は Laravel News(Laravelの公式ニュース。英語で、ほぼ毎日更新)で、追える時と追えない時の差が激しく、どこまで読んだか分からなくなる。そこで Claude Code で収集を自動化して、2026年1〜6月の記事を日本語訳して手元にアーカイブし、出典リンク付きの月次まとめ6本を公開した(末尾にリンク)。

全て出典のリンクを貼っているので、気になる内容があればすぐに開ける
スクリーンショット 2026-06-30 12.29.26.png

作ったもの

中身は Claude Code のスキルで、役割で3つに分けた。本文抽出は既存のスキルを借り、残り2つは自分の用途に合わせて作った。といっても、そのスキル(指示書)も手では書かず、Claude Code と対話して作った。sitemap の列挙や最後のチェックといった決定的にやりたい所は、小さなスクリプトに固定してある。

  • 本文抽出web-content-extraction):URLを安全に取得して本文だけ Markdown にする前処理。Claude Code Starter Kit(Cloud Native Inc./MIT License)のスキルをそのまま使わせてもらっている。
  • 収集とアーカイブlaravel-news-catchup):sitemapで列挙し、本文を取得して翻訳し、検証して索引にする。
  • 記事化(発信)laravel-news-monthly-roundup):翻訳アーカイブから、月1本のまとめを書く。目玉のリリースはコード付きで深掘り、パッケージはテーマ別に厳選、残りは網羅リンクで拾う。仕上げに3観点(技術精度/日本語/作法)の並列レビューと、網羅/除外/UTM の決定的チェックを通して下書きに残す。

3つのスキルの関係:収集エンジン+継ぎ目+発信

この3つは対等に並ぶのではない。本文抽出収集とアーカイブは実行時に密結合した1つのエンジンで(図の実線)、記事化は全文訳アーカイブ(translations/)というファイルを読むだけの疎結合な下流だ(点線)。

3つのスキルと成果物を1つのパイプラインとして並べるとこうなる。

laravel-news-pipeline/
├─ skills/
│  ├─ web-content-extraction/        # 本文抽出(Defuddle+SSRFガード)
│  │  └─ scripts/defuddle-url.mjs
│  ├─ laravel-news-catchup/          # 収集→翻訳→検証→索引
│  │  ├─ scripts/fetch-sitemap.mjs   # sitemap列挙(依存ゼロ)
│  │  ├─ last-checked.txt            # 前回どこまで見たか
│  │  ├─ digests/YYYY-MM-DD.md       # 日次キャッチアップの要約
│  │  └─ translations/YYYY-MM/       # 月別の全文訳+README索引
│  └─ laravel-news-monthly-roundup/  # 記事化(月次まとめ生成)
│     └─ assets/check-article.py     # 網羅/除外/UTMの決定的チェック
└─ public/laravel-php-YYYY-MM-matome.md  # 公開する月次まとめ記事

「収集とアーカイブ」スキルの全文は下の折りたたみに置いた。この手順書があるから、「○月をバックフィルして」と言うだけで毎回同じ品質が出る。

laravel-news-catchup スキル全文(スクラブ済み・そのままは動かない指示書)

記事ではバックフィル側を中心に書いたが、実際のスキルは日次の新着差分キャッチアップも含む。コードはAIに書かせるので、ここにあるのは手順と判断基準だけだ。社内パスや業務文脈はスクラブしてある。

---
name: laravel-news-catchup
description: Laravel News (https://laravel-news.com) の新着記事をキャッチアップする。記事サイトマップで新着URLを列挙し、前回確認(lastmod)からの差分を抽出、必要な記事は本文をDefuddleで取得して日本語で要約する。トリガー例: Laravel Newsを確認/Laravelの新着/今週のLaravel。
when_to_use: Laravel News の新着を定期的に把握したいとき。新しいリリース・パッケージ・チュートリアル・エコシステムの動向を、前回からの差分でまとめて確認したいときに使う。
---

# Laravel News Catch-up

## 目的

Laravel News の新着記事を効率よくキャッチアップする。ブログ一覧ページ(HTML)は
日付が出ず取りこぼしやすいので、記事サイトマップ(sitemap_articles.xml)をURL列挙の
一次情報として使う。各記事の本文・公開日・著者は本文抽出(Defuddle)で取得する。

## 情報源

| 種類 | URL | 用途 |
|---|---|---|
| 記事サイトマップ(一次情報・URL列挙) | https://laravel-news.com/sitemap_articles.xml | 全記事URL+lastmod の取得 |
| 個別記事HTML(精読) | 各記事URL | Defuddleで本文・公開日・著者を取得 |

- サイトマップは <loc><lastmod> のみ。title・著者・カテゴリ・要約・公開日は持たない
  ので、各記事をDefuddleして補う。
- lastmod は更新時刻で、タイムゾーンは US-Eastern(-04:00/-05:00)。公開日とずれること
  があるので、lastmod は新着候補を絞るフィルタにだけ使い、公開日・新着判定は Defuddle の
  published で行う。

## 状態管理

- last-checked.txt に、前回取得した新着候補の最大 lastmod(= lastmod の高水位)を入れる。
  無ければ初回。
- 既出記事の判定は、別ファイルを持たず既存の digests/*.md に出したURLを正とする。

## 進め方(日次キャッチアップ)

1. 前回の lastmod 高水位を読む:last-checked.txt(無ければ初回)。
2. サイトマップ取得+候補抽出(同梱スクリプト。依存ゼロ・Node標準のみ):

   # 前回以降の候補だけ(slackで取りこぼし防止、maxで暴走防止)
   node scripts/fetch-sitemap.mjs --since="$(cat last-checked.txt)"
   # 初回は全件から新しい順に少数だけ
   node scripts/fetch-sitemap.mjs --max=10

   出力JSON: { success, sitemapUrl, fetchedAt, since, slackHours, max, truncated,
   count, totalUrls, warnings, items:[{url,lastmod,lastmodInstant}] }(lastmod 降順)
   - success:false のときは「サイトマップ取得失敗」と明示し、last-checked.txt を進めず止める。
   - truncated:true(候補が多すぎ)や長期間の未確認なら、日次の要約でなくバックフィルへ切り替える。

3. 本文取得+新着確定(候補のみ・新しい順):各候補URLを本文抽出で精読し、published で確定:

   node ../web-content-extraction/scripts/defuddle-url.mjs "<記事URL>"

   - 既存 digests/*.md に既出のURLはスキップ。published(JST) が前回確認より新しいものだけ採用。
   - success:false や published 空は「要再取得」として残し次回リトライ(黙って捨てない)。
4. 分類と要約:URLスラッグと title/本文から、リリース / 新パッケージ・ツール /
   チュートリアル / エコシステム・その他 に振り分け、本文をもとに日本語1〜2行で要約。
   必要なら「自分の業務での使いどころ」を一言添える。
5. 記録と状態更新:要約を digests/YYYY-MM-DD.md に保存し、last-checked.txt を今回の候補の
   最大 lastmod で上書きする(新着が0件でも前進させる)。

## フォールバック

同梱スクリプトが動かない場合は raw XML を取得して手で読む:

   curl -sL "https://laravel-news.com/sitemap_articles.xml" -o /tmp/laravel-news-sitemap.xml
   # 末尾=最新。<lastmod> の新しい順に <url><loc> を数件取り、各URLを Defuddle で精読する

- どの手段でも出典URLと取得日時を必ず残す。取得失敗時は断定しない。

## 過去記事バックフィル(全文翻訳アーカイブ)

特定期間(例: ある月)の全記事を遡って日本語全文訳で残すときも、日次と同じ
sitemap → Defuddle を使う(違いは深さ=全文訳+索引)。

1. 列挙:fetch-sitemap.mjs で対象期間+前後マージンのURLを取る(--since/--max を調整、
   または raw sitemap を lastmod で絞る)。
   - lastmod は更新時刻で、公開の数日後のことがある。最終的な期間判定は次の
     Defuddleの published で行う。
2. 取得+確定:各URLを本文抽出で取得し、published(JST) が対象期間内の記事だけ確定:

   node ../web-content-extraction/scripts/defuddle-url.mjs "<記事URL>"

   title / author / published / content(Markdown) / fetchedAt を使う。
3. 選別(キュレーション):期間内の記事を、下記基準で 全文訳する記事 と 収録対象外
   に振り分ける。対象外は全文訳せず、索引末尾に タイトル|URL|除外理由 の1行だけ
   残す(黙って消さない)。
4. 全文翻訳+保存:収録対象の本文を日本語に全文訳(コード・コマンド・識別子・
   バージョン・URLは原文維持)し、日本語技術ライティングの規範に従う。冒頭に3行
   まとめ+一言メモを付け、translations/YYYY-MM/YYYY-MM-DD-<slug>.md に1記事1
   ファイルで保存。
5. 検証:別エージェントで原文と突き合わせ、欠落・コード/版の保全・日本語の自然さ
   をチェックし必要なら修正(独立した第三者視点で)。
6. 索引:translations/YYYY-MM/README.md をカテゴリ別に生成し、末尾に「収録対象外
   (参考)」を付ける。
7. 規模が大きい場合は「Defuddle取得→翻訳→保存→検証」を記事ごとにパイプライン並列化
   する(記事ごとに別ファイルなので競合しない)。

### 収録の選別基準(キュレーション)

全文訳の資産にならない記事は全文訳しない。日次の要約でも同じ基準でトーンを落とす。

収録対象外(全文訳しない/索引は1行):
- 動画コンパニオン記事:本文に技術的実体がなく中身が動画・GitHub頼みのもの。
- 賞味期限の短い単発告知:アンケート/調査の参加募集、IDEバッジ等の小ネタ、締切や
  開催で陳腐化するもの。
- 宣伝寄りの機能告知:実務に直結しないベンダー製品のリリース告知。

収録する(全文訳する):
- Laravel コア/フレームワークのリリース(バージョン挙動は必ず残す)。
- 実装・設計の中身があるパッケージ/ツール紹介・チュートリアル。
- エコシステムの節目で実務価値が高いもの(主要カンファレンスの登壇内容など)。
  単なる「○○が始まりました」告知は対象外。

判断に迷う記事は収録対象外に倒さず、収録してメモで価値を一言添える(後から消す方が安全)。

## 注意

- 公開日は JST で表記する。
- 要約は日本語。タイトルは原文のままでよい。
- 重要な事実(バージョン番号・非互換変更など)は個別記事の一次情報で裏取りする。
- 1記事も新着がなければ「前回以降の新着なし」と明記して終える。

情報源の罠

過去ぶんをまとめてアーカイブするのが主目的だ。https://laravel-news.com/sitemap_articles.xml に全記事のURLが日付つきで載っているので、新着の差分も過去の遡りも、ここから対象を拾う。

ただし sitemap の <lastmod>更新日時で、公開日とずれる。実際、先月公開の記事が今月の lastmod で並んでいたことがあった。なので sitemap はURLの列挙にだけ使い、どの月かは記事本文の公開日(published を JST に直したもの)で確定する。

いつ走らせても、前回の続きから

この sitemap と「前回どこまで見たか」(last-checked.txt)の組み合わせが、最初の悩みに効く。前回確認した位置を覚えているので、いつ実行しても前回以降の新着だけが対象になる。毎日でも、数週間ぶりでも、空いた分はまとめて差分で埋まる。月の途中で一度アーカイブを作り、月末にまた走らせれば、増えたぶんだけ足される。「どこまで読んだか」を自分で抱えなくてよくなった。

本文抽出は専用ツールに任せる

本文抽出には、スターターキットに入っていた web-content-extraction スキルをそのまま使った1。生HTMLをそのままLLMに渡すより精度が出る。自分は呼び出しているだけで、抽出も SSRF2 ガードも中身は書いていないし、手を入れてもいない。

なお、月の確定に使う公開日(published)も、Defuddle がページのメタデータ3(OGP の article:published_time や schema.org の datePublished など)から読むものだ。ニュースやブログはたいてい出しているが、どのソースにも必ずあるとは限らない。更新日しか持たなかったり、日付が本文テキストにしか無いサイトでは取れない。その場合は公開日で月を確定できないので、取れなかった記事はその回では確定させず次に回す(「要再取得」にして黙って捨てない)。

何を載せ、何を落とすか

全部を機械的に訳すと、動画の紹介だけの記事や賞味期限切れの告知まで溜まる。なので動画コンパニオンと短命な告知(アンケート募集、IDEバッジ等)は落として、リリースや中身のあるパッケージ紹介だけ訳した。落とした記事も、索引に「タイトル|URL|除外理由」を1行だけ残す。

検証は別のエージェントにやらせる

1か月ぶんの翻訳は数十本になる(多い月で40本超)。そこで、翻訳した本人ではなく別のエージェントに検証させる。自己採点が甘くなるからだ。

検証側が見るのは、段落やコード例の欠落、クラス名やバージョンの保全、日本語の自然さだ。ただし「原文に根拠がある箇所だけ直す」という縛りを検証プロンプトに入れてある。正しい訳を別エージェントが良かれと思って改悪するのを防ぐためだ。

たとえばあるパッケージ紹介では、見出しが Installation Usage のまま英語で残っていた。検証エージェントが、同じ月の他の訳に合わせて「インストール」「使い方」へ直した。翻訳した本人はできたつもりでいた箇所だ。別の記事では、本文の手順説明が訳の途中で数行に要約されて中身が抜けていた。これも検証側が原文と突き合わせ、省かれた部分を訳し直した。見た目には完成して見えるぶん、原文と照らさないと気づけない欠落だ。

最後の機械チェック

翻訳の検証(前節)とは別に、出来上がった月次まとめ記事のレビューもAIにやらせる(技術精度、日本語、体裁を別々のエージェントで)。ただし最後の確認だけはAIに任せない。まとめ記事を、数十行のPythonで機械的に検査するだけだ。見るのはこの3つ。

  • 収録した記事を全部1回はリンクしているか(載せ忘れ)
  • 除外した記事を載せていないか(出どころ不明のリンク)
  • URLに計測パラメータ(UTM)が混ざっていないか

AIの判断がブレても、ここで弾ける。

ただし、この機械チェックが見るのは構造だけ。訳の正しさ自体は別エージェントの検証と、まとめを書くとき自分が通す目に委ねている。翻訳AIと検証AIが同系統である以上、同じ誤読を双方が見逃す余地は残る。そこは正直、完全には潰せていない。

ハマりどころ

実際に半年ぶんを流すと、きれいには終わらなかった。

  • 数か月ぶんは1セッションで終わらない。途中で止まらないよう、Claude Code の /goal に「1月分まで終わるまで」のような完了条件を置いた。条件を満たすまで止まれないので、放っておいても最後まで回り続ける。失敗の再実行(次項)と組み合わせると、寝ている間に進む。
  • 長時間実行でAPIの接続が切れる。数十記事を一度に回すと、途中で翻訳や検証のエージェントが落ちる。落ちたぶんだけを拾って再翻訳と再検証をする「埋め戻し」を別に用意した。最初から落ちる前提で、欠落検出と再実行をセットにしておくべきだった。
  • 日付の境界でブレる。米国東部の夜に公開された記事はJSTだと翌日にずれ、月末・月初がどちらの月か揺れる。さらに lastmod が今年でも前年公開の記事が紛れ込むことがある(実際、2025年の記事が1本混ざっていた)。公開日(JST)の「年月」で機械的に振り分け、際どい数本だけ手で寄せた。
  • sitemap が一時的に404。サイト側の都合で sitemap が引けない日があった。前日に取得済みのものへフォールバックして止めずに済ませた。

アーカイブと公開記事

2026年1〜6月で、月別アーカイブはこうなった。

収録記事
2026-01 45
2026-02 38
2026-03 35
2026-04 42
2026-05 36
2026-06 28
224

アーカイブは月ごとに、全文訳の個別記事(各 .md がフロントマター+3行まとめ+本文の全文訳)とカテゴリ別の README 索引で構成される。そこから書いた月次まとめ6本がこれだ。

Qiita のまとめは人に読んでもらう用だが、半年後に「5月は何があったか」を月1本で引ける索引になっているのが、書いた自分にいちばん効いている。

他のソースに流用するなら

Laravel News に限らず、英語の技術ソースを追う場面に同じ骨格が使える。

  • 日付は lastmod(更新日)でなく本文の公開日で月を確定する。タイムゾーンは1つに統一する(自分は JST)。ただし公開日メタ(OGP/schema.org 等)はソース次第で無いこともあるので、無ければ本文中の日付や手動で補う。
  • 本文抽出は専用ツール(Defuddle など)に任せる。外部URLを叩くなら SSRF 対策を入れる。
  • 翻訳と検証は別のエージェントに分ける。自己採点はしない。
  • 何を収録し何を落とすかの基準を、コードでなく文章(スキル)で明文化する。落とした分も理由を1行残す。
  • 最後の確認は決まったスクリプトで機械的にやる(網羅と除外、リンクのチェック)。
  • 配布の線引きを最初に決める。全文訳は私的利用にとどめ、公開は出典リンク付きの要約だけにする(原文の全文転載はしない)。
  1. 前述の Claude Code Starter Kit(Cloud Native Inc./MIT)のスキル。Defuddle でHTMLのノイズ(ナビ・フッタ等)を除いて本文を Markdown 化し、外部URL用の SSRF 対策(プライベートIP・DNS リバインディングの遮断)や Defuddle の upstream 追従まで最初から内蔵している。

  2. SSRF(Server-Side Request Forgery)=外部から渡したURLを使って、サーバーに社内ネットワークやクラウドのメタデータ等へアクセスさせる攻撃。対策では併せて DNS リバインディング(名前解決時と接続時でIPをすり替える手口)も塞ぐ。

  3. OGP・schema.org=ページに埋め込む構造化メタデータの規格。SNS共有や検索エンジン向けに、公開日・著者・タイトルなどを機械可読な形で宣言する。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?