how to enter value into website inputs by excel vba - excel

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.

Related

Login to web page and scraping data using VBA

I'm coding a macro that will load a web page, login in it and get the datas from a table.
Thanks to several topics here I've done that:
Sub sail2()
Dim ie As Object
Set ie = New(InternetExplorer.Application")
ie.Visible = True
ie.Navigate "http://pfrwtekref/websail/"
With ie
Dim oLogin As Object, oPassword As Object
Set oLogin = .document.getElementById("txtPwd")(0)
Set oPassword = .document.getElementById("txtPwd")(0)
oLogin.Value = test
oPassword.Value = test
.document.forms(0).submit
End With
End Sub
But I have two type of errors "automation error" if I launch the macro and "error 462 - server not available"
Can anyone help me ?
Thanks for reading and have a good day !
The first issue seems to be that you have a mismatched comma on the third line; however, seeing as you're are complaining about an automation error I think that may be just a typo on this site.
I can't see your internal website so I'm just guessing but I suspect the next issue is that there is no element with ID "txtPwd". You can check to confirm by pressing Ctrl-Shift-C and then selecting the username and password entry boxes.
Finally, depending on how the site is set up your .document.forms(0).submit may not work. You may need to find the ID for the submit button class submit. Below is a function I created a while back for such a task:
Function logIn(userName As String, password As String) As Boolean
'This routine logs into the grade book using given credentials
Dim ie As New InternetExplorer
Dim doc As HTMLDocument
On Error GoTo loginFail
ie.Navigate "[website here]"
'ie.Visible = True
Do While ie.ReadyState <> READYSTATE_COMPLETE Or ie.Busy: DoEvents: Loop 'Wait server to respond
Set doc = ie.Document
doc.getElementsByName("u_name").Item(0).Value = userName 'These may be different for you
doc.getElementsByName("u_pass").Item(0).Value = password
doc.getElementsByClassName("btn").Item(0).Click
Do While ie.ReadyState <> READYSTATE_COMPLETE Or ie.Busy: DoEvents: Loop 'Wait server to respond
Set doc = ie.Document
'Add a check to confirm you aren't on the same page
ie.Quit
Set ie = Nothing
LogIn = True
Exit Function
loginFail:
MsgBox "There was an issue logging in. Please try again."
logIntoGradeBook = False
End Function
Note that the site I was dealing with was set up poorly and so I needed to switch to GetElementsByName and GetElementsByClassName to get access to what I needed. You may be fine with IDs.
Why don't you try to use the Excel PowerQuery to get your data from the tables you need? When your desired columns are done, you just click in close and load, select data model e now you can use a macro to perform a PivotTable whenever you load the document or just use a PivotTable and the data will be refreshed when you use the refresh data in data ribbon.

Click on webpage button function doesnt work in excel macro

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

Excel VBA - Web Scraping - Get value in HTML Table cell

I am trying to create a macro that scrapes a cargo tracking website.
But I have to create 4 such macros as each airline has a different website.
I am new to VBA and web scraping.
I have put together a code that works for 1 website. But when I tried to replicate it for another one, I am stuck in the loop. I think it maybe how I am referring to the element, but like I said, I am new to VBA and have no clue about HTML.
I am trying to get the "notified" value in the highlighted line from the image.
IMAGE:"notified" text to be extracted
Below is the code I have written so far that gets stuck in the loop.
Any help with this would be appreciated.
Sub FlightStat_AF()
Dim url As String
Dim ie As Object
Dim nodeTable As Object
'You can handle the parameters id and pfx in a loop to scrape dynamic numbers
url = "https://www.afklcargo.com/mycargo/shipment/detail/057-92366691"
'Initialize Internet Explorer, set visibility,
'call URL and wait until page is fully loaded
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = False
ie.navigate url
Do Until ie.readyState = 4: DoEvents: Loop
'Wait to load dynamic content after IE reports it's ready
'We can do that in a loop to match the point the information is available
Do
On Error Resume Next
Set nodeTable = ie.document.getElementByClassName("block-whisper")
On Error GoTo 0
Loop Until Not nodeTable Is Nothing
'Get the status from the table
MsgBox Trim(nodeTable.getElementsByClassName("fs-12 body-font-bold").innerText)
'Clean up
ie.Quit
Set ie = Nothing
Set nodeTable = Nothing
End Sub
Some basics:
For simple accesses, like the present ones, you can use the get methods of the DOM (Document Object Model). But there is an important difference between getElementByID() and getElementsByClassName() / getElementsByTagName().
getElementByID() searches for the unique ID of a html tag. This is written as the ID attribute to html tags. If the html standard is kept by the page, there is only one element with this unique ID. That's the reason why the method begins with getElement.
If the ID is not found when using the method, VBA throws a runtime error. Therefore the call is encapsulated in the loop from the other answer from me, into switching off and on again the error handling. But in the page from this question there is no ID for the html area in question.
Instead, the required element can be accessed directly. You tried the access with getElementsByClassName(). That's right. But here comes the difference to getElementByID().
getElementsByClassName() and getElementsByTagName() begin with getElements. Thats plural because there can be as many elements with the same class or tag name as you want. This both methods create a html node collection. All html elements with the asked class or tag name will be listet in those collections.
All elements have an index, just like an array. The indexes start at 0. To access a particular element, the desired index must be specified. The two class names fs-12 body-font-bold (class names are seperated by spaces, you can also build a node collection by using only one class name) deliver 2 html elements to the node collection. You want the second one so you must use the index 1.
This is the VBA code for the asked page by using the IE:
Sub FlightStat_AF()
Dim url As String
Dim ie As Object
'You can handle the parameters id and pfx in a loop to scrape dynamic numbers
url = "https://www.afklcargo.com/mycargo/shipment/detail/057-92366691"
'Initialize Internet Explorer, set visibility,
'call URL and wait until page is fully loaded
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = False
ie.navigate url
Do Until ie.readyState = 4: DoEvents: Loop
'Wait to load dynamic content after IE reports it's ready
'We do that with a fix manual break of a few seconds
'because the whole page will be "reload"
'The last three values are hours, minutes, seconds
Application.Wait (Now + TimeSerial(0, 0, 3))
'Get the status from the table
MsgBox Trim(ie.document.getElementsByClassName("fs-12 body-font-bold")(1).innerText)
'Clean up
ie.Quit
Set ie = Nothing
End Sub
Edit: Sub as function
This sub to test the function:
Sub testFunction()
Dim flightStatAfResult As String
flightStatAfResult = FlightStat_AF("057-92366691")
MsgBox flightStatAfResult
End Sub
This is the sub as function:
Function FlightStat_AF(cargoNo As String) As String
Dim url As String
Dim ie As Object
Dim result As String
'You can handle the parameters id and pfx in a loop to scrape dynamic numbers
url = "https://www.afklcargo.com/mycargo/shipment/detail/" & cargoNo
'Initialize Internet Explorer, set visibility,
'call URL and wait until page is fully loaded
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = False
ie.navigate url
Do Until ie.readyState = 4: DoEvents: Loop
'Wait to load dynamic content after IE reports it's ready
'We do that with a fix manual break of a few seconds
'because the whole page will be "reload"
'The last three values are hours, minutes, seconds
Application.Wait (Now + TimeSerial(0, 0, 3))
'Get the status from the table
result = Trim(ie.document.getElementsByClassName("fs-12 body-font-bold")(1).innerText)
'Clean up
ie.Quit
Set ie = Nothing
'Return value of the function
FlightStat_AF = result
End Function

Automate IE via Excel to fill in a dropdown and continue

Admittedly still a newbie with automating IE via Excel but would appreciate whatever help anyone can offer with this. Basically, this opens up a webpage, selects a button, fills in 2 dropdowns, enters a value and then presses another button to display what I need.
I do have this working using SendKeys with a bunch of {Tabs}, {`}, {Down}, etc but it's rather clunky.
I'd rather do this the right way but I can only get to the 1st dropdown, select the value that I need and then it stops. What I'm missing, I guess, is telling IE to accept what I've entered and continue on.
Coding is below. Comments included to show what it's doing and where it stops.
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
Ok, because you wrote you want to understand how it works I have commented the whole code by detail.
This is the working code:
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
This is the 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
Here are two screenshots from FireFox html inspector with the events of the elements
If you don't know which event(s) are needed you must try till it works ;-)
All events for the used dropdowns on the page
The events for the used input field on the page

How to automate a dynamically changing web page url and autofill using Excel VBA?

How to automate a dynamically changing web page url and autofill using Excel VBA?
Your question is a light on the details, but from what I understand your code is working, but you are wanting to grab a new tab that opens up after your code completes.
You can do this with a function I have and use somewhat regularly. This will look at the URLs in your open browser (whether the browser is hidden or not) and allow you to set your object declaration to the tab containing your url.
Warning: Just as JohnRC stated in his comment, automatic manipulation of web pages handling financial transactions is ill-advised. An error in your coding can produce unexpected results. I do not personally recommend automation of financial transactions and any advice you take out of this you do so at your own risk.
Function:
Function GetIE(sLocation As String) As Object
Dim objShell As Object, objShellWindows As Object, o As Object
Dim sURL As String
Dim RetVal As Object
Set RetVal = Nothing
Set objShell = CreateObject("shell.application")
Set objShellWindows = objShell.Windows
For Each o In objShellWindows
sURL = ""
On Error Resume Next
'check the URL and if it's the one you want then
'assign it to the return value and exit the loop
sURL = o.document.Location
On Error GoTo 0
If sURL Like sLocation Then
Set RetVal = o
Exit For
End If
Next o
Set GetIE = RetVal
End Function
In your below code, you are now setting ie2 as the new webpage, with the URL string "*bildesk.com/id*". Once you accomplish this, you can manipulate ie2 just as you did with your first IE object.
Sub SearchBot()
'dimension (declare or set aside memory for) our variables
Dim IE As InternetExplorer 'special object variable representing the IE browser
Dim aEle As HTMLLinkElement 'special object variable for an <a> (link) element
Dim y As Integer 'integer variable we'll use as a counter
Dim result As String 'string variable that will hold our result link
'initiating a new instance of Internet Explorer and asigning it to objIE
Set IE = New InternetExplorer
Dim iedoc As Object
'navigate IE to this web page (a pretty neat search engine really)
IE.navigate "https://www.nbpdcl.co.in/(S(qq5avnlkl4xr2iqstldu0ehl))/frmQuickBillPaymentAll.aspx"
'wait here a few seconds while the browser is busy
Do Until IE.readyState = READYSTATE_COMPLETE: DoEvents: Loop
'in the search box put cell "A2" value
IE.document.getElementById("MainContent_txtCANO").Value = _
Sheets("Sheet1").Range("A2").Value
'click the 'go' button
IE.document.getElementById("MainContent_btnSubmit").Click
'wait here a few seconds while the browser is busy
Do While IE.Busy = True Or IE.readyState <> 4: DoEvents: Loop
'in the amount box put cell "B2" value
IE.document.getElementById("MainContent_txtAmountPayable").Value = _
Sheets("Sheet1").Range("B2").Value
'in the EMAIL box put cell "C2" value
IE.document.getElementById("txtEmailId").Value = _
Sheets("Sheet1").Range("C2").Value
'in the PHONE box put cell "D2" value
IE.document.getElementById("txtMobileNo").Value = _
Sheets("Sheet1").Range("D2").Value
'click the 'verify' button
IE.document.getElementById("MainContent_rbtnlstPaymode_0").Checked = True
'click the 'verify' button
IE.document.getElementById("MainContent_btnConfirmPay").Click
'wait here a few seconds while the browser is busy
Do While IE.Busy = True Or IE.readyState <> 4: DoEvents: Loop
'click the 'verify' button
IE.document.getElementById("MainContent_btnPayNow").Click
'<--------- Use the function here ---------->
Dim ie2 As InternetExplorer
Set ie2 = GetIE("*bildesk.com/id*")
End Sub
So just include the function provided with your module and you should be set.

Resources