所要時間: 約40分 | 難易度: ★★☆☆☆

この記事で作るもの

  • 指定したRSSフィードやニュースサイトから情報を取得し、自分の関心事に沿ってフィルタリング・要約してDiscordやSlackに通知するPythonスクリプト。
  • 月額3,000円程度のAIニュースレターサービスや、情報収集効率化ツールの代わりを自前で構築します。
  • 前提知識:Pythonの基本的な文法(変数、関数、pipでのライブラリ導入)がわかること。
  • 必要なもの:Anthropic APIキー(Claude 3.5 Sonnet推奨)、Python 3.10以上の環境。

📦 この記事に関連する商品

Raspberry Pi 5

24時間稼働のニュース監視スクリプトを自宅で安価に運用するなら、ラズパイ5が最高のサーバーになります

Amazonで見る 楽天で見る

※アフィリエイトリンクを含みます

なぜこの方法を選ぶのか

世の中にはAIを活用したキュレーションサービスがあふれていますが、その多くが月額20ドル以上のサブスクリプションを要求します。 しかし、その実態は「RSSで記事を取得してLLMに投げているだけ」のものが少なくありません。 APIを直接叩けば、1回の実行コストは0.05ドル(約7円)以下に抑えられ、フィルタリングの精度も自分好みに100%カスタマイズできます。

Redditで話題になっていた「議論に明け暮れるエンジニアを横目に、サクッと自作アプリで3つのサブスクを解約した男」になるための、最も実用的な第一歩がこれです。 汎用的なツールは「万人向け」に作られていますが、自分の仕事に必要な情報だけを抜き出すには、自分でコードを書くのが結局一番速くて安上がりです。

Step 1: 環境を整える

まずは必要なライブラリをインストールします。記事のスクレイピングとRSSの解析、そしてClaude APIとの通信用です。

pip install anthropic feedparser beautifulsoup4 requests

feedparserはRSSフィードの解析に、beautifulsoup4は取得したHTMLから余計な広告やタグを除去して「本文だけ」を抽出するために使用します。 LLMに渡すトークン数を節約し、コストを抑えるために、この前処理が非常に重要です。

⚠️ 落とし穴: requestsでサイトを取得しようとすると、一部のサイト(Cloudflare導入済みサイトなど)から403エラーでブロックされることがあります。 その場合は、headersにブラウザを装飾したUser-Agentを設定する必要がありますが、まずは基本構成で進めます。

Step 2: 基本の設定

APIキーなどの機密情報は、コードに直書きせず環境変数から読み込むようにしましょう。 SIer時代、コードにキーを直書きしてコミットし、本番環境を危険に晒した新人を見てきましたが、プロなら徹底すべきポイントです。

import os
import feedparser
import requests
from bs4 import BeautifulSoup
from anthropic import Anthropic

# APIキーは環境変数から取得
# Windows: set ANTHROPIC_API_KEY=your_key
# Mac/Linux: export ANTHROPIC_API_KEY=your_key
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))

# あなたが追いたいニュースのRSS URL
RSS_URLS = [
    "https://feeds.feedburner.com/TheHackersNews",
    "https://techcrunch.com/feed/"
]

# 自分の「関心事」を定義
MY_INTERESTS = "LLM, ローカルLLM, GPU, NVIDIA, Python, 自動化"

MY_INTERESTSには、あなたが今仕事で必要としているキーワードを具体的に入れてください。 Claudeはこのキーワードを元に、大量のニュースの中から「読む価値があるもの」を選別します。

Step 3: 動かしてみる

まずは、RSSから記事のタイトルとURLを取得し、その中身を抽出する最小限のロジックを組みます。

def get_article_text(url):
    try:
        response = requests.get(url, timeout=10)
        soup = BeautifulSoup(response.text, 'html.parser')
        # 記事本文が含まれそうなタグを抽出(サイトに合わせて調整が必要)
        paragraphs = soup.find_all('p')
        return "\n".join([p.get_text() for p in paragraphs[:10]]) # 最初の10段落に限定して節約
    except Exception as e:
        return f"エラー: {e}"

# 1件だけテスト
feed = feedparser.parse(RSS_URLS[0])
first_entry = feed.entries[0]
content = get_article_text(first_entry.link)

