Claude API + Cloudflare Workers で毎日の技術記事収集を自動化
背景
日々の技術情報のキャッチアップは欠かせません。Apple Developer News、Swift.org Blog、技術ブログなど、複数の情報源を毎日チェックします。
しかし、複数の情報源を毎日巡回し、記事を読んで要約を作成して共有する作業は、かなりの時間を取られていました。見逃しや確認漏れのリスクもあります。
そこで、Claude API と Cloudflare Workers を使って、情報収集から共有までを完全自動化することにしました。
なぜ Claude API + Cloudflare なのか
n8n や Zapier のようなワークフロー自動化ツールも選択肢でしたが、以下の理由で Claude API と Cloudflare Workers を選びました。
まず、Claude Sonnet 4.5 による要約の品質が非常に高いです。文脈を理解した上で、記事の要点を的確にまとめてくれます。
次に、TypeScript で自由に処理を拡張できる柔軟性があります。情報源の追加やフィルタリングロジックの変更が容易です。
そして、Cloudflare Workers の無料枠内で運用できるため、完全無料で使えます。Cloudflare Workflows によるステップごとのリトライ機構と、Dashboard での実行状況の可視化も便利です。
システム概要
情報源
毎日、以下の情報源から記事を収集しています。
RSS フィード(xml2js で解析)から取得するもの:
Web ページ(cheerio で解析)から取得するもの:
アーキテクチャ
毎日 10:00 JST (01:00 UTC) に Cloudflare Cron Trigger がワークフローを起動します。RSS/Web から記事を取得し、昨日以降の記事のみフィルタリング。Claude API で記事を一括要約し、Slack に投稿します。
Cron Trigger (毎日 01:00 UTC / 10:00 JST)
↓
Cloudflare Workflow
↓
├─ Step 1: fetch-articles (リトライ3回)
│ └─ 7つの情報源から記事取得
↓
├─ Step 2: summarize-articles (リトライ2回)
│ └─ Claude Sonnet 4.5 で一括要約
↓
└─ Step 3: post-to-slack (リトライ3回)
└─ Slack Webhook 投稿
Slack への投稿例

情報源ごとにグループ化され、各記事のタイトル、URL、要約が自動投稿されます。
セットアップ手順
1. プロジェクトの初期化
npm create cloudflare@latest kusumoto-daily-report
cd kusumoto-daily-report
npm install @anthropic-ai/sdk cheerio xml2js
npm install -D @types/xml2js
2. 実装
プロジェクト構成に従って実装を行います。
src/
├── index.ts # Cron エントリポイント
├── workflow.ts # Workflow 定義
├── types.ts # 型定義
├── steps/
│ ├── fetch-articles.ts
│ ├── summarize.ts
│ └── post-slack.ts
├── parsers/
│ ├── rss.ts
│ └── web.ts
├── clients/
│ ├── claude.ts
│ └── slack.ts
└── utils/
└── date.ts
wrangler.toml に Cron Trigger と Workflow の設定を追加します。
name = "kusumoto-daily-report"
main = "src/index.ts"
compatibility_date = "2025-10-01"
compatibility_flags = ["nodejs_compat"]
[triggers]
crons = ["0 1 * * *"]
[[workflows]]
binding = "DAILY_REPORT_WORKFLOW"
name = "daily-report-workflow"
class_name = "DailyReportWorkflow"
3. Cloudflare にログイン
npx wrangler login
4. Secret の設定
Slack Webhook URL と Anthropic API Key を設定します。
npx wrangler secret put SLACK_WEBHOOK_URL
# プロンプトが表示されたら Slack Webhook URL を入力
npx wrangler secret put ANTHROPIC_API_KEY
# プロンプトが表示されたら Anthropic API Key を入力
5. デプロイ
npm run deploy
6. 動作確認
Cloudflare Dashboard で手動実行と実行状況を確認します。
ワークフロー画面

Workflows タブでは、過去 7 日間の実行履歴、完了したインスタンス数、エラー数などを確認できます。右上の「トリガー」ボタンから手動実行が可能です。
手動実行手順
- https://dash.cloudflare.com/ にアクセス
- Workers & Pages → kusumoto-daily-report を選択
- Workflows タブを開く
- 右上の「トリガー」ボタンをクリック

