【MV】恋するフォーチュンクッキー / AKB48[公式]
わたしはYouTubeの動画を連続再生して、それを作業用BGMにしたりしています。
きょうはAKB48だ!!って思って聴いていて、ふとしたときに動画ページに戻ってみると、こういうコメントが目につきました。
「このときが一番よかった!」
「この頃がまさに黄金期!」
これは…! いろんなジャンルでよく見る“懐古厨”のみなさんだ!!
ちょっと見てみると、AKBの少し古めの曲のMVなら、どの動画にもこういうコメントをつけている人がいらっしゃいます。
わたしは思いました。
“懐古厨”のみなさんは、ほんとはいったいいつの時代が一番好きなんだろう…。
というわけで、今回はプログラムを書いて、それを調べてみることにしました。
途中までずっとプログラム書いているので、結論を知りたいひとはジャンプしてください!
(今回の記事は歌詞関係ありません。ざんねん…。)
あつめようYouTubeコメ
まずはYouTubeから、AKBの動画を探しましょう。
AKBの動画は、公式のものから、TV番組を勝手にアップロードしたもの(きっとすぐ消されちゃう)までたくさんあります。
今回は、公式のMVを対象にします。AKBはわりと早い時期から公式の動画をYouTubeに上げてた実績があるので、蓄積がたくさんあって最高です。
公式の動画はここにあります。再生リストっていうんだって。
www.youtube.com
この44曲のコメントを収集することにしましょう。
ネットとかから情報を体系的に収集することをスクレイピングって言うそうです。HTMLを解析してごりごり…って方法もありますが、YouTubeにはAPIという仕組みがあります。我々の味方です!
developers.google.com
にほんごだ!!
前にTwitterのAPIを使ったことがあるんですが、このときにはドキュメント英語でした…。
hacosato.hatenablog.com
それに比べたら、(英語の部分もあるけど)日本語で説明してくれるなんてYouTube最高です♪
ここの指示通りにアカウントをつくったりしましょう。「プロジェクト ID」は自動で付くし変更もできるけど、べつに自分がわかればなんでもいいみたい。
再生リストからどうやって情報を得るのかは、ここに書いてあります。
developers.google.com
いろいろ説明があって難しいように思えますが、とりあえずこれを入力して、ブラウザのアドレスバーに入力しましょう。
「自分のキー」っていうのは
console.developers.google.com
から確認できます。
アドレスバーに入力したらEnter!
すごい! プログラミングやってる感ある!!
あとはここから必要な情報を拾っていけばいいです♪ 今回は動画のIDだけ拾っておいて、あとでIDからコメントを探していこうと思います。
IDを拾っておけば、そこからさらに詳しい情報を得ることができます。今回はそういう作戦を取ります。
developers.google.com
IDからコメントを拾うには、CommentThreadの情報を使います。
developers.google.com
コメントについているコメントを拾うには、Commentsを使います。
CommentThreadは100までしか手に入りませんが、pageTokenっていうパラメーターを設定すれば、次の100件、その次の100件…って探すことができます。これを順に繰り返していけばいいので、たぶんこれはプログラミングでいうと再帰ってやつだと思います! はじめて使った!
これをすべての動画に対して繰り返して処理するようにしたらよいです。
たくさんの情報を得ることができますが、そんなにいらないので、今回はコメントの中身と、それについているlikeの数を集めました。やる気になればコメントを書いた人とか、その日時とかもつかむことができますが、今回はなしです。
たいていの言語で可能だとは思いますが、わたしはRubyを使います。
# AKB48のプレイリストから、動画のIDを取得し、コメントをテキストファイルで出力 # -*- coding: utf-8 -*- start_time = Time.now require 'open-uri' require 'json' require 'retryable' apikey = "APIキーだよ〜〜" order = "relevance" part = "replies,snippet" maxresults = 100 # YouTube動画のURLを受け取って、付いているコメントと評価のハッシュを配列にしたものを返すdef。 # resultには空の配列を与えておくと埋めて返してくれる。 def scrapecomments(url, result) p url begin hash = Retryable.retryable(:tries => 3) do |retries, exception| next if retries == 2 JSON.parse(open(url).read) end rescue => err p err return result end # エラーじゃなければ続ける unless hash.has_key?("error") hash["items"].each do |comment| result.push({"text" => comment["snippet"]["topLevelComment"]["snippet"]["textDisplay"], "likeCount" => comment["snippet"]["topLevelComment"]["snippet"]["likeCount"]}) # リプがあるならそれも数える if comment.has_key?("replies") comment["replies"]["comments"].each do |replycomment| result.push({"text" => replycomment["snippet"]["textDisplay"], "likeCount" => replycomment["snippet"]["likeCount"]}) end end end # 次のページがあったら再帰で読み込む if hash.has_key?("nextPageToken") url = url.split("&pageToken=")[0]+"&pageToken=#{hash["nextPageToken"]}" scrapecomments(url, result) end end return result end # https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=PL72C7672926C69324&key=キーだよ〜〜 # AKB48のシングルMVコレクションプレイリストのデータを取得できるよ。 # 今回はサーバに負担をかけないように、一度ローカルに落としました。 mvlist = File.read("ファイルパスだよ〜〜" hash = JSON.parse(mvlist) # 1曲ずつ処理を回す hash["items"].each_with_index do |movie, idx| # タイトルにスラッシュが入るとうまく動かない title = movie["snippet"]["title"].gsub!(/【MV】\s*|\s*\/\s*AKB48\s*\[公式\]/, "") videoId = movie["snippet"]["resourceId"]["videoId"] result = [] url = "https://www.googleapis.com/youtube/v3/commentThreads?part=#{part}&order=#{order}&key=#{apikey}&textFormat=plainText&videoId=#{videoId}&maxResults=#{maxresults}" # この行で、実際にスクレイピングの処理を呼んでる result = scrapecomments(url, result) sleep 1 # 結果は1曲ずつファイルに書き出す File.write("ファイルパスだよ〜〜/result/#{idx}_#{title}.txt", result) p "#{idx}.『#{title}』のコメント数は#{result.length}でした。" end p "所要時間は #{Time.now - start_time}s でした。"
こういう感じ。動かすと、指定したフォルダにファイルがひとつずつできてきます。
ところで、今回ここに積み残しがあります。
コメント数が2000を超えると調子が悪くなるのです…。
曲ごとの取得率をグラフにしたところ、こういう感じでした。
2000ぐらいまでしかコメントを取得できていないことがわかります。が、原因ははっきりしませんでした。PageTokenが数千文字にもなる(ページが増すに連れてどんどん伸びるのです)のが遠因かなと思うんですが、よくわかりませんでした…)。
見つけよう懐古コメ
さて、コメントを集めたら、今度はそこから懐古コメントを探します。
懐古コメントの判断方法はカンタンです!
「あの頃は〜〜」とか「この頃は〜」とかっていってるコメを探せばいいのです。
今回は強引に、正規表現/[あこ]の(ころ|頃|とき|時)/にマッチするコメをすべて懐古コメント
- あの頃
- あのころ
- あの時
- あのとき
- この頃
- このころ
- この時
- このとき
のどれかを含むコメを探せばいいだけのカンタン仕様です♪
さっきと違うプログラムを書いて、コメントを探します。
こっちはネットに繋がるプログラムじゃないし、テキストファイルから文字を探して数を数えるだけなので、さっきよりもカンタンです!
# AKB48のプレイリストから、動画のIDを取得し、コメントをテキストファイルで出力したのを受け取って、 # そこから懐古厨のコメントを集計する require 'pp' # ハッシュが入ったファイルを受け取って、懐古なコメントを集計する def aggregatefromfile(path) # クエリ re = /[あこ]の(ころ|頃|とき|時)/ text = File.open(path).read # 中身が安全とわかっているファイルにしか使えないやつeval hash = eval(text) anokorocomments = [] # コメントの総数とlikeの総数 commentcount = 0 likecount = 0 # 懐古コメントの数と、それについたlikeの数 commentscore = 0 likescore = 0 hash.each do |comment| if comment["text"].match(re) anokorocomments.push(comment) commentscore += 1 likescore += comment["likeCount"] end likecount += comment["likeCount"].to_i end commentcount = hash.length result = {"comments"=>anokorocomments, "score"=>commentscore+likescore*coefficient, "commentscore"=>commentscore, "likescore"=>likescore, "commentcount"=>commentcount, "likecount"=>likecount} return result end path = "パスだよ〜〜/result" print "番号 曲名 該当コメ 総コメ 該当like 総like\n" dir = Dir.open(path) dir.each do |name| next if name == "." next if name == ".." result = aggregatefromfile(path + "/" + name) print name.split("_")[0]+"\t"+name.split("_")[1]+"\t"+result["commentscore"].to_s+"\t"+result["commentcount"].to_s+"\t"+result["likescore"].to_s+"\t"+result["likecount"].to_s+"\n" print name.split("_")[1] # コメントの中身を見るとき用 # p result["comments"]end dir.close
でーきた! 結果がコレです。
コメについてるlikeは、コメの半分の重みを付けてカウントしました。
懐古コメント1つが1点だとしたら、懐古コメントにつくlikeひとつが0.5点です。
番号 | 曲名 | 該当コメ | 総コメ | 該当like | 総like | 該当コメ率 | 該当like率 | スコア |
0 | ハロウィン・ナイト.txt | 0 | 197 | 0 | 301 | 0 | 0 | 0 |
1 | 僕たちは戦わない.txt | 1 | 579 | 2 | 809 | 0.172711572 | 0.247218789 | 0.203355363 |
2 | Green Flash.txt | 0 | 415 | 0 | 630 | 0 | 0 | 0 |
3 | 希望的リフレイン.txt | 1 | 956 | 0 | 1174 | 0.10460251 | 0 | 0.064808814 |
4 | 心のプラカード.txt | 1 | 673 | 0 | 661 | 0.14858841 | 0 | 0.099651221 |
5 | ラブラドール・レトリバー.txt | 2 | 729 | 3 | 536 | 0.274348422 | 0.559701493 | 0.351053159 |
6 | 前しか向かねえ.txt | 0 | 334 | 0 | 461 | 0 | 0 | 0 |
7 | 鈴懸の木の道で「君の微笑みを夢に見る」と言ってしまったら僕たちの関係はどう変わってしまうのか、僕なりに何日か考えた上でのやや気恥ずかしい結論のようなもの.txt | 2 | 354 | 1 | 310 | 0.564971751 | 0.322580645 | 0.491159136 |
8 | ハート・エレキ -Dance ver.-.txt | 2 | 402 | 5 | 513 | 0.497512438 | 0.974658869 | 0.683371298 |
9 | 恋するフォーチュンクッキー.txt | 5 | 2196 | 3 | 3473 | 0.227686703 | 0.086380651 | 0.165289256 |
10 | さよならクロール.txt | 2 | 1365 | 2 | 1438 | 0.146520147 | 0.139082058 | 0.143953935 |
11 | So long !.txt | 1 | 518 | 0 | 542 | 0.193050193 | 0 | 0.126742712 |
12 | 永遠プレッシャー.txt | 10 | 1907 | 26 | 1463 | 0.524383849 | 1.777170198 | 0.87170741 |
13 | UZA -Dance ver.-.txt | 4 | 1688 | 0 | 2587 | 0.236966825 | 0 | 0.134160657 |
14 | ギンガムチェック.txt | 2 | 2064 | 12 | 2712 | 0.096899225 | 0.442477876 | 0.233918129 |
15 | 真夏のSounds good ! (Dance ver.).txt | 9 | 1603 | 32 | 2602 | 0.561447286 | 1.229823213 | 0.860881543 |
16 | GIVE ME FIVE !.txt | 14 | 1574 | 15 | 1831 | 0.889453621 | 0.819224468 | 0.863627234 |
17 | 上からマリコ.txt | 3 | 1367 | 0 | 1713 | 0.219458669 | 0 | 0.13492242 |
18 | 風は吹いている(DANCE! DANCE! DANCE! ver.).txt | 8 | 895 | 18 | 2378 | 0.893854749 | 0.756938604 | 0.815738964 |
19 | フライングゲット (ダンシングバージョン).txt | 25 | 2014 | 65 | 3736 | 1.241310824 | 1.739828694 | 1.48119526 |
20 | Everyday、カチューシャ.txt | 16 | 2050 | 6 | 2901 | 0.780487805 | 0.206825233 | 0.542779603 |
21 | 桜の木になろう.txt | 13 | 999 | 6 | 321 | 1.301301301 | 1.869158879 | 1.379905132 |
22 | チャンスの順番.txt | 7 | 1024 | 20 | 814 | 0.68359375 | 2.457002457 | 1.187980433 |
23 | Beginner.txt | 10 | 1834 | 35 | 1454 | 0.54525627 | 2.407152682 | 1.073799297 |
24 | ヘビーローテーション.txt | 15 | 2362 | 13 | 3353 | 0.635055038 | 0.387712496 | 0.532375882 |
25 | ポニーテールとシュシュ.txt | 47 | 2064 | 185 | 1547 | 2.277131783 | 11.95862961 | 4.916299559 |
26 | 涙サプライズ !.txt | 61 | 2017 | 199 | 3280 | 3.024293505 | 6.067073171 | 4.388843314 |
27 | RIVER.txt | 36 | 2053 | 92 | 3466 | 1.753531417 | 2.654356607 | 2.165874274 |
28 | 大声ダイヤモンド.txt | 73 | 1977 | 359 | 3662 | 3.692463328 | 9.803386128 | 6.630777311 |
29 | 言い訳Maybe.txt | 69 | 2051 | 243 | 3351 | 3.364212579 | 7.251566697 | 5.112035422 |
30 | 10年桜.txt | 44 | 1743 | 138 | 3832 | 2.524383247 | 3.60125261 | 3.088275485 |
31 | 野菜シスターズ.txt | 25 | 1965 | 106 | 4019 | 1.272264631 | 2.637472008 | 1.962511008 |
32 | マジスカロックンロール.txt | 10 | 1065 | 36 | 1789 | 0.938967136 | 2.012297373 | 1.428935953 |
33 | 君のことが好きだから.txt | 30 | 983 | 48 | 794 | 3.051881994 | 6.04534005 | 3.913043478 |
34 | 遠距離ポスター.txt | 9 | 1020 | 15 | 2648 | 0.882352941 | 0.566465257 | 0.703924915 |
35 | マジジョテッペンブルース.txt | 16 | 1301 | 60 | 2096 | 1.229823213 | 2.86259542 | 1.958280119 |
36 | 涙のシーソーゲーム.txt | 2 | 274 | 0 | 693 | 0.729927007 | 0 | 0.322320709 |
37 | 僕のYELL.txt | 1 | 247 | 1 | 787 | 0.4048583 | 0.127064803 | 0.234192037 |
38 | 飛べないアゲハチョウ.txt | 14 | 478 | 89 | 1348 | 2.928870293 | 6.602373887 | 5.078125 |
39 | 盗まれた唇.txt | 10 | 349 | 28 | 838 | 2.865329513 | 3.341288783 | 3.125 |
40 | 桜の栞.txt | 19 | 1348 | 23 | 2764 | 1.409495549 | 0.832127352 | 1.117216117 |
41 | ラッキーセブン.txt | 15 | 572 | 27 | 1287 | 2.622377622 | 2.097902098 | 2.344714109 |
42 | ひこうき雲(シアターガールズver).txt | 1 | 164 | 0 | 263 | 0.609756098 | 0 | 0.338409475 |
43 | Choose me !.txt | 15 | 697 | 45 | 3304 | 2.152080344 | 1.361985472 | 1.59642401 |
グラフにすると、こうなります。
というわけで、結論!
1番は『大声ダイヤモンド』でした。2番は『言い訳Maybe』です!
2008年から2009年ごろの曲に人気が集まっているみたいだ!
どちらもわたしもスキな曲♪
こうやって見ると、全体としてやっぱり古い曲にみんな想いを寄せていることがわかります。最近の曲だと懐古コメントと判断されたものはほとんどなかったりするので、あの正規表現もわりと筋がいいのかもしれません。
個人的には『ヘビーローテーション』といったもっとめっちゃ有名な曲にも票が集まるかな?って思ったんですが、そうでもありませんでした。有名だといまでもTVとかで露出が多いので、そんなに懐かしい気持ちにならないのかもしれないです。単にコメントの総数が多いので、割合だけでカウントすると不利なのかもしれません(だれか教えてください…Guiraud値とか関係ある…?)。
おそまつさまでした。
やってみてとってもたのしかったです。わたしが勝手に思う“懐古厨”よりは、暗くないコメントが多くて、AKB界隈のヲタのみなさんの愛を感じました。昔はよかったけど、いまはダメだよ!!ってタイプのコメントはすごく少なくて、らぶに満ち溢れた世界です〜。
こういうのは、基礎的なプログラミングができれば、動画のコメントを集めるのはとってもカンタンです! みんなもやろう! わたしにもたくさん教えてください!
参考:
今回みたいに、ネットの情報を効率的に収集するにはどうすれば?っていうのが書いてある本です。
この本でひと通り学習すれば、もうスクレイピングに困ることはほとんどなくなるんじゃないかなって思っています。
わたしはまだ最後まで読破できてないけど、これからもたゆまずに学んでいこうって思っています☆
ところでこの本、YouTubeのスクレイピングに関してはなぜか記述がちょっと手薄なのですが、この本が出た直前にYouTubeのAPIが変わったので、それが原因かなぁってわたしは勝手に考えています。ネットの情報も、旧APIのものが散見されるので、検索するとき大変でした。「v3」ってキーワードで絞り込みがおすすめです。
またあそびたい〜!٩(๑❛ᴗ❛๑)۶
※もちろん今回コメント拾えてないところもあるし、重みの付け方もなんとなくなので、ぜったいこの記事おあそびとしてお楽しみください!