Excel VBA中的WinHttpRequest仅在前面有浏览器调用时才起作用

Excel VBA中的WinHttpRequest仅在前面有浏览器调用时才起作用,excel,vba,msxml,winhttprequest,Excel,Vba,Msxml,Winhttprequest,以下URL返回美元汇率的XML: http://www.boi.org.il/currency.xml?curr=01 我需要调用并提取(通过解析结果)Excel VBA中的返回率 在浏览器中手动调用VBA后,在VBA中调用时,它可以正常工作。但是,经过一定时间后,它不再从VBA工作,除非首先在浏览器中再次手动调用。相反,它返回此字符串作为结果: <html><body><script>document.cookie='ddddddd=978a2f9dddd

以下URL返回美元汇率的XML:

http://www.boi.org.il/currency.xml?curr=01
我需要调用并提取(通过解析结果)Excel VBA中的返回率

在浏览器中手动调用VBA后,在VBA中调用时,它可以正常工作。但是,经过一定时间后,它不再从VBA工作,除非首先在浏览器中再次手动调用。相反,它返回此字符串作为结果:

<html><body><script>document.cookie='ddddddd=978a2f9dddddddd_978a2f9d; path=/';window.location.href=window.location.href;</script></body></html>

你知道为什么VBA函数一开始不起作用吗?

你可以使用MSXML2.ServerHttp60对象而不是WinHTTP,这样你就可以用它做更多的事情,包括
setTimeout
setRequestHeader
——对你来说,访问页面可能值得一试,如果你得到“Cookie”页面,解析Cookie,设置“Cookie”请求头,然后使用相同的对象重新发送GET请求。例如,关于如何设置请求标头的以下代码:

Sub tester()
Dim objCON As MSXML2.ServerXMLHTTP60
Dim URL As String
Dim MYCOOKIE As String

MYCOOKIE = "ddddddd=978a2f9dddddddd_978a2f9d" '(Parsed from first visit)

Set objCON = New MSXML2.ServerXMLHTTP60

    URL = "http://www.boi.org.il/currency.xml?curr=01"

    objCON.Open "GET", URL, False
    objCON.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
    objCON.setRequestHeader "Cookie", MYCOOKIE
    objCON.send

    MsgBox (objCON.responseText)

End Sub

您可以使用MSXML2.ServerHttp60对象而不是WinHTTP,这样您就可以用它做更多的事情,包括
setTimeOuts
setRequestHeader
——对于您来说,访问页面可能值得一试,如果您得到“Cookie”页面,解析Cookie,设置“Cookie”请求标头,然后使用同一对象重新发送GET请求。例如,关于如何设置请求标头的以下代码:

Sub tester()
Dim objCON As MSXML2.ServerXMLHTTP60
Dim URL As String
Dim MYCOOKIE As String

MYCOOKIE = "ddddddd=978a2f9dddddddd_978a2f9d" '(Parsed from first visit)

Set objCON = New MSXML2.ServerXMLHTTP60

    URL = "http://www.boi.org.il/currency.xml?curr=01"

    objCON.Open "GET", URL, False
    objCON.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
    objCON.setRequestHeader "Cookie", MYCOOKIE
    objCON.send

    MsgBox (objCON.responseText)

End Sub

利用jamheadart在初始化调用中捕获cookie的方法,我修改了该函数,以允许在后续http请求中捕获cookie并通过标头重新发送(这里我最多允许6次尝试,但通常在两次之后就解决了)

因此,工作守则是:

Function GetExchangeRate(ByVal curr As Integer, Optional ByVal exDate As Date = 0) As Single
'Finds the exchange rate for a given requested date and requested currency.
'If date is omitted, returns the most recent exchange rate available (web service behavior by design)
'If curr = 0 then return  1 = for New Shekel
'The call to the BOI service first sends a cookie, and only subsequent calls return the XML structure with the result data.
'The cookie has a timeout of several minutes. That's why, we challenge a couple of calls until the cookie string is not returned - then we extract the data from result.

    Dim strCurrCode As String
    Dim strExDate As String
    Dim strDateParamURL As String
    Dim intStartPos As Integer
    Dim intEndPos As Integer
    Dim sngRate As Single

    sngRate = -1

    On Error GoTo FailedCurr

    If (curr = 0) Then
        sngRate = 1
        GoTo CloseSub
    End If

    strDateParamURL = ""

    strCurrCode = Format(curr, "00")
    If (exDate > 0) Then
        strExDate = Format(exDate, "yyyymmdd")
        strDateParamURL = "&rdate=" & strExDate
    End If


    Dim result As String
    Dim myURL As String
    Dim winHttpReq As Object
    Dim i As Integer
    Dim strCookie As String
    Dim intTries As Integer

    Set winHttpReq = CreateObject("WinHttp.WinHttpRequest.5.1")

    myURL = "http://www.boi.org.il/currency.xml"
    myURL = myURL & "?curr=" & strCurrCode & strDateParamURL

    With winHttpReq

        .Open "GET", myURL, False
        .Send
        .waitForResponse 4000
        result = .responseText

        'Is cookie received?
        intTries = 1
        Do Until ((InStr(1, result, "cookie") = 0) Or (intTries >= MAX_HTTP_COOKIE_TRIES))

            intStartPos = InStr(1, result, "cookie") + 8
            intEndPos = InStr(1, result, ";") - 1
            strCookie = Mid(result, intStartPos, intEndPos - intStartPos + 1)

            .Open "GET", myURL, False
            .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
            .setRequestHeader "Cookie", strCookie
            .Send
            .waitForResponse 4000
            result = .responseText
            intTries = intTries + 1
        Loop

    End With

    'Extract the desired value from result
    intStartPos = InStr(1, result, "<RATE>") + 6
    intEndPos = InStr(1, result, "</RATE>") - 1

    If (intEndPos > 10) Then
        sngRate = CSng(Mid(result, intStartPos, intEndPos - intStartPos + 1))
    End If

CloseSub:
    GetExchangeRate = sngRate
    Set winHttpReq = Nothing
    Exit Function
FailedCurr:
    GoTo CloseSub
End Function
函数GetExchangeRate(ByVal curr为整数,可选ByVal exDate为Date=0)为单个 '查找给定请求日期和请求货币的汇率。 '如果省略日期,则返回最新的可用汇率(web服务行为按设计) '如果curr=0,则返回1=表示新谢克尔 '对BOI服务的调用首先发送一个cookie,只有随后的调用返回带有结果数据的XML结构。 “cookie的超时时间为几分钟。这就是为什么,我们挑战几个调用,直到cookie字符串没有返回——然后我们从结果中提取数据。 Dim strCurrCode作为字符串 像绳子一样散开 Dim strDateParamURL作为字符串 Dim intStartPos作为整数 作为整数的Dim intEndPos 单身 sngRate=-1 错误时转到FailedCurr 如果(curr=0),则 sngRate=1 后藤闭子 如果结束 strDateParamURL=“” strCurrCode=格式(当前,“00”) 如果(exDate>0),则 strExDate=格式(exDate,“yyyyymmdd”) strDateParamURL=“&rdate=“&strExDate 如果结束 将结果变暗为字符串 将myURL设置为字符串 Dim winHttpReq作为对象 作为整数的Dim i 作为字符串的暗淡strCookie 整数形式的整数 设置WinHttpRequest=CreateObject(“WinHttp.WinHttpRequest.5.1”) myURL=”http://www.boi.org.il/currency.xml" myURL=myURL&“?curr=“&strCurrCode&strDateParamURL 使用winHttpReq .打开“获取”,myURL,False .发送 .waitForResponse 4000 结果=.responseText “收到饼干了吗? 整数=1 直到((InStr(1,result,“cookie”)=0)或(inttrys>=MAX\u HTTP\u cookie\u TRIES)) intStartPos=InStr(1,结果,“cookie”)+8 intEndPos=InStr(1,结果“;”)-1 strCookie=Mid(结果,intStartPos,intEndPos-intStartPos+1) .打开“获取”,myURL,False .setRequestHeader“内容类型”、“应用程序/x-www-form-urlencoded” .setRequestHeader“Cookie”,strCookie .发送 .waitForResponse 4000 结果=.responseText 整数=整数+1 环 以 '从结果中提取所需的值 intStartPos=InStr(1,结果“”)+6 intEndPos=InStr(1,结果“”)-1 如果(intEndPos>10),则 sngRate=CSng(Mid(结果、intStartPos、intEndPos-intStartPos+1)) 如果结束 闭合接头: GetExchangeRate=snRate 设置winHttpReq=Nothing 退出功能 失效电流: 后藤闭子 端函数
利用jamheadart在初始化调用中捕获cookie的方法,我修改了函数,允许在后续http请求中捕获cookie并通过标头重新发送(这里我最多允许6次尝试,但通常在两次之后就解决了)

