【问题标题】:Automate IE via Excel to fill in a dropdown and continue通过 Excel 自动化 IE 以填写下拉列表并继续
【发布时间】:2020-11-27 08:06:24
【问题描述】:

诚然,仍然是通过 Excel 自动化 IE 的新手,但如果有人能提供任何帮助,我将不胜感激。基本上,这会打开一个网页,选择一个按钮,填写 2 个下拉菜单,输入一个值,然后按另一个按钮来显示我需要的内容。 我确实使用带有一堆 {Tabs}、{`}、{Down} 等的 SendKeys 来工作,但它相当笨重。 我宁愿以正确的方式这样做,但我只能进入第一个下拉菜单,选择我需要的值,然后它就会停止。我想我缺少的是告诉 IE 接受我输入的内容并继续。 编码如下。包括评论以显示它正在做什么以及它停止的位置。

Dim WebIDStr As String: WebIDStr = "CD00003630"
Dim IE As Object
WebNavStr = "https://a810-dobnow.nyc.gov/Publish/#!/"
On Error Resume Next
Set IE = Nothing
Set IE = CreateObject("InternetExplorer.Application")
With IE
    .Visible = True
    .navigate WebNavStr
    Do Until .readyState = 4: DoEvents: Loop
End With
' Won't work without a delay??
Application.Wait (Now + TimeValue("00:00:03"))
IE.document.getElementsByClassName("white ng-scope")(3).Click
' the next command works and fills-in the dropdown with the value
' that I need but then locks up. Can't move on from here.
IE.document.getElementById("DeviceOptions").selectedIndex = 4
' GOOD to HERE. Tried the next 2 lines but they don't do anything, unfortunately
IE.document.getElementById("DeviceOptions").Focus
IE.document.getElementById("DeviceOptions").Click
' This is where I need to get to. Next Dropdown Value = 1
IE.document.getElementById("craneDeviceOption").selectedIndex = 1
' Once 2nd dropdown selected, fill in "DevCraneID" box
IE.document.getElementById("DevCraneID").Value = WebIDStr
' Press the "Select" button
IE.document.getElementById("Search4")(0).Click
' IE.Quit
' Set IE = Nothing

【问题讨论】:

  • 嗨,John,我已经尝试过这种方法,但它非常脆弱,而且 IE 对象也很笨拙。我在 C# 和 HTMLAgilityPack DLL 中做这件事取得了更大的成功,它允许您以 XML 格式抓取网页、查询/填写表单、然后发布和解析结果。这与您的方法完全不同,但我希望您可以将其视为替代方法。祝你好运。
  • 我尝试了上面的示例代码并得到了与您类似的结果。根据我的测试结果,如果不使用 Sendkeys(),它似乎无法工作。因此,要使其使用 VBA 工作,您需要使用 Sendkeys()。如果您可以使用任何其他替代方案,那么我建议您查看Selenium web driver

标签: excel vba internet-explorer ie-automation


【解决方案1】:

好的,因为你写了你想了解它是如何工作的,所以我已经详细注释了整个代码。

这是工作代码:

Sub DeviceSearch()

  'Define constants
  Const url As String = "https://a810-dobnow.nyc.gov/Publish/#!/"
  
  'Declare variables
  Dim ie As Object
  Dim htmlDoc As Object
  Dim nodeDeviceTypeDropdown As Object
  Dim nodeCraneDeviceDropdown As Object
  Dim nodeCraneDeviceID As Object
  
  Dim searchTerm As String
  
  'Initialize variables
  searchTerm = "CD00003630" 'craneID
  
  'Initialize Internet Explorer, set visibility,
  'call URL and wait until page is fully loaded
  Set ie = CreateObject("InternetExplorer.Application")
  ie.Visible = True
  ie.navigate url
  Do Until ie.readyState = 4: DoEvents: Loop
  'Wait to load dynamic content after IE reports it's ready
  Application.Wait (Now + TimeSerial(0, 0, 3))
  'Shorten html document string for lazy coders ;-)
  'Seriously: You can of course also use "With ie.document"
  Set htmlDoc = ie.document
  
  'Open the Device Search section
  htmlDoc.getElementsByClassName("white ng-scope")(3).Click
  
  'Try to get the first dropdown.
  'Never use "On Error Resume Next" for the whole code.
  'We use it here because if an html id can't be found
  'a runtime error occours. But after the critical part
  'we switch the error detection back on with "On Error GoTo 0"
  '(I use this here only to show you what to do if not sure if
  'you can get an element by id. In this case it's not realy
  'requiered because we can assume the dropdown is present.)
  On Error Resume Next
  Set nodeDeviceTypeDropdown = htmlDoc.getElementById("DeviceOptions")
  On Error GoTo 0
  
  'Now we can check if the dropdown element was found
  'If an object variable has no value it is "Nothing"
  'To check if it has a value we must check if it's
  '"Not" "Nothing"
  'You can use this mechanism for every object variable
  'in VBA
  If Not nodeDeviceTypeDropdown Is Nothing Then
    'Select the wanted dropdown entry
    nodeDeviceTypeDropdown.selectedIndex = 4
    
    'To make the selection work you must trigger the
    'html change event of the dropdown
    Call TriggerEvent(htmlDoc, nodeDeviceTypeDropdown, "change")
    
    'Give time to generate the code for the second dropdown
    Application.Wait (Now + TimeSerial(0, 0, 1))
  Else
    'Dropdown not found
    MsgBox "The Dropdown for Device Search was not found"
    'Stop makro
    Exit Sub
  End If
  
  'Here we can use the second dropdown "Search Crane Device"
  'We do it from here without error handling
  Set nodeCraneDeviceDropdown = htmlDoc.getElementById("craneDeviceOption")
  'Select the wanted dropdown entry
  nodeCraneDeviceDropdown.selectedIndex = 1
  'Trigger the change event of this dropdown
  Call TriggerEvent(htmlDoc, nodeCraneDeviceDropdown, "change")
  'Give time to generate the code for the text field
  Application.Wait (Now + TimeSerial(0, 0, 1))
    
  'Now we have the text field present and can enter the search term (craneID)
  'Get the html input element
  Set nodeCraneDeviceID = htmlDoc.getElementById("DevCraneDeviceID")
  '
  'It is not enough to enter the ID. The input field also has html events
  'that must be triggered so that the entered value is not only displayed
  'but also taken over to submit.
  'We have to embed the entering of the crane id in the both events
  '"compositionstart" and "compositionend"
  Call TriggerEvent(htmlDoc, nodeCraneDeviceID, "compositionstart")
  nodeCraneDeviceID.Value = searchTerm
  Call TriggerEvent(htmlDoc, nodeCraneDeviceID, "compositionend")
  
  'Click the submit button
  htmlDoc.getElementById("search4").Click
  
  'Give time to load the result page
  Application.Wait (Now + TimeSerial(0, 0, 5))
  
  'Do here what you want with the result
  '...
End Sub

这是触发html事件的过程

Private Sub TriggerEvent(htmlDocument As Object, htmlElementWithEvent As Object, eventType As String)

  Dim theEvent As Object

  htmlElementWithEvent.Focus
  Set theEvent = htmlDocument.createEvent("HTMLEvents")
  theEvent.initEvent eventType, True, False
  htmlElementWithEvent.dispatchEvent theEvent
End Sub

这是来自 FireFox html 检查器的两个屏幕截图,其中包含元素的事件
如果您不知道需要哪些事件,您必须尝试直到它起作用;-)

页面上使用的下拉菜单的所有事件

页面上使用的输入字段的事件

【讨论】:

  • 对我的问题的回答比我预期的要详细得多,并且完美地解决了我的问题,我从您的解决方案中学到了很多东西,以后可以使用。干得好!!!
  • 这个答案太好了。它帮助我解决了我在宏中遇到的一个大问题,并且您的解决方案非常有效。此外,您已经正确解释和详细说明了所有内容。非常感谢
  • @JohnWilson 如果您的问题得到解决,我很高兴,并且总的来说,您已经了解了解决方案的工作原理,以便下次更容易找到方法。
  • @FoxfireAndBurnsAndBurns 哇!非常感谢您的认可 :-) 帮助有时有点令人沮丧,而且没有反馈。在这种情况下,John Wilson 发送了一个非常好的反馈。但是,您会为自己没有要求的答案提供赏金。我也很高兴,我的回答解决了你的问题。这就是像 SO 这样的社区应该如何运作 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-03
  • 2020-01-16
相关资源
最近更新 更多