【问题标题】:Macro gets partial response using serverxmlhttp requests宏使用 serverxmlhttp 请求获得部分响应
【发布时间】:2021-11-24 15:06:49
【问题描述】:

我正在尝试从webpage 中提取street addressbuilder name。当我使用 xmlhttp60 请求时,我会相应地获取这些字段。但是,当我提出serverxmlhttp60 请求时,大多数时候我都会得到部分响应,因此脚本只打印street adddress。我使用json converter 从该站点的json 内容中解析出builder name

这是概念证明:

Sub GrabPropertyInfo()
    Const siteLink$ = "https://www.redfin.com/TX/Austin/604-Amesbury-Ln-78752/unit-2/home/171045975"

    Dim oPost As Object, oData As Object, Html As HTMLDocument
    Dim jsonObject As Object, jsonStr As Object, propertyMainRaw$
    Dim itemStr As Variant, sResp As String, oElem As Object
    Dim propertyContainer As Object, propertyMain As Object
    
    Set Html = New HTMLDocument
    
'    With CreateObject("MSXML2.XMLHTTP")
'        .Open "GET", siteLink, False
'        .setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"
'        .send
'        sResp = .responseText
'        Html.body.innerHTML = .responseText
'    End With
    
    With CreateObject("MSXML2.ServerXMLHTTP.6.0")
        .Open "GET", siteLink, True
        .setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"
        .send
        While .readyState < 4: DoEvents: Wend
        sResp = .responseText
        Html.body.innerHTML = .responseText
    End With

    Debug.Print "Street address: " & Html.querySelector("h1.homeAddress > .street-address").innerText
    
    With CreateObject("VBScript.RegExp")
        .Global = True
        .Pattern = "reactServerState\.InitialContext = (.*);"
        .MultiLine = True
        Set jsonStr = .Execute(sResp)
    End With
    

    itemStr = jsonStr(0).submatches(0)
    Set jsonObject = JsonConverter.ParseJson(itemStr)
    Set propertyMain = jsonObject("ReactServerAgent.cache")("dataCache")("/stingray/api/home/details/mainHouseInfoPanelInfo")("res")
    propertyMainRaw = Replace(propertyMain("text"), "{}&&", "")

    On Error Resume Next
    Set propertyContainer = JsonConverter.ParseJson(propertyMainRaw)("payload")("mainHouseInfo")("amenitiesInfo")("superGroups")
    On Error GoTo 0

    If Not propertyContainer Is Nothing Then
        For Each oElem In propertyContainer
            For Each oPost In oElem("amenityGroups")
                If InStr(oPost("groupTitle"), "Building Information") > 0 Then
                    For Each oData In oPost("amenityEntries")
                        If InStr(oData("amenityName"), "Builder Name") > 0 Then
                            Debug.Print "Builder Name: " & oData("amenityValues")(1)
                        End If
                    Next oData
                End If
            Next oPost
        Next oElem
    End If
End Sub

使用 xmlhttp 请求,我总是得到:

Street address: 604 Amesbury Ln #2,
Builder Name: Zach Savage

使用 serverxmlhttp 请求,我大部分时间得到以下结果:

Street address: 604 Amesbury Ln #2,

如何使用 serverxmlhttp 请求获得完整响应?

编辑:

根据答案和 cmets,很明显,如果我使用 xmlhttp 请求从该站点刮取 browserid 并在使用 serverxmlhttp 发送请求时使用该 browserid 的值作为 cookie,我会得到想要的结果。但是,问题是我使用xmlhttp 请求得到的browserid 的值是sz9u0xmCQKKV9Wu0jRa3Yg,而我可以在页面源中看到这个值v-J5D2IUSyqXizI7MG67fQ。我怎样才能得到后一个值?这就是我解析browserid的方式。

Sub FetchBrowserId()
    Const siteLink$ = "https://www.redfin.com/TX/Austin/604-Amesbury-Ln-78752/unit-2/home/171045975"
 
    Dim Rxp As Object, browserId As Object, sRes$, cookie$
 
    Set Rxp = CreateObject("VBScript.RegExp")
 
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", siteLink, False
        .setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36"
        .send
        sRes = .responseText
    End With
 
    With Rxp
        .Global = True
        .Pattern = "window.__rfBrowserId=""(.*?)"";"
        .MultiLine = True
        Set browserId = .Execute(sRes)
    End With
 
    cookie = browserId(0).submatches(0)
    Debug.Print cookie
End Sub

【问题讨论】:

  • xmlhttp60?如果您的意思是xmlhttp,它应该返回与ServerXMLHTTP.6.0 相同的返回值,引用'Microsoft XML,v6.0',我想。试用代码时您是否已登录?
  • 我使用的正是我在@FaneDuru 上面粘贴的代码。如您所见,我没有在脚本中使用凭据,所以我没有登录。我也没有手动登录。但是,它们(xmlhttpServerXMLHTTP)都应该返回相同的响应,但实际上并非如此。在这里你可以看到一个例外。我想知道如何解决这个问题。谢谢。
  • 当前脚本正在使用ServerXMLHTTP 请求。您可以通过取消注释上面的相关部分来使用XMLHTTP60 请求。
  • 上面的代码返回完全一样,当我测试它...当然,取消注释部分并跳过ServerXMLHTTP。我在询问有关登录的问题,因为我不知道该站点是否会在登录时公开更多内容。XMLHTTP 不关心 cookie,ServerXMLHTTP 关心,但是当我尝试解释时进行测试,它们都返回"Street address: 604 Amesbury Ln #2,"...
  • 为什么你需要来自页面源的browserid?它与 cookie 有什么关系?

标签: vba web-scraping xmlhttprequest serverxmlhttp


【解决方案1】:

所以我猜的实际问题是为什么MSXML2.XMLHTTPMSXML2.ServerXMLHTTP 对同一个 URL 的请求会返回不同的响应。

MSXML2.XMLHTTP 使用 WinINet 堆栈,MSXML2.ServerXMLHTTP 使用 WinHTTP 堆栈。查看WinINet vs. WinHTTP文章了解更多详情。

WinINet 提供完整的 cookie 处理(BTW IE 也依赖它)。因此,您有不同响应的第一个原因是发送到服务器的 cookie 可能会影响流量。它可以很容易地与 e 等任何服务进行比较。 G。 Webhook.site。当您使用 MSXML2.XMLHTTP 发出第二个请求时,网络服务会记录从第一个响应中接受的 cookie。

还要考虑 SSL 条件。通过MSXML2.XMLHTTPMSXML2.ServerXMLHTTPHow's My SSL? 发出请求,然后点击浏览器(即Chrome)中的链接并比较结果。

【讨论】:

  • 感谢您详尽的回答。在遵从@FaneDuru 的建议后,我可以发现当我使用这个cookie .setRequestHeader "Cookie", "RF_BROWSER_ID=v-J5D2IUSyqXizI7MG67fQ;" 时我得到了完整的响应。现在,我的问题是,除了对值进行硬编码之外,我可以不自动化这部分v-J5D2IUSyqXizI7MG67fQ 吗?
  • 如果 cookie 很重要并使用 MSXML2.ServerXMLHTTP,那么您必须接收、存储和发送 cookie。硬编码的 cookie 迟早会被服务器拒绝。
  • @robots.txt 您能否用新部分更新您的问题,包括您粘贴在 pastebin 上的代码和问题描述,从而使讨论保持一致并集中在一个地方。
  • 我已经编辑了问题以包括进一步的尝试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-03
  • 1970-01-01
  • 2017-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多