访问 VBA 将值插入没有可预测元素 ID 的网络表单

Access VBA insert values into webform without predictable element id

我正在编写一个 vba 脚本,通过 IE 11 将信息从 Access 2010 数据库插入到 Web 表单中。我有 Microsoft Internet Controls、Microsoft HTML Object Library 和 Microsoft Form Library参考集。

目的是通过网络表单将付款信息从我办公室的数据库插入到客户的数据库中。我现有的代码遍历两页登录。第一页将我们验证为客户系统的适当用户。第二页要求提供有关帐户持有人的信息。第三页是我 运行 遇到问题的地方。每个账户持有人可能有多个账户。第三页是动态生成的,我不知道如何获取正确的元素 ID 并将正确的 ID 与我的数据库中的信息匹配,以便可以插入值。

例如,我的数据库将包含以下关于拥有 4 个账户的账户持有人的样本数据:

Anum        Pay
8677229     
10289183    
11981680    null
13043481    

第三页,我想在其中插入信息,输入元素如下所示:

<input name="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:0:paymentAmount" class="paymentInput" id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:0:paymentAmount" style="text-align: right;" onkeyup="handlePaymentChange(this,'13043481')" type="text">

<input name="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:1:paymentAmount" class="paymentInput" id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:1:paymentAmount" style="text-align: right;" onkeyup="handlePaymentChange(this,'10289183')" type="text">

<input name="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:2:paymentAmount" class="paymentInput" id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:2:paymentAmount" style="text-align: right;" onkeyup="handlePaymentChange(this,'8677229')" type="text">

<input name="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:paymentAmount" class="paymentInput" id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:paymentAmount" style="text-align: right;" onkeyup="handlePaymentChange(this,'11981680')" type="text">

我的数据库中的帐号(Anum)在每个输入框的 onkeyup 事件中找到。如您所见,它不是按可预测的顺序排列的。我想获取该数字并将数据库中的 Pay 值插入到相应的输入元素中。不幸的是,我不知道如何。研究了.GetElementsByName、htmlelementscollection等方法,none好像是关键。我也看了 innertext 方法,但我读了很多书后不确定如何调用它。

据我所知,VBA 如下所示。 SendKeys§ 函数是我在网上找到的 Sendkeys 的替代品,有时我会发送一个零长度的字符串作为睡眠函数的替代品:

Public Sub Login_Pay2()
'set reference to microsoft internet controls and microsoft html library
'add reference to microsft form library by browsing for FM20.dll in system32
Dim ieApp As InternetExplorer
Dim iePage As HTMLDocument
Dim ieObj As HTMLInputElement
Dim tries As Integer
Dim user As String
Dim pass As String
Dim dnumorig As String
Dim govone As String

user = "myuser"
pass = "mypass"
dnumorig = "mydnum"
govone = "mygov"

Set ieApp = New InternetExplorer
ieApp.Visible = True
ieApp.Navigate "myurl"
'wait for page to load

Do Until ieApp.ReadyState = READYSTATE_COMPLETE
Loop
Set iePage = ieApp.Document

AppActivate ("mywindow")
tries = 0
tryagain:
With ieApp
Set ieObj = iePage.getElementById("username")
If ieObj Is Nothing Then
SendKeys§ "", 750
tries = tries + 1
If tries < 5 Then
GoTo tryagain
Else
Exit Sub
End If
End If
ieObj.Value = user

Set ieObj = iePage.getElementById("password")
ieObj.Value = pass
SendKeys§ "", 40
AppActivate ("mywindow")
SendKeys§ "{TAB}", 40
AppActivate ("mywindow")
SendKeys§ "{RETURN}", 40
End With

Do Until ieApp.ReadyState = READYSTATE_COMPLETE
Loop
Set iePage = ieApp.Document

AppActivate ("mywindow")

tries = 0
tryagain2:
With ieApp
Set ieObj = iePage.getElementById("myaccountpage:manageAccountsBlock:j_id2:searchText")
If ieObj Is Nothing Then
SendKeys§ "", 750
tries = tries + 1
If tries < 5 Then
GoTo tryagain2
Else
Exit Sub
End If
End If
ieObj.Value = dnumorig

Set ieObj = iePage.getElementById("myaccountpage:manageAccountsBlock:j_id2:j_id10")
ieObj.Value = govone
AppActivate ("mywindow")
SendKeys§ "", 40
AppActivate ("mywindow")
SendKeys§ "{RETURN}", 40
End With

'??? at this point I am at page 3 and am stumped.

