YouTube APIを使って自動で自分の動画の分析情報を収集する【GAS】

今回は、YouTube APIを用いて「自分のチャンネルで投稿しているすべての動画に対して、特定の月の分析情報を取得」というシナリオを実現する方法について解説しています。YouTube APIでは、癖が結構あるのでコピペして使えるように変更しています。ソースを読んでカスタマイズをしていただければなと思います。

ご挨拶

ども!こんにちは!ブログ投稿が好調で、ルンルンで執筆をしている龍ちゃんです。時間を見つけては、ちょこっと執筆してコーティングというサイクルで仕事をしています。

今回は、プロジェクト外の仕事で「YouTube API」を触っていたのでブログにまとめていきたいと思います。「YouTube API」については、前回のブログ(YouTube APIを使う前に読んでほしい:初心者向け)で軽くまとめていました。今回は、実際に使ってみて取得する部分を記述していきたいと思います。

今回扱うシナリオとしては、「月初めに、自分のチャンネルで投稿している動画に対して、先月分の分析情報を取得する」というものになります。

また、今回のブログでわかることとしては以下になります。

  • 自分のチャンネルの投稿している動画をYouTube Data APIを用いてすべて取得
  • 特定の期間の動画分析情報を取得する(YouTube Analytics API)
  • Google Apps Scriptを用いてGoogle Sheetに新規書き込み

それでは、本題に入っていきたいと思います。ソースコードのみが欲しい方は、こちらのGistにソースのみ置いてあります。

問題の切り分け

前回のブログ「YouTube APIを使う前に読んでほしい:初心者向け」で取り扱ったトピックですが、YouTube APIは機能によって使用するAPIが異なります。今回のシナリオでは、以下のような切り分けになります。

月初めに、自分のチャンネルで投稿している動画に対して、先月分の分析情報を取得

GASでトリガーを実行して定期実行を実現
自分のチャンネルで投稿している動画を取得はYouTube Data APIを使用
先月分の分析情報を取得では、YouTube Analytics APIを使用

月初めに定期実行するという部分に関しては、Google Apps Scriptのトリガー用いて実行します。こちらの方法に関しては、ブログでも書いていますのでそちらを参照してください。もう少しAPIの設計に寄せて分割すると、以下になります。

チャンネルが投稿している動画のプレイリストIDを取得
プレイリストIDからすべての動画情報を取得
動画IDから、先月の分析情報を取得

「自分のチャンネルで投稿している動画を取得する」だけでも、「YouTube Data API」で2つのAPIを組み合わせる必要があります。ファーストステップでは、チャンネルをキーとして、チャンネルが投稿している動画をまとめたプレイリストIDを取得します。次に、プレイリストIDをキーとして、プレイリスト内の動画(動画ID・タイトル・投稿日)をすべて取得します。最後に、動画IDを使用して先月の分析情報を取得します。

コーディング

先ほどの図では、3段階に分けていました。コードレベルでは、「チャンネルが投稿したすべての動画を取得」と「動画IDから先月の分析情報を取得」に分けて実装していきたいと思います。

コードの分割としてVideo ListとVideo Reportを作成します。

それぞれの関数の実行結果として、チャンネルが所持しているすべての動画の情報を書き出すシート「Video List」と動画と分析情報を書き出す「Video Report」というシートが作成されます。

以下は、簡易な注意点になります。

ソース中にcreateSheetという既存のシートがある場合は、上書きして新規作成するという関数が登場します。こちらは、「Google Apps Script(GAS)でスプレッドシートを新規シート作成」で解説しています。こちらのブログでは解説しませんので、ご注意ください。

シートを出力する場所として「Google Sheet(旧:スプレッドシート)」を利用します。シートIDが必要になります。もしわからない方がいましたら、こちらのブログを参照してください。

ソース中にYouTubeのチャンネルIDを使用する場所があります。そちらは公式のこちらのページに書いてありますのでメモをお願いします。

GASでYouTube Data APIとYouTube Analytics APIを使用する場合は、サービスで追加する必要があります。この状態になっていれば大丈夫です。

