毎日のニュース記事をクロールしてブログ記事を自動生成したい…そんな悩みはありませんか?本記事では、n8nとApifyを組み合わせて、1日1回の定期実行でニュースサイトから自動的にコンテンツを収集し、重複なくAIでブログ記事に変換する完全自動化ワークフローを段階的に解説します。コード知識がない初心者でも、ノーコード環境で実装できる実践的な手法です。
目次
- なぜn8n×Apifyの組み合わせが必要か
- Website Content Crawlerの基本概要
- 第1段階:ワークフロー全体の設計
- 第2段階:Website Content Crawlerの最適設定
- 第3段階:n8n内でのクローリング実装
- 第4段階:重複排除の仕組み
- 第5段階:AIによる記事生成
- 実装上の注意点とトラブルシューティング
- まとめ
なぜn8n×Apifyの組み合わせが必要か
ニュースサイトやブログから定期的にコンテンツを自動収集する場合、単純なWeb APIではできない課題が生じます。
n8nの役割:複数の外部サービスを連携させて、スケジュール実行と条件分岐を実現するワークフロー基盤
Apifyの役割:JavaScriptが実行される動的ページから正確にテキストコンテンツを抽出し、LLM(ChatGPT等)の入力に適したフォーマット(Markdown)で返す
この2つを組み合わせることで、完全な自動化が実現します。
Website Content Crawlerの基本概要
Website Content Crawlerとは、Apifyが提供する「Webサイト全体を自動で巡回してテキストコンテンツを抽出するツール」です。LLM(ChatGPT、Claude等の大規模言語モデル)向けに特別に設計されており、広告やナビゲーションなどのノイズを自動削除し、重要なコンテンツのみを抽出します。
主な特徴:
- 複数のクローラータイプから選択可能(自動最適化、ブラウザレンダリング、HTTP直接アクセス)
- 出力形式をプレーンテキスト、Markdown、HTMLから選択可能
- ページメタデータ(タイトル、著者、公開日)も自動抽出
- 日本語サイトの対応も良好
第1段階:ワークフロー全体の設計
n8nで実装するワークフローは以下の10段階から構成されます。
必要なコンポーネント一覧
| コンポーネント | 役割 |
|---|---|
| Schedule(Cron) | 毎日決まった時刻(例:午前9時)にワークフロー開始 |
| Apify ノード | Website Content Crawlerを実行してページをクロール |
| SQLite/PostgreSQL | 過去にクロール済みのURLを記録するデータベース |
| Crypto ノード | URLのMD5ハッシュ生成(重複判定用) |
| If ノード | 重複判定の条件分岐 |
| Loop Over Items | 複数のページを順番に処理 |
| Wait ノード | レート制限対策の待機 |
| OpenAI ノード | AIでブログ記事を自動生成 |
| HTTP Request | WordPress等に記事を自動公開 |
| Error Handler | エラー時の通知処理 |

