web-dev-qa-db-ja.com

Mac用のExcelVBAからHTTPGETを発行するにはどうすればよいですか

Excel for Mac2011からWebサービスにクエリ文字列を含むHTTPGetを発行する必要があります。QueryTablesを使用するための回答を見てきました( HTTPを送信するにはどうすればよいですかPOST = VBAを使用してExcelからサーバーにリクエストしますか? )しかし、彼らはGETメソッドではなくPOSTメソッドを使用します。Windowsマシンからは簡単だと思いますが、私はMacで立ち往生。

何か提案がありますか、それとも絶望的ですか?

14
John Stephens

さらに調査を行ったところ、この質問に対するRobert Knightのコメントに出くわしました Office 2011 for MacのVBAシェル関数 そして彼のexecShell関数を使用してcurlを呼び出すHTTPGet関数を作成しました。 Mac OS X 10.8.3(Mountain Lion)を実行しているMacでExcel for Mac2011を使用してこれをテストしました。VBAコードは次のとおりです。

_Option Explicit

' execShell() function courtesy of Robert Knight via StackOverflow
' https://stackoverflow.com/questions/6136798/vba-Shell-function-in-office-2011-for-mac

Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As Long
Private Declare Function pclose Lib "libc.dylib" (ByVal file As Long) As Long
Private Declare Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long, ByVal items As Long, ByVal stream As Long) As Long
Private Declare Function feof Lib "libc.dylib" (ByVal file As Long) As Long

Function execShell(command As String, Optional ByRef exitCode As Long) As String
    Dim file As Long
    file = popen(command, "r")

    If file = 0 Then
        Exit Function
    End If

    While feof(file) = 0
        Dim chunk As String
        Dim read As Long
        chunk = Space(50)
        read = fread(chunk, 1, Len(chunk) - 1, file)
        If read > 0 Then
            chunk = Left$(chunk, read)
            execShell = execShell & chunk
        End If
    Wend

    exitCode = pclose(file)
End Function

Function HTTPGet(sUrl As String, sQuery As String) As String

    Dim sCmd As String
    Dim sResult As String
    Dim lExitCode As Long

    sCmd = "curl --get -d """ & sQuery & """" & " " & sUrl
    sResult = execShell(sCmd, lExitCode)

    ' ToDo check lExitCode

    HTTPGet = sResult

End Function    
_

これを使用するには、上記のコードをコピーし、Excel for Mac 2011でVBAエディターを開きます。モジュールがない場合は、[挿入]-> [モジュール]をクリックします。コードをモジュールファイルに貼り付けます。 VBAエディター(clover-Q)を終了します。

天気予報Webサービスを使用した特定の例を次に示します( http://openweathermap.org/wiki/API/JSON_API

セルA1は都市の名前のために予約されます。

セルA2に、URL文字列を入力します:_http://api.openweathermap.org/data/2.1/forecast/city_

クエリ文字列を作成するセルA3に、次のように入力します。_="q=" & A1_

セルA4に、次のように入力します。=HTTPGet(A2, A3)

ここで、セルA1に都市名を入力します(例:London)。セルA4には、ロンドンの天気予報を含むJSON応答が表示されます。 A1の値をLondonからMoscowに変更します-A4はモスクワのJSON形式の予測に変更されます。

もちろん、VBAを使用すると、JSONデータを解析して再フォーマットし、ワークシートの必要な場所に配置できます。

パフォーマンスやスケーラビリティについての主張はありませんが、Excel for Mac 2011からWebサービスへの簡単なワンショットアクセスの場合、これでうまくいくようで、元の質問を投稿したニーズに応えました。 [〜#〜] ymmv [〜#〜]

23
John Stephens

John Stephensからの上記の回答は素晴らしいですが(賛成してください!)、最近のExcel:mac 2016では機能しなくなり、64ビットシステムで使用するにはコードを更新する必要があるというエラーが発生しました。

関連するリポジトリで見つけた問題 からいくつかのヒントを得て、Excel:mac2016で正しく機能するようにJohnのスクリプトのデータ型を調整することができました。

Option Explicit

' execShell() function courtesy of Robert Knight via StackOverflow
' http://stackoverflow.com/questions/6136798/vba-Shell-function-in-office-2011-for-mac

Private Declare PtrSafe Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As LongPtr
Private Declare PtrSafe Function pclose Lib "libc.dylib" (ByVal file As LongPtr) As Long
Private Declare PtrSafe Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As LongPtr, ByVal items As LongPtr, ByVal stream As LongPtr) As Long
Private Declare PtrSafe Function feof Lib "libc.dylib" (ByVal file As LongPtr) As LongPtr

Function execShell(command As String, Optional ByRef exitCode As Long) As String
    Dim file As LongPtr
    file = popen(command, "r")

    If file = 0 Then
        Exit Function
    End If

    While feof(file) = 0
        Dim chunk As String
        Dim read As Long
        chunk = Space(50)
        read = fread(chunk, 1, Len(chunk) - 1, file)
        If read > 0 Then
            chunk = Left$(chunk, read)
            execShell = execShell & chunk
        End If
    Wend

    exitCode = pclose(file)
End Function

Function HTTPGet(sUrl As String, sQuery As String) As String

    Dim sCmd As String
    Dim sResult As String
    Dim lExitCode As Long

    sCmd = "curl --get -d """ & sQuery & """" & " " & sUrl
    sResult = execShell(sCmd, lExitCode)

    ' ToDo check lExitCode

    HTTPGet = sResult

End Function
8
Scott Dudley

別のオプション(カールが/ opt/local/bin/curlにない場合は、それに応じて更新します):

VBA:

Public Function getUrlContents(url) As String
    Dim command As String
    command = "do Shell script ""/path_to/getUrl.sh " + url + """"
    getUrlContents = VBA.MacScript(command)
End Function

/path_to/getUrl.sh:

#!/bin/sh

if [ -z "$1" ]
  then
    echo "missing url argument"
else
    /opt/local/bin/curl "$1"
fi

GetUrl.shが実行可能であることを確認する必要があることに注意してください。

chmod u+x getUrl.sh
0
mwag