はじめに
これは、Visual Basic Advent Calendar 2020の22日目の記事となります。
- 【Python】Youtube Data Apiを使ってYouTube 動画コメントを全取得する
- 【VBA】ExcelでYoutube Data Apiを使ってYouTube 動画コメントを全取得する
- 【VBA】Excel for MacでYoutube Data Apiを使ってYouTube 動画コメントを全取得する
どんだけ同じネタを使い回すのか、とはいえ、.NET版を作ってなかったんだよね。
環境
- Windows 10 Home
- .NET 5
- Visual Studio 2019
- Google.Apis.Youtube.v3 v1.49.0.2173
準備
今回のプログラムではYoutube Data Apiを使用するので、Apiキーの有効化を行っていきます。
Apiキーの有効化などは下記サイトを参考にしてください。
Youtube Data APIを使用して、Youtube Liveのコメントを取得する
ライブラリーの追加
.NETでYoutube Data Apiを使用するにはGoogle.Apis.Youtube.v3が必要なので、NuGetパッケージマネージャーから追加してください。
- NuGetパッケージマネージャーを起動します。
- 参照タブで、Google.Apis.Youtube.v3を検索します。
- Google.Apis.Youtube.v3をインストールします。
仕様
連番を付与しユーザー名と子コメントが取得できるようになっています。
タブ区切りでコメントの改行は半角空白に置換しています。
コメントのフォーマットはhtmlかplain textがあるのですが、plain textになっています。
並び順はrelevanceで評価順が多い順にしています。子コメントについては順不動(並び順を指定しても動画サイトと同じにならない)です。
親連番は4桁、子の連番は3桁にしているので桁数を超えるコメントを取得したい場合は表示する桁数を変更増やすといいでしょう。
※APIの使用回数を減らすため 親コメントはmaxResults=100、子コメントはmaxResults=50とする。
※コメントでは低評価(disLike)数は取得できない。
000X (コメント) (Like数) (ユーザー名) (投稿日時) (返信数)
000X-00X (子コメント) (グッド数) (ユーザー名) (投稿日時)
使用方法
' ここにAPI KEYを入力PrivateConstAPI_KEYAsString="(API KEYを入力)"' ここにVideo IDを入力PrivateConstVIDEO_IDAsString="(Video IDを入力)"// ここにAPI KEYを入力privateconststringAPI_KEY="(API KEYを入力)"// ここにVideo IDを入力privateconststringVIDEO_ID="(Video IDを入力)"本来は、Video IDは外部から変更できるようにしておくといいと思います。
API_KEYを入力
Youtube Data APIのAPI有効化の認証情報でAPIキーが発行されるので、プログラムのAPI_KEYを入力で発行されたAPIキーに書き換えてください。
Video IDを入力
例えば、「https://www.youtube.com/watch?v=oeJ_b0iG9lM」であれば、oeJ_b0iG9lMがVideo IDとなりますので、プログラムのVideo IDを入力で対象動画のVideo IDに書き換えてください。
プログラム
VisualBasic
ImportsGoogle.Apis.ServicesImportsGoogle.Apis.YouTube.v3' ここにAPI KEYを入力PrivateConstAPI_KEYAsString="(API KEYを入力)"' ここにVideo IDを入力PrivateConstVIDEO_IDAsString="(Video IDを入力)"PublicClassCommentInfoPublicParentNoAsIntegerPublicChildNoAsIntegerPublicTextAsStringPublicLikeCountAsLongPublicAuthorNameAsStringPublicPublishedAtAsDateTimePublicReplyCountAsLongEndClassPublicClassForm1'ここにAPI KEYを入力PrivateConstAPI_KEYAsString="(API KEYを入力)"'ここにVideo IDを入力PrivateConstVIDEO_IDAsString="(Video IDを入力)"PrivateAsyncSubButton1_Click(senderAsObject,eAsEventArgs)HandlesButton1.ClickDimyoutubeService=NewYouTubeService(NewBaseClientService.Initializer()With{.ApiKey=API_KEY})DimvideoId=VIDEO_IDDimcommentListAsList(OfCommentInfo)=NewList(OfCommentInfo)()AwaitGetComment(commentList,videoId,youtubeService,1,Nothing)ForEachinfoIncommentListDimlineAsStringIfinfo.ChildNo=0Thenline=String.Format("{0:0000}\t{1}\t{2}\t{3}\t{4}\t{5}",info.ParentNo,info.Text.Replace(vbLf,""),info.LikeCount,info.AuthorName,info.PublishedAt,info.ReplyCount)Elseline=String.Format("{0:0000}-{1:000}\t{2}\t{3}\t{4}\t{5}",info.ParentNo,info.ChildNo,info.Text.Replace(vbLf,""),info.LikeCount,info.AuthorName,info.PublishedAt)EndIfline=line.Replace("\t",vbTab)System.Diagnostics.Debug.WriteLine(line)NextMessageBox.Show("出力完了しました。")EndSub' コメント取得PublicSharedAsyncFunctionGetComment(ByValcommentListAsList(OfCommentInfo),ByValvideoIdAsString,ByValyoutubeServiceAsYouTubeService,ByValnoAsInteger,ByValnextPageTokenAsString)AsTaskDimrequest=youtubeService.CommentThreads.List("snippet")request.VideoId=videoIdrequest.Order=CommentThreadsResource.ListRequest.OrderEnum.Relevancerequest.TextFormat=CommentThreadsResource.ListRequest.TextFormatEnum.PlainTextrequest.MaxResults=100request.PageToken=nextPageTokenDimresponse=Awaitrequest.ExecuteAsync()ForEachitemInresponse.ItemsTryDiminfoAsCommentInfo=NewCommentInfo()info.ParentNo=noinfo.ChildNo=0info.Text=item.Snippet.TopLevelComment.Snippet.TextDisplayinfo.LikeCount=CLng(item.Snippet.TopLevelComment.Snippet.LikeCount)info.AuthorName=item.Snippet.TopLevelComment.Snippet.AuthorDisplayNameinfo.PublishedAt=JsonDateToDate(item.Snippet.TopLevelComment.Snippet.PublishedAt)info.ReplyCount=CLng(item.Snippet.TotalReplyCount)DimparentIdAsString=item.Snippet.TopLevelComment.IdcommentList.Add(info)Ifitem.Snippet.TotalReplyCount>0ThenAwaitGetReplyComment(commentList,youtubeService,parentId,no,1,Nothing)EndIfno+=1CatchEndTryNextIfresponse.NextPageTokenIsNotNothingThenAwaitGetComment(commentList,videoId,youtubeService,no,response.NextPageToken)EndIfEndFunction' 返信コメント取得PublicSharedAsyncFunctionGetReplyComment(ByValcommentListAsList(OfCommentInfo),ByValyoutubeServiceAsYouTubeService,ByValparentIdAsString,ByValnoAsInteger,ByValcnoAsInteger,ByValnextPageTokenAsString)AsTaskDimrequest=youtubeService.Comments.List("snippet")request.TextFormat=CommentsResource.ListRequest.TextFormatEnum.PlainTextrequest.MaxResults=50request.ParentId=parentIdrequest.PageToken=nextPageTokenDimresponse=Awaitrequest.ExecuteAsync()ForEachitemInresponse.ItemsTryDiminfoAsCommentInfo=NewCommentInfo()info.ParentNo=noinfo.ChildNo=cnoinfo.Text=item.Snippet.TextDisplayinfo.LikeCount=CLng(item.Snippet.LikeCount)info.AuthorName=item.Snippet.AuthorDisplayNameinfo.PublishedAt=JsonDateToDate(item.Snippet.PublishedAt)commentList.Add(info)cno+=1CatchEndTryNextIfresponse.NextPageTokenIsNotNothingThenAwaitGetReplyComment(commentList,youtubeService,parentId,no,cno,response.NextPageToken)EndFunction' JSON日付変換PrivateSharedFunctionJsonDateToDate(ByValdtAsString)AsDateTimeDimresultAsDateTimeDateTime.TryParse(dt,result)ReturnresultEndFunctionEndClassCSharp
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;usingSystem.Windows.Forms;usingGoogle.Apis.Services;usingGoogle.Apis.YouTube.v3;publicclassCommentInfo{publicintParentNo;publicintChildNo;publicstringText;publiclongLikeCount;publicstringAuthorName;publicDateTimePublishedAt;publiclongReplyCount;}namespaceWindowsFormsApp{publicpartialclassForm1:Form{// ここにAPI KEYを入力privateconststringAPI_KEY="(API KEYを入力)"// ここにVideo IDを入力privateconststringVIDEO_ID="(Video IDを入力)"publicForm1(){InitializeComponent();}privateasyncvoidbutton1_Click(objectsender,EventArgse){varyoutubeService=newYouTubeService(newBaseClientService.Initializer(){ApiKey=API_KEY});varvideoId=VIDEO_ID;List<CommentInfo>commentList=newList<CommentInfo>();awaitGetComment(commentList,videoId,youtubeService,1,null);foreach(varinfoincommentList){stringline;if(info.ChildNo==0)line=string.Format("{0:0000}\t{1}\t{2}\t{3}\t{4}\t{5}",info.ParentNo,info.Text.Replace("\n",""),info.LikeCount,info.AuthorName,info.PublishedAt,info.ReplyCount);elseline=string.Format("{0:0000}-{1:000}\t{2}\t{3}\t{4}\t{5}",info.ParentNo,info.ChildNo,info.Text.Replace("\n",""),info.LikeCount,info.AuthorName,info.PublishedAt);System.Diagnostics.Debug.WriteLine(line);}MessageBox.Show("出力が完了しました。");}// コメント取得staticpublicasyncTaskGetComment(List<CommentInfo>commentList,stringvideoId,YouTubeServiceyoutubeService,intno,stringnextPageToken){varrequest=youtubeService.CommentThreads.List("snippet");request.VideoId=videoId;request.Order=CommentThreadsResource.ListRequest.OrderEnum.Relevance;request.TextFormat=CommentThreadsResource.ListRequest.TextFormatEnum.PlainText;request.MaxResults=100;request.PageToken=nextPageToken;varresponse=awaitrequest.ExecuteAsync();foreach(variteminresponse.Items){try{CommentInfoinfo=newCommentInfo();info.ParentNo=no;info.ChildNo=0;info.Text=item.Snippet.TopLevelComment.Snippet.TextDisplay;info.LikeCount=(long)item.Snippet.TopLevelComment.Snippet.LikeCount;info.AuthorName=item.Snippet.TopLevelComment.Snippet.AuthorDisplayName;info.PublishedAt=JsonDateToDate(item.Snippet.TopLevelComment.Snippet.PublishedAt);info.ReplyCount=(long)item.Snippet.TotalReplyCount;stringparentId=item.Snippet.TopLevelComment.Id;commentList.Add(info);if(item.Snippet.TotalReplyCount>0)awaitGetReplyComment(commentList,youtubeService,parentId,no,1,null);no++;}catch{}}if(response.NextPageToken!=null)awaitGetComment(commentList,videoId,youtubeService,no,response.NextPageToken);}// 返信コメント取得staticpublicasyncTaskGetReplyComment(List<CommentInfo>commentList,YouTubeServiceyoutubeService,stringparentId,intno,intcno,stringnextPageToken){varrequest=youtubeService.Comments.List("snippet");request.TextFormat=CommentsResource.ListRequest.TextFormatEnum.PlainText;request.MaxResults=50;request.ParentId=parentId;request.PageToken=nextPageToken;varresponse=awaitrequest.ExecuteAsync();foreach(variteminresponse.Items){try{CommentInfoinfo=newCommentInfo();info.ParentNo=no;info.ChildNo=cno;info.Text=item.Snippet.TextDisplay;info.LikeCount=(long)item.Snippet.LikeCount;info.AuthorName=item.Snippet.AuthorDisplayName;info.PublishedAt=JsonDateToDate(item.Snippet.PublishedAt);commentList.Add(info);cno++;}catch{}}if(response.NextPageToken!=null)awaitGetReplyComment(commentList,youtubeService,parentId,no,cno,response.NextPageToken);}// JSON日付変換staticprivateDateTimeJsonDateToDate(stringdt){DateTimeresult;DateTime.TryParse(dt,outresult);returnresult;}}}実行結果
郡司りかさんを御存知でしょうか?
マツコ・デラックスさんと村上信五(関ジャニ∞)さんがMCの「月曜から夜更かし」の中で、運動音痴として注目を浴びた女性です。
郡司りかさんはYoutubeとTwitterをやられており、ツイート画像に「おはよー」を隠すという遊びをしています。
郡司りかさんのツイート画像の「おはよー」を見つける
「【NiziU】郡司さんMake You Happyにチャレンジ (練習前)」の動画コメントを取得すると、下記のようになります。
悩んだところ
出力画面に表示されない
Console.WriteLineを使用したが出力画面に何も表示されなかったので、Debug.WriteLineにしました。
WinFormだと出ないんでしたっけ。
返信コメントの取得
返信コメントは5件までだったら、item.snippet.replies.commentsの配下で取得出来るはずなんですが、駄目でした。取得できるならもう少し高速化できたんですけどね。
Google App Scriptでは取得出来るので、.NET版で取れないのかも知れません。
Google Apps ScriptとYoutubeのAPIを利用して動画のコメントを取得する
最後に
最初に C# で作成しておき、「Telerik Code Converter」のサイトでVisual Basicに変換しました。
Visual BasicからC#への変換について