How to fill in html autocomplete fields using vba? - html

I am writing a macro that enter data into a online calculator and get the computed results
Link: https://www.icao.int/environmental-protection/CarbonOffset/Pages/default.aspx
I am trying to fill the values of "from city/airport" in the website.
Here is my Code:
Sub get_CO2()
Dim ie As Object
Set ie = New InternetExplorerMedium
ie.Navigate "https://applications.icao.int/icec"
Do While ie.ReadyState <> 4: DoEvents: Loop
ie.Visible = True
With ie.Document
.getElementById("passengerNo").Value = 7
.getElementById("select1").selectedIndex = 1
.getElementById("select2").selectedIndex = 1
' .getElementByName("frm1").Value = "XXX"
' .getElementByName("to1").Value = "XXX"
.getElementById("computeByInput").Click
End With
End Sub
It is doesnt work. It shows "object do not support this property or method"
How can i fill in this kind of types? What function can i use? If the airport code is not known, is there anyway to enter the name of the country and just pick to first option showing up?

I have figured out how to do this with vba.
EDIT: complete code requested
iedoc.getElementsByName("frm1")(0).innerText = "somecountry" ' enter string of country
Set li_arr = iedoc.getElementById("ui-id-1").getElementsByTagName("li")
Do While li_arr.Length = 0: DoEvents: Loop ' wait for the drop down menu to come up
li_arr(0).Click ' now click the first option

If using browser I would go with Selenium basic automation as it is easy to trigger the events associated with the input fields. Note I am using the iframe src url direct to avoid having to navigate the iframe containing the form. After installing selenium you need to ensure latest Chrome and Chromedriver with chromedriver.exe in the same folder as the selenium executables. Also, go vbe > tools > references and add a reference to selenium type library.
It is also possible, I think, to do a series POST xmlhttp request provided you can grab and pass on the right cookies.
The lines in code below
.FindElementByCss("#ui-id-1 li.ui-menu-item")
and
.FindElementByCss("#ui-id-2 li.ui-menu-item")
select the first list element in the dropdowns.
The drop down values are generated continuously from JSON repsonse to POST requests as you type. I have sent the entire required airport string in one go to ensure the first item is the desired.
Option Explicit
Public Sub GetInfo()
Dim d As WebDriver
Set d = New ChromeDriver
Const Url = "https://applications.icao.int/icec"
With d
.Start "Chrome"
.get Url
.FindElementByCss("[name=frm1]").SendKeys "AAD"
.FindElementByCss("#ui-id-1 li.ui-menu-item").Click
.FindElementByCss("[name=to1]").SendKeys "MGQ"
.FindElementByCss("#ui-id-2 li.ui-menu-item").Click
.FindElementById("computeByInput").Click
Stop 'delete me later
.Quit
End With
End Sub

Related

VBA Web search button - GetElementsbyClassName

