如何从Excel VBA for Mac发出HTTP GET

时间:2013-04-12 22:38:05

标签: excel-vba http-get excel-vba-mac vba excel

我需要从Excel for Mac 2011向Web服务发出带有查询字符串的HTTP Get。我已经看到了使用QueryTables(How can I send an HTTP POST request to a server from Excel using VBA?)的答案,但他们使用的是POST方法,而不是GET方法。我也看到从Windows机器上很容易,但我被卡在了Mac上。

有任何建议,还是没有希望?

3 个答案:

答案 0 :(得分:21)

进一步研究,我遇到了Robert Knight对这个问题VBA Shell function in Office 2011 for Mac的评论,并使用他的execShell函数构建了一个HTTPGet函数来调用curl。我在运行Mac OS X 10.8.3(Mountain Lion)的Mac上使用Excel for Mac 2011进行了测试。这是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)。

以下是使用天气预报网络服务(http://openweathermap.org/wiki/API/JSON_API

的具体示例

单元格A1将保留为城市名称。

在单元格A2中,输入网址字符串: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

答案 1 :(得分:6)

John Stephens的上述答案非常棒(请注意它!),但在最新的Excel:mac 2016中它不再适用于我,错误代码需要更新以便在64位上使用系统

an issue I found in a related repository获取一些提示,我能够调整John脚本中的数据类型,以便在Excel中正常工作:mac 2016:

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

答案 2 :(得分:0)

另一个选项(如果您的卷曲不在/ 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