ClaudeCodeでニュースサイトをスクレイピングする方法【合法・倫理的に】
毎朝、業界ニュースをチェックするのに30分以上かかっていませんか。複数のメディアを巡回し、関係する記事だけ抜き出して、要点をまとめる。この作業は地味に時間を奪います。ClaudeCodeを使えば、こうしたニュース収集と要約を自動化できます。ただし、スクレイピングには法的・倫理的な注意点が多くあり、何でも自由にやって良いわけではありません。本記事では、初心者でも安全に始められる「合法かつ倫理的なニュース収集の自動化」を、実プロンプト例とPythonコード付きで丁寧に解説します。RSSの活用や要約のコツも含め、明日から実践できる手順をまとめました。
結論:まずRSS、次に許可されたAPIやスクレイピング、最後にClaudeで要約
最初に結論をお伝えします。ニュース収集を自動化するなら、原則として次の順序で検討してください。第一にRSSフィードを使う。第二に公式のAPIや提携プログラムを使う。第三にスクレイピングを検討する。スクレイピングは「最後の手段」と捉えるのが安全です。なぜなら、サイトの利用規約違反や著作権法・不正アクセス禁止法に抵触するリスクがあるためです。
ClaudeCodeはこのフローの中で、(1)RSSやスクレイピングのコードを生成し、(2)取得した記事を要約し、(3)CSVやNotion・Slackに整形して送る、という3つの役割を担います。つまりClaudeCodeは「人の判断の代わり」ではなく「人の判断を補助する道具」です。本記事ではこの考え方に従い、合法的な手段から順に紹介し、技術的にどう実装するかを具体的に示します。途中で必ず守るべき法的・倫理的ルール、そして実務でつまずきやすい落とし穴も合わせて解説します。
1. スクレイピングを始める前に知っておくべき法的・倫理的注意
ニュースサイトのスクレイピングは「グレーゾーン」と呼ばれることが多い領域です。ですが実際には、いくつかの明確なルールを守ればリスクは大きく減らせます。
最初に押さえるべきは著作権法です。日本の著作権法第30条の4では、情報解析目的のための複製は一定の条件下で許されています。ただし「必要と認められる限度」「著作権者の利益を不当に害しない」など条件があります。記事を全文そのままブログに転載する、有料記事を無断公開する、といった行為は明確にアウトです。
次に重要なのが利用規約とrobots.txtです。多くのニュースサイトは利用規約で自動取得を禁止しています。これに違反すると、契約違反として民事責任を問われる可能性があります。robots.txtはサイト運営者が「ここはクローラーで取らないでね」と意思表示している場所です。法的拘束力はありませんが、倫理的には必ず尊重すべきです。
不正アクセス禁止法にも注意してください。ログインが必要な領域、有料会員エリア、APIキーが必要な領域に対して、認証回避でアクセスすれば違法行為になります。会員ページのIDとパスワードをコードに埋め込んでスクレイピングする、といった発想は最初から捨ててください。
サーバへの負荷も倫理上の問題です。1秒間に何度もリクエストを送ると、相手のサーバを意図せず攻撃することになります。最低でも1リクエストにつき2〜3秒の間隔を空けるのが目安です。本記事のサンプルコードもすべて待ち時間を入れた実装にしています。
最後に「公開・再配布の有無」を意識してください。自分が個人的に読むためにローカルに保存するのと、収集した記事をSNSやブログに転載するのとでは、リスクが全く違います。本記事は前者、つまり「個人または社内利用の自動化」を前提に解説します。社外公開する場合は必ず弁護士か著作権の専門家に相談してください。
2. RSSフィードを最優先で使う理由
法的・倫理的に最も安全な方法はRSSフィードです。RSSはサイト運営者が「自由に取得してください」と公開している配信形式で、新着記事のタイトル・概要・URLが構造化された形で手に入ります。スクレイピングと違ってHTML解析が不要なので、コードも短くなります。
多くのニュースサイトはRSSを今でも提供しています。例えば日経新聞の主要RSS、ITmedia、Yahoo!ニュースの主要トピック、技術系ならPublickeyやはてなブックマークの人気エントリーなどです。「サイト名 RSS」で検索すれば見つかることが多いです。
ClaudeCodeでRSSフィードを取得するプロンプトは次のように書きます。
複数のRSSフィードを巡回して新着記事のタイトル・URL・公開日・概要を
CSVに保存するPythonスクリプトを書いてください。
要件:
- feedparserライブラリを使用
- RSS URLは feeds.txt から1行1URLで読み込む
- 過去24時間以内に公開された記事のみ対象
- 取得結果は news_YYYYMMDD.csv に保存
- 各リクエスト間に2秒のスリープを入れる
- エラーが出てもスクリプト全体は止めず、ログに記録して次へ進む
- User-Agent は "MyNewsBot/1.0 (contact: me@example.com)" を指定
このプロンプトのポイントは、(1)使うライブラリを指定、(2)入出力ファイル名を明確に、(3)条件分岐(過去24時間)を明示、(4)サーバへの礼儀(スリープとUser-Agent)を含めている点です。曖昧な指示だとClaudeも曖昧なコードを返しますが、ここまで書けば実用レベルのコードが出てきます。
ClaudeCodeが生成する典型的なコードは次のようになります。
import feedparser
import csv
import time
from datetime import datetime, timedelta, timezone
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
USER_AGENT = "MyNewsBot/1.0 (contact: me@example.com)"
SLEEP_SEC = 2
WINDOW_HOURS = 24
def load_feeds(path="feeds.txt"):
with open(path, "r", encoding="utf-8") as f:
return [line.strip() for line in f if line.strip() and not line.startswith("#")]
def fetch_recent(feed_url, since):
feedparser.USER_AGENT = USER_AGENT
parsed = feedparser.parse(feed_url)
items = []
for entry in parsed.entries:
published = entry.get("published_parsed") or entry.get("updated_parsed")
if not published:
continue
dt = datetime(*published[:6], tzinfo=timezone.utc)
if dt < since:
continue
items.append({
"title": entry.get("title", ""),
"url": entry.get("link", ""),
"published": dt.isoformat(),
"summary": entry.get("summary", "")[:300]
})
return items
def main():
since = datetime.now(timezone.utc) - timedelta(hours=WINDOW_HOURS)
feeds = load_feeds()
all_items = []
for url in feeds:
try:
logging.info(f"fetching {url}")
items = fetch_recent(url, since)
all_items.extend(items)
except Exception as e:
logging.warning(f"failed {url}: {e}")
time.sleep(SLEEP_SEC)
out = f"news_{datetime.now().strftime('%Y%m%d')}.csv"
with open(out, "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["title", "url", "published", "summary"])
writer.writeheader()
writer.writerows(all_items)
logging.info(f"saved {len(all_items)} items to {out}")
if __name__ == "__main__":
main()
このコードを動かすには pip install feedparser が必要です。feeds.txtに以下のように1行1URLでフィードを並べておきます。
# feeds.txt
https://example.com/feed
https://news.example.jp/rss
これだけで、毎朝1回スクリプトを動かすだけで関係するニュースが自動収集されます。
3. robots.txtの確認と読み方
RSSがないサイトを対象にする場合、スクレイピングを検討します。その前に必ずrobots.txtを確認しましょう。robots.txtはサイトのルートURLに /robots.txt を付ければ閲覧できます(例: https://example.com/robots.txt)。
User-agent: *
Disallow: /private/
Disallow: /admin/
Crawl-delay: 5
User-agent: GPTBot
Disallow: /
この例は「すべてのクローラーは /private/ と /admin/ を取らないでね。リクエスト間隔は5秒空けてね。ただしGPTBotという名前のクローラーは全部禁止だよ」という意味です。自分のスクリプトのUser-Agentがどう扱われるかを必ず確認します。
ClaudeCodeにrobots.txtを読ませて判定するプロンプトも便利です。
次のURLのrobots.txtを取得して、これから取得したい以下のパスが
許可されているか判定してください。判定根拠も併記してください。
サイトURL: https://example.com
対象パス: /news/2026/
User-Agent名: MyNewsBot/1.0
ClaudeCodeはrobots.txtの内容を取得・解析し、許可/拒否と該当行を返してくれます。判断に迷う場合は「許可されていない可能性が高いので取得を控える」が安全側の選択です。
4. ニュース記事ページのスクレイピング実装
RSSが無く、robots.txtでも許可されている前提でスクレイピングをするケースを見ていきます。Pythonの requests と BeautifulSoup を使うのが定番です。ClaudeCodeへのプロンプトはこう書きます。
以下の条件でニュース記事の本文を取得するPython関数を書いてください。
- 入力: 記事URL
- 出力: dict(title, author, published, body)
- requests + BeautifulSoup を使用
- User-Agent は "MyNewsBot/1.0 (contact: me@example.com)"
- タイムアウト10秒、リトライ最大2回、リトライ間隔3秒
- 文字コードはレスポンスヘッダ優先、無ければchardetで判定
- HTMLからの抽出は <article> タグ優先、無ければ og:description
- 1リクエスト毎に3秒待機
- robots.txt が拒否しているドメインは事前にチェックして例外を投げる
生成されるコード例は次のようになります。
import requests
from bs4 import BeautifulSoup
from urllib.robotparser import RobotFileParser
from urllib.parse import urlparse
import time
HEADERS = {"User-Agent": "MyNewsBot/1.0 (contact: me@example.com)"}
def is_allowed(url):
parsed = urlparse(url)
rp = RobotFileParser()
rp.set_url(f"{parsed.scheme}://{parsed.netloc}/robots.txt")
try:
rp.read()
except Exception:
return True
return rp.can_fetch(HEADERS["User-Agent"], url)
def fetch_article(url, retries=2):
if not is_allowed(url):
raise PermissionError(f"robots.txt disallows: {url}")
for attempt in range(retries + 1):
try:
r = requests.get(url, headers=HEADERS, timeout=10)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
title = soup.title.get_text(strip=True) if soup.title else ""
article = soup.find("article")
body = article.get_text("\n", strip=True) if article else ""
if not body:
og = soup.find("meta", property="og:description")
body = og["content"] if og and og.get("content") else ""
author = ""
author_meta = soup.find("meta", attrs={"name": "author"})
if author_meta:
author = author_meta.get("content", "")
published = ""
time_tag = soup.find("time")
if time_tag:
published = time_tag.get("datetime", time_tag.get_text(strip=True))
time.sleep(3)
return {"title": title, "author": author, "published": published, "body": body, "url": url}
except Exception as e:
if attempt == retries:
raise
time.sleep(3)
重要なポイントは3つです。第一に is_allowed でrobots.txtを毎回チェックしていること。第二に必ず time.sleep(3) でサーバ負荷を抑えていること。第三にUser-Agentに連絡先を含めていることです。連絡先を入れておくと、もしサイト管理者から「やめてほしい」と連絡が来たら止められます。これが「礼儀正しいクローラー」の基本です。
5. Claudeで記事を要約・分類する
集めた記事をそのまま読んでいては時短になりません。ClaudeCodeに要約と分類を任せます。プロンプト例を3つ示します。
要約プロンプト:
次のニュース記事を日本語で要約してください。
要件:
- 3行要約 (各行40字以内)
- 末尾に「論点」を1行で追加 (例: 規制強化の是非、競合への影響、など)
- 中立的なトーン、推測を加えない
記事タイトル: {title}
記事本文: {body}
分類プロンプト:
次のニュース記事を以下のカテゴリのいずれかに分類してください。
カテゴリ: [AI/機械学習, クラウド, セキュリティ, スタートアップ, 規制/政策, その他]
出力形式: カテゴリ名のみ1単語
記事タイトル: {title}
記事本文の冒頭500字: {body_excerpt}
重要度判定プロンプト:
あなたは社内向けニュースキュレーターです。
次の記事について、SaaS事業を運営する中小企業の経営者にとっての
重要度を1〜5で評価してください。
評価軸:
1=社内共有不要
3=参考程度に共有
5=即座に対応検討が必要
出力形式: JSON {"score": int, "reason": str(60字以内)}
タイトル: {title}
要約: {summary}
これらをPythonから呼び出すには、ClaudeCodeをコマンド経由で使う方法と、APIを直接叩く方法があります。社内利用ならローカルでClaudeCodeを使う方が安全で、APIキーをコードに書く必要もありません。
import subprocess
import json
def claude_summarize(title, body):
prompt = f"次のニュース記事を3行で要約してください。\nタイトル: {title}\n本文: {body[:2000]}"
result = subprocess.run(
["claude", "-p", prompt],
capture_output=True, text=True, timeout=60
)
return result.stdout.strip()
claude -p "プロンプト" という形でコマンド実行できるので、シェルから呼び出して結果を受け取るだけです。これでスクレイピング→要約→保存のパイプラインが完成します。
6. 1日1回の定期実行とSlack通知
最後の仕上げは「自動で毎朝動かす」ことです。Macなら launchd、Linuxなら cron、社内サーバを持っていない場合はCloudflare Workersの定期実行(Cron Triggers)が選択肢になります。
cronで毎朝7時に動かす例:
0 7 * * * cd /home/user/news-bot && /usr/bin/python3 fetch_and_summarize.py >> log.txt 2>&1
Slack通知のプロンプト:
収集した記事リスト(CSV)を読み込み、重要度4以上の記事だけを抽出して、
Slackに送信するメッセージを以下のフォーマットで作成してください。
フォーマット:
:newspaper: 今日のニュースまとめ (YYYY-MM-DD)
1. [カテゴリ] タイトル (重要度: 5)
要約3行
URL: ...
Slack Webhookに送る部分は requests.post(webhook_url, json={"text": message}) の1行で済みます。Webhook URLは必ず環境変数に入れ、コードに書かないでください。
7. やってはいけない実装パターン
最後に、よくある「やってはいけない」パターンをまとめます。
第一に、有料記事や会員限定記事を取得する実装。たとえ技術的に可能でも、規約違反と著作権侵害のリスクがあります。第二に、JavaScriptで動的に保護されているサイトをヘッドレスブラウザで突破する実装。これも規約違反のリスクが高く、相手サーバへの負荷も大きいです。第三に、取得した本文をそのままブログやSNSに転載する行為。引用の範囲(主従関係・出所明示)を超えると著作権侵害です。第四に、スクレイピング先のサイトに「自分のサービスのリンク」や「自分のブランド」と紐づけて公開する行為。トラブルの元です。
迷ったら「自分が運営者だったらこれは嫌か?」と考えてみてください。それが倫理判定の最も信頼できる物差しです。
実践チュートリアル:朝のニュースまとめBotを30分で作る
ここまでのパーツを組み合わせて、実際に動くBotを作ってみます。所要時間は約30分です。
ステップ1: 作業フォルダを作る
mkdir news-bot && cd news-bot
python3 -m venv .venv && source .venv/bin/activate
pip install feedparser requests beautifulsoup4
ステップ2: feeds.txtを作る
https://b.hatena.ne.jp/hotentry/it.rss
https://publickey1.jp/atom.xml
ステップ3: ClaudeCodeに以下のプロンプトを投げる
news-bot ディレクトリに main.py を作成してください。
仕様:
- feeds.txt のRSSを巡回し、過去24時間の記事を取得
- 各記事について claude -p で3行要約を作成
- 結果を today.md に Markdown形式で保存
(見出しに日付、各記事はタイトル・URL・要約)
- 各リクエスト間に2秒スリープ
- エラー時はログに記録して継続
依存: feedparser, subprocess
ステップ4: 実行
python main.py
cat today.md
これで「今日のニュースまとめ」が手に入ります。あとはcronで毎朝7時に走らせれば完成です。
FAQ
Q1. スクレイピングは違法ですか? 一概には言えません。著作権法・不正アクセス禁止法・利用規約・サーバ負荷といった複数の観点で判断する必要があります。RSSや公式APIを使う、robots.txtを尊重する、個人利用に留める、適切な間隔を空ける、といった配慮があればリスクは大きく下がります。社外公開を伴う場合は必ず専門家に相談してください。
Q2. ClaudeCodeはスクレイピングコードを書いてくれますか? 書いてくれます。ただしClaudeはコードを書く道具であって、法的判断や倫理判断は人間の責任です。「robots.txtを無視して取得して」といった指示にはClaudeも警告を返すことが多いですが、最終判断はあなた自身がしてください。
Q3. 取得した記事を自社ブログに載せても良いですか? 原則NGです。著作権侵害になります。引用として使う場合も、引用部分と自分の文章の主従関係、出所明示、改変なし、といった要件を満たす必要があります。要約を独自に書き起こして紹介するのは引用ではなく「翻案」になりうるため、これも注意が必要です。
Q4. RSSが提供されていないサイトはどうすれば良いですか? まずサイト内に「ニュースレター」「メール配信」がないか確認します。あればそれを購読するのが最も安全です。次にX(旧Twitter)の公式アカウントをRSS化するサービスを使う方法もあります。最終手段としてスクレイピングを検討しますが、その場合も本記事の注意事項を必ず守ってください。
Q5. ヘッドレスブラウザ(Playwright等)を使うのはアリですか? 技術的には可能ですが、JavaScriptで動的にレンダリングされているサイトはたいてい利用規約で自動取得を禁じています。また、サーバ負荷も通常のHTTPリクエストより重くなります。基本的には避け、どうしても必要なときだけ、規約と相談しながら使ってください。
Q6. ClaudeCodeで要約するとき、記事本文の何文字まで渡せますか? ClaudeCodeのコンテキストは十分長いので、通常のニュース記事(数千字)は1リクエストで処理できます。ただし数十記事をまとめて渡すと処理時間とコストが増えます。記事ごとに1リクエスト、要約だけまとめて再度渡す、といった二段階要約が現実的です。
Q7. 個人情報を含む記事を扱うときの注意は? 事件・事故報道などで個人名が含まれる記事を扱う場合、要約や分析の出力を社外公開しないでください。ローカル保存・社内共有に留め、第三者に再配布しない運用にします。個人情報保護法の観点では、報道機関による報道はある程度除外規定がありますが、個人や企業が再加工する場合は別の規律が適用されます。
まとめ
ClaudeCodeを使えば、ニュース収集と要約の自動化は半日で構築できます。ただし、最も大事なのはコードを書くことではなく「合法・倫理的にやる」という姿勢です。RSSを最優先で使い、robots.txtを尊重し、サーバ負荷を抑え、取得したコンテンツを社外に再配布しない。この4点を守れば、ニュース収集Botはあなたの仕事を大きく加速させる味方になります。最初は1サイト・1要約から始めて、少しずつ対象を広げていきましょう。