I have a problem with the VBA code.
I would like to open this website: https://www.tnt.com/express/en_us/site/tracking.html and in Shipment numbers search box I would like to put active cells from Excel file. At the beginning I tried to put only a specific text for example: "777777".
I wrote the below code but unfortunately, the search button is empty and there is no error. I tried everything and I have no idea what should I change in my code.
Any clues? Thank you in advance.
HTML:
<input class="__c-form-field__text ng-touched ng-dirty ng-invalid" formcontrolname="query" pbconvertnewlinestocommasonpaste="" pbsearchhistorynavigation="" shamselectalltextonfocus="" type="search">
VBA:
Sub TNT2_tracker()
Dim objIE As InternetExplorer
Dim aEle As HTMLLinkElement
Dim y As Integer
Dim result As String
Set objIE = New InternetExplorer
objIE.Visible = True
objIE.navigate "https://www.tnt.com/express/en_us/site/tracking.html"
Do While objIE.Busy = True Or objIE.readyState <> 4: DoEvents: Loop
Dim webpageelement As Object
For Each webpageelement In objIE.document.getElementsByClassName("input")
If webpageelement.Class = "__c-form-field__text ng-pristine ng-invalid ng-touched" Then
webpageelement.Value = "777"
End If
Next webpageelement
End Sub
You could use the querySelector + class name to find an element.
something like
'Find the input box
objIE.document.querySelector("input.__c-form-field__text").value = "test"
'Find the search button and do a click
objIE.document.querySelector("button.__c-btn").Click
No need to loop through elements. Unless the site allows you to search multiple tracking numbers at the same time.
It seems automating this page is a litte tricky. If you change the value of the input field it doesn' t work. Nothing happen by clicking the submit button.
A look in the dom inspector shows several events for the input field. I checked them out and it seems we need to paste the value over the clipboard by trigger the paste event of the shipping field.
In order for this to work without Internet Explorer prompting, its security settings for the Internet zone must be set to allow pasting from the clipboard. I'm using a German version of IE, so I have problems explaining how to find the setting.
This macro works for me:
Sub TNT2_tracker()
Dim browser As Object
Dim url As String
Dim nodeDivWithInputField As Object
Dim nodeInputShipmentNumber As Object
Dim textToClipboard As Object
'Dataobject by late binding to use the clipboard
Set textToClipboard = CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
url = "https://www.tnt.com/express/en_us/site/tracking.html"
'Initialize Internet Explorer, set visibility,
'call URL and wait until page is fully loaded
Set browser = CreateObject("internetexplorer.application")
browser.Visible = True
browser.navigate url
Do Until browser.ReadyState = 4: DoEvents: Loop
'Manual break for loading the page complitly
'Application.Wait (Now + TimeSerial(pause_hours, pause_minutes, pause_seconds))
Application.Wait (Now + TimeSerial(0, 0, 3))
'Get div element with input field for shipment number
Set nodeDivWithInputField = browser.Document.getElementsByClassName("pb-search-form-input-group")(0)
If Not nodeDivWithInputField Is Nothing Then
'If we got the div element ...
'First child element is the input field
Set nodeInputShipmentNumber = nodeDivWithInputField.FirstChild
'Put shipment number to clipboard
textToClipboard.setText "7777777"
textToClipboard.PutInClipboard
'Insert value by trigger paste event of the input field
Call TriggerEvent(browser.Document, nodeInputShipmentNumber, "paste")
'Click button
browser.Document.getElementsByClassName("__c-btn")(0).Click
Else
MsgBox "No input field for shipment number found."
End If
End Sub
And this function to trigger a html 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
As #Stavros Jon alludes to..... there is a browserless way using xhr GET request via API. It returns json and thus you ideally need to use a json parser to handle the response.
I use jsonconverter.bas as the json parser to handle the response. Download raw code from here and add to standard module called JsonConverter . You then need to go VBE > Tools > References > Add reference to Microsoft Scripting Runtime. Remove the top Attribute line from the copied code.
Example request with dummy tracking number (deliberately passed as string):
Option Explicit
Public Sub TntTracking()
Dim json As Object, ws As Worksheet, trackingNumber As String
trackingNumber = "1234567" 'test input value. Currently this is not a valid input but is for demo.
Set ws = ThisWorkbook.Worksheets("Sheet1") 'for later use if writing something specific out
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "https://www.tnt.com/api/v3/shipment?con=" & trackingNumber & "&searchType=CON&locale=en_US&channel=OPENTRACK", False
.send
Set json = JsonConverter.ParseJson(.responseText)
End With
'do something with results
Debug.Print json("tracker.output")("notFound").Count > 0
Debug.Print JsonConverter.ConvertToJson(json("tracker.output")("notFound"))
End Sub

vba: How to click on element within iframe

