Отправка данных через IE в онлайн-форму MS не работает

Кто-нибудь может понять, что я делаю не так?

Когда я пытаюсь отправить данные в онлайн-форму MS, отправка не выполняется после нажатия кнопки отправки, потому что данные в текстовом поле ввода исчезают.

Код, который я использую:

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

2 ответа

Решение

Я бы не рекомендовал использовать IE для автоматизации отправки форм VBA.

Вот мой опыт: вы тратите много времени, пытаясь решить такого рода ошибки типа "что произошло, когда клик должен был работать". Или почему страница не загружалась полностью из-за ошибок? или как мне дождаться загрузки страницы и щелкнуть то, что ей нужно.

TBS: потратил слишком много времени, пытаясь заставить такие вещи работать, и часто получал хороший результат. Я бы предложил использовать ваши DevTools (f12 в IE) на странице. Сначала нажмите кнопку в обычном режиме и посмотрите, что произойдет. Далее Нажмите кнопку, используя запуск JavaScript в разделе консоли. Это будет что-то очень похожее на синтаксис вашего клика. Обратите внимание на то, по какому элементу на самом деле щелкают, используя инспектор в инструментах разработки, и какой скрипт выполняется с событием.

В IE есть способы запустить точный javascript на странице, вам может потребоваться реплицировать событие щелчка формы и javascript, используя этот синтаксис:

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

Источник

У меня был гораздо больший успех, когда я использовал execScript для запуска OnClick(); события на странице / родительском окне. Просто имейте в виду, что с помощью iFrames может быть сложно определить, какой документ вы выбираете, поэтому обязательно проверьте источник, чтобы увидеть, есть ли на тестовой странице несколько html-документов.

В качестве альтернативы вы можете попытаться использовать методы HTTP post / get для отправки формы с помощью объекта запроса MSXML2.XMLHTTP VBA и репликации отправки заголовков / формы, которые вы видите в DevTools на вкладке Network, когда вы нажимаете кнопку. Это позволит исключить время загрузки страницы из уравнения и упростить отправку.

ИЗМЕНИТЬ ПРИМЕРЫ:

Вот подпрограмма, которую я использовал для выполнения скриптов.

Сначала протестируйте сценарий в консоли IE. В своем комментарии вы ссылаетесь на всю свернутую библиотеку JS. Что вы хотите сделать, так это найти в окне функцию, которая выполняет отправку формы.

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

Обычно форма отправляется с помощью базовой функции, например submitForm(). Итак, откройте DevTools с открытой страницей, затем перейдите в консоль и введите Document.submitForm(); в консоли и посмотрите, что произойдет. Надеюсь, форма отправится вместе с этим. Тогда вы могли бы что-то вроде:

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

Если это не работает, иногда сайту требуется, чтобы вы щелкнули / наведите указатель мыши, чтобы отправить форму. Вы можете попробовать эти варианты по отдельности или вместе, чтобы увидеть, воспроизводится ли он на веб-странице.

Идея 1, Метод события пожара

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

Идея 2: Базовый сценарий Exec

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

Идея 3: проверьте кнопку, чтобы убедиться, что она активна. иногда веб-формы, заполненные с помощью программирования, не регистрируются как заполненные, особенно если вы просто присваиваете значения. Я знаю много форм, с которыми я имел дело, когда требовалось событие щелчка на входе, чтобы зарегистрировать, что изменение произошло, поэтому проверьте кнопку отправки, чтобы убедиться, что он даже доступен для нажатия с помощью этого кода:

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

Идея 4: заполнить рамку

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

Идея 5: дождитесь загрузки

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

Удачи!

Я пробовал использовать Sendkeys(), и это решило проблему.

Вам необходимо заменить эти строки кода.

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

со строками кода ниже.

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

Полный модифицированный код:

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

Выход:

Другие вопросы по тегам