連載第11回の目的
連載第11回では、前回の続きとしてExcel VBAにおけるYouTube APIの活用について紹介します。前回で、APIの概要を紹介し、APIキーの取得やAPI呼び出しをテストしました。今回はワークシートを準備してスクリプトを作成し、サンプルを完成させます(図1)。
▼完成サンプルのExcelファイル
https://github.com/wateryinhare62/mynavi_excelvba_webservice
なお、本連載では動作確認をWindows 10 Pro(64bit)、Microsoft 365(Excel 16.0、VBA 7.1)で行っています。旧バージョンや単体のExcelで試す場合にはご注意ください。今回はWebブラウザも使用しますが、Google Chromeに限定しています。他のWebブラウザは考慮していませんのでご注意ください。
ワークシートの準備
APIが使えることを確認できたら、ワークシートを用意し、基本的なデザインを行っていきましょう。配置および書き込むものは、以下の通りです。
- アプリケーションのタイトル(セルのテキスト)
- 「キーワード検索する」ボタン(SearchCommandButton)
- 「動画を再生する」ボタン(PlayCommandButton)
- キーワードと検索結果を収納する表(セルのテキスト)
上記のテキストおよびコントロールを、図2を参考に書き込み、配置してください。具体的な手順は、第6回などを参考にしてください。
コントロールを配置する
2つのコントロール(コマンドボタン×2)をワークシート上部に配置して、プロパティを設定します。これらのプロパティの内容は、表1のとおりです。
表1:各コントロールに設定するプロパティ
コントロール | プロパティ | 値 |
---|---|---|
「キーワード検索する」ボタン | Name | SearchCommandButton |
Caption | キーワード検索する | |
「動画を再生する」ボタン | Name | PlayCommandButton |
Caption | 動画を再生する |
キーワードと検索結果を収納する表
表は、以下の構成とします。とりあえず、10個のキーワードを登録することにします。
- 「No」(番号、プログラム上は意味はありません)
- 「キーワード」(検索する動画のキーワード)
- 「タイトル」(検索で取得した動画のタイトル)
- 「ID」(検索で取得した動画のID)
ここで、ブックを保存します。ブック名は何でもよいですが、形式を「Excel マクロ有効ブック (*.xlsm)」にしてください。マクロを有効にしておかないと、VBAのスクリプトを実行できないからです。このあとも、適当なタイミングでブックを保存してください。
ライブラリ等を準備する
スクリプトを書き始める前に、必要なライブラリ等の準備をしておきます。
VBA-JSON
Data APIは、基本的に結果をJSONデータで返します。このようにVBAからJSONデータを使いますので、そのために必要なライブラリを準備します。第3回などと同様に、「VBA-JSON」というサードパーティのライブラリを使用します。第3回の記事を参照して、「Microsoft Scripting Runtime」への参照設定を有効にすることを含めて、VBA-JSONを準備してください。
Selenium Type Library
VBAから、第10回でインストールしたSelenium Basicを利用するために、タイプライブラリである「Selenium Type Library」への参照を有効にしておきます。参照設定の方法は上記の「Microsoft Scripting Runtime」と同様です。以下の画面を参考に、有効にしてください。
[NOTE]オートメーションエラーが発生する場合
--------------------------------------------------------------------------------
Seleniumの呼び出しで、「オートメーションエラー」が発生することがあります。これは、.NET Framework 3.5がインストールされていないことが原因です。Windows 10では、.NET Framework 3.5が有効になっていないことがありますので、エラーが発生する場合には有効化してください。具体的には、スタートメニューから「設定」(歯車アイコン)を開き、[アプリ]から[プログラムと機能]をクリックします。ここから[Windowsの機能の有効化または無効化]をクリックして表示される画面で、「.NET Framework 3.5(.NET 2.0および3.0を含む)」にチェックを入れて[OK]をクリックします。これで.NET Framework 3.5が有効になります。
--------------------------------------------------------------------------------
スクリプトを書いていく
ここから、Visual Basic Editorを使って、以下の順番でスクリプトを書いていきます。左ペインの「Microsoft Excel Objects」の「Sheet1 (Sheet1)」をダブルクリックして開くファイルに、以下のスクリプトを記述していきます。
- エンドポイントURLやAPIキーの定数を定義するスクリプト
- APIにアクセスするスクリプト
- キーワードから動画名とIDを取得するスクリプト
- IDから動画を再生するスクリプト
エンドポイントURLやAPIキーの定数を定義するスクリプト
エンドポイントURLやAPIキーといった、アプリケーションの実行中に変化しない文字列は、定数として定義しておきます。なお、定数の定義とは直接の関係はないですが、安全のために冒頭でOption Explicit文によって未定義の変数を使えないようにしています(リスト1)。ApiKeyには、おのおの取得したAPIキーを設定してください。
[リスト1]エンドポイントURLやAPIキーの定数を定義
' 未定義の変数を使えないようにする
Option Explicit
' エンドポイントURLを定数で共有
Const EndPoint = "https://www.googleapis.com/youtube/v3/"
' APIキーを定数で共有
Const ApiKey = "AIzaS…"
' 作成するHTMLファイルのベース名
Const VideoFilenameBase = "video$$$.html"
APIにアクセスするスクリプト
続けて、APIにアクセスするスクリプトを書いていきます。拡張性を考慮して、APIへのアクセスは関数として独立させます。APIを呼び出すスクリプトは、KickWebServiceという関数にします。KickWebServiceは、引数にパス(APIの種類を表すエンドポイントの一部)とクエリパラメータを受け取って、結果としてのJSON文字列を返す関数です(リスト2)。
[リスト2]KickWebService関数
' APIを呼び出す(引数はAPIの種類とパラメータ、戻り値はJSON文字列)
Private Function KickWebService(ByVal Path As String, _
ByVal Param As String)
' URLを作成する
Dim Url As String
Url = EndPoint & Path & Param & "&key=" & ApiKey '(1)
' リクエストを送信する
Dim http As Object
Set http = CreateObject("MSXML2.XMLHTTP") '(2)
With http
.Open "GET", Url, False '(3)
.send
' リクエスト結果を取得する
KickWebService = .responseText '(4)
End With
End Function
変数Urlに、エンドポイント、パス、クエリパラメータ、そしてAPIキーをセットします(1)。HTTPアクセスに必要なMSXML2.XMLHTTPモジュールのオブジェクトを作成後(2)、HTTPメソッドとURLを指定してOpenメソッドを呼び出し、必要なリクエストパラメータを設定した後、sendメソッドで実際に呼び出します(3)。呼び出した結果はResponseTextプロパティで取得できます(4)。これが空なら何らかのエラーが発生していますが、これをそのまま関数の戻り値として返します。
キーワードから動画名とIDを取得するスクリプト
次に、キーワードから動画名とIDを取得するスクリプトを書いていきましょう。このスクリプトは、「キーワード検索する」ボタンをクリックした際に呼び出されるイベントハンドラとして記述します。コンボボックスにイベントハンドラを追加した要領で、イベントハンドラSearchCommandButton_Clickを作成してください(リスト3)。以下のような流れで、キーワードを検索して結果をセルに書き込んでいます。
①アクティブなセルからキーワードを取り出して空でないか判定する
③キーワードを指定してAPIを呼び出す
③結果がJSONか判定する
④JSONをディクショナリに変換する
⑤ディクショナリから必要な情報を取り出してセルに書き込む
[リスト3]キーワードから動画名とIDを取得するスクリプト
' キーワード検索ボタンを押したときの処理
Private Sub SearchCommandButton_Click()
Dim Row As Integer, Col As Integer
Row = ActiveCell.Row '(1)
Col = 2
' 動画名を取得するキーワードを取得。空なら終了
Dim Keyword As String
Keyword = Cells(Row, Col).Value '(2)
If Keyword = "" Then
Exit Sub
End If
Col = 3
' キーワードをURLエンコードしてAPIを呼び出す
Keyword = "?q=" & WorksheetFunction.EncodeURL(Keyword) _
& "®ionCode=jp&part=snippet" '(3)
Dim Result As String
Result = KickWebService("search", Keyword)
' JSONデータが戻ってこない場合は処理を終了する
If Left(Result, 1) <> "[" And Left(Result, 1) <> "{" Then '(4)
Cells(Row, Col) = "取得結果不正"
Exit Sub
End If
' JSON文字列をディクショナリ形式に変換する
Dim Json As Object
Set Json = JsonConverter.ParseJson(Result) '(5)
' kindキーが存在しなければ処理を終了する
If Json.Exists("kind") = False Then
Cells(Row, Col) = "検索キーワード取得エラー"
Exit Sub
End If
Dim Title As String, Id As String
Title = ""
Id = ""
' itemsは配列なので要素数分繰り返す(ここでは1回で終了)
Dim i As Integer
For i = 1 To Json("items").Count '(6)
Title = Json("items")(i)("snippet")("title")
Id = Json("items")(i)("id")("videoId")
Exit For
Next
Cells(Row, Col) = Title '(7)
Cells(Row, Col + 1) = Id
End Sub
(1)で、アクティブなセルの行番号を求めています。このように、キーワードの取得は、アクティブなセルのある行に対して行うことにします。続けて(2)でキーワード欄をチェックし、空であればそのまま終了します。
(3)は、キーワード欄の内容をURLエンコードしています。これは、日本語のキーワードをそのままURLに含めることはできないためです。URLエンコードには、第9回と同様にWorksheetFunctionオブジェクトのEncodeURL関数を使用しています。
Search APIを指定してAPIを呼び出し、有効なJSON文字列が返ってきていないと判断される場合には、エラーメッセージをセルに設定して終了させます(4)。有効ならば、VBA-JSONのParseJsonメソッドを使って、JSON文字列をディクショナリ形式のオブジェクトに変換します。kindキーが存在していなければ何らかのエラーが発生していますので、ここでもエラーメッセージをセルに設定して処理を終了させます(5)。
(6)からは、items配列の要素だけ繰り返しますが、最初に見つかったsnippet配下のtitleキーとid配下のvideoIdキーの値を、タイトルとIDとして取得してセルに設定します(7)。
IDから動画を再生するスクリプト
さらに、動画IDから動画を再生するスクリプトを書いていきましょう。このスクリプトは、「動画を再生する」ボタンをクリックした際に呼び出されるイベントハンドラとして記述します。コンボボックスにイベントハンドラを追加した要領で、イベントハンドラPlayCommandButton_Clickを作成してください。以下のような流れで、IDを取り出して動画を再生しています。
①アクティブなセルからIDを取り出して空でないか判定する
②IDを指定してAPIを呼び出す
③結果がJSONか判定する
④JSONをディクショナリに変換する
⑤ディクショナリから必要な情報を取り出す
⑥取得した情報をもとにHTMLファイルを作成する
⑦HTMLファイルをWebブラウザに渡して動画を再生する
少々長いので、2つに分割します。まずは、API呼び出しで情報を取得するまでです(リスト4)。
[リスト4]IDから動画を再生するスクリプト(その1)
' 再生ボタンを押したときの処理
Private Sub PlayCommandButton_Click()
Dim Row As Integer, Col As Integer
Row = ActiveCell.Row '(1)
Col = 4
' IDが空なら終了
Dim Id As String
Id = Cells(Row, Col).Value '(2)
If Id = "" Then
Exit Sub
End If
' IDから動画の詳細を得る
Dim Query As String
Query = "?id=" & Id & "&part=snippet" '(3)
Dim Result As String
Result = KickWebService("videos", Query)
' JSONデータが戻ってこない場合は処理を終了する
If Left(Result, 1) <> "[" And Left(Result, 1) <> "{" Then
MsgBox "取得結果不正"
Exit Sub
End If
' JSON文字列をディクショナリ形式に変換する
Dim Json As Object
Set Json = JsonConverter.ParseJson(Result) '(4)
' kindキーが存在しなければ処理を終了する
If Json.Exists("kind") = False Then
MsgBox "検索キーワード取得エラー"
Exit Sub
End If
Dim Title As String, Published As String, Description As String
Title = ""
Published = ""
Description = ""
' itemsは配列なので要素数分繰り返す(ここでは1回で終了)
Dim i As Integer
For i = 1 To Json("items").Count '(5)
Title = Json("items")(i)("snippet")("title")
Published = Json("items")(i)("snippet")("publishedAt")
Description = Json("items")(i)("snippet")("description")
Exit For
Next
(1)で、アクティブなセルの行番号を求めています。このように、IDの取得は、アクティブなセルのある行に対して行うことにします。続けて(2)でID欄をチェックし、空ならばそのまま終了します。
(3)は、IDから動画の情報を取得するクエリを作成しています。Videos APIを指定してAPIを呼び出し、有効なJSON文字列が返ってきていないと判断される場合には、エラーメッセージを表示して終了させます。
有効ならば、VBA-JSONのParseJsonメソッドを使って、JSON文字列をディクショナリ形式のオブジェクトに変換します。kindキーが存在しなければ何らかの問題が発生していますので、ここでもエラーメッセージを表示して処理を終了させます(4)。
(5)からは、items配列の要素だけ繰り返しますが、最初に見つかったtitleキーとsnippetキーの値から動画のタイトル、発行日時、説明を取得しておきます。
続けて、取得した情報をもとにHTMLファイルを作成し、それをWebブラウザで開いて動画を再生するまでです(リスト4)。
[リスト5]IDから動画を再生するスクリプト(その2)
' ブラウザ用にフルパスのファイル名とする
Dim Filename As String
Filename = ThisWorkbook.Path & "\" & VideoFilenameBase '(6)
' HTMLファイルを作成する
Dim fso As FileSystemObject '(7)
Set fso = New FileSystemObject
Dim ts As TextStream
Set ts = fso.OpenTextFile(Filename, ForWriting, True, TristateTrue)
ts.Write ("<!DOCTYPE html>")
ts.Write ("<html><head>")
ts.Write ("<title>" & Title & "</title>")
ts.Write ("</head><body>")
ts.Write ("<h1>" & Title & "</h1>")
ts.Write ("<h2>" & Published & "</h2>")
ts.Write ("<p>" & Description & "</p>")
ts.Write ("<iframe width=""480"" height=""270"" " _
& "src=""https://www.youtube.com/embed/" & Id & """ frameborder=""0"" " _
& "allow=""accelerometer; autoplay; clipboard-write; encrypted-media; " _
& "gyroscope; picture-in-picture"" allowfullscreen></iframe>")
ts.Write ("<div><input id=""close"" type=""checkbox""/><label for=""close"">" _
& "視聴を終了して閉じる</label></div>") '(8)
ts.Write ("</body></html>")
ts.Close
Set ts = Nothing
Set fso = Nothing
' ブラウザでHTMLを表示、チェックボックスがチェックされるまで待つ
With New ChromeDriver '(9)
.Start
.Get Filename
While .FindElementById("close").Attribute("checked") = False
Wend
.Close
End With
Kill Filename
End Sub
(6)は、ブラウザによる表示のためのHTMLファイルを作成する準備です。フルパスで、Excelブックと同じ場所の一時ファイル名を取得しています。このように動画の再生は、いったんHTMLファイルを作成し、それをWebブラウザに渡すことで実現しています。
そして、(7)からFileSystemObjectオブジェクトを使ってHTMLをファイルに書き込みます。動画の指定は、iframeタグにURLを埋め込むことで行っています。このiframeタグの形式は、Videos APIでパートにplayerを指定した際に取得できるものと同じです。これに、取得したID、タイトル、発行日時、説明を埋め込んでいます。
なお、(8)ではブラウザのウインドウを閉じる操作をユーザに委ねるため、チェックボックスを1個設けています。Seleniumでは、ブラウザオブジェクト(この場合はChromeDriverオブジェクト)が破棄されるのと同時にブラウザも閉じてしまうため、ユーザによる何らかのアクションを必要とさせるためです。
最後に(9)からは、SeleniumのChromeDriverオブジェクトを作成して、Startメソッドでブラウザを開き、Getメソッドで作成したHTMLファイルを呼び出しています。HTMLには、ブラウザを閉じるためのチェックボックスを埋め込んでありますので、これがチェックされるまでFindElementByIdメソッドで監視します。チェックされたらループを終了し、それとともにブラウザのウインドウも閉じます。
これで、スクリプトの作成は終了です。ワークシートの形を整えて冒頭の図1のようになれば完成です。キーワードをいろいろ変えて試してみてください。
まとめ
前回と今回は、YouTube APIのYouTube Data APIを使って、動画の取り扱いについて紹介しました。今回は、APIの提供する最も基本的な部分のみを使った例を紹介しましたが、取得する情報の種類を増やしたり、他のAPIを使うことで活用の幅が拡がりそうだと感じていただけたのではないでしょうか。
WINGSプロジェクト 山内直著/山田祥寛監修
<WINGSプロジェクトについて>テクニカル執筆プロジェクト(代表山田祥寛)。海外記事の翻訳から、主にWeb開発分野の書籍・雑誌/Web記事の執筆、講演等を幅広く手がける。一緒に執筆をできる有志を募集中