GASで外部のサービスを使うときに理想的な画面

チャンネルが投稿したすべての動画を取得

ここでは、「チャンネルが投稿したすべての動画を取得」という部分のコーディングになります。

const createReportPlaylistInfo = () => {

	// チャンネルが投稿した動画のプレイリストIDを取得
  // <https://developers.google.com/youtube/v3/docs/channels?hl=ja#contentDetails.relatedPlaylists.uploads>
  const result = YouTube.Channels.list("contentDetails,statistics", {
    mine: true,
  })
  const channelInfo = result.items[0]
	
	// 登録者数
  const subscriberCount = channelInfo.statistics.subscriberCount
  // 投稿数
	const videoCount = channelInfo.statistics.videoCount
	// プレイリストID
  const playListId = channelInfo.contentDetails.relatedPlaylists.uploads

  // プレイリストID内の動画をすべて取得
	// <https://developers.google.com/youtube/v3/docs/playlistItems/list?hl=ja>
  const pageList = []
  let nextPageToken = null
	
	// 50件の情報を取得:50件以上ある場合は再帰的に取得
  do {
    const pageContent = YouTube.PlaylistItems.list("contentDetails,snippet", {
      playlistId: playListId,
      maxResults: 50,
      pageToken: nextPageToken == null ? "" : nextPageToken
    })
    nextPageToken = pageContent.nextPageToken
    pageContent.items.forEach((item) => {
      pageList.push([item.contentDetails.videoId, item.snippet.title, Utilities.formatDate(new Date(item.snippet.publishedAt), 'Asia/Tokyo', 'yyyy-MM-dd')])
    })
  } while (nextPageToken != null)

  const fileId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //書き出したい Google SheetのIDを記入
	
	// View listというシートを作成
  const { sheet } = createSheet(fileId, "video list")
  sheet.getRange(1, 1, 1, 3).setValues([["ページid", "タイトル", "投稿日"]])
  sheet.getRange(2, 1, pageList.length, 3).setValues(pageList)

}

const createSheet = (fileId, name) => {
  const file = SpreadsheetApp.openById(fileId)
  const isSheetExist = file.getSheetByName(name)
  if (isSheetExist) {
    file.deleteSheet(isSheetExist)
  }
  const newSheet = file.insertSheet()
  newSheet.setName(name)
  return { sheet: file.getSheetByName(name) }
}

「チャンネルが投稿したすべての動画を取得」を実現するために、Channels listPalylistItems listというAPIをそれぞれ実行します。

ソースに必要なコメントを残しているので、順を追って理解することができるかと思います。詰まった点としては、PlaylistItems listでは最大200件の動画情報しか取得することができません。それ以上データがある場合は、APIのレスポンス内でnextPageTokenが返答されます。nextPageTokenがある場合は、繰り返し取得することで、チャンネルが投稿したすべての動画を取得することができます。

動画IDから先月の分析情報を取得する

ここでは、「動画IDから先月の分析情報を取得」という部分のコーディングになります。前提条件として、createReportPlaylistInfoで作成したVideo listから情報を取得しています。なので、createReportPlaylistInfoの実行が必要となります。

