Submitting data via IE to an online MS Form is not working

一个人想着一个人 提交于 2020-04-05 06:50:31

问题


Can anyone figure out what I am doing wrong?

When I try to submit data to an online MS Form the submission fails upon clicking the submit button because the data in the input text box disappears.

The code I am using:

Sub Hello()

    Dim objIE As Object
    Dim URL As String
    Dim doc As HTMLDocument

    Dim oServ As Object
    Dim cProc As Variant
    Dim oProc As Object

    URL = "https://forms.office.com/Pages/ResponsePage.aspx?id=1tUOxOPgeU2DDHmR8zp8jnPOq1Zxq2ZMgF9BFdtxEI9UNTJUSlpaNVU3S0pYRDI0MzE3UkZZQzdZNi4u"

    Set objIE = CreateObject("InternetExplorer.Application")
    objIE.Visible = True
    objIE.navigate URL
    Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop
    Set doc = objIE.document

    Set oServ = GetObject("winmgmts:")
    Set cProc = oServ.ExecQuery("Select * from Win32_Process")

    Dim input_text As String
    input_text = "Hello!"

    doc.getElementsByTagName("input")(0).Value = input_text
    doc.getElementsByTagName("input")(0).setAttribute("value") = input_text

    'Let us wait 5 secconds to see if the text was entered into the textbox
    Application.Wait (Now() + TimeValue("00:00:05"))

    doc.getElementsByTagName("button")(2).Click


    'Let us wait 10 secconds to see the results before terminating IE
    Application.Wait (Now() + TimeValue("00:00:10"))


    Set objIE = Nothing
    For Each oProc In cProc
      If oProc.Name = "iexplore.exe" Then
          'MsgBox "KILL"   ' used to display a message for testing pur
          oProc.Terminate  'kill exe
      End If
    Next

End Sub

回答1:


I wouldn't recommend using IE for automating VBA form submission.

Here's my experience: You spend a lot of time trying to solve this kind of 'what happened the click was supposed to work' errors. Or why did the page not load all the way errors? or how do I wait for the page to load and click what it needs.

TBS: having spent too much time trying to make this sort of thing work, and oftentimes getting a good result. I'd suggest using your DevTools (f12 in IE) while on the page. First click the button normally and see what happens. Next Click the button using JavaScript run in the console section. It'll be something very similar to your click syntax. Take note of what element is actually being clicked by using the inspector in dev tools and what script is running with the event.

IE does have ways to run the exact javascript on the page, you might need to replicate the form click event and javascript using this syntax:

 Call IE.document.parentWindow.execScript("document.all.myElement.focus();buttonMovimenti();", "JavaScript") 

Source

I've had a lot better success using execScript to trigger OnClick(); events on the page / parentwindow. Just keep in mind iFrames can be a pain to figure out which document you're selecting so be sure to inspect the source to see if there's multiple html documents on the test page.

Alternatively you could attempt to use HTTP post / get methods to submit the form with VBA's MSXML2.XMLHTTP request object, and replicating the headers / form submission that you see in DevTools under Network tab when you click the button. This would take the timing of the page loads out of the equation, and make a more streamlined submission.

EDIT EXAMPLES:

Here's the sub I used to use for this purpose of executing scripts.

Test the script in the console of IE first. In your comment you're referencing the entire minimized JS library. What you want to do is find the function from the window that does the form submission.

Public Sub RunScriptZ(IeObjectDoc As Object, sJavaScript As String)
'run any java script on a page

    Dim CurrentWindow As HTMLWindowProxy
    Set CurrentWindow = IeObjectDoc.parentWindow
    Call CurrentWindow.execScript(sJavaScript)


End Sub

Usually a form is submitted with a basic function like 'submitForm()'. So open DevTools with the page open, then go to Console, and type Document.submitForm(); in the console, and see what happens. Hopefully the form submits with this. Then you could something like:

 Call RunScriptZ(objie.Document, "submitForm()")

If this doesn't work, sometimes a site needs you to click / hover to submit the form. You can try these variations alone or combined to see if it replicates on the web page.

Idea 1, Fire Event Method

Dim ieo As New SHDocVw.InternetExplorerMedium
Set ieoDoc = ieo.Document
ieoDoc.getElementById("buttonId").FireEvent ("Onclick")

Idea 2: Basic Exec Script

Dim ieo As New SHDocVw.InternetExplorerMedium
Set ieoDoc = ieo.Document
Dim CurrentWindow As HTMLWindowProxy
Set CurrentWindow = ieoDoc.parentWindow
Call CurrentWindow.execScript("submitForm()") ''or whatever the JS function 
'name is that runs in console and triggers the event

Idea 3: test the button to see if it's clickable. sometimes web forms filled out with programming, dont register as filled in, especially if you're just assigning values. I know a lot of forms i dealt with used to require a click event on the input in order to register that a change had occurred, so check the submit button to make sure it's even clickable with this code:

Public Function TestLinkClick(linkelement As HTMLButtonElement, ForceClick 
As Boolean) As Boolean
 If ForceClick = True Then GoTo clickawaylabel

   If IsNull(linkelement.OnClick) = False Then