My goal is to click an element within a html Iframe, but nothing worked for me so far. Hope someone can advise how to approach this task correctly as I am running in circles for weeks now.
I have tried to click on a div Id, span title but nothing worked so far. I believe it is because a wrong syntex
Option Explicit
Sub it_will_work()
'make the app work faster?
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'--------------------------------
Dim sht As Worksheet
Set sht = ThisWorkbook.Sheets("Fields") 'my data will be stored here
Dim LastRow As Long
LastRow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row 'range definition
Dim i As Long 'Will be used for a loop that navigate to different url
For i = 2 To LastRow 'First url starts at row 2 untill the last row
Dim IE As Object 'Internet Explorer declaration
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.navigate sht.Range("A" & i).Value 'My url that I want to navigate to
While IE.readyState <> 4 Or IE.Busy: DoEvents: Wend
Dim Doc As New HTMLDocument 'Will be used for the main html page
Set Doc = IE.document
Doc.getElementById("tab7").Click 'data taht need to be updated is here
'Global workgroup data that will effect the workgroup data(dependency)
Doc.getElementById("mcdResourceGlobalWorkgroup_ddltxt").Value = sht.Range("W" & i).Value
Doc.getElementById("mcdResourceGlobalWorkgroup_ddltxt").Focus
Doc.getElementById("mcdResourceGlobalWorkgroup_ddlimg").Click
'Workgroup dropdown, that need to be choosen within the Iframe:
Doc.getElementById("ResourceWorkgroup").Value = sht.Range("X" & i).Value '1) worgroup that I want to insert
Doc.getElementById("ResourceWorkgroup").Focus
Doc.getElementById("_IB_imgResourceWorkgroup").Click '2) Cliking here will generate dropdown values according the value inserted above
Application.Wait Now + TimeValue("00:00:5") 'before refering to Iframe I let the values to be loaded
'***from this point I have the issue where I try to access Iframe and click on the desired element:***
'Here I declare Iframe
Dim objIFRAME As Object
Set objIFRAME = IE.document.getElementsByTagName("iframe")
Debug.Print TypeName(objIFRAME)
'Here I ask to click on a title within the Iframe where value = X
objIFRAME.getElementsByName("title").Value = sht.Range("X" & i).Value.Click
Next i
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
After the url loads the following steps should happen:
Click on tab 7 -> this will open the correct tab to work on
inseart value from clumn "W" to "Global workgroup" field
focus on "Global workgroup" field
Click on an image that validate the "Global workgroup" field
(validates the instered value)
inseart value from clumn "X" to "Workgroup" field
focus on "Workgroup" field
Click on image that opens the drop down options, which is generated
according the inserted value to "Workgroup" field
Within the Iframe, Click on the title that is equal to value
which was inserted to "Workgroup" field
I have also tried to use Selenium IDE so I can see how the recorded macro access the Iframe and click the desired elemnt:
Command: Select frame | Target: Index=2
Click | Target: css=span[title="APAC"]
I have tried to mimic the stpes above in VBE, but couldn't find a way to write it properly. I event tried to download & apply selenium driver and run the code using the selenium library but got stuck as well.
Below image is the html code of the Iframe and the desired element I want to click on:
You should be able to use the following syntax
ie.document.querySelector("[id='_CPDDWRCC_ifr']").contentDocument.querySelector("span[title=APAC]").click
With selenium you can use
driver.SwitchToFrame driver.FindElementByCss("[id='_CPDDWRCC_ifr']")
driver.FindElementByCss("span[title=APAC]").click
With your existing tag solution you need to use an index. For example,
objIFRAME(0)
Then querySelector on the contentDocument of that.

Access VBA code to extract google map result from AA mileage calculator website

