プログラマー向けモードで表示中ビジネスユーザー向けへ
Bright Data 学習ポータル

Step 4Lv3 ・ 目安 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 ScraperYouTube 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");

検証

  1. Amazon
    • df_amazonpricereview_count カラムが存在し、df_amazon.shape[0] == 100 であることを確認
    • 可視化グラフが表示され、価格帯とレビュー数の分布が把握できること
  2. YouTube
    • df_channelsubscriber_count が取得できていること
    • DuckDB の集計結果に「1 日あたりの投稿件数」や「再生数上位 5 本」が正しく表示されること

実務ポイント

項目説明
snapshot_id の扱いジョブ作成直後に取得した snapshot_id を永続化(例: DB やファ)し、再実行時に同じ ID を再利用しないようにする
冪等性同一キーワード・ASIN で再取得すると重複データが生成される可能性があるため、取得後に asin でユニーク化する
更新頻度商品価格は数時間ごとに変動することが多い。定期的にジョブを再実行し、snapshot_id を新規取得するバッチを構築
レートリミットBright Data のプランに応じて API 呼び出し上限がある。大量取得はジョブキューを活用し、max_results を適切に設定
エラーハンドリングstatusfailed の場合は error_message をログに残し、リトライロジックを実装することが推奨される

次に読む

  • /usecases/UC-FEED-003 – 商品トレンド分析の実践例
  • /usecases/UC-FEED-004 – YouTube エンゲージメント指標ダッシュボード
  • /hands-on/step-3-crawl-rag – RAG(Retrieval‑Augmented Generation)向けデータ収集手順