【ExcelVBA・マクロ】WinHTTP完全ガイド|Web APIからデータ取得・REST呼び出し・JSONパース【コピペOK】

Web APIからデータ取得・REST呼び出し・JSONパース ExcelVBA

ExcelVBAからWebのAPIにアクセスして、天気予報・為替レート・社内システムのデータを自動で取得できたら、どれだけ業務が楽になるか想像してみてください。
実はVBAには標準で WinHttp.WinHttpRequest.5.1 というHTTP通信オブジェクトが搭載されており、外部ライブラリ不要でREST APIを叩けます。

この記事では、WinHTTPの基礎から実践までを一気に解説します。GET・POST・認証ヘッダー・JSONパース・エラーハンドリングまで、すべてコピペ即使えるコードで説明します。

📌 この記事で学べること

  • WinHTTPオブジェクトの取得方法(Late Binding / Early Binding)
  • GETリクエストでAPIからデータ取得
  • POSTリクエストでJSONデータを送信
  • APIキー・Bearerトークンをヘッダーに設定する方法
  • VBAで外部ライブラリ不要のJSONパース
  • タイムアウト設定・ステータスコード別エラーハンドリング
スポンサーリンク
スポンサーリンク

WinHTTPとは?VBAでHTTP通信できる理由

WinHTTP(Windows HTTP Services)は、Windowsに標準搭載されているHTTP通信ライブラリです。VBAからは WinHttp.WinHttpRequest.5.1 というProgIDで呼び出すことができます。

比較項目WinHttp.WinHttpRequest.5.1MSXML2.XMLHTTP60MSXML2.ServerXMLHTTP60
推奨度⭐⭐⭐(最推奨)⭐⭐⭐⭐
TLS1.2対応✅ 標準対応△ 設定必要な場合あり
プロキシ設定✅ 自動検出△ IEの設定を使用✅ 独立設定
用途汎用REST APIブラウザ連携系サーバーサイド
参照設定不要(Late Binding)Microsoft XML v6.0Microsoft XML v6.0

一般的なWebサービスのREST APIを叩く場合、WinHttp.WinHttpRequest.5.1 が最もシンプルで安定しています。本記事はこちらを中心に解説します。

事前準備:参照設定は不要?Late Binding vs Early Binding

VBAでWinHTTPを使う方法は2通りあります。

① Late Binding(参照設定不要・おすすめ)

最初はLate Bindingを使いましょう。参照設定なしで動き、PCの環境差異も少なく済みます。

' Late Binding:参照設定不要・どのPCでも動く
Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

② Early Binding(参照設定あり・入力補完が使える)

開発効率を上げたい場合は Early Binding を使います。VBAエディタ(VBE)のメニュー「ツール」→「参照設定」で 「Microsoft WinHTTP Services, version 5.1」 にチェックを入れてください。

' Early Binding:参照設定「Microsoft WinHTTP Services, version 5.1」が必要
' → VBEで ツール > 参照設定 > "Microsoft WinHTTP Services, version 5.1" にチェック
Dim http As WinHttp.WinHttpRequest
Set http = New WinHttp.WinHttpRequest

💡 どちらを選ぶ?
配布するマクロや社内共有ファイルには Late Binding を推奨。自分だけが使う開発中は Early Binding で補完機能を活用するのがベストです。

【基本】GETリクエストでAPIからデータを取得する

まずは最もシンプルなGETリクエストの流れを覚えましょう。下図が基本の3ステップです。

ステップコード説明
①オープン.Open "GET", URL, Falseメソッド・URL・同期/非同期を指定
②送信.Sendリクエストを送信
③レスポンス取得.ResponseText受け取った文字列(JSON等)を変数に格納

サンプルコード:JSONPlaceholderのAPIを叩いてA列に書き込む

練習に最適なのが JSONPlaceholder(無料のダミーAPI)です。https://jsonplaceholder.typicode.com/users にGETすると、ユーザー情報のJSONが返ってきます。