I am trying to use vba (Access 2013) to automate a route finder website (https://www.theaa.com/driving/mileage-calculator.jsp)
I have some working code that on a form command button allows me to:
1. open an external instance of internet explorer (as opposed to a browser control)
2. enter postcode/address information from my db
3. click a link that adds further destination fields if required
4. change cost per mile default from a text box on my form
5. click a button called "Get Route"
When "Get Route" is clicked this produces a page with the results of the search, which include a static google map with the route steps marked on a purple line A B C etc. I want to capture this image and use in my db form using a webbrowser or image field control so I can use it in a report when I have conducted searches for the most economical route.
I have looked at the DOM Explorer and source code but I can't work out how to do this or if it is possible? There is a div "gmnoprint" that is highlighted when the map is selected and in the source code there is a reference to "mapContainer" which seems to be in the right area of the sequence of actions/results.
I don't know how to drill through the references and create code which will allow me to put the map in my form. The selection of code I have posted is one part of a select case which determines what can be entered into my text boxes, the GoogleMap image code would presumably go where indicated?
I would say I am an enthusistic learner and a moderate user without any formal training. I would very much appreciate any replies.
Dim IE As New InternetExplorer
Dim doc As HTMLDocument
Dim RDate As String
On Error GoTo Errorhandler
RDate = Me.TxtRouteDate
'................................................................
Select Case Me.TxtNoSum
Case Is = IsNull(Me.TxtPC1) Or IsNull(Me.TxtPC2)
MsgBox "Please Enter at least 2 Postcodes"
Case Is <= 2
MsgBox "Please Enter at least 2 Postcodes"
Case Is = 3
IE.Visible = True
IE.Navigate "https://www.theaa.com/driving/mileage-calculator.jsp"
IE.Top = 20
IE.Left = 50
IE.Height = 1300
IE.Width = CInt(Int((1000 * Rnd()) + 1))
While IE.Busy
DoEvents
Wend
Set doc = IE.Document
With doc
'Clears previous searches
doc.all("mcDeleteRoutesLink").Click
'Inserts info into web site text boxes.
doc.getElementById("RouteDate").Value = RDate
doc.getElementById("RouteFrom").Value = Me.TxtPC1
doc.getElementById("RouteTo").Value = Me.TxtPC2
doc.getElementById("fuelPricePerLitre").Value = Me.TxtPPL
End With
While IE.Busy
DoEvents
Wend
'Clicks "Get Route" Button
Dim btn As Object
Set btn = doc.getElementById("getRouteWrapper").Children(0)
If Not btn Is Nothing Then
btn.Click
While IE.Busy
DoEvents
Wend
' Inserts distance recorded by AA mileage calculator into text control on my form
Set htmlDist = doc.all("routeDistanceTotal")
If Not htmlDist Is Nothing Then
Me.TxtDistance = htmlDist.innerText
'Google image code to go here after map page loads?
End If
End If
(Next Case)

href attribute not found when searching for elements by tagname in vba

Using VBA, I am attempting to find the href attribute for weekly share price data of a given stock in the HTML of Yahoo finance. I need this to automate the download of the csv file containing the data. I have done my research, and have written the following code which I believe should find the URL. However, the code continues to end with an error. Is there a small error in my code or is there a bigger problem at hand.
I have searched for the parent of the hyperlink by classname to narrow the search which is successful. But when I search within this parent the code returns the error "The remote server machine does not exist or is unavailable".
I am new HTML scraping so any help would be much appreciated. Thanks in advance for any help.
Sub webpage()
Dim internet As Object
Dim internetdata As Object
Dim Find_Parent As Object
Dim Stock_Links As Object
Dim Link As Object
Dim URL As String
Set internet = CreateObject("InternetExplorer.Application")
internet.Visible = True
URL = "https://finance.yahoo.com/quote/GTE.AX/history?period1=1341266400&period2=1499032800&interval=1wk&filter=history&frequency=1wk"
internet.Navigate URL
Do While internet.ReadyState <> READYSTATE_COMPLETE
Loop
Set internetdata = internet.Document
Set Find_Parent = internetdata.getElementsByClassName("Fl(end) Pos(r) T(-6px)")
Set Stock_Links = Find_Parent.getElementsByTagName("a")
NextRow = 1
For Each Link In Stock_Links
Sheet1.Range("A" & NextRow) = Link.getAttribute("href")
NextRow = NextRow + 1
Next
MsgBox "Link Found"
End Sub
The first issue is that you're using the InternetExplorer constant READYSTATE_COMPLETE, while using late binding. Therefore, it sees it as an empty variable instead of its value, which is 4. This means that the Do While/Loop will always evaluate to True. So you'll need to replace the constant with its value...
Do While internet.ReadyState <> 4
Loop
The other issue is with getElementsByClass. It returns a collection of elements, where the indexing starts at 0. So you'll need to refer to one of the elements from that collection. In this example, it looks like only the one element that you're looking for is returned. So you'll need to refer to the first element, which has an index of 0...
Set Stock_Links = Find_Parent(0).getElementsByTagName("a")

Extracting multiple search results

I have created a VBA application that allows you to extract search results from the canada411.ca site. You simply insert values into to the values "Where" and "What" and "Title", "Location, and "Phone" will spit out. In my code What = "Name". Here is my code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row = Range("Name").Row And _
Target.Column = Range("Name").Column Then
End If
If Target.Row = Range("Where").Row And _
Target.Column = Range("Where").Column Then
'Set Variables What and Where from Canada411.ca to Values on Excel WorkSheet
Dim IE As New InternetExplorer
IE.Visible = True
IE.navigate ("http://canada411.yellowpages.ca/search/si/1/") & _
Range("Name").Value & "/" & Range("Where").Value
Do
DoEvents
Loop Until IE.readyState = READYSTATE_COMPLETE
Dim Doc As HTMLDocument
Set Doc = IE.document
'Extract from Canada411.ca Source element (first search result)
Range("Title").Value = Trim(Doc.getElementsByTagName("h3")(0).innerText)
Range("Phone").Value = Trim(Doc.getElementsByTagName("h4")(0).innerText)
Range("Location").Value = Trim(Doc.getElementsByClassName("address")(0).innerText)
IE.Quit
'Extract for Second Search result
'Third Search result etc.
End If
End Sub
My problem is that I don't know how to get the remaining results on the page, I can only get the first result on the first page. The source code for the subsequent search results are the same as the first, but I cannot seem to make it work. (Perhaps there is a shortcut after you have the code for the first one, to get the rest?) I am new to VBA and HTML and appreciate the help.
Well, you have two options.
1) Learn how to navigate the DOM using the Tools->References library 'Microsoft HTML Object Library' and extract that way.
2) It is possible to pull the web page into a Excel worksheet and then you only need to pull out data from each cell. Much easier but ties you to Excel. Use the Macro recorder and then use the GUI , on the Ribbon Data->From Web and follow the wizard.
In your link change the « 1 » for a 2, 3, 4 ... These are the page numbers !
http://canada411.yellowpages.ca/search/si/1/
http://canada411.yellowpages.ca/search/si/2/
http://canada411.yellowpages.ca/search/si/3/
...