clickawaylabel:
    TestLinkClick = True
    Debug.Print "the link is clickable"
    Else 'the linkelement is not clickable

      TestLinkClick = False
       Debug.Print "the link is not clickable"

    End If

 End Function

Idea 4: Fill in a box

Public Sub FillInBox(TextValue As String, BoxName As String, IECVdoc As Object)

'fill in a box on a html page
Dim tries As Integer
tries = 0

On Error GoTo errorhandler

If tries >= 3 Then GoTo HappyEnd

startAgain:
With IECVdoc
    .getElementById(BoxName).Value = TextValue
    .getElementById(BoxName).FireEvent ("onchange")
End With

GoTo HappyEnd
errorhandler:

''Call a wait timer I'm using a wait sub: WaitForLoadSETx(IECVdoc, 2, 3)
tries = tries + 1
GoTo startAgain

HappyEnd:
End Sub

Idea 5: Wait for Load

Public Sub WaitForLoadSETx(ieo As Object, Maxtime As Integer, Maxtime2 As Integer)
' Wait for page to load before continuing

Dim sngTime As Single

'Const Maxtime As Integer = 5
'Const Maxtime2 As Integer = 10
    sngTime = VBA.Timer ' a snapshot of the timer at the time the subroutine starts



    ' Wait until the webpage is doing something ...                'READYSTATE_COMPLETE <<< replaced 9/16/13 to click quicker with interactive
    Do Until ieo.ReadyState <> READYSTATE_COMPLETE
        DoEvents
        If VBA.Timer > sngTime + Maxtime And VBA.Left(ieo.statusText, 4) = "Done" Then Exit Sub
        If VBA.Timer > sngTime + Maxtime2 And ieo.ReadyState = 4 Or ieo.ReadyState = "complete" Then Exit Sub 'added this to make a real max time 1-12-15 'aded OR complete 1/14/15
     '   If VBA.Left(IEo.StatusText, 4) = "" Then GoTo outloop
     Debug.Print "ONE LOOP Page Loading [" & VBA.Timer & "]/[" & sngTime + Maxtime & "]" & " [" & ieo.ReadyState & "]" & " [" & ieo.statusText & "]"  '<<<< added 1/02/14
    Loop
'outloop:
    ' ... and then wait for it to finish 'READYSTATE_INTERACTIVE  <<< replaced 9/18/13 to click quicker with interactive
    Do Until ieo.ReadyState = READYSTATE_COMPLETE
        DoEvents
        On Error GoTo 0
       ' If VBA.Timer > sngTime + Maxtime And VBA.Left(ieo.statusText, 4) = "Done" Then Exit Sub 'removed 1/14/15 because or error 438 not found on .statusText
        If VBA.Timer > sngTime + Maxtime2 And ieo.ReadyState = 4 Or ieo.ReadyState = "complete" Then Exit Sub 'added this to make a real max time 1-12-15 'aded OR complete 1/14/15
    Debug.Print "TWO LOOP Page Loading [" & VBA.Timer & "]/[" & sngTime + Maxtime & "]" & " [" & ieo.ReadyState & "]" '& " [" & 'ieo.statusText & "]" '<<<< added 1/02/14
    Loop

0:
End Sub

Best of luck!




回答2:


I tried with Sendkeys() and it solved the issue.

You need to replace these lines of code.

doc.getElementsByTagName("input")(0).Value = input_text
doc.getElementsByTagName("input")(0).setAttribute("value") = input_text

with lines of code below.

doc.getElementsByTagName("input")(0).Focus
SendKeys (input_text)

Full modified code:

Sub Hello()

    Dim objIE As Object
    Dim URL As String
    Dim doc As HTMLDocument

    Dim oServ As Object
    Dim cProc As Variant
    Dim oProc As Object

    URL = "https://forms.office.com/Pages/ResponsePage.aspx?id=1tUOxOPgeU2DDHmR8zp8jnPOq1Zxq2ZMgF9BFdtxEI9UNTJUSlpaNVU3S0pYRDI0MzE3UkZZQzdZNi4u"

    Set objIE = CreateObject("InternetExplorer.Application")
    objIE.Visible = True
    objIE.navigate URL
    Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop
    Set doc = objIE.document

    Set oServ = GetObject("winmgmts:")
    Set cProc = oServ.ExecQuery("Select * from Win32_Process")

    Dim input_text As String
    input_text = "Hello!"

   ' doc.getElementsByTagName("input")(0).Value = input_text
   ' doc.getElementsByTagName("input")(0).setAttribute("value") = input_text

   doc.getElementsByTagName("input")(0).Focus
   SendKeys (input_text)

    'Let us wait 5 secconds to see if the text was entered into the textbox
    Application.Wait (Now() + TimeValue("00:00:05"))

    doc.getElementsByTagName("button")(2).Click


    'Let us wait 10 secconds to see the results before terminating IE
    Application.Wait (Now() + TimeValue("00:00:10"))


    Set objIE = Nothing
    For Each oProc In cProc
      If oProc.Name = "iexplore.exe" Then
          'MsgBox "KILL"   ' used to display a message for testing pur
          oProc.Terminate  'kill exe
      End If
    Next

End Sub

Output:



来源:https://stackoverflow.com/questions/59721130/submitting-data-via-ie-to-an-online-ms-form-is-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!