Sub GetAPI_Basic()
    '─────────────────────────────────────────
    ' 【基本】GETリクエストでJSONを取得してA1に表示
    '─────────────────────────────────────────
    Dim http    As Object
    Dim sUrl    As String
    Dim sRes    As String

    sUrl = "https://jsonplaceholder.typicode.com/users/1"

    ' ① WinHTTPオブジェクトを生成
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

    ' ② リクエストを開く(GET, URL, 同期=False)
    http.Open "GET", sUrl, False

    ' ③ 送信
    http.Send

    ' ④ ステータス確認
    If http.Status = 200 Then
        sRes = http.ResponseText
        Sheet1.Range("A1").Value = sRes
        MsgBox "取得成功!A1に書き込みました。", vbInformation
    Else
        MsgBox "エラー: HTTP " & http.Status & vbCrLf & http.StatusText, vbCritical
    End If

    Set http = Nothing
End Sub

▲ 実行するとA1セルにJSONが丸ごと入ります。次のセクションでJSONをパースして各列に分解する方法を解説します。

リクエストヘッダーの設定:APIキー・Bearerトークン・Content-Type

実際のAPIでは認証ヘッダーが必要なケースがほとんどです。.SetRequestHeader メソッドでヘッダーを追加します。

パターン① APIキーをヘッダーに設定する

Sub GetAPI_WithApiKey()
    Dim http  As Object
    Dim sUrl  As String

    sUrl = "https://api.example.com/data"

    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    http.Open "GET", sUrl, False

    ' ─ ヘッダー設定は Open の後・Send の前に行う ─
    http.SetRequestHeader "X-API-Key", "ここにAPIキーを貼り付ける"
    http.SetRequestHeader "Accept", "application/json"

    http.Send

    If http.Status = 200 Then
        Debug.Print http.ResponseText
    Else
        MsgBox "HTTP " & http.Status, vbCritical
    End If

    Set http = Nothing
End Sub

パターン② Bearerトークン(OAuth2)を設定する

Sub GetAPI_WithBearer()
    Dim http    As Object
    Dim sUrl    As String
    Dim sToken  As String

    sUrl   = "https://api.example.com/resource"
    sToken = "eyJhbGci..."   ' ←実際のアクセストークンを設定

    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    http.Open "GET", sUrl, False

    ' Authorization: Bearer {token} の形式で設定
    http.SetRequestHeader "Authorization", "Bearer " & sToken
    http.SetRequestHeader "Content-Type", "application/json"
    http.SetRequestHeader "Accept", "application/json"

    http.Send

    Debug.Print "Status : " & http.Status
    Debug.Print "Response: " & http.ResponseText

    Set http = Nothing
End Sub

⚠️ セキュリティ注意
APIキーやトークンをVBAコードに直書きするのは危険です。実運用ではセル参照(例:Sheet2.Range("B1").Value)や入力ダイアログInputBox)から取得する設計にしましょう。

【実践】POSTリクエストでJSONデータを送信する

フォーム送信やデータ登録にはPOSTリクエストを使います。ボディ部にJSONを入れて送信するのが現代のREST APIの標準形式です。

Sub PostAPI_JSON()
    '─────────────────────────────────────────
    ' POSTリクエスト:JSONデータを送信して結果を受け取る
    '─────────────────────────────────────────
    Dim http     As Object
    Dim sUrl     As String
    Dim sBody    As String
    Dim sRes     As String

    sUrl = "https://jsonplaceholder.typicode.com/posts"

    ' ── 送信するJSONボディを作成 ──
    ' ※実際はセルの値から組み立てる(後述のサンプル参照)
    sBody = "{""title"":""VBAからの投稿"",""body"":""WinHTTPでPOSTしました"",""userId"":1}"

    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    http.Open "POST", sUrl, False

    ' ヘッダー:Content-Typeは必須
    http.SetRequestHeader "Content-Type", "application/json; charset=UTF-8"
    http.SetRequestHeader "Accept", "application/json"

    ' Send にボディを渡す
    http.Send sBody

    ' ステータス201=作成成功
    If http.Status = 200 Or http.Status = 201 Then
        sRes = http.ResponseText
        MsgBox "POST成功!" & vbCrLf & sRes, vbInformation
    Else
        MsgBox "エラー: HTTP " & http.Status & vbCrLf & http.StatusText, vbCritical
    End If

    Set http = Nothing
