目的
YouTube Data API v3を使って、特定のチャンネルにアップロードされた動画に関するデータをすべて取得することが目的です。
APIの仕様上取得できる件数に制限があったり、動画のIDであるVideoIdの一覧を取得する際にちょっと苦労ので、それらを中心に解説していきますが、基本的には以下のリファレンスを見れば、時間はかかるかもしれませんが大体の操作は簡単に実装できるかと思います。
YouTube API Reference
前提
- Go言語を使える環境が前提です
- 使っているバージョンは
1.18.3
- 使っているバージョンは
- 以下の記事を参考に、YouTube Data API v3を有効にし、APIキーが取得済み
YouTube Data API v3 を使って YouTube 動画を検索する
流れ
私のGitHubページに以下の一連の流れを実装したリポジトリがありますので、よかったら参考にしてみてください
https://github.com/tokuchi765/youtube-analyze/compare/v1.0.0...main
- クライアント / サービス生成
- チャンネルのアップロード動画の動画リストID取得(ここがややこしい)
- アップロード動画すべてが格納されている再生リストが存在するので、その再生リストのIDを取得することで、後続の動画ID取得が可能となる
- チャンネルIDを指定したらすべてのアップロード動画IDが取得できるような仕組みにしてくれないかな・・・(小声)
- 動画リストIDを元にチャンネルにアップロードされたすべての動画IDを取得
- ここも少し面倒で、50件以上の動画が存在する場合に
NextPageToken
を使って再度APIを呼び出す必要がある
- ここも少し面倒で、50件以上の動画が存在する場合に
- すべての動画データ取得
コード全体
- 各章でメソッドの中身を解説していきます
// クライアント / サービス生成
service := createService()
// チャンネルのアップロード動画の動画リストID取得
uploadsID := getUploadsID(channelID, service)
// 動画リストIDを元にチャンネルにアップロードされたすべての動画IDを取得
videoIDs := getVideoIDs(uploadsID, service)
// 最終目的:すべての動画データ取得
videoDatas := getVideoDatas(videoIDs, service)
クライアント / サービス生成
- APIキーを用いてクライアントを生成
-
developerKey
の部分にAPIキーを設定する - 生成した
http.Client
を元にサービスを作成- 作成したサービスを使いまわす形でこの後のAPI呼び出しを行う
- 現在は非推奨なので改修予定、課題に詳細を記載
-
import (
"log"
"net/http"
"google.golang.org/api/googleapi/transport"
"google.golang.org/api/youtube/v3"
)
func createService() (service *youtube.Service) {
client := &http.Client{
Transport: &transport.APIKey{Key: "developerKey"},
}
service, err := youtube.New(client)
if err != nil {
log.Fatalf("Error creating new YouTube client: %v", err)
}
return service
}
チャンネルのアップロード動画の動画リストID取得
- 指定したチャンネルの動画をすべて取得するためには、この後の動画リスト取得時に
動画リストID
が必要
そのIDを取得するための処理 - Channels API を使用する
- APIコールの流れ
基本的なAPIコールの流れをここで説明しちゃいますが、今後もAPIコール処理が出てきますのでこの流れを覚えておいてください-
service.Xxxxx
で呼び出したいAPIの種別を指定(今回の場合はChannels) -
service.Xxxxx.List([]string{"任意のプロパティ"})
で、APIコール時に取得したいリソースを指定する- どういったリソースがあるかは公式リファレンスを参照
- 例 channelsのリソース
-
service.Xxxxx.List([]string{"任意のプロパティ"}).Id("任意のID")
でフィルターを設定- 今回はチャンネルIDを指定しているが、カテゴリーやユーザー名なども指定可能
- 詳しくは公式リファレンスを参照 channelsのパラメータ
- 上記の一連の流れで
youtube.ChannelsListCall
が取得可能(コード例のchannelsCall
) - 取得したオブジェクトに対して
Do()
を実行 - レスポンスが取得できるのであとはよしなに(コード例の
channelsResponse
)- 今回は動画リストIDが欲しいので、
ContentDetails.RelatedPlaylists.Uploads
を取得
- 今回は動画リストIDが欲しいので、
-
import (
"log"
"net/http"
"google.golang.org/api/youtube/v3"
)
func getUploadsID(channelID string, service *youtube.Service) string {
// channelIDには任意のYouTubeチャンネルIDを指定
channelsCall := service.Channels.List([]string{"contentDetails"}).Id(channelID)
channelsResponse, err := channelsCall.Do()
if err != nil {
log.Fatalf("Error call YouTube API: %v", err)
}
channelsItem := channelsResponse.Items[0]
// 目的の動画リストID
return channelsItem.ContentDetails.RelatedPlaylists.Uploads
}
動画リストIDを元にチャンネルにアップロードされたすべての動画IDを取得
- 先ほど取得した動画リストIDを用いて、チャンネルに紐づくすべての動画IDを取得する
- PlaylistItems API を使用する
- API呼び出しの流れは先ほど説明した通りで、指定した動画リストIDに紐づくデータを最大50件取得可能
-
PlaylistId
に先ほど取得したuploadsID
を設定し、MaxResults
に50を指定(これを指定しないとデフォルト設定で5件しか取れない) - じゃあ50件以上動画がアップロードされてるチャンネルはどうすればええの?というと
NextPageToken
を使う - 50件以上結果が存在する場合、レスポンス内の
NextPageToken
が入力されているので、それをPageToken
の引数に設定してあげると次の50件が取得可能 - 以下のコードも複雑に見えるが、
NextPageToken
が取得できなくなるまでAPIを呼び出してるだけ - もうちょっとシンプルなロジックで書けそうだけどゆるして
-
import (
"log"
"net/http"
"google.golang.org/api/youtube/v3"
)
func getVideoIDs(uploadsID string, service *youtube.Service) (videoIDs []string) {
playlistsCall := service.PlaylistItems.List([]string{"contentDetails"}).PlaylistId(uploadsID).MaxResults(50)
playlistsResponse, err := playlistsCall.Do()
if err != nil {
log.Fatalf("Error call YouTube API: %v", err)
}
for _, item := range playlistsResponse.Items {
videoIDs = append(videoIDs, item.ContentDetails.VideoId)
}
if playlistsResponse.NextPageToken != "" {
nextPageToken := playlistsResponse.NextPageToken
for {
nextCall := service.PlaylistItems.List([]string{"contentDetails"}).PlaylistId(uploadsID).PageToken(nextPageToken).MaxResults(50)
nextResponse, err := nextCall.Do()
if err != nil {
log.Fatalf("Error call YouTube API: %v", err)
}
for _, nextItem := range nextResponse.Items {
videoIDs = append(videoIDs, nextItem.ContentDetails.VideoId)
}
nextPageToken = nextResponse.NextPageToken
if nextPageToken == "" {
break
}
}
}
return videoIDs
}
すべての動画データ取得
- 先ほど取得した、チャンネルに紐づくすべての動画IDリストをループして、動画データを取得する
- 動画データ取得に使うのは Videos
- 使い方は簡単で、動画IDを引数に設定してあげるだけ
-
VideoData
のstructを用意してデータを格納してるが、のちの処理で扱いやすいかと思ってやってるだけ
import (
"log"
"net/http"
"google.golang.org/api/youtube/v3"
)
type VideoData struct {
VideoID string
Title string
ViewCount uint64
LikeCount uint64
DislikeCount uint64
FavoriteCount uint64
CommentCount uint64
PublishedAt string
}
func getVideoDatas(videoIDs []string, service *youtube.Service) (videoDatas []VideoData) {
for _, videoID := range videoIDs {
call := service.Videos.List([]string{"snippet", "statistics"}).Id(videoID)
response, err := call.Do()
if err != nil {
log.Fatalf("Error call YouTube API: %v", err)
}
item := response.Items[0]
videoData := VideoData{
VideoID: videoID,
Title: item.Snippet.Title,
ViewCount: item.Statistics.ViewCount,
LikeCount: item.Statistics.LikeCount,
DislikeCount: item.Statistics.DislikeCount, // ※oauth認証じゃないと取得できない
FavoriteCount: item.Statistics.FavoriteCount,
CommentCount: item.Statistics.CommentCount,
PublishedAt: item.Snippet.PublishedAt,
}
videoDatas = append(videoDatas, videoData)
}
return videoDatas
}
課題
- APIキーだと低評価などの非公開データが取得できないので、oauth認証によるクライアント生成が必要
- クライアント生成に使用している "google.golang.org/api/googleapi/transport" パッケージが非推奨
- https://pkg.go.dev/google.golang.org/api@v0.86.0/googleapi/transport
- 代わりに、"google.golang.org/api/youtube/v3" NewService を使用する
参考
- 公式のサンプル(これを見れば大体実装できる)
- 公式のリファレンス