VBA对象variables或块variables未设置错误 – 网页抓取

所以我写了一些VBA代码来通过一个网站,我不断收到一个“对象variables或块variables没有设置错误”我通常可以通过代码没有错误,这导致我相信这是一个时间问题。 我用等待语句加载了这个代码,仍然会得到这个错误。 有什么想法吗? 我在做一些疯狂的事情吗?

Sub Do_Work_Son() Dim IE As InternetExplorer Dim doc As HTMLDocument Dim plnSelect As HTMLSelectElement 'this selects the plan Dim adrInput As HTMLInputElement 'this selects the address Dim dirSelect As HTMLSelectElement 'this selects the distance Dim strSQL As String Dim LString As String Dim LArray() As String strSQL = "http://avmed.prismisp.com/?tab=doctor" Set IE = CreateObject("InternetExplorer.Application") With IE .Visible = True .navigate strSQL Do Until .readyState = READYSTATE_COMPLETE: DoEvents: Loop Application.Wait (Now + TimeValue("0:00:5")) Set doc = IE.document 'Call WaitBrowser(IE) '----------------------------- '--Start Page Select Criteria-- '----------------------------- Set plnSelect = doc.getElementsByClassName("full jqSelectPlan")(0) plnSelect.selectedIndex = 1 Set adrInput = doc.getElementsByClassName("address-type-ahead enteredText ac_input defaultText")(0) adrInput.Value = "32258" 'this is where we will link to zip code table Set dirSelect = doc.getElementsByName("Proximity")(0) dirSelect.selectedIndex = 0 doc.getElementsByClassName("button large")(0).click 'this submits the initial page '------------------------------------------------------ 'Call WaitBrowser(IE) Application.Wait (Now + TimeValue("0:00:03")) Debug.Print (doc.getElementsByClassName("profileDetails")(0).innerText) LString = doc.getElementsByClassName("profileDetails")(0).innerText LArray = Split(LString, vbCrLf) Debug.Print (LArray(0)) Application.Wait (Now + TimeValue("0:00:2")) Sheet1.Range("A1") = LArray(0) Sheet1.Range("B1") = LArray(2) Sheet1.Range("C1") = LArray(3) Sheet1.Range("D1") = LArray(4) Sheet1.Range("E1") = LArray(5) Sheet1.Range("F1") = LArray(6) End With End Sub 

你有一个等待循环来启动网站,但不是按下button – 你只是有一个任意的时间设置 – 代码在这里抛出一个错误?

我可以推荐使用MSXML2.ServerXMLHTTP60对象发送GET / POST请求,然后parsinghtml响应,而不是自动化Internet Explorer。

通过以同步方式发送请求,它将等待请求完全完成,然后再运行代码的下一部分,这意味着您不必执行“等待循环”或设置结果的随机时间。

我知道这不是一个真正的个人问题的答案,但这可能会让你开始:

 Sub do_rework_son() Dim oHTTP As MSXML2.ServerXMLHTTP60 Dim URL As String Dim myHTMLresult As String Dim zipCODE As String Dim myREQUEST As String Set oHTTP = New MSXML2.ServerXMLHTTP60 URL = "http://avmed.prismisp.com/Search" zipCODE = "32258" myREQUEST = "SearchType=ByProvider&ProviderType=Provider&Plan=1&City=&County=&State=&Zip=&Address=" & zipCODE & "&Proximity=5&PrimaryCareProvider=true&Name=" oHTTP.Open "POST", URL, False oHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" oHTTP.send (myREQUEST) URL = "http://avmed.prismisp.com/ResetFilters" oHTTP.Open "POST", URL, False oHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" oHTTP.send (myREQUEST) oHTTP.Open "GET", "http://avmed.prismisp.com/SearchResults?PageRequested=1", False oHTTP.send myHTMLresult = oHTTP.responseText End sub 

这个网站有点有趣,需要从第一个search重新提交相同的信息(注意前两个POST请求的URL差异 – 是唯一可以访问search结果的方法)。

一旦这个search已经完成,ohttp连接仍然有效,你可以使用一个更简单的GET请求(只依赖于URL – 请求的主体string)。

GET请求可以浏览结果页面(根据需要多次更改URL到pagerequested = xyz页面,只需通过一个简单的循环或其他东西来重复这两个GET请求行,即可浏览所有页面)。

为了获得循环的限制,即结果页面的数量,它们接近html响应的底部。