const createLastMonthConversionReport =()=> {
  const channelId = "xxxxxxxxxxxxxxxxxxxx" // YouTube チャンネルID
  const fileId = "  xxxxxxxxxxxxxxxxxxxxxxxx" // createReportPlaylistInfo.gsで使用したGoogle Sheetと同一のシートID
  const file = SpreadsheetApp.openById(fileId)
  const videoListSheet = file.getSheetByName("video list")
  const videoList = videoListSheet.getRange(2, 1, videoListSheet.getLastRow() - 1, 1).getValues().map((value) => value[0])

  const { startDate, endDate, targetDate } = getLastMonthRenge()

  const videoLists = []
	
	// 取得した動画を25個ずつに分割
  while (25 <= videoList.length) {
    videoLists.push(videoList.splice(0, 25))
  }
  if (videoList.length != 0) videoLists.push(videoList)

  const videoListConversion = []

  // <https://developers.google.com/youtube/analytics/reference/reports/query?hl=ja>
  let headers = []
  videoLists.forEach((videoList) => {
    const filters = "video==" + videoList.join(",")
    const metrics = [
      'views',
      'estimatedMinutesWatched',
      'subscribersGained'];
    const result = YouTubeAnalytics.Reports.query({
      ids: 'channel==' + channelId,
      dimensions: "video",
      startDate: startDate,
      endDate: endDate,
      maxResults: 25,
      filters: filters,
      sort: "-estimatedMinutesWatched",
      metrics: metrics.join(',')
    });

    if (!result.rows) {
      console.log('No rows returned.');
      return;
    }

    headers = result.columnHeaders.map(
      (column) => {
        return column.name;
      });

    videoListConversion.push(...result.rows)
  })
	// Header情報を日本語に変換
  const japaneseHeaders = headers.map((value) => {
    if (value.includes("video")) return "VideoId"
    if (value.includes("views")) return "視聴回数"
    if (value.includes("estimatedMinutesWatched")) return "視聴時間"
    if (value.includes("subscribersGained")) return "登録者増加数"
  })
  videoListConversion.unshift(japaneseHeaders)
  
	const { sheet } = createSheet(fileId, targetDate)
  sheet.getRange(1, 1, videoListConversion.length, 4).setValues(videoListConversion)
}

const getLastMonthRenge = () => {
  const now = new Date()
  // month 0 ~ 11
  const targetDate = now.getFullYear() + "/" + now.getMonth() + "月"
  const monthStartDate = Utilities.formatDate(new Date(now.getFullYear(), now.getMonth() - 1, 1), "Asia/Tokyo", "yyy-MM-dd")
  const monthEndDate = Utilities.formatDate(new Date(now.getFullYear(), now.getMonth(), 0), "Asia/Tokyo", "yyy-MM-dd")
  return {
    targetDate: targetDate,
    startDate: monthStartDate,
    endDate: monthEndDate
  }
}

const createSheet = (fileId, name) => {
  const file = SpreadsheetApp.openById(fileId)
  const isSheetExist = file.getSheetByName(name)
  if (isSheetExist) {
    file.deleteSheet(isSheetExist)
  }
  const newSheet = file.insertSheet()
  newSheet.setName(name)
  return { sheet: file.getSheetByName(name) }
}

「動画に対して、先月の分析情報を取得」を実現するために、YouTubeAnalytics.Reportsを使用しています。

詰まった点としては、YouTubeAnalytics Reportsの仕様になります。動画IDを送って取得というイメージではなく、動画IDでフィルターをかけて取得するというイメージをつかむのに苦労しました。

YouTubeAnalytics Reportsで、視聴回数が高い動画を取得することはできます。この場合、視聴回数の上位というものをキーとして検索しています。実際にサンプルは、公式で用意されています。動画のIDをフィルターとして渡すことで、「特定の動画の分析情報」を取得することができます。

あと、dimensionsでvideoを指定するときはsortのパラメータを必須で指定する必要があります。これはAPIリファレンスにちょろっと書いてあるので見逃して時間を浪費してしましました。

終わりに

上のコードでプロパティ値を設定し、GASのトリガーを設定することで、投稿したすべての動画に対して先月分の分析情報を取得することができます。

トピックとしては、YouTube Studioで見れる情報と大差ありませんし、コーディングの手間もないのでそちらを使うことをお勧めします。ただ、アカウント情報を共有したくない人ぐらいしかこの方法を調べてないと思うので、どこかの誰かの役に立つことを祈っています。

だいぶニッチな需要だとは思いますがww

はい!お疲れ様でした。

GASはGoogleのサービスとの相性が良いので、ほかにもいろいろ使うことができるかと思います。Googleサービスの簡単な共有レポートであれば、GAS以外を使うことのほうが少ないかと思います。これからもGASの開発で、社内の定常業務を効率化していきましょう!!

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

1人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です