Magicode logo
Magicode
0
6 min read

[GAS] Youtubeチャンネル内の動画情報を取得したいならSearch.listとVideos.listを使用する

はじめに

YouTubeチャンネルに含まれる動画から、各種データを取得したいという相談がありました。相談者はWEBスクレイピングを考えていたようですが、公式のAPIがあるのでそれはお断りしました。同種の案件は受けることはないですが、APIを利用した公式のデータ取得に関してはやぶさかではありませんので備忘録として残しておきたいと思います。

本記事では、ベースとなるロジックのみを公開しておきます。GAS前提ではありますが、言語ごとに特別に振る舞いが異なるわけでもないので、使用環境に合わせて応用できると思います。

なお、前提としてスクリプトを設置するプロジェクトにおいては、拡張サービスにてYouTube Data APIを追加する必要があります。追加、設定方法につきましては、拙記事ではありますがこちらを参考にしていただければと思います。

目的

特定のYouTubeチャンネルに含まれる動画に関する情報を取得し、スプレッドシートで管理したい。 具体的には以下の項目を取得したい。

  • サムネイル画像
  • 動画タイトル
  • 動画の説明
  • アップロード日時
  • 動画再生回数
  • 高く評価された数
  • お気に入りの数
  • コメント数

※低く評価された数は公式で自身管理の動画以外は取得できないように変更されました。

ロジックについて

フローアウトライン

  1. Search.listでチャンネルID指定によるチャンネル内動画ID取得
  2. Videos.listで必要な動画ごとの詳細情報を取得

補足

Channels.listからアップロード済み動画リストのIDを取得した後、PlaylistItems.listを経由しリスト内の動画IDを取得する、という方法を紹介したブログもありました。(当該ブログへのリンクは控えさせていただきます)

ただ、この方法はAPIリクエスト数、処理負荷、実行時間、1日あたりのQuotaの消費など諸々考慮するとおすすめできません。

チャンネルIDについて

特定のチャンネルということで、すでにチャンネルIDがわかっている前提となります。

お問い合わせ時によくあるのは、URLはわかっているけどチャンネルIDがわからないというものです。以下のような標準のURL形式なら、channel/以降のUCで始まる英数字をコピペ頂くか、数式等で抽出も可能です。

https://youtube.com/channel/UC*******************

上記以外のカスタムURLの場合、当該チャンネルのHTMLソース内の記述部分を探して取得する必要があります。

※これをスクレイピングで取得するツールもあるようですが、利用規約的にどうかと思いますので紹介はいたしません。

カスタムURLについては以下をご確認ください。

チャンネル URL について - YouTube ヘルプ

ロジック詳細

以下、ステップごとにサンプルコードを記述していますが、エラー処理等は割愛しています。

1. Search.listよりチャンネル内動画のID取得と同時にカンマ区切りテキスト化しておく

データ総量削減のため、partにはidのみを設定しています。また、初期状態では1リクエストあたり最大5件しか取得できませんので、50件まで取得するようにしています。

動画数が50件超の場合、nextPageTokenを確認し、再帰処理を行うようにしています。ただし、チャンネルによっては1日あたりのQuotaを超えてしまう可能性があるため、別途繰り返し上限数を設定するか、取得期間の設定をするなどの対応が必要になります。

なお、当方で受注する際には初期状態で1チャンネルにつき500件までに制限していますが、運用状況や実行時間などの様子を見て、適宜上限数の調整をしていただいています。

補足

Search.list及びVideos.listともに、query内で複数IDを指定する際はカンマ区切りテキストにする必要があります。指定できる最大値の明記はありませんが、やはり50件が上限となります。

そのため、このステップでは次の処理用に、取得した動画ID50件をtoString()により一括でカンマ区切りテキストにし、最終的に一次元配列で返すようにしています。

つまり、下記getVideoIdsの戻り値videoIdsの1要素は最大50件分の動画IDのカンマ区切りテキストとなります。

const channelId    = __ チャンネルID __;
const channelPart  = 'id';
const channelQuery = {
    channelId: channelId,
    type: 'video',
    maxResults: 50,
    pageToken:''
};

// 動画IDリストの取得
const getVideoIds = (ids, res) => {
    // videoIdをカンマ区切りテキストにして一次元配列の要素としてセットする
    ids.push(res.items.flatMap(item => item.id.videoId).toString());

    let next = res.nextPageToken || false;

    // 再帰処理
    if(next){
        channelQuery.pageToken = next;
        getVideoIds(ids, YouTube.Search.list(channelPart, channelQuery));
    }

    return ids;
}

const videoIds = getVideoIds([], YouTube.Search.list(channelPart, channelQuery));

2. Videos.listより各動画の詳細データを取得する

スプレッドシートへの展開用に最終的に二次元配列で返すようにしています。

サムネイル画像につきましては、標準画質のURLを取得し、IMAGE関数にてスプレッドシート側で処理する前提となります。必要に応じて低画質、高画質を選択できますし、URLのみにすることもできます。

なお、descriptions取得後の処理に関しましては、一般的なシートへの展開処理となりますので、割愛しています。

const videoPart = 'id,snippet,statistics'; // idはなくても良い

// 動画ごと詳細データの取得
const getVideoData = item => [
    `=IMAGE("${item.snippet.thumbnails.default.url}",1)` || '-', // サムネイル画像
    item.snippet.title || '-', // 動画タイトル
    item.snippet.description || '-', // 動画の説明
    new Date(item.snippet.publishedAt) || '-', // アップロード日時
    item.statistics.viewCount || 0, // 動画再生回数
    item.statistics.likeCount || 0, // 高く評価された数
    item.statistics.favoriteCount || 0, // お気に入りの数
    item.statistics.commentCount || 0 // コメント数
];

// 動画詳細データ取得後シート展開用に二次元配列として返す
const getDescriptions = ids => ids.flatMap(id => {
    let query = {id: id};
    let res   = YouTube.Videos.list(videPart, query);
    return res.items.map(item => getVideoData(item));
});

const descriptions = getDescriptions(videoIds);

/* 以降の処理は割愛 */
補足

約1000件の動画詳細情報取得について動作検証した際、getDescriptionsではArray.flatMapを使うより、Array.forEachを使うほうが約3秒ほど早く終了しました。以下が参考コードです。

const getDescriptions = ids =>  {
    const descriptions = [];

    ids.forEach(id => {
        let query = {id: id};
        let res   = YouTube.Videos.list(videoPart, query);
        res.items.forEach(item => descriptions.push(getVideoData(item)));
    });

    return descriptions;
};

最後に

シートへの展開時、データの並び順はデフォルトで検索クエリの関連性が高い順となっています。データの並び替えはシート上でもできますが、Search.listqueryorderプロパティを追加し、任意の並び順にすることもできます。

コードボリュームも多くないので、その他色々ご要望に合わせたカスタマイズも容易かと思います。

誰かの役に立てば幸いです。

Discussion

コメントにはログインが必要です。