这段代码将导航到该网站,提交表单,并且可以在“myREQUEST”string中replace表单的各个部分(正如我在这里用zipCODE所做的那样,这是一个variables,您可以更改x次的次数并重新提交代码循环或其他)。 这一切都是在没有互联网浏览器的背景下完成的,并且完全否定使用任何等待function。

为了parsing结果,你可以查看string操作的文本string响应或加载到一个HTML文档,你可以使用getelementsbyID等的响应

这是我为工作而创build的一个基本的“仅string”parsing器(小心查找包含引号的string)

 Sub parse_my_example_string() Dim string_to_parse As String Dim extracted_info As String string_to_parse = "<spec tag>Woah!</spec tag><class='this'>This is my result!</class><p>Chicken</p>" extracted_info = parseResult(string_to_parse, "<class='this'>", "</class>") MsgBox extracted_info extracted_info = parseResult(string_to_parse, "<spec tag>", "<") MsgBox extracted_info End Sub Function parseResult(ByRef resStr As String, ByRef schStr As String, ByRef endStr As String) Dim t1 As Integer: Dim t2 As Integer: Dim t3 As Integer If InStr(1, resStr, schStr, vbBinaryCompare) > 0 Then t1 = InStr(1, resStr, schStr, vbBinaryCompare) + Len(schStr) t2 = InStr(t1, resStr, endStr, vbBinaryCompare) t3 = t2 - t1 parseResult = Mid(resStr, t1, t3) End If End Function 

就像我在评论中提到的那样,这种做法可能被许多编码者所诟病,但是我发现它适合我的工作,特别是当xml dom文档使Excel无缘无故时!

我在这里看到一些问题。

一个是等待就绪状态完成的循环继续,并由于某种原因。 我会把这条线

 Do Until .readyState = READYSTATE_COMPLETE: DoEvents: Loop 

因为我不认为这是必要的。

您不要将Sheet1设置为任何内容,我怀疑这是代码实际上引发错误的地方。 尝试这个

 Set Sh1 = Worksheets("Sheet1") 

并使用新的参考Sh1来引用该工作表。

你在这个数组中没有7个元素

 LArray = Split(LString, vbCrLf) 

也许你永远不知道你会有多less元素。 在这种情况下,我会这样做

 For i = LBound(LArray) to UBound(LArray) Sh1.Cells(1, i+1) = LArray(i) Next i 

代替

  Sheet1.Range("A1") = LArray(0) Sheet1.Range("B1") = LArray(2) Sheet1.Range("C1") = LArray(3) Sheet1.Range("D1") = LArray(4) Sheet1.Range("E1") = LArray(5) Sheet1.Range("F1") = LArray(6) 

这是我的代码与所有上述更改完成:

 Sub Do_Work_Son() Dim strSQL As String Dim LString As String Dim LArray() As String strSQL = "http://avmed.prismisp.com/?tab=doctor" Set IE = CreateObject("InternetExplorer.Application") With IE .Visible = True .navigate strSQL 'Do Until .readyState = READYSTATE_COMPLETE: DoEvents: Loop Application.Wait (Now + TimeValue("0:00:10")) Set doc = IE.document 'Call WaitBrowser(IE) '----------------------------- '--Start Page Select Criteria-- '----------------------------- Set plnSelect = doc.getElementsByClassName("full jqSelectPlan")(0) plnSelect.selectedIndex = 1 Set adrInput = doc.getElementsByClassName("address-type-ahead enteredText ac_input defaultText")(0) adrInput.Value = "32258" 'this is where we will link to zip code table Set dirSelect = doc.getElementsByName("Proximity")(0) dirSelect.selectedIndex = 0 doc.getElementsByClassName("button large")(0).Click 'this submits the initial page '------------------------------------------------------ 'Call WaitBrowser(IE) Application.Wait (Now + TimeValue("0:00:03")) LString = doc.getElementsByClassName("profileDetails")(0).innerText LArray = Split(LString, vbCrLf) Application.Wait (Now + TimeValue("0:00:02")) Set Sh1 = Worksheets("Sheet1") For i = LBound(LArray) To UBound(LArray) Sh1.Cells(1, i + 1) = LArray(i) Next i End With End Sub 

你会注意到我的页面加载的时间比以前多一点。 5秒可能不够。 如果10是不够的,增加更多,但这似乎是一个相当快的加载页面。

希望这可以帮助。