因此,工作守则是:

Function GetExchangeRate(ByVal curr As Integer, Optional ByVal exDate As Date = 0) As Single
'Finds the exchange rate for a given requested date and requested currency.
'If date is omitted, returns the most recent exchange rate available (web service behavior by design)
'If curr = 0 then return  1 = for New Shekel
'The call to the BOI service first sends a cookie, and only subsequent calls return the XML structure with the result data.
'The cookie has a timeout of several minutes. That's why, we challenge a couple of calls until the cookie string is not returned - then we extract the data from result.

    Dim strCurrCode As String
    Dim strExDate As String
    Dim strDateParamURL As String
    Dim intStartPos As Integer
    Dim intEndPos As Integer
    Dim sngRate As Single

    sngRate = -1

    On Error GoTo FailedCurr

    If (curr = 0) Then
        sngRate = 1
        GoTo CloseSub
    End If

    strDateParamURL = ""

    strCurrCode = Format(curr, "00")
    If (exDate > 0) Then
        strExDate = Format(exDate, "yyyymmdd")
        strDateParamURL = "&rdate=" & strExDate
    End If


    Dim result As String
    Dim myURL As String
    Dim winHttpReq As Object
    Dim i As Integer
    Dim strCookie As String
    Dim intTries As Integer

    Set winHttpReq = CreateObject("WinHttp.WinHttpRequest.5.1")

    myURL = "http://www.boi.org.il/currency.xml"
    myURL = myURL & "?curr=" & strCurrCode & strDateParamURL

    With winHttpReq

        .Open "GET", myURL, False
        .Send
        .waitForResponse 4000
        result = .responseText

        'Is cookie received?
        intTries = 1
        Do Until ((InStr(1, result, "cookie") = 0) Or (intTries >= MAX_HTTP_COOKIE_TRIES))

            intStartPos = InStr(1, result, "cookie") + 8
            intEndPos = InStr(1, result, ";") - 1
            strCookie = Mid(result, intStartPos, intEndPos - intStartPos + 1)

            .Open "GET", myURL, False
            .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
            .setRequestHeader "Cookie", strCookie
            .Send
            .waitForResponse 4000
            result = .responseText
            intTries = intTries + 1
        Loop

    End With

    'Extract the desired value from result
    intStartPos = InStr(1, result, "<RATE>") + 6
    intEndPos = InStr(1, result, "</RATE>") - 1

    If (intEndPos > 10) Then
        sngRate = CSng(Mid(result, intStartPos, intEndPos - intStartPos + 1))
    End If

CloseSub:
    GetExchangeRate = sngRate
    Set winHttpReq = Nothing
    Exit Function
FailedCurr:
    GoTo CloseSub
End Function
函数GetExchangeRate(ByVal curr为整数,可选ByVal exDate为Date=0)为单个 '查找给定请求日期和请求货币的汇率。 '如果省略日期,则返回最新的可用汇率(web服务行为按设计) '如果curr=0,则返回1=表示新谢克尔 '对BOI服务的调用首先发送一个cookie,只有随后的调用返回带有结果数据的XML结构。 “cookie的超时时间为几分钟。这就是为什么,我们挑战几个调用,直到cookie字符串没有返回——然后我们从结果中提取数据。 Dim strCurrCode作为字符串 像绳子一样散开 Dim strDateParamURL作为字符串 Dim intStartPos作为整数 作为整数的Dim intEndPos 单身 sngRate=-1 错误时转到FailedCurr 如果(curr=0),则 sngRate=1 后藤闭子 如果结束 strDateParamURL=“” strCurrCode=格式(当前,“00”) 如果(exDate>0),则 strExDate=格式(exDate,“yyyyymmdd”) strDateParamURL=“&rdate=“&strExDate 如果结束 将结果变暗为字符串 将myURL设置为字符串 Dim winHttpReq作为对象 作为整数的Dim i 作为字符串的暗淡strCookie 整数形式的整数 设置WinHttpRequest=CreateObject(“WinHttp.WinHttpRequest.5.1”) myURL=”http://www.boi.org.il/currency.xml" myURL=myURL&“?curr=“&stru