事前準備:APIキーの取得
実装前に3つのAPIキーを用意します。
1. Apify API キー
Apifyのアカウント作成後、Settings → API & Integrations から取得
2. OpenAI API キー
OpenAI Platform(platform.openai.com)のAPI keysセクションから生成
3. WordPress REST API認証情報(オプション)
自社ブログに自動公開する場合のみ必要
これらをn8nのCredential Manager(画面左下の鍵マーク)で登録しておくと、ノード設定時に選択するだけで使用可能になります。
第2段階:Website Content Crawlerの最適設定
クローラータイプの選択ガイド
Website Content Crawlerは3種類のクローラーから選択できます。1日周期のニュース収集を想定した場合の選択基準は以下の通り。
| クローラータイプ | 速度 | コスト | 用途 | 推奨度 |
|---|---|---|---|---|
| Raw HTTP | 高速 | 最安(1000ページ/0.2ドル) | 静的サイト(テキスト記事中心) | ★★☆ |
| Adaptive | 中速 | 中程度(1000ページ/1-3ドル) | 混合型(推奨) | ★★★ |
| Headless Browser | 低速 | 最高(1000ページ/5-10ドル) | 動的ページ(JavaScript必須) | ★★☆ |
ニュース・ブログサイトの場合、Adaptiveが最適です。Adaptiveは静的ページではHTTPリクエストで高速処理し、JavaScriptが必要なページでは自動的にブラウザに切り替えるため、パフォーマンスとコストのバランスが最良です。
設定例:複数ニュースサイトのクロール
{
"startUrls": [
{"url": "https://techcrunch.com"},
{"url": "https://www.theverge.com"},
{"url": "https://news.ycombinator.com"}
],
"maxCrawlPages": 50,
"crawlerType": "adaptive",
"outputFormat": "markdown",
"removeHtmlElements": "nav, header, footer, .modal, .advertisement, script",
"removeCookieWarnings": true
}
各パラメータの説明:
startUrls:クロール開始URL(複数指定可能)maxCrawlPages:1回のクロールで取得する上限ページ数crawlerType:自動最適化を選択outputFormat:LLM入力用にMarkdownを指定removeHtmlElements:ナビゲーション、フッター、広告などを自動削除removeCookieWarnings:クッキー同意バナーを自動非表示
動的コンテンツ対応(無限スクロール対応)
ニュースサイトの中には無限スクロールで記事を読み込むサイトもあります。その場合は以下を追加:
{
"waitForDynamicContent": 5,
"maxScrollHeight": 3000,
"expandClickableElements": false
}
これにより、ページ読み込み後5秒待機し、その間にJavaScriptで動的に生成されたコンテンツも取得します。
第3段階:n8n内でのクローリング実装
ステップ1:Daily Cronトリガーの設定
n8n Canvasを開き、「Add Node」から「Schedule」を選択します。
設定項目:
- Trigger Interval:Daily
- Time:09:00(毎日午前9時)
Cron式では 0 9 * * * と指定することも可能です。
ステップ2:Apifyノードの追加
Schedule ノードの下にApifyノードを追加します。
操作選択:「Run an Actor synchronously and get dataset items」を選択
入力パラメータ設定:
| 項目 | 入力値 |
|---|---|
| Actor ID | apify/website-content-crawler |
| startUrls | [{"url": "https://example.com"}] |
| maxCrawlPages | 50 |
| crawlerType | adaptive |
| outputFormat | markdown |
ノード実行後、以下の形式でデータが返されます:
{
"url": "https://example.com/article-123",
"markdown": "# 記事タイトル\n\n本文内容...",
"text": "記事タイトル\n本文内容...",
"metadata": {
"title": "記事タイトル",
"author": "著者名",
"publishedDate": "2025-01-15"
}
}
ステップ3:SQLiteデータベースの初期設定
別途のSQLiteノードで、クローリング履歴テーブルを作成します。
SQL実行例:
CREATE TABLE IF NOT EXISTS crawled_urls (
id INTEGER PRIMARY KEY AUTOINCREMENT,
url TEXT UNIQUE NOT NULL,
url_hash TEXT NOT NULL,
title TEXT,
content_hash TEXT,
crawled_date DATETIME DEFAULT CURRENT_TIMESTAMP,
status TEXT DEFAULT 'new'
);
CREATE INDEX idx_url_hash ON crawled_urls(url_hash);
CREATE INDEX idx_content_hash ON crawled_urls(content_hash);
この実行は初回のみ。以降は重複判定に使用されます。
第4段階:重複排除の仕組み
MD5ハッシュ生成による重複判定
重複を排除するために、URL のMD5ハッシュ値を生成して比較します。
ステップ1:Cryptoノードでハッシュ生成
Apifyノード後にCryptoノードを追加:
設定:
- Type:MD5
- Value:
{{ $json.url }} - Property Name:
url_hash
出力例:
{
"url": "https://example.com/article-1",
"url_hash": "abc123def456ghi789..."
}
ステップ2:SQL クエリで重複判定
SQL ノードを追加して、既にクロール済みのURLかを判定:
SELECT COUNT(*) as duplicate_count
FROM crawled_urls
WHERE url_hash = '{{ $json.url_hash }}'
結果が0なら新規、1以上なら重複です。
ステップ3:If ノードで条件分岐
Ifノードを追加して、重複判定の結果に基づいて処理を分岐:
If duplicate_count > 0:
→ End workflow (スキップ)
Else:
→ Continue to next step (新規コンテンツとして処理)
コンテンツハッシュによる高度な重複排除
URLは異なっても、記事コンテンツが全く同じ(転載、配信記事等)場合も排除したい場合:
SELECT COUNT(*) as dup_content
FROM crawled_urls
WHERE content_hash = md5('{{ $json.markdown }}')
AND crawled_date > DATETIME('now', '-30 days')
このようにコンテンツ自体のハッシュ値を比較することで、異なるURL、同一内容の記事を排除できます。
第5段階:AIによる記事生成
OpenAIノードの設定
重複判定を通過した新規コンテンツを、OpenAI ノードでブログ記事に変換します。
Model:gpt-4 または gpt-4-turbo(品質重視の場合)
Temperature:0.7(創造性と一貫性のバランス)
Prompt(プロンプト):以下を参考にカスタマイズ
以下のニュース記事「{{ $json.metadata.title }}」を日本語でわかりやすいブログ記事に執筆してください。
元の記事:
{{ $json.markdown }}
要件:
- 1000~1500字程度
- 読みやすい日本語で、複雑な専門用語は説明を付ける
- H2見出しを2~3個含める
- 導入:なぜこのニュースが重要か
- 本論:詳細な解説
- 結論:読者への示唆・応用例
- 最後に「参考記事」セクションを追加(元のURL記載)
出力フォーマット:Markdown
重要:客観的かつ中立的なトーンを保ってください。
プロンプト最適化のコツ
プロンプトは実装後も継続的に改善するものです。以下を意識します:
1. ターゲット読者の明示
「初心者向けに」「技術者向けに」など、対象を明確にするとAIの出力がブレません。
2. 記事の長さを具体的に
「1000~1500字」と範囲指定することで、短すぎたり冗長になるのを防げます。
3. 禁止事項の明記
「推測や不確実な内容は避ける」など、品質管理を重視。
4. 出力フォーマットの指定
Markdown形式で返すよう指定すると、WordPress等に自動公開する際の処理が簡潔になります。
API コスト削減のテクニック
大規模クロール時のOpenAI API コスト削減:
方法1:ベクトルデータベース活用
初回クロール時のMarkdownをPinecone等のベクトルDBに格納し、LLMが必要な箇所のみ参照させることで、毎回のAPI呼び出しを削減。
方法2:バッチプロセッシング
複数記事をまとめて処理するPromptを作成し、1回のAPI呼び出しで複数記事を生成。
例:
以下の3つのニュース記事を日本語ブログ記事に変換。
各記事は「---」で区切られています。
各記事について同じ要件を適用してください。
記事1:
---
{{ $json[0].markdown }}
記事2:
---
{{ $json[1].markdown }}
実装上の注意点とトラブルシューティング
よくあるエラーと対応方法
| エラー | 原因 | 対応方法 |
|---|---|---|
| CAPTCHA検出 | アクセス頻度が高い | Headless Browser + プロキシ設定 |
| 404エラー | ページが削除された | excludeUrls設定で該当URLを除外 |
| JavaScriptが実行されない | Raw HTTPクローラー使用 | crawlerType: “adaptive”に変更 |
| タイムアウト | ページが重い | waitForDynamicContent を増加(秒数UP) |
レート制限への対策
外部サイト(OpenAI、Apify等)のレート制限を超えないため:
1. Waitノードの挿入
各バッチ処理間に90秒の待機を設定
After each batch: 90 seconds wait
2. バッチサイズの調整
Loop Over Items で「Batch Size: 5」に設定し、5ページずつ纏めて処理
3. 実行時間の分散
複数ワークフローを1日の異なる時間帯に実行
エラーハンドリングの実装
ワークフロー内の重要なステップ後にError nodeを設定:
失敗時の処理例:
- Slack/Discordに通知を送信
- ログをファイルに記録
- ワークフローを停止
まとめ
本記事では、n8nとApifyを使用して、ニュースサイトからの完全自動ブログ生成ワークフローを段階的に解説しました。
主な要点:
- n8n × Apifyの組み合わせにより、ノーコードでプロフェッショナルな自動化を実現
- Website Content Crawlerの設定では「Adaptive」クローラーが費用効率面で最適
- MD5ハッシュによる重複排除で、同じ記事の二重取得を防止
- SQLiteデータベースでクロール履歴を管理し、1日周期実行に対応
- OpenAI統合でAIが記事を自動生成。プロンプト工夫でコスト削減も可能
- エラーハンドリングを実装することで、長期的に安定稼働するワークフローに
次に試すべきこと
段階1:n8nに無料登録し、Apifyノードをインストール
段階2:1つのニュースサイトで試験クロール(maxCrawlPages: 5に設定して低コスト実装)
段階3:クロール結果をローカルで確認し、Markdownフォーマットが正しいか検証
段階4:SQLiteデータベースを構築し、重複排除ロジックをテスト
段階5:OpenAIノードを統合し、ブログ記事の自動生成をテスト
段階6:本格運用に向けて、スケジュール設定、エラー処理、モニタリング環境を整備