感谢您的耐心等待,如有任何帮助,我们将不胜感激。

编辑:

我应该注意到,我试图操作的元素位于较大代码行的末尾 - 下面的示例:

</div></td><td class="dataCell clsCenter " id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:j_id63" colspan="1">ACCOUNT TYPE</td><td class="dataCell clsCenter " id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:j_id70" colspan="1"> ,555.55</td><td class="dataCell clsCenter " id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:j_id74" colspan="1"> .55</td><td class="dataCell clsCenter " id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:j_id78" colspan="1"> 5.55</td><td class="dataCell clsCenter " id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:j_id81" colspan="1"> ,666.66</td><td class="dataCell clsCenter " id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:j_id85" colspan="1" style="min-width:195px;">$<input id="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:paymentAmount" type="text" name="myaccountpage:myAccountsBlock:accountForm:contactDisplayArea2:3:paymentAmount" class="paymentInput" onkeyup="handlePaymentChange(this,'11981680')" style="text-align:right" /></td></tr></tbody></table>

编辑 2: 太感谢了。我添加了以下代码,并在调整加载时间后添加了延迟,您的代码可以将一笔付款金额注入一个 paymentInput 元素:

Do Until ieApp.ReadyState = READYSTATE_COMPLETE
Loop
Set iePage = ieApp.Document
SendKeys§ "", 2000
AppActivate ("Case Representative - Internet Explorer")

Dim paymentInputElements As IHTMLElementCollection
Set paymentInputElements = iePage.getElementsByClassName("paymentInput")
Dim Anum As String
Anum = "10289183"
Dim pay As String
pay = "40.00"


' Assuming that the account number is in a string variable called Anum
Dim paymentInput As IHTMLElement
' Use this to check if we found the account - initializes to False
Dim bFoundAnum As Boolean
For Each paymentInput In paymentInputElements
    If (InStr(paymentInput.getAttribute("onkeyup"), Anum) > 0) Then
        ' do stuff
        bFoundAnum = True
        paymentInput.Value = pay
        Exit For
    End If
Next paymentInput

' Check we found something
If Not bFoundAnum Then
    MsgBox ("no matching anum")
End If

如果我的声誉允许,我会尝试将您的答案标记为已接受。如果你愿意继续帮助我,我在弄清楚如何从我的数据库中导出多个 Anums 和支付金额并将它们与每个匹配的 paymentInput 元素匹配时遇到了一些麻烦(每个账户持有人将有一个或多个 Anum 来申请付款).如果您对此有任何想法,我会洗耳恭听。

如果您安装了 IE9 或更高版本,则 HTMLDocument 有一个 getElementsByClassName 方法,该方法选择其 class 属性包含指定 class 的每个元素,因此:

Dim paymentInputElements As IHTMLElementCollection
Set paymentInputElements = iePage.getElementsByClassName("paymentInput")

(对于IE8,你可以通过将第二行替换为Set paymentInputElements = iePage.querySelectorAll(".paymentInput")来达到相同的结果)

我们现在可以遍历集合,直到找到相关元素:

' Assuming that the account number is in a string variable called Anum
Dim paymentInput As IHTMLElement
' Use this to check if we found the account - initializes to False
Dim bFoundAnum As Boolean
For Each paymentInput In paymentInputElements
    If (Instr(paymentInput.getAttribute("onkeyup"), Anum) > 0) Then
        ' do stuff
        bFoundAnum = True
        Exit For
    End If
Next paymentInput

' Check we found something
If Not bFoundAnum Then
    ' do something - e.g. report an error
End If

您可以使用 dictionaryquerySelector 来定位 CSS 要更新的元素。字典键 (Anum) 用于连接到 CSS 选择器以定位 input 标签,其中 onkeyup 属性的值等于键。键的关联 dictionary 值用于分配值。

Option Explicit
Public Sub MakePayments()
    Dim paymentDict As Object
    Set paymentDict = CreateObject("Scripting.Dictionary")

    paymentDict.Add 8677229, ""
    paymentDict.Add 10289183, ""
    paymentDict.Add 11981680, "null"
    paymentDict.Add 13043481, ""

    'Code to get HTMLDocument

    For Each Key In paymentDict.keys
       On Error Resume Next
       iePage.querySelector("input[onkeyup='handlePaymentChange(this,'" & Key & "')']").Value = paymentDict(Key)
      On Error GoTo 0
    Next Key
End Sub

下面是使用最后一个键 (13043481) 的 CSS 选择器示例: