Click on webpage button function doesnt work in excel macro - excel

I'm trying to create a fedex tracking automation but I'm unable to get the Track button clicked. any idea please?
Sub Fedex()
Dim IE As Object
Dim doc As HTMLDocument
Set IE = New InternetExplorerMedium
IE.Visible = True
IE.navigate "https://www.fedex.com/en-us/home.html"
Do While IE.Busy Or IE.READYSTATE = 4
Loop
Application.Wait (Now + TimeValue("0:00:07"))
Set searchbx = IE.document.getElementsByName("trackingnumber")(0)
searchbx.Value = "Howdy!"
IE.document.getElementById("btnSingleTrack").Click
End Sub

Edit - Do it direct via url parameter
You can manipulate the url you navigate. Look at the following example. Change the value of the last parameter YourTrackingNumberHere to a working tracking number and test it manually:
https://www.fedex.com/apps/fedextrack/?action=track&cntry_code=us&locale=en_US&trackingnumber=YourTrackingNumberHere
First answer to make it work in your way
The search box has events. You must trigger the change event after setting your tracking number. I never seen it before, but after triggering the change event, you must wait a few seconds to make the button click work.
Sub Fedex()
Dim ie As Object
Dim searchBox As Object
'Initialize Internet Explorer, set visibility,
'call URL and wait until page is fully loaded
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True
ie.navigate "https://www.fedex.com/en-us/home.html"
Do While ie.READYSTATE <> 4: DoEvents: Loop
Set searchBox = ie.document.getElementsByName("trackingnumber")(0)
searchBox.Value = "Howdy!"
'Trigger the change event of the input box
Call TriggerEvent(ie.document, searchBox, "change")
'I don't know why, but you have to wait a few seconds
'Otherwise the button click will not work
'In my tests, I need 5 seconds to make it work in every case
'You can make your own tests for your environment
Application.Wait (Now + TimeValue("0:00:05"))
ie.document.getElementById("btnSingleTrack").Click
End Sub
With this procedure you can trigger every event:
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

Related

input data into div on login page

https://imgur.com/a/QauSk1H
Set IE = New InternetExplorer
IE.Visible = True
IE.navigate "https://mdemo.cqg.com/cqg/desktop/logon"
Do While IE.Busy = True: DoEvents: Loop
Set HTMLDoc = IE.document
Set wpfe = HTMLDoc.getElementsByClassName("wpfe-logon-input-full wpfe-native-faded-input ng-untouched ng-pristine ng-valid")(0)
wpfe.Value = "User Login"
I'm tyring to enter login but it looks like emm... nothing good. Screens of interesting code part and error attached at the top. I hope that you might be able to help.
You want to get the first input field by the css class names "wpfe-logon-input-full wpfe-native-faded-input ng-untouched ng-pristine ng-valid". I wrote names because every string seperated by a space is an own css class name. The last css class name is not ng-valid when you load the page. It's ng-invalid. That's the reason for your error.
The solution is to use only the first css class wpfe-logon-input-full. But that's not enough to get your goal.
After the first html code was loaded and the IE reports the browser is no more busy, the IE lies to you ;-) There is dynamic content which will be load after that. So you have to wait till that's done.
But even then the login still does not work. You have to trigger two html events per input field.
This code works:
Sub Login()
Const url As String = "https://mdemo.cqg.com/cqg/desktop/logon"
Dim ie As Object
Dim HTMLDoc As Object
Dim nodeUsername As Object
Dim nodePassword As Object
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True
ie.navigate url
Do While ie.Busy = True: DoEvents: Loop
Application.Wait (Now + TimeSerial(0, 0, 5))
Set HTMLDoc = ie.document
Set nodeUsername = HTMLDoc.getElementsByClassName("wpfe-logon-input-full")(0)
Call TriggerEvent(HTMLDoc, nodeUsername, "compositionstart")
nodeUsername.Value = "TestName"
Call TriggerEvent(HTMLDoc, nodeUsername, "compositionend")
Set nodePassword = HTMLDoc.getElementsByClassName("wpfe-logon-input-full")(1)
Call TriggerEvent(HTMLDoc, nodePassword, "compositionstart")
nodePassword.Value = "TestPassword"
Call TriggerEvent(HTMLDoc, nodePassword, "compositionend")
HTMLDoc.getElementByID("login").Click
End Sub
Use this procedure to trigger html events:
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

VBA - Excel - Scraping website using IE - How to avoid forever loops when user close IE application while I'm waiting for readystate?

I'm trying to access an internal webpage that requires authentication. Once the user login in correctly, I look for an specific pattern in the application webpage and turn IE.visible = False. I've managed to make it work, but if for ever reason the user close the IE window before the authentication is completed, my macro looses control and remains waiting an answer forever.
Is there any way to prevent it from happening?
This is my code:
Sub myapplication()
Dim IE As New InternetExplorerMedium
Dim elements As MSHTML.IHTMLElementCollection: Dim element As MSHTML.IHTMLElement
Dim URL As String: Dim flag As Boolean
logindate = Format(Date, "dd mmm yyyy"): clockon = Timer: delay = 10
URL = "http://app1.htm"
IE.Visible = True: IE.navigate URL
Do While IE.readyState <> READYSTATE_COMPLETE Or IE.Busy
Loop
Set HTMLDoc = IE.document
Set elements = HTMLDoc.getElementsByClassName("normalText")
flag = False
While flag = False
For Each element In elements
If InStr(element.innerHTML, logindate) Then
IE.Visible = False: flag = True
Exit For
End If
clockoff = Timer
If delay > clockoff - clockon Then flag = True
Next
Wend
End Sub
I understand that your code launching the IE and make it visible so that the user can finish the login process and then after executing some code you make the IE visible false.
You said that if the user closes the IE window manually during the authentication then your code loses the control.
There are several approaches you can try to handle this issue.
You can try to launch the IE browser in fullscreen. So it will not show any browser window controls and close button.
Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
IE.FullScreen = True
Note that With this approach, the user can use the ALT + TAB key to switch the window, and then the user can try to close it manually.
Another thing you can try is to use the OnQuit event.
OnQuit event will get fired when the IE browser gets closed. So you can try to set the objects to Nothing on this event or take the necessary steps to reset your code. In this way, you can keep control of the code.
You can refer to the steps below to implement the OnQuit event.
Create a Class module with the name clsIE.
Add the code below in the class module.
Option Explicit
Public WithEvents IE As InternetExplorer
Private Sub Class_Initialize()
Set IE = New InternetExplorer
End Sub
Private Sub Class_Terminate()
Set IE = Nothing
End Sub
Private Sub Ie_OnQuit()
MsgBox "Closed now"
End Sub
Create a new module and add the code below in it.
Option Explicit
Dim objApp As clsIE
Sub Tester()
'// Ivan F Moala
Set objApp = New clsIE
With objApp
.IE.FullScreen = True
.IE.Visible = True
.IE.Navigate ("http://example.com")
End With
End Sub
Now if you run the module and try to close the IE browser manually then it will show a message. Further, you can try to modify the code as per your requirements.
Reference:
Code in IE's Close event

how to enter value into website inputs by excel vba

I am trying to enter a value in a website filter, I can enter the username and password in login page by using the HTML element ID, after login I want to enter a value in filter input, the filter input id is units-grid-search-filter, but it automatically changed to units -grid -search -filter,
I don't the problem is in wherein element id space or delay
this is my code.
Sub Button3_Click()
On Error GoTo Err_Clear
sURL = "http://103.215.211.2/Web/Account/Login?ReturnUrl=%2fWeb%2f#25/-3/"
Set oBrowser = New InternetExplorer
oBrowser.Silent = True
oBrowser.timeout = 60
oBrowser.Navigate sURL
oBrowser.Visible = True
Do
' Wait till the Browser is loaded
Loop Until oBrowser.readyState = READYSTATE_COMPLETE
Set HTMLdoc = oBrowser.Document
HTMLdoc.all.UserName.Value = "abc"
HTMLdoc.all.Password.Value = "abc123"
HTMLdoc.all.units -grid - Search - Filter.Value = "123"
For Each oHTML_Element In HTMLdoc.getElementsByTagName("input")
Debug.Print oHTML_Element.Name
Next
Set frm = HTMLdoc.forms(0)
frm.submit
Set IE = CreateObject("InternetExplorer.Application")
' oBrowser.Refresh ' Refresh If Needed
Do Until Not IE.Busy And IE.readyState = 4
DoEvents
Loop
e.Click
Err_Clear:
If Err <> 0 Then
Err.Clear
Resume Next
End If
End Sub
The site you are trying to automate is using knockoutjs.
The Textbox in which you are trying to set the value using your VBA code is set as observable in knockoutjs code.
If this parameter is an observable value, the binding will update the
element’s value whenever the value changes. If the parameter isn’t
observable, it will only set the element’s value once and will not
update it again later.
Whenever the user edits the value in the associated form control, KO
will update the property on your view model. KO will always attempt to
update your view model when the value has been modified and a user
transfers focus to another DOM node (i.e., on the change event), but
you can also trigger updates based on other events by using the
valueUpdate parameter described below.
Reference:
The "value" binding
Which means the value is coming from the knockoutjs model. If you modify the value manually then it will also modifies the value in model.
When you are trying to assign the value using your VBA code, no events occur and value not get updated to that model.
I tried to fire an event from VBA code. but it is not modifying the value in model. I tested with multiple JS events and it did not worked. If you try to pass the same event from your HTML code then it will give an error in VBA.
At last, I suggest you to make a test with Sendkeys.
Sendkeys is essentially the same as typing with the keyboard. You need to make sure the correct windows and objects are selecting before proceeding. Sendkeys can also trigger events that run based on user interaction on the web.
Sample code:
Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal HWND As Long) As Long
Sub demo()
Dim i As Long
Dim URL As String
Dim IE As Object
Dim HWNDSrc As Long
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
URL = "example.com"
IE.Navigate URL
Do While IE.ReadyState = 4: DoEvents: Loop
Do Until IE.ReadyState = 4: DoEvents: Loop
HWNDSrc = IE.HWND
SetForegroundWindow HWNDSrc
IE.Document.getElementById("abc").Focus
SendKeys "123", True
Set IE = Nothing
End Sub
Further, you can try to modify the code as per your requirement.

VBA to click on a button on an IE form to submit it

I'm quite new to VBA so please bear with me. I've been trying to create an automation to fill in username and password and login to a site (to start with) but I've been having trouble trying to click on the submit button. Scoured the internet and learnt a whole bunch of things but I didnt find anything that seems to work. The page loads and fills in the details and nothing happens when I run the code below.
Would greatly appreciate some help with this. Thanks in advance as always!
Sub worldcheck()
Dim lastrow As Long
Dim IE As Object
Dim cel As Range
Dim post As Object
Dim ws As Worksheet
Dim element As Object
Set ws = Sheets("sheet1")
Set IE = CreateObject("internetexplorer.application")
lastrow = ws.Range("B" & ws.Rows.Count).End(xlUp).Row
IE.Visible = True
IE.Navigate "https://www.world-check.com/frontend/login/"
Do While IE.busy
DoEvents
Loop
Application.Wait (Now + TimeValue("0:00:2"))
IE.document.getElementbyID("username").Value = ws.Range("D2")
IE.document.getElementbyID("password").Value = ws.Range("D3")
IE.document.getElementbyClass("button").click
Do While IE.busy
DoEvents
Loop
End Sub
Nothing else happens? You should be getting an error message at the very least as you are trying to use a non existent method (VBA Run-time error 438 Object doesn't support this property or method) . The method is getElementsByClassName - note the s indicating it returns a collection and the ending is ClassName. You would then need to index into that collection before attempting to access the Click method
As there is only a single element with classname button you can use a faster css class selector (this is also faster than using a type selector of form; likewise, you can use the faster css equivalent of getElementById for the other two DOM elements). document.querySelector stops at the first match so is also more efficient.
Finally, rather than hard coded waits use proper page load waits as shown below:
Option Explicit
Public Sub WorldCheck()
Dim ie As Object
Set ie = CreateObject("InternetExplorer.Application")
With ie
.Visible = True
.Navigate2 "https://www.world-check.com/frontend/login/"
While .busy Or .readystate <> 4: DoEvents: Wend
With .document
.querySelector("#username").Value = "ABCDEF" ' equivalent to .getElementbyID("username").Value = "ABCDEF"
.querySelector("#password").Value = "GHIJKL" '.getElementbyID("password").Value = "GHIJKL"
.querySelector(".button").Click
End With
While .busy Or .readystate <> 4: DoEvents: Wend
Stop '<== delete me later
.Quit
End With
End Sub

IE click on a button that has no link associated to it (using Excel VBA)

I want to click on a "button" on a web page, but my problem is that this button doesn't seem to have link attach to it. By the way I'm phrasing this you can see I'm not familiar at all with the language of web browser.
Anyway I most use internet explorer and here's the code I have so far
Sub click_button_no_hlink()
Dim i As Long
Dim IE As Object
Dim Doc As Object
Dim objElement As Object
Dim objCollection As Object
Set IE = CreateObject("InternetExplorer.Application") 'create IE instance
IE.Visible = True
IE.Navigate "https://apex.xyz.qc.ca/apex/prd1/f?p=135:LOGIN_DESKTOP::::::" ' Adress of web page
Do While IE.Busy 'loading page
Application.Wait DateAdd("s", 1, Now)
Loop
'-------------Usually I would do something like that and it would works well.-----------------
Set link = IE.document.getElementsByTagName("a")
For Each l In link
a = l.innerText
If l.innerText = "Créer" Then '
l.Click
Exit For
End If
Next
'-------------That method works fine on other type of hlink to the page by the way------------
'-----------------------I also tried various methods around this with no luck------------------------------
Set objCollection = IE.document.getElementsByClassName("rc-content-buttons") 'recherche du bouton "Créer"
'---------------------------------
'--------------------or this also doesn't work-------------------------------
For Each btn In IE.document.getElementsByClassName("rc-content-buttons")
If btn.getAttribute("id") = "B91938241817236808" Then
btn.Click
Exit For
End If
Next btn
End Sub
For sake of clarity here's the code of the web page around the "button" I'm trying to interact with.
I've made many research but I'm in a dead end right now. Any help will be greatly appreciate.
Tx in advance.
SOLVED FINAL CODE: With help from DOMENIC and QHARR and Yu Zhou
Sub click_button_no_hlink()
Dim i As Long
Dim IE As Object
Dim Doc As Object
Dim objElement As Object
Dim objCollection As Object
Set IE = CreateObject("InternetExplorer.Application") 'create IE instance
IE.Visible = True
IE.Navigate "https://apex.xyz.qc.ca/apex/prd1/f?p=135:LOGIN_DESKTOP::::::" ' Adress of web page
While IE.Busy: DoEvents: Wend 'loading page
IE.document.querySelector("[value='Créer']").FireEvent "onclick" 'works like a charm
' IE.document.querySelector("div.rc-content-buttons input").Click
'also works but speaks less by itself when reading code
' IE.document.getElementById("B91938241817236808").Click
'also works
End Sub
It is within an input not a tag element so gathering a tags will not capture what you want. Using the id, as suggested in comments is one way to go. If you get element not found then check whether your element is within a parent frame or iframe which needs to be negotiated. General syntax for that is
ie.document.getElementsByTagName("frame")(appropriateIndexHere).contentDocument.getElementById("B91938241817236808")
ie.document.getElementsByTagName("iframe")(appropriateIndexHere).contentDocument.getElementById("B91938241817236808")
If the id is dynamic you can use the value attribute
ie.document.querySelector("[value='Créer']")
ie.document.getElementsByTagName("frame")(appropriateIndexHere).contentDocument.querySelector("[value='Créer']") 'etc
As there is an event, you may need to fire it.
ie.document.querySelector("[value='Créer']").FireEvent "onclick"
ie.document.getElementsByTagName("frame")(appropriateIndexHere).contentDocument.querySelector("[value='Créer']").FireEvent "onclick" 'etc
And use a proper page load wait. So this,
Do While IE.Busy 'loading page
Application.Wait DateAdd("s", 1, Now)
Loop
Should be
While ie.Busy Or ie.ReadyState <> 4: DoEvents:Wend
getElementsByClassName returns an array-like object of all child elements which have all of the given class names, so I think it should be IE.document.getElementsByClassName("rc-content-buttons")(0).Click if it is the first element with the classname.
You could also try: IE.document.querySelector("div.rc-content-buttons input").Click.
And I think IE.document.getElementById("B91938241817236808").Click is also right.

Resources