【ExcelVBA】HTTP/HTTPS通信でWebページを取得する

# はじめに

業務でVBAのプログラムを作っていた時に、[内閣府の祝日情報](https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html)を扱いたいと思ったのですが、VBAではお手軽にHTTP/HTTPS通信出来る組み込みの関数が用意されていませんでした。
（※内閣府の祝日情報はCSV形式で提供されています。）

そこで様々なサイトを参考にしながら、HTTP/HTTPS通信でWebページを取得できるモジュール（クラス）を作成してみました。

# 作成したクラス

* VBAでHTTP通信するプログラムを作るにあたり、[こちらの記事](https://tonari-it.com/excel-vba-http-request/)を参考にしてベースのプログラムを作りました。
* また、HTTPS通信に対応させるにあたって、[こちらの記事](https://qiita.com/aratana_ogawa/items/609953a85d713759610e)を参考にしました。
  * 幾つかのサイトで紹介されていたサンプルコードには`CreateObject("MSXML2.XMLHTTP")`が使われていましたが、この書き方だとTLS1.2を利用しているページでエラーとなってしまいます。
* HTMLではなく単なるテキストファイルをDLする場合などは、レスポンスヘッダに適切な文字コードが指定されていないことがありますが、その場合は`StrConv(httpObj.responseBody, {適切な文字コード})`でコンテンツを取得してください。
  * [StrConv関数](http://officetanaka.net/excel/vba/function/StrConv.htm)
  * [データをバイト配列として取得](https://plaza.rakuten.co.jp/newwife/diary/200906100000/)
  * [バイト配列を文字列に変換](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1383024513)
  * [レスポンスヘッダに文字コードが無い場合の挙動](https://q.hatena.ne.jp/1131855304)

```vb:HttpClient.bas
Option Explicit
​'--------------------------------------------------------------------------------
' HTTP通信用クラス。
'--------------------------------------------------------------------------------
​
' HTTP通信用オブジェクト
Private httpObj As Object
​
'--------------------------------------------------------------------------------
' コンストラクタ
'--------------------------------------------------------------------------------
Public Sub Class_Initialize()
    'Set httpObj = CreateObject("MSXML2.XMLHTTP")           ' TLS1.2に非対応
    Set httpObj = CreateObject("MSXML2.ServerXMLHTTP")
End Sub
​
'--------------------------------------------------------------------------------
' デストラクタ
'--------------------------------------------------------------------------------
Public Sub Class_Terminate()
    Set httpObj = Nothing
End Sub
​
'--------------------------------------------------------------------------------
' 引数のURLをGETメソッドで取得する。
'
' url：URL文字列。
' return：取得したページ。
'--------------------------------------------------------------------------------
Public Function GetPage(url As String) As String
    httpObj.Open "GET", url
    httpObj.send

    ' readyState=4で読み込みが完了
    Do While httpObj.readyState < 4
        DoEvents
    Loop

    Dim statusCode As Integer
    statusCode = httpObj.Status
    
    ' HTTPのステータスコードが200(OK)以外であれば、ステータスコードなどを返す。
    If (statusCode = 200) Then
'        GetPage = httpObj.responseText ' レスポンスの文字コードがShift_JIS(MS932)の時はこちらを使う。
        GetPage = StrConv(httpObj.responseBody, vbUnicode)
    Else
        GetPage = "HTTP StatusCode:" & statusCode & ", HTTP StatusText:" & httpObj.statusText
    End If

End Function
```

# テストコード

```vb:TestHttpClient.bas
Option Explicit
​
'--------------------------------------------------------------------------------
' Getメソッドのテストを実行する。
'--------------------------------------------------------------------------------
Public Sub Test_GetPage()
    Dim httpObj As HttpClient
    Set httpObj = New HttpClient
    
    Dim response As String
    response = httpObj.GetPage("https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv")
    Debug.Print response
End Sub
```

* 2016年から2026年（現在年の翌年までの10年分）の祝日の情報が返されるため、実行結果を一部省略しています。

```text:実行結果
2016/3/21,休日
2016/4/29,昭和の日
2016/5/3,憲法記念日
...
2025/1/1,元日
2025/1/13,成人の日
2025/2/11,建国記念の日
2025/2/23,天皇誕生日
2025/2/24,休日
2025/3/20,春分の日
2025/4/29,昭和の日
2025/5/3,憲法記念日
2025/5/4,みどりの日
2025/5/5,こどもの日
2025/5/6,休日
2025/7/21,海の日
2025/8/11,山の日
2025/9/15,敬老の日
2025/9/23,秋分の日
2025/10/13,スポーツの日
2025/11/3,文化の日
2025/11/23,勤労感謝の日
2025/11/24,休日
...
2026/10/12,スポーツの日
2026/11/3,文化の日
2026/11/23,勤労感謝の日
```

# まとめ

* 当初はHTTPS通信に対応させる方法が分からずに四苦八苦しましたが、結果的に簡単な方法でクリアできて良かったです。
 * 中には「レジストリを書き換える」というような方法を紹介しているページもありましたが、そこで諦めずに色々調べてみて良かったです...

# その他

* VBAの組み込み関数を補うために作成した自作の関数などは、以下のページにもアップしています。
 * [【ExcelVBA】文字列操作用のユーティリティ関数を自作してみた](https://qiita.com/nkojima/items/a1702d5b0964a119c07b)
 * [【ExcelVBA】日時操作用のユーティリティ関数を自作してみた](https://qiita.com/nkojima/items/92c12c416fb6dea3e804)
 * [【ExcelVBA】ハッシュ値を取得する関数を自作してみた](https://qiita.com/nkojima/items/89d2c53d34631b33d51e)