- インスタンス ID(任意)とパラメータ(任意)を入力
- 「トリガー インスタンス」ボタンで実行
- インスタンス一覧から実行状況を確認
- 各ステップの成功/失敗
- リトライ回数
- 実行時間
- エラーログ
技術詳細
プロジェクト構成
KusumotoDailyReport/
├── src/
│ ├── index.ts # Cron エントリポイント
│ ├── workflow.ts # Workflow 定義
│ ├── types.ts # 型定義
│ ├── steps/
│ │ ├── fetch-articles.ts
│ │ ├── summarize.ts
│ │ └── post-slack.ts
│ ├── parsers/
│ │ ├── rss.ts # RSS パーサー
│ │ └── web.ts # Web スクレイパー
│ ├── clients/
│ │ ├── claude.ts # Claude API クライアント
│ │ └── slack.ts # Slack Webhook クライアント
│ └── utils/
│ └── date.ts # 日付ユーティリティ
├── wrangler.toml # Cloudflare 設定
├── tsconfig.json
└── package.json
記事取得の仕組み
情報源ごとに専用パーサーを実装しました。RSS は xml2js、Web ページは cheerio で解析します。
各情報源は独立して処理され、失敗時は最大 3 回試行します(初回 + リトライ 2 回、指数バックオフで 2 秒 → 4 秒)。リトライ後も失敗した情報源は、Slack に通知されます。
// 情報源ごとのリトライ処理
async function fetchFromSource(
source: Source,
targetDate: string,
retries = 3
): Promise<Article[]> {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
let articles: Article[] = [];
if (source.type === 'rss') {
articles = await parseRSS(source.url, source.name, targetDate);
} else {
// Web スクレイピング
if (source.url.includes('ios-osushi')) {
articles = await parseIOSOsushi(targetDate);
} else if (source.url.includes('xcode-cloud')) {
articles = await parseXcodeCloud(targetDate);
} else if (source.url.includes('swift.org')) {
articles = await parseSwiftBlog(targetDate);
}
}
console.log(`✓ ${source.name}: ${articles.length}件 (試行 ${attempt}/${retries})`);
return articles;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`✗ ${source.name}: ${errorMessage} (試行 ${attempt}/${retries})`);
if (attempt === retries) {
throw error;
}
// 指数バックオフでリトライ: 2s → 4s → 8s
const delay = Math.pow(2, attempt) * 1000;
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
return [];
}
// 全情報源から並列取得
export async function fetchArticles(sinceDate?: string): Promise<FetchSummary> {
const targetDate = sinceDate || getYesterday();
const allArticles: Article[] = [];
const failedSources: Array<{ name: string; error: string }> = [];
// 並列処理で全情報源から記事を取得
const results = await Promise.allSettled(
SOURCES.map((source) => fetchFromSource(source, targetDate, 3))
);
// 結果を集約
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
allArticles.push(...result.value);
} else {
const errorMessage =
result.reason instanceof Error ? result.reason.message : String(result.reason);
failedSources.push({
name: SOURCES[index].name,
error: errorMessage,
});
}
});
return {
articles: allArticles,
failedSources,
};
}
失敗した情報源は、以下のように Slack に通知されます。
⚠️ *取得に失敗した情報源*
• *Yahoo! ニュース*
エラー: Network timeout after 3 retries
• *Swift.org Blog*
エラー: Failed to parse HTML structure
要約生成の仕組み(Claude API)
Claude API(Sonnet 4.5 モデル)を使って、全記事を一括で要約生成します。
export class ClaudeClient {
private client: Anthropic;
constructor(apiKey: string) {
this.client = new Anthropic({ apiKey });
}
async summarizeArticles(articles: Article[]): Promise<ArticleWithSummary[]> {
const prompt = this.buildPrompt(articles);
const message = await this.client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 4000,
messages: [{ role: 'user', content: prompt }],
});
const responseText = message.content[0].type === 'text'
? message.content[0].text
: '';
const summaries = this.parseResponse(responseText);
// 記事と要約をマージ
return articles.map((article) => {
const summary = summaries.find((s) => s.url === article.url);
return {
...article,
summary: summary?.summary || '要約を生成できませんでした',
};
});
}
private buildPrompt(articles: Article[]): string {
const articlesJson = JSON.stringify(
articles.map((a) => ({
title: a.title,
url: a.url,
source: a.source,
})),
null,
2
);
return `以下の記事リストを要約してください。各記事を200文字以内の日本語で要約し、JSON配列で出力してください。
英語の記事も含め、すべて日本語で要約してください。
要約のみを出力し、「要約:」などの前置きは不要です。
記事リスト:
${articlesJson}
出力形式:
[
{"url": "記事のURL", "summary": "要約文"},
...
]`;
}
}
Claude Sonnet 4.5 を使うことで、文脈を理解した高品質な要約が生成されます。全記事を 1 回の API 呼び出しでバッチ処理するため、コストも抑えられます。英語記事も含めすべて日本語で要約されるため、統一感のある出力が得られます。
Workflow の実装
Cloudflare Workflows でステップごとにリトライを制御しています。各情報源は独立して最大 3 回試行され、Step 1 全体の失敗時にも追加で最大 3 回試行します。
export class DailyReportWorkflow extends WorkflowEntrypoint<Env> {
async run(event: unknown, step: WorkflowStep) {
// Step 1: 記事取得
// - 各情報源で最大3回試行(初回 + リトライ2回、指数バックオフ: 2s → 4s)
// - Step 全体でも最大3回試行(初回 + リトライ2回、5秒間隔、指数バックオフ)
const fetchResult: FetchSummary = await step.do(
'fetch-articles',
{
retries: {
limit: 3,
delay: 5000,
backoff: 'exponential',
},
},
async () => {
return await fetchArticles();
}
);
const { articles, failedSources } = fetchResult;
// 記事がある場合のみ要約を生成
let summaries: ArticleWithSummary[] = [];
if (articles.length > 0) {
// Step 2: 要約生成(リトライ2回、10秒間隔)
summaries = await step.do(
'summarize-articles',
{
retries: {
limit: 2,
delay: 10000,
},
},
async () => {
return await summarizeArticles(articles, this.env.ANTHROPIC_API_KEY);
}
);
}
// Step 3: Slack 投稿(リトライ3回、5秒間隔)
// 失敗した情報源も含めて通知
await step.do(
'post-to-slack',
{
retries: {
limit: 3,
delay: 5000,
},
},
async () => {
return await postToSlack(summaries, this.env.SLACK_WEBHOOK_URL, failedSources);
}
);
}
}
GitHub との連携による自動デプロイ
Cloudflare Workers と GitHub を連携することで、コードの変更が自動的にデプロイされます。
PR でのデプロイ確認

PR 内で Cloudflare によるデプロイ状況を確認できます。
運用とモニタリング
Cloudflare Dashboard での監視
Workflows タブで以下を確認できます。
- 各ステップの実行状況(成功/失敗)
- リトライ回数
- 実行時間
- エラーログ
ログ確認
ローカルでリアルタイムログを確認できます。
npx wrangler tail
コスト
完全無料で運用可能です。
- Cloudflare Workers の無料枠(1 日 100,000 リクエスト)
- Cloudflare Workflows の無料枠(Beta 期間中)
- Cron Triggers の無料提供
合計で月額 $0 です。
まとめ
TypeScript、Claude API、Cloudflare Workers を組み合わせることで、技術記事の収集・要約・共有を完全自動化できました。
人手を介さず毎朝定時に情報収集が完了し、Cloudflare Dashboard で実行状況を可視化できます。設定さえ済ませてしまえば、あとは毎朝 Slack に要約が届くのを待つだけです。
以前は毎朝 30 分ほどかけて複数の情報源を巡回していましたが、今では自動化により、その時間を本来の業務に充てられるようになりました。Claude API の要約品質も高く、記事の要点を的確に把握できます。
同じような情報収集の課題を抱えている方は、ぜひ試してみてください。