print(f"Title: {first_entry.title}")
print(f"Content snippet: {content[:100]}...")

期待される出力

Title: New Linux Malware targeting Servers...
Content snippet: A new strain of malware has been discovered targeting Linux-based servers globally. The attackers...

ここで「本文が正しく取れているか」を確認してください。 もしHTMLタグが混ざりすぎている場合は、soup.get_text()の処理を見直す必要があります。

Step 4: 実用レベルにする

ここからが本番です。取得した本文をClaudeに渡し、「私の関心に合致するか」を判定させ、合致する場合のみ要約を作成させます。 これが有料サービスのコア機能を自作する部分です。

def analyze_article(title, content):
    prompt = f"""
    以下の記事は私の関心事({MY_INTERESTS})に関連していますか?
    関連がある場合のみ、以下の形式で出力してください。関連がない場合は「SKIP」とだけ出力してください。

    【判定】: 関連あり
    【重要度】: 1-10で評価
    【要約】: 3行で簡潔に説明
    【理由】: なぜ私の関心に関連すると判断したか

    記事タイトル: {title}
    記事本文: {content}
    """

    message = client.messages.create(
        model="claude-3-5-sonnet-20240620",
        max_tokens=500,
        temperature=0, # 分析精度を上げるためランダム性を排除
        messages=[{"role": "user", "content": prompt}]
    )
    return message.content[0].text

# 全RSSフィードをスキャン
for url in RSS_URLS:
    feed = feedparser.parse(url)
    for entry in feed.entries[:3]: # テスト用に各フィード3件まで
        full_text = get_article_text(entry.link)
        result = analyze_article(entry.title, full_text)

        if "SKIP" not in result:
            print(f"--- 注目記事 ---\n{result}\nURL: {entry.link}\n")

このコードのポイントは temperature=0 です。 クリエイティブな文章は不要で、論理的なフィルタリングが欲しいため、モデルの振れ幅を最小限に抑えています。 また、プロンプトで「SKIP」を定義することで、不要な情報の出力を防ぎ、APIコストと確認の手間を削減しています。

よくあるトラブルと解決法

エラー内容原因解決策
403 Forbiddenサイト側のスクレイピング対策requests.getの引数にheaders={'User-Agent': 'Mozilla/5.0'}を追加する
AuthenticationErrorAPIキーの読み込み失敗os.environではなく一時的に直書きして確認するか、シェルを再起動する
Context Window Exceeded記事が長すぎるparagraphs[:10]のように、渡すテキスト量を制限する。Claude 3.5 Sonnetなら200kトークンまで入るが、コスト節約のために絞るのが吉

次のステップ

この記事の内容をマスターしたら、次は「定期実行」と「通知」の自動化に挑戦してください。 私はこのスクリプトをGitHub Actionsで3時間おきに実行し、自分のDiscordサーバーの専用チャンネルにWebhookで投稿するようにしています。 これで、わざわざニュースサイトを巡回する時間はゼロになりました。

また、抽出したデータをSQLiteなどのデータベースに保存し、1週間分をまとめて「今週のトレンドレポート」としてClaudeに再構成させるのも面白いでしょう。 APIコストは月額に換算しても数百円程度です。 20ドルのサブスクを払う代わりに、その予算でRTX 4090の電気代を賄う方が、AIエンジニアとしては健全な投資だと私は思います。

よくある質問

Q1: Claude 3 OpusではなくSonnetを使う理由は?

実務上のコスパと速度です。要約やフィルタリングというタスクにおいて、Sonnet 3.5はOpusに匹敵する、あるいは上回る精度を見せつつ、料金は1/5程度で済みます。レスポンスも圧倒的に速いです。

Q2: 記事が数千件ある場合、API破産しませんか?

まずタイトルだけでフィルタリングし、関連度が高そうなものだけ本文を取得してLLMに投げる二段構えにしてください。これにより、APIに投げる件数を1/10以下に絞り込めます。

Q3: 日本語のサイトでも同じように動きますか?

全く問題ありません。Claudeは多言語に非常に強いため、プロンプトが日本語であれば、英語の記事を日本語で要約させることも、その逆もシームレスに行えます。これこそが自作の醍醐味です。


あわせて読みたい