Step 4 ・ Lv3 ・ 目安 90 分
Step 4 Amazon / YouTube 分析
Scraper API で EC/動画領域の構造化データを取得し、最小限の分析ノートブックを回す。
リード文
このハンズオンを終えると、Bright Data の Scraper API を使って Amazon 商品データと YouTube チャンネルメタデータを取得し、pandas と DuckDB で簡易分析できるようになります。Jupyter ノートブックの 5‑6 セルで実装例を示すので、すぐに手を動かして結果を確認できます。
ゴールと所要時間
- ゴール
- Amazon 商品(ASIN もしくはキーワード検索)を 100 件取得し、価格・レビュー数を可視化
- YouTube チャンネルのメタデータと動画一覧を取得し、DuckDB で投稿頻度・再生数を集計
- 所要時間:約 90 分
- 難易度:Lv3(中級)
前提
- Step 1(Bright Data アカウント作成・API キー取得)完了済み
- Amazon Scraper と YouTube Scraper のゾーンが有効化されている
- Python 3.9+(pandas、requests、matplotlib、duckdb)と Node.js 14+ がインストール済み
- 環境変数
BRIGHTDATA_API_KEYに API キーが設定されている
手順
手順 1 – Amazon 商品検索スクレイパーを curl で呼ぶ
# Cell 1: Amazon 商品検索(キーワード)ジョブ作成
curl -X POST "https://api.brightdata.com/v1/scrapers/amazon/search" \
-H "Authorization: Bearer $BRIGHTDATA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"keyword": "wireless headphones",
"max_results": 100,
"region": "us",
"output": "json"
}' \
-o amazon_job.json- レスポンス例(抜粋)
{ "snapshot_id": "snap_123abcde", "status": "queued" }
手順 2 – Python で商品 100 件取得 → pandas DataFrame
# Cell 2: Amazon ジョブ結果取得と DataFrame 化
import time, json, requests, pandas as pd
API_KEY = os.getenv("BRIGHTDATA_API_KEY")
snapshot_id = json.load(open("amazon_job.json"))["snapshot_id"]
url = f"https://api.brightdata.com/v1/snapshots/{snapshot_id}/results"
# ポーリング(最大 30 秒待機)
for _ in range(30):
r = requests.get(url, headers={"Authorization": f"Bearer {API_KEY}"})
if r.status_code == 200:
data = r.json()
if data.get("status") == "finished":
break
time.sleep(1)
else:
raise RuntimeError("Amazon ジョブがタイムアウトしました")
# データはリストの辞書形式と仮定
items = data["results"]
df_amazon = pd.DataFrame(items)
df_amazon.head()手順 3 – 価格分布・レビュー分布の可視化(matplotlib)
# Cell 3: 可視化
import matplotlib.pyplot as plt
plt.figure(figsize=(12,5))
# 価格分布
plt.subplot(1,2,1)
plt.hist(df_amazon["price"], bins=20, color="#4c72b0", edgecolor="white")
plt.title("Price Distribution")
plt.xlabel("Price (USD)")
plt.ylabel("Count")
# レビュー数分布
plt.subplot(1,2,2)
plt.hist(df_amazon["review_count"], bins=20, color="#55a868", edgecolor="white")
plt.title("Review Count Distribution")
plt.xlabel("Number of Reviews")
plt.ylabel("Count")
plt.tight_layout()
plt.show()手順 4 – YouTube チャンネルのメタデータ取得(channel_id 指定)
# Cell 4: YouTube チャンネルメタデータ取得
curl -X POST "https://api.brightdata.com/v1/scrapers/youtube/channel" \
-H "Authorization: Bearer $BRIGHTDATA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channel_id": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
"region": "us"
}' \
-o youtube_channel.json# Cell 5: YouTube チャンネルメタデータ取得と表示
import json, pandas as pd
channel_info = json.load(open("youtube_channel.json"))
df_channel = pd.DataFrame([channel_info])
df_channel[["channel_id","title","subscriber_count","video_count"]]手順 5 – 動画一覧を DuckDB に投入し、投稿頻度・再生数の SQL 集計
# Cell 6: YouTube 動画リスト取得(別ジョブ)と DuckDB 集計
import requests, time, duckdb, json, os
# 1️⃣ 動画一覧ジョブ作成
resp = requests.post(
"https://api.brightdata.com/v1/scrapers/youtube/channel/videos",
headers={"Authorization": f"Bearer {os.getenv('BRIGHTDATA_API_KEY')}"},
json={"channel_id": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "max_results": 200}
)
snapshot_id_vid = resp.json()["snapshot_id"]
# 2️⃣ ポーリング取得url_vid = f"https://api.brightdata.com/v1/snapshots/{snapshot_id_vid}/results"
for _ in range(30):
r = requests.get(url_vid, headers={"Authorization": f"Bearer {os.getenv('BRIGHTDATA_API_KEY')}"})
if r.status_code == 200 and r.json().get("status") == "finished":
videos = r.json()["results"]
break
time.sleep(1)
else:
raise RuntimeError("YouTube 動画ジョブがタイムアウトしました")
# 3️⃣ DuckDB にロード(pandas DataFrame 経由が最も簡単)
import pandas as pd
videos_df = pd.DataFrame(videos)
con = duckdb.connect()
con.register("videos_src", videos_df)
con.execute("CREATE TABLE videos AS SELECT * FROM videos_src")
# 4️⃣ SQL 集計例
print("=== 1 日あたりの投稿件数 ===")
print(con.execute("""
SELECT DATE(published_at) AS day, COUNT(*) AS cnt
FROM videos
GROUP BY day
ORDER BY day DESC
LIMIT 10
""").df())
print("\n=== 再生数上位 5 本 ===")
print(con.execute("""
SELECT title, view_count
FROM videos
ORDER BY view_count DESC
LIMIT 5
""").df())手順 6 – Node.js でデータフィード取得する版
// Cell 7: Node.js 版 Amazon データ取得(fetch)
import fetch from "node-fetch";
import fs from "fs";
const API_KEY = process.env.BRIGHTDATA_API_KEY;
const jobRes = await fetch(
"https://api.brightdata.com/v1/scrapers/amazon/search",
{
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
keyword: "wireless headphones",
max_results: 100,
region: "us",
output: "json"
})
}
);
const job = await jobRes.json();
const snapshotId = job.snapshot_id;
// ポーリング
let result;
for (let i = 0; i < 30; i++) {
const res = await fetch(
`https://api.brightdata.com/v1/snapshots/${snapshotId}/results`,
{ headers: { "Authorization": `Bearer ${API_KEY}` } }
);
const data = await res.json();
if (data.status === "finished") {
result = data.results;
break;
}
await new Promise(r => setTimeout(r, 1000));
}
if (!result) throw new Error("Amazon job timeout");
// 結果をローカルに保存
fs.writeFileSync("amazon_results.json", JSON.stringify(result, null, 2));
console.log("Amazon data saved to amazon_results.json");検証
- Amazon
df_amazonにpriceとreview_countカラムが存在し、df_amazon.shape[0] == 100であることを確認- 可視化グラフが表示され、価格帯とレビュー数の分布が把握できること
- YouTube
df_channelにsubscriber_countが取得できていること- DuckDB の集計結果に「1 日あたりの投稿件数」や「再生数上位 5 本」が正しく表示されること
実務ポイント
| 項目 | 説明 |
|---|---|
| snapshot_id の扱い | ジョブ作成直後に取得した snapshot_id を永続化(例: DB やファ)し、再実行時に同じ ID を再利用しないようにする |
| 冪等性 | 同一キーワード・ASIN で再取得すると重複データが生成される可能性があるため、取得後に asin でユニーク化する |
| 更新頻度 | 商品価格は数時間ごとに変動することが多い。定期的にジョブを再実行し、snapshot_id を新規取得するバッチを構築 |
| レートリミット | Bright Data のプランに応じて API 呼び出し上限がある。大量取得はジョブキューを活用し、max_results を適切に設定 |
| エラーハンドリング | status が failed の場合は error_message をログに残し、リトライロジックを実装することが推奨される |
次に読む
- /usecases/UC-FEED-003 – 商品トレンド分析の実践例
- /usecases/UC-FEED-004 – YouTube エンゲージメント指標ダッシュボード
- /hands-on/step-3-crawl-rag – RAG(Retrieval‑Augmented Generation)向けデータ収集手順