End Sub

セルの値からJSONボディを組み立てる

実務ではセルの値を使ってJSONを動的に構築します。

Sub PostAPI_FromSheet()
    '─────────────────────────────────────────
    ' シートA2:C2のデータをJSONに変換してPOSTする
    ' A2=title, B2=body, C2=userId
    '─────────────────────────────────────────
    Dim http     As Object
    Dim sUrl     As String
    Dim sBody    As String
    Dim sTitle   As String
    Dim sBodyTxt As String
    Dim lUserId  As Long

    sUrl     = "https://jsonplaceholder.typicode.com/posts"
    sTitle   = Sheet1.Range("A2").Value
    sBodyTxt = Sheet1.Range("B2").Value
    lUserId  = CLng(Sheet1.Range("C2").Value)

    ' JSON文字列を組み立て(ダブルクォートは "" でエスケープ)
    sBody = "{" & _
            """title"":""" & EscapeJson(sTitle) & """," & _
            """body"":"""  & EscapeJson(sBodyTxt) & """," & _
            """userId"":"  & lUserId & _
            "}"

    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    http.Open "POST", sUrl, False
    http.SetRequestHeader "Content-Type", "application/json; charset=UTF-8"
    http.Send sBody

    Debug.Print "Status: " & http.Status
    Debug.Print http.ResponseText

    Set http = Nothing
End Sub

' ─────────────────────────────────────────────────
' 【ヘルパー関数】JSON用文字列エスケープ
' ダブルクォート・バックスラッシュ・改行コードを処理
' ─────────────────────────────────────────────────
Function EscapeJson(s As String) As String
    s = Replace(s, "\", "\\")
    s = Replace(s, """", "\""")
    s = Replace(s, Chr(13) & Chr(10), "\n")
    s = Replace(s, Chr(10), "\n")
    s = Replace(s, Chr(13), "\n")
    EscapeJson = s
End Function

タイムアウト設定:応答待ちで固まらないようにする

APIサーバーが応答しない場合、.Send のまま永遠に待ち続けてExcelが固まります。.SetTimeouts メソッドで必ず制限時間を設定しましょう。

引数意味単位推奨値
第1引数名前解決タイムアウトミリ秒5000(5秒)
第2引数接続タイムアウトミリ秒10000(10秒)
第3引数送信タイムアウトミリ秒10000(10秒)
第4引数受信タイムアウトミリ秒30000(30秒)
Sub GetAPI_WithTimeout()
    Dim http As Object
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

    ' タイムアウト設定(名前解決, 接続, 送信, 受信)単位: ミリ秒
    http.SetTimeouts 5000, 10000, 10000, 30000

    http.Open "GET", "https://jsonplaceholder.typicode.com/posts/1", False
    http.Send

    Debug.Print http.ResponseText

    Set http = Nothing
End Sub

エラーハンドリング:ステータスコード別の対処法

APIはHTTPステータスコードで結果を通知します。2xx が成功、4xx がクライアントエラー、5xx がサーバーエラーです。

ステータスコード意味対処法
200 OK取得成功正常処理
201 Created作成成功(POST)正常処理
400 Bad Requestリクエスト不正ボディ・ヘッダーを確認
401 Unauthorized認証失敗APIキー・トークンを確認
403 Forbidden権限なしアクセス権を確認
404 Not FoundURLが存在しないエンドポイントURLを確認
429 Too Many Requestsレート制限待機後リトライ
500 Internal Server Errorサーバー障害時間をおいてリトライ
Sub GetAPI_ErrorHandling()
    '─────────────────────────────────────────
    ' エラーハンドリング完全版:On Error + ステータス分岐
    '─────────────────────────────────────────
    Dim http   As Object
    Dim sUrl   As String

    sUrl = "https://jsonplaceholder.typicode.com/users/1"

    On Error GoTo ErrHandler  ' ← ネットワーク接続不可などの実行時エラーを捕捉

    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    http.SetTimeouts 5000, 10000, 10000, 30000
    http.Open "GET", sUrl, False
    http.Send

    ' ── HTTP ステータスコードで分岐 ──
    Select Case http.Status
        Case 200, 201
            ' 成功
            Debug.Print "成功: " & http.ResponseText

        Case 400
            MsgBox "400 Bad Request: リクエスト内容を確認してください。", vbCritical

        Case 401
            MsgBox "401 Unauthorized: APIキー/トークンが無効です。", vbCritical

        Case 403
            MsgBox "403 Forbidden: アクセス権がありません。", vbCritical

        Case 404
            MsgBox "404 Not Found: URLが見つかりません。" & vbCrLf & sUrl, vbCritical

        Case 429
            MsgBox "429 Too Many Requests: リクエスト制限中です。しばらく待ってから再実行してください。", vbExclamation

        Case Is >= 500
            MsgBox "5xx Server Error (" & http.Status & "): サーバー側の問題です。", vbCritical

        Case Else
            MsgBox "予期しないステータス: " & http.Status & " " & http.StatusText, vbExclamation
    End Select

    GoTo Finally

ErrHandler:
    ' ネットワーク未接続・タイムアウトなどの実行時エラー
    MsgBox "通信エラーが発生しました。" & vbCrLf & _
           "エラー番号: " & Err.Number & vbCrLf & _
           "詳細: " & Err.Description, vbCritical

Finally:
    Set http = Nothing
End Sub

【核心】JSONパース:ライブラリ不要でVBAだけで解析する

VBAにはJSONを直接扱う機能がありません。しかしInStr・Mid・Splitを使えば、外部ライブラリなしで主要な値を取り出せます。

方法① 汎用JSONパース関数(InStr + Mid)

シンプルなフラット型JSON(ネストなし)なら以下の関数で対応できます。

' ─────────────────────────────────────────────────
' 【ヘルパー関数】JSON文字列から特定キーの値を取り出す
' 対応形式: {"key":"value"} または {"key":123}
' ─────────────────────────────────────────────────
Function GetJsonValue(sJson As String, sKey As String) As String
    Dim lStart As Long
    Dim lEnd   As Long
    Dim sSearch As String

    ' キー文字列のパターン: "key":
    sSearch = """" & sKey & """:"

    lStart = InStr(sJson, sSearch)
    If lStart = 0 Then
        GetJsonValue = ""
        Exit Function
    End If

    ' キーの後ろから値を取り出す
    lStart = lStart + Len(sSearch)

    ' 値が文字列(ダブルクォートあり)か数値かを判定
    If Mid(sJson, lStart, 1) = """" Then
        ' 文字列値:次のダブルクォートまで
        lStart = lStart + 1
        lEnd = InStr(lStart, sJson, """")
        GetJsonValue = Mid(sJson, lStart, lEnd - lStart)
    Else
        ' 数値・真偽値:次の , または } まで
        lEnd = InStr(lStart, sJson, ",")
        If lEnd = 0 Then lEnd = InStr(lStart, sJson, "}")
        GetJsonValue = Trim(Mid(sJson, lStart, lEnd - lStart))
    End If
End Function

この関数を使って、先ほどのGETレスポンスから各フィールドを取り出してみましょう。

Sub GetAPI_ParseJSON()
    '─────────────────────────────────────────
    ' JSONPlaceholderのユーザー情報をパースしてシートに書き込む
    '─────────────────────────────────────────
    Dim http  As Object
    Dim sJson As String

    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    http.SetTimeouts 5000, 10000, 10000, 30000
    http.Open "GET", "https://jsonplaceholder.typicode.com/users/1", False
    http.Send

    If http.Status <> 200 Then
        MsgBox "エラー: " & http.Status, vbCritical
        Exit Sub
    End If

    sJson = http.ResponseText

    ' ── シートに書き込み ──
    With Sheet1
        .Range("A1").Value = "ID"
        .Range("B1").Value = "名前"
        .Range("C1").Value = "ユーザー名"
        .Range("D1").Value = "メール"
        .Range("E1").Value = "電話"

        .Range("A2").Value = GetJsonValue(sJson, "id")
        .Range("B2").Value = GetJsonValue(sJson, "name")
        .Range("C2").Value = GetJsonValue(sJson, "username")
        .Range("D2").Value = GetJsonValue(sJson, "email")
        .Range("E2").Value = GetJsonValue(sJson, "phone")
    End With

    MsgBox "シートに書き込みました!", vbInformation
    Set http = Nothing
End Sub

方法② JSON配列をループ処理してシート全行に書き込む

APIが配列形式[{...},{...}])を返す場合は、Splitでオブジェクト単位に分割してループ処理します。

Sub GetAPI_ParseArray()
    '─────────────────────────────────────────
    ' JSONPlaceholderのユーザー一覧(配列)を全行シートに書き込む
    '─────────────────────────────────────────
    Dim http    As Object
    Dim sJson   As String
    Dim aItems  As Variant
    Dim i       As Long
    Dim sItem   As String

    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    http.SetTimeouts 5000, 10000, 10000, 30000
    http.Open "GET", "https://jsonplaceholder.typicode.com/users", False
    http.Send

    If http.Status <> 200 Then
        MsgBox "エラー: " & http.Status, vbCritical
        Exit Sub
    End If

    sJson = http.ResponseText

    ' 配列の先頭 [ と末尾 ] を取り除く
    sJson = Mid(sJson, 2, Len(sJson) - 2)

    ' ─ オブジェクト単位に分割(区切り文字: "},{" )─
    sJson = Replace(sJson, "},{", "}|{")
    aItems = Split(sJson, "|")

    ' ── ヘッダー行 ──
    With Sheet1
        .Cells.ClearContents
        .Range("A1").Value = "ID"
        .Range("B1").Value = "名前"
        .Range("C1").Value = "ユーザー名"
        .Range("D1").Value = "メール"

        ' ── データ行ループ ──
        For i = 0 To UBound(aItems)
            sItem = aItems(i)
            .Cells(i + 2, 1).Value = GetJsonValue(sItem, "id")
            .Cells(i + 2, 2).Value = GetJsonValue(sItem, "name")
            .Cells(i + 2, 3).Value = GetJsonValue(sItem, "username")
            .Cells(i + 2, 4).Value = GetJsonValue(sItem, "email")
        Next i
    End With

    MsgBox UBound(aItems) + 1 & " 件のデータを書き込みました!", vbInformation
    Set http = Nothing
End Sub

💡 ネストが深いJSONの場合
address.cityのようなネストしたオブジェクトを取り出す場合は、まず外側のオブジェクト文字列を取り出してから再度 GetJsonValue を適用します。複雑なJSONには VBA-JSON ライブラリ(GitHub: VBA-tools/VBA-JSON)の使用も検討してください。

【実践サンプル】為替レートAPIから最新レートを取得してシートに表示

実務に近い例として、無料の為替APIからUSD/JPYレートを取得してシートに書き込むサンプルです。

使用API:Exchange Rate API(無料プラン) ※登録不要・APIキー不要

Sub GetExchangeRate()
    '─────────────────────────────────────────
    ' 【実践】USD→JPY為替レートを取得してA1に書き込む
    ' 使用API: https://open.er-api.com/v6/latest/USD
    '─────────────────────────────────────────
    Dim http    As Object
    Dim sJson   As String
    Dim sRate   As String
    Dim sDate   As String

    On Error GoTo ErrHandler

    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    http.SetTimeouts 5000, 10000, 10000, 30000
    http.Open "GET", "https://open.er-api.com/v6/latest/USD", False
    http.SetRequestHeader "Accept", "application/json"
    http.Send

    If http.Status <> 200 Then
        MsgBox "HTTP エラー: " & http.Status, vbCritical
        GoTo Finally
    End If

    sJson = http.ResponseText

    ' JPYレートを取得("JPY":xxx.xx の形式)
    sRate = GetJsonValue(sJson, "JPY")
    sDate = GetJsonValue(sJson, "time_last_update_utc")

    With Sheet1
        .Range("A1").Value = "通貨ペア"
        .Range("B1").Value = "レート"
        .Range("C1").Value = "更新日時(UTC)"
        .Range("A2").Value = "USD/JPY"
        .Range("B2").Value = CDbl(sRate)
        .Range("B2").NumberFormat = "#,##0.00"
        .Range("C2").Value = sDate
    End With

    MsgBox "USD/JPY = " & sRate & " 円", vbInformation
    GoTo Finally

ErrHandler:
    MsgBox "エラー: " & Err.Number & " " & Err.Description, vbCritical

Finally:
    Set http = Nothing
End Sub

▼ 実行するとシートに下記のように書き込まれます。

通貨ペアレート更新日時(UTC)
USD/JPY149.50Fri, 01 Mar 2026 00:02:21 +0000

よくあるエラーと対処法

エラー内容原因対処法
実行時エラー -2147012894接続タイムアウトSetTimeoutsで時間を延ばす。ネットワーク接続を確認
実行時エラー -2147012891名前解決失敗(URLが間違い)URLをブラウザで確認。スペルミス注意
HTTP 401認証失敗APIキー・Bearerトークンの値・ヘッダー名を再確認
HTTP 400リクエスト形式エラーContent-Type: application/json の設定を確認。JSON文字列の文法チェック
文字化け(レスポンス)文字コードの不一致ResponseBodyを使いADODB.Streamでデコード(後述)
GetJsonValueが空を返すキー名のスペルミス・大小文字の違いDebug.Printでsのままの ResponseText を確認してキー名を照合

文字化け対策:ADODB.Streamでレスポンスをデコードする

日本語を含むAPIレスポンスで文字化けする場合は ResponseBody プロパティと ADODB.Stream を組み合わせます。

Function GetResponseUtf8(http As Object) As String
    '─────────────────────────────────────────
    ' ResponseBodyをUTF-8としてデコードして返す
    ' ADODB.StreamはExcel標準で使用可能
    '─────────────────────────────────────────
    Dim stream As Object
    Set stream = CreateObject("ADODB.Stream")

    With stream
        .Type    = 1   ' adTypeBinary
        .Open
        .Write   http.ResponseBody
        .Position = 0
        .Type    = 2   ' adTypeText
        .Charset = "UTF-8"
        GetResponseUtf8 = .ReadText
        .Close
    End With

    Set stream = Nothing
End Function

' 呼び出し例
Sub Test_Utf8()
    Dim http As Object
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    http.Open "GET", "https://jsonplaceholder.typicode.com/users/1", False
    http.Send
    ' ResponseText の代わりにこちらを使う
    Debug.Print GetResponseUtf8(http)
    Set http = Nothing
End Sub

まとめ:WinHTTPでVBAをAPI連携の入口にしよう

この記事で学んだこと

  • CreateObject("WinHttp.WinHttpRequest.5.1") でHTTP通信オブジェクトを作成
  • Open → SetRequestHeader → Send の3ステップがREST APIの基本
  • APIキー・Bearerトークンは SetRequestHeader "Authorization", "Bearer ..." で設定
  • SetTimeouts でタイムアウトを必ず設定してExcelフリーズを防止
  • Select Case http.Status でHTTPステータスコード別にエラー処理
  • GetJsonValue 関数(InStr + Mid)でライブラリ不要のJSONパース
  • 日本語対応には ADODB.Stream でUTF-8デコード

WinHTTPを使いこなすと、天気予報・為替・社内API・Microsoft Graph APIなど、あらゆるWebサービスとExcelを繋げることができます。次は認証が必要な本格的なREST APIへの接続や、取得したデータをListObject(テーブル)に自動整形する応用にも挑戦してみましょう。

スポンサーリンク
スポンサーリンク
ExcelVBA
いがぴをフォローする

コメント

タイトルとURLをコピーしました