【Python】Youtube Data Apiを使ってYouTube 動画コメントを全取得する

# はじめに
Youtubeをよく見るんですが、Youtube本サイトのコメントってスクロールさせると次がある程度データが取得されてきて表示されるようになっています。人気動画だと１０００件以上はコメントが付いていますが、全部見るのは辛いんで自分が実際に見るのって上から１００件程度（並び替え 評価順）なんですよね。

「[【GACKTの勝ち方】海外移住・生き方・ビジネス・ボランティアを語る - Youtube](https://www.youtube.com/watch?v=oeJ_b0iG9lM)」の動画を見て感動したんで、コメントを全部閲覧してみたいなと思ったんですよ。
それで、Youtube Data APIを使えば、コメントを全部取得してから一括で見れると思ったんでやってみました。

# 調査
## APIキーの有効化
Youtube Data APIを今回初めて使います。
Youtube Data APIを使用するには、APIキーの有効化をする必要があるので、下記サイトを参考にしました。
[Youtube Data APIを使用して、Youtube Liveのコメントを取得する](https://qiita.com/MCK9595/items/fdbd543ff938febcd136)

## Google Colaboratory
今回は誰でも手軽にコメント取得が出来ればいいなと思って、Googleアカウントさえあれば直ぐに使える「Google Colaboratory」を使ってやりたかったので、プログラム言語としてはPythonにしたかった。

下記サイトがまさに要望に一致しました。
[PythonでYouTubeのコメントを取得](https://qiita.com/shirayuca/items/0318ee7ac92953a42375)

## コメントの取得
Google Colaboratoryを開いて上記サイトの「getYouTubeComments.py」をコピペで貼り付け、APIキーとVIDEO IDを書き換えて実行してみました。
コメントを取得することは出来たのですが、対象の動作のコメントを比べると何か足りない。コメントには返信による子コメントがあるのですが、このプログラムでは子コメントまでは取得できるようにはなっていませんでした。

## 子コメントの取得
子コメントを取得するようにするには、どうするのか？
返信数は今でも取得できるので、返信数が1以上なら子コメントを取得するようにすればいいのは分かるんですがね。
検索して見つけたのが下記サイトでプログラム言語はPHPなんですが、仕組みさえ分かればいい。
[YouTube コメントの全取得 - 眠たいお粥](http://sleepyokayu.blogspot.com/2018/04/youtube_12.html)

子コメントの場合、commentsのメソッドに親ID(parentId)をパラメータとして渡せば取得できる。

```
コメント   https://www.googleapis.com/youtube/v3/commentThreads
子コメント https://www.googleapis.com/youtube/v3/comments
```

# 仕様
参考にしたプログラムとの違いとして、連番を付与しユーザー名と子コメントが取得できるようになっています。

タブ区切りでコメントの改行は半角空白に置換しています。
コメントのフォーマットは`html`か`plain text`があるのですが、`plain text`になっています。
並び順は`relevance`で評価順が多い順にしています。子コメントについては順不動（並び順を指定しても動画サイトと同じにならない）です。
親連番は4桁、子の連番は3桁にしているので桁数を超えるコメントを取得したい場合は表示する桁数を変更増やすといいでしょう。

※APIの使用回数を減らすため 親コメントはmaxResults=100、子コメントはmaxResults=50とする。
※コメントでは低評価(disLike)数は取得できない。

```
000X	(コメント)	（Like数）	（ユーザー名）	（返信数)
000X-00X	(子コメント)	（グッド数）	（ユーザー名）
```
【2021/05/28追記】
並び順を評価順(relevance)にした場合、YouTube Data API v3の制約上2000件を超える親コメントが取得できません。
並び順を新しい順(time)にした場合、上限が不明ですが2000件を超える親コメントが取得できます。

【2024/06/02追記】
並び順を新しい順(time)にした場合、取得数に不安定な時があり安定した方法を提示。

https://qiita.com/Kaoru_Pythoness/items/f8996296a86ed47d8821

# 使用方法
Google Colaboratoryを開いて上記サイトの「getYouTubeComments.py」をコピペで貼り付け、APIキーとVIDEO IDを書き換えて実行します。

## API_KEYを入力
Youtube Data APIのAPI有効化の認証情報でAPIキーが発行されるので、プログラムの`API_KEYを入力`で発行されたAPIキーに書き換えてください。

## Video IDを入力
例えば、「[https://www.youtube.com/watch?v=oeJ_b0iG9lM](https://www.youtube.com/watch?v=oeJ_b0iG9lM)」であれば、`oeJ_b0iG9lM`がVideo IDとなりますので、プログラムの`Video IDを入力`で対象動画のVideo IDに書き換えてください。

# プログラム
【2021/05/26追記】
101以降の返信が取得できていなかったのと、改行コードがあるコメントで正常に出力されない不具合の2点を修正

```py:getYouTubeComments.py
import requests
import json

URL = 'https://www.googleapis.com/youtube/v3/'
# ここにAPI KEYを入力
API_KEY = 'API KEYを入力'
# ここにVideo IDを入力
VIDEO_ID = 'Video IDを入力'

def print_video_comment(no, video_id, next_page_token):
  params = {
    'key': API_KEY,
    'part': 'snippet',
    'videoId': video_id,
    'order': 'relevance',
    'textFormat': 'plaintext',
    'maxResults': 100,
  }
  if next_page_token is not None:
    params['pageToken'] = next_page_token
  response = requests.get(URL + 'commentThreads', params=params)
  resource = response.json()

  for comment_info in resource['items']:
    # コメント
    text = comment_info['snippet']['topLevelComment']['snippet']['textDisplay']
    # グッド数
    like_cnt = comment_info['snippet']['topLevelComment']['snippet']['likeCount']
    # 返信数
    reply_cnt = comment_info['snippet']['totalReplyCount']
    # ユーザー名
    user_name = comment_info['snippet']['topLevelComment']['snippet']['authorDisplayName']
    # Id
    parentId = comment_info['snippet']['topLevelComment']['id']
    print('{:0=4}\t{}\t{}\t{}\t{}'.format(no, text.replace('\r', '\n').replace('\n', ' '), like_cnt, user_name, reply_cnt))
    if reply_cnt > 0:
      cno = 1
      print_video_reply(no, cno, video_id, None, parentId)
    no = no + 1

  if 'nextPageToken' in resource:
    print_video_comment(no, video_id, resource["nextPageToken"])

def print_video_reply(no, cno, video_id, next_page_token, id):
  params = {
    'key': API_KEY,
    'part': 'snippet',
    'videoId': video_id,
    'textFormat': 'plaintext',
    'maxResults': 50,
    'parentId': id,
  }

  if next_page_token is not None:
    params['pageToken'] = next_page_token
  response = requests.get(URL + 'comments', params=params)
  resource = response.json()

  for comment_info in resource['items']:
    # コメント
    text = comment_info['snippet']['textDisplay']
    # グッド数
    like_cnt = comment_info['snippet']['likeCount']
    # ユーザー名
    user_name = comment_info['snippet']['authorDisplayName']

    print('{:0=4}-{:0=3}\t{}\t{}\t{}'.format(no, cno, text.replace('\r', '\n').replace('\n', ' '), like_cnt, user_name))
    cno = cno + 1

  if 'nextPageToken' in resource:
    print_video_reply(no, cno, video_id, resource["nextPageToken"], id)

# コメントを全取得する
video_id = VIDEO_ID
no = 1
print_video_comment(no, video_id, None)
```

# 実行結果
「[【GACKTの勝ち方】海外移住・生き方・ビジネス・ボランティアを語る - Youtube](https://www.youtube.com/watch?v=oeJ_b0iG9lM)」の動画コメントを取得すると、下記のようになります。

```bath:コメント取得例
0006	内容はもちろんんですが、話し方、聞き方の面で勉強させてもらいました。 「チャレンジした経験は何ものにも代え難い宝」と子どもたちに身をもって伝えられるよう精進します。	622	とある男が授業をしてみた	9
0006-001	こちらのコメント欄で拝見して、感激しております。今日は良い事がありそう	0	星乃あかり
      ⋮
0006-008	いつも勉強させてもらってます	14	水。
0006-009	本物で草	16	ひゃかく
0007	あっちゃん 話の聞き方がやっぱうまい 「へぇ〜」とか「新潟ですか」とか短い言葉で返してることが多いのにどんどんGACKTの話を引き出してる	67	一滴の影響	0
```

# 最後に
もうすぐAdvent Calendarです。今年も「[Visual Basic Advent Calendar 2020](https://qiita.com/advent-calendar/2020/vb)」を記事を募集しています。
これでPythonではなく Visual BasicやExcelでやってみるなどのネタができそうです。

【2020/12/20追記】
Excelで作成しました。
[【VBA】ExcelでYoutube Data Apiを使ってYouTube 動画コメントを全取得する](https://qiita.com/yaju/items/dd0d8359d8f926c32627)