GAS: YouTube再生リストの全動画の再生数を取得

最初に断っておくけど,素晴らしいコードではきっとないと思う.参考程度にどうぞ.

作例をグラフにしてみた

メイン

// 動画データ = id, date, view のリストを作る
function getVideoData(){
  
  // APIリクエストごとに変わらない値を入れておく
  var params = {
    maxResults : 50,
    playlistId : "YOUR-PLAYLIST-ID-HERE",
    key        : "YOUR-API-KEY-HERE"
  }
  
  // 動画の総数を取得
  var videoCount = getVideoCount(params);
  
  // 動画のIDと公開日のデータを取得
  var id_date = getId_date(params, videoCount);
  
  // 取得した再生回数と id_date を結合して出力用の変数に入れる
  var videoData = getViewCount(params, id_date);
  
  return videoData;
}

このスクリプトでは合計3種類のYouTube APIにアクセスする.2と3の処理を一緒にできないか調べてみたんだけど,できなさそうだった.面倒くさいなあ…

  1. 再生リスト内の動画の総数を数えるAPI
  2. 再生リスト内の動画のIDと公開日を取得するAPI
  3. 動画IDから再生回数を取得するAPI

ちなみに maxResults=50 は,3でアクセスする video リソースのリクエスト時にかかってくる制約.このリクエストでは最大50個までしか1回のAPIリクエストでデータを取得できないので,それ以下の値を指定します.

1: 動画総数を取得

// プレイリスト内の動画の数を取得
// https://developers.google.com/youtube/v3/docs/playlists
function getVideoCount(params){

  var url = "https://www.googleapis.com/youtube/v3/playlists";
  
  url += "?part=" + "contentDetails";
  url += "&id="   + params.playlistId;
  url += "&key="  + params.key;
  
  var res = JSON.parse(UrlFetchApp.fetch(url));
  
  return res.items[0].contentDetails.itemCount;
}

見て分かる通り,playlist リソースにアクセスして動画の総数を取得する.APIの詳細はドキュメントを見てね.

2: 動画のIDと公開日を取得

// プレイリストから動画のIDと公開日を取得
// https://developers.google.com/youtube/v3/docs/playlistItems/list
function getId_date(params, videoCount){
  
  var url = "https://www.googleapis.com/youtube/v3/playlistItems";
  
  url += "?part="       + "contentDetails";
  url += "&playlistId=" + params.playlistId;
  url += "&maxResults=" + params.maxResults;
  url += "&key="        + params.key;
  
  // APIレスポンスを入れる変数
  var data = [];
  
  // 2回目以降のAPIリクエスト時に,次のページを要求するためのトークン
  var pageToken = "";
  
  // 動画の数だけデータをAPIリクエストを出す
  do{
    // ページトークンの有無によってURLをちょっと変える
    var req = url;
    if(pageToken != "") req += "&pageToken=" + pageToken;
    
    // APIリクエストを変数に入れる
    var res = JSON.parse(UrlFetchApp.fetch(req));
    
    // リクエストデータから,IDと公開日を取り出す
    for (var i in res.items){
      data.push(res.items[i].contentDetails);
    }
    
    // 次のページのトークンがあれば更新
    if(res.nextPageToken != "") pageToken = res.nextPageToken;
    
  } while (data.length < videoCount);
  
  return data;
}

実は1つ目のAPIリクエストを実行しなくても,この playlistItem リソースにアクセスすれば再生リスト内の動画の総数は分かるんだよね.でもこの関数の内容が妙に複雑になる (19行目から始まるループの初回だけ再生数を取得する処理を入れなきゃいけない) のが嫌だったので,こういう構成にしてみました.

3: 動画IDから再生数を取得

// 取得した再生回数と id_date を結合して出力用の変数に入れる
function getViewCount(params, id_date){
  
  // id のカンマ区切りリストを作る
  var idList = makeIdList(params, id_date);
  
  // 出力用の変数
  var videoData = [];
  
  // maxResults 個ずつAPIリクエストでデータを取得
  for (var i in idList){
    
    // APIのエンドポイントとパラメータ
    var url = "https://www.googleapis.com/youtube/v3/videos";
  
    url += "?part="   + "statistics";
    url += "&amp;id="     + idList[i];
    url += "&amp;fields=" + "items%2Fstatistics";
    url += "&amp;key="    + params.key;
  
    // idList に ID が含まれる動画のデータを取得
    var res = JSON.parse(UrlFetchApp.fetch(url));
    
    // 取得した再生回数と id_date を結合して出力用の変数に入れる
    for (var j in res.items) {
      
      var stats = {
        id   : id_date[Number(i)*params.maxResults + Number(j)].videoId, 
        date : id_date[Number(i)*params.maxResults + Number(j)].videoPublishedAt.slice(0, 10),
        view : Number(res.items[j].statistics.viewCount)
      }
    
      videoData.push(stats);
    }
  }
  
  return videoData;
}

これがやたらと複雑.ここの処理をどう書いたらいいのか分からず,結構な時間悩んだ.video リソースpart=statistics から動画の再生数を取得できるんだけど,動画IDを1回のAPIリクエストで最大で50個までしか送ることができない.

再生リスト内に51個以上の動画がある場合は,2で取得したIDの50個ずつに分けて連結して,それをGETパラメータに載せる必要がある.まずはその処理をやってますね.

ちなみに,29行目では取得した公開日情報のテキストを .slice(0, 10) で切り取ってる.もともと例えば YYYY-MM-DDThh:mm:ss.sZ みたいな形式 (ISO 8601 形式と言うらしい) の string が入ってるんだけど,僕の場合は時刻は要らないので (というか時刻情報載ってない?) ,それを切り取って YYYY-MM-DD だけ取り出してます.

3′: IDを maxResults 個ずつに分けて結合

// 動画のIDを maxResults 個ずつに分割して,それぞれをコンマ連結のテキストにする
function makeIdList(params, id_date){
    
  var length = id_date.length;              // 動画の数
  var loops = Math.ceil(length/params.maxResults); // 外側ループの回数.動画が130個なら3回ループが要る
  var idList = [];                          // 出力用の変数
  
  // 外側ループ
  for (var i=0; i < loops; i++){
    
    // IDのコンマ連結を入れる変数
    var idText = "";
    
    // maxResults 個ずつに分けて動画IDのコンマ連結を作る
    for (var count=0; count < params.maxResults; count++){
      
      // コンマ連結を作る
      try { idText += id_date[params.maxResults*i + count].videoId + ","; }
      
      // 最後のループ (i = loops-1) では maxResults 回も繰り返す必要がないので,その場合はループを抜ける
      // 例えば maxResults=50 なら,
      // 0<id<49 (i=0), 50<id<99 (i=1), 100<id<149 (i=2), ... という感じ
      catch(e) { break; }
    }
    
    // 末尾に不要なコンマを付けているので,削除してリストに追加
    idList.push(idText.slice(0, -1));
  }
  
  return idList;
}

for が2重になるといきなり読むのが難しくなるけど,なんとか見てみてくださいな.

使ってみると

試しにこの再生リストのデータを取ってみますか.

バイオハザード7 ゲーム実況
注) スクリプトではタイトルは未取得

簡単!便利 (?) !楽しい!

コメントを残す

Powered by WordPress.com. テーマ: Baskerville 2 by Anders Noren

ページ先頭へ ↑

%d人のブロガーが「いいね」をつけました。