I'm trying to create a VBA macro in Excel that:
Navigates to a webpage
Searches the HTML document for all elements with the tag name "input"
Prints the attributes of each element found (name, type, and value)
Clicks the button on the webpage to navigate to the second webpage.
Search the HTML document on the second page for all elements with the tag name "input"
Prints the attributes of each element found (name, type, and value)
Everything works find up until Step 5. When I try to search the HTML document, for some reason it doesn't search the HTML document of the second page, instead it looks at the HTML of the initial webpage in Step 2 and prints out the same results in Step 3.
Could you guys please take a look at my code to see what I am doing wrong? I listed my code below and tried to make comments to make it readable.
Sub C_R()
Dim ie As New SHDocVw.InternetExplorer
Dim HTMLDoc As MSHTML.HTMLDocument
Dim HTMLInput As MSHTML.IHTMLElement
Dim HTMLButtons As MSHTML.IHTMLElementCollection
Dim HTMLButton As MSHTML.IHTMLElement
'Opens Internet Explorer and navigates to website.
ie.Visible = True
ie.navigate "http://openaccess.sb-court.org/OpenAccess/"
Do While ie.ReadyState <> READYSTATE_COMPLETE
Loop
'Searches HTML(initial page) to find all elements with "input" tag name.
'Prints attributes of each element (name, type, and value".
Set HTMLDoc = ie.Document
Set HTMLButtons = HTMLDoc.getElementsByTagName("input")
Debug.Print "Initial Page"
For Each HTMLButton In HTMLButtons
Debug.Print HTMLButton.getAttribute("name"), HTMLButton.getAttribute("type"), HTMLButton.getAttribute("value")
Next HTMLButton
'Navigates to second page
HTMLButtons(1).Click
Do While ie.ReadyState <> READYSTATE_COMPLETE
Loop
'Searches HTML(second page) to find all elements with "input" tag name.
'Prints attributes of each element (name, type, and value".
Set HTMLDoc = ie.Document
Set HTMLButtons = HTMLDoc.getElementsByTagName("input")
Debug.Print "Second Page"
For Each HTMLButton In HTMLButtons
Debug.Print HTMLButton.getAttribute("name"), HTMLButton.getAttribute("type"), HTMLButton.getAttribute("value")
Next HTMLButton
End Sub
Any help you can provide will be greatly appreciated. Thank you so much.
It looks like your second loop is continuing even though the webpage hasn't completely loaded.
Do While ie.ReadyState <> READYSTATE_COMPLETE
Loop
To see this, put a break point at the second loop, and wait for the second web page to load. Then continue the code, and it should work fine.
You will need to either add a wait time in the loop, which may not always work, or find another way to tell if the ie.ReadyState is complete.
Related
I'm fairly new to HTML, so please bear with me on this. I am using Excel VBA to interact with an website, with the intent to automate this interaction.
Problem Statement
I have a web page with (what looks like) a button that I need to click on. In the HTML it is listed as a Menu Item. Im able to successfully click other buttons on the page, but those have < button > tags.
I have tried to use the click method by selecting it by ID but I get an 'Object Variable or With block variable not set' error.
Sub WD_auto()
Dim IE As New SHDocVw.InternetExplorer
Dim HTMLDoc As MSHTML.HTMLDocument
Dim HTMLSel As MSHTML.IHTMLElement
IE.Visible = True
IE.navigate "https://wd3.myworkday.com/redacted/d/home.htmld"
Do While IE.Busy = True Or IE.readyState <> 4: DoEvents: Loop
Set HTMLDoc = IE.document
Set HTMLSel = HTMLDoc.getElementById("88831e18a0894109a83c10bc9a9be6c7")
HTMLSel.Click
End Sub
The block of HTML that i think i need to interact with is shown below.
<div class="GNMRENADFGC GNMRENADBHC GNMRENADHHC" tabindex="-2"
id="88831e18a0894109a83c10bc9a9be6c7" role="menuitem"
aria-posinset="1" aria-setsize="3">
Any pointers or literature would be appreciated.
Ok after some more research i have a solution. I am just looping all the div tags and checking the Inner Text property of each until I find the one I want to click.
It works, but if anyone has a more elegant solution I'm all ears. The loop seems a bit wasteful, I would prefer to just refer directly to, and then click the element.
Set ElementsA = IE.document.getElementsByTagName("div")
For Each ElementA In ElementsA
On Error Resume Next
If ElementA.innerText = "User Name and Password login" Then
ElementA.Click
Exit For
End If
Next ElementA
Here is a piece of code of the HTML page I am working on.
I am trying to programmatically click on the element highlighted in blue in the picture above.
Here is the code I wrote:
Set objIE = New SHDocVw.InternetExplorer
Do While objIE.Busy: DoEvents: Loop
Do Until objIE.readyState = READYSTATE_COMPLETE: DoEvents: Loop
Set IeDoc2 = objIE.Document
Set the_input_elements2 = IeDoc2.getElementsByClassName("parent-item")
For Each input_element2 In the_input_elements2
If input_element2.href = "javascript:directToSearch()" Then
input_element2.Click
Exit For
End If
Next input_element2
How do I click on an element of a ul in HTML using VBA?
When I run this code, nothing happens. No errors but no result.
Here's a couple of ways to refer to the element you're interested in:
'Targeted (if you know exactly at which order the elements appear in the list)
Dim li As HTMLListElement
Set li = IeDoc2.getElementById("accordion-leftmenu") 'get the list item you're interested in...
Debug.Print li.Children(1).innerText '...and access its sub-element in a targeted way
Debug.Print li.getElementsByTagName("a")(1).innerText '...or find all <a></a> elements contained in it and access the one you're interested in, in a targeted way
'Non targeted (you have to search for it)
Dim element As HTMLObjectElement
For Each element In IeDoc2.getElementsByTagName("a") 'loop through all <a></a> elements...
If element.innerText = "Advanced Search" Then '...and find the one you're interested in
Debug.Print element.innerText
End If
Next element
For demonstration purposes the above code just prints the inner text of the element. You can modify it accordingly.
References used: Microsoft HTML Object Library
Also on a side note, please post the actual HTML next time rather than a screenshot of it. It would make it easier for people to help you.
Loop all "a" tags inside the ID of the left menu
IeDoc2.getElementById("accordion-leftmenu").getElementsByTagName("a")
in the loop check if the .innerText is "Advanced Search". click if it is.
Dim IeDoc2 As MSHTML.HTMLDocument
Dim the_input_elements2 As MSHTML.IHTMLElementCollection
Dim input_element2 As MSHTML.IHTMLElement
...
Set the_input_elements2 = IeDoc2.getElementById("accordion-leftmenu").getElementsByTagName("a")
For Each input_element2 In the_input_elements2
If input_element2.innerText = "Advanced Search" Then
input_element2.Click
Exit For
End If
Next input_element2
Edit: Alright, I've tested the code and it works. I did however have to make sure that Two references were checked: "Microsoft HTML Object Library" and "Microsoft Internet Controls".
I have some experience and knowledge how to scrape by tagName or ClassName. However in this particular case className is not unique also link is changing all the time after accessing the page so it is not possible to get a direct link. The only unique combination is class and link text. What would be the code to access for example Budget and Forecast updating with a_1_610 and Budget and Forecast updating with a_1_611?
My code (edited according to QHarr answer):
Sub GoToLiinosBot()
'This will load a webpage in IE
Dim ie As InternetExplorer
Dim HWNDSrc As Long
Dim elements As Object
Set ie = Nothing
Set ie = New InternetExplorerMedium
ie.Visible = True
ie.Navigate "http://link.com"
With ie
Do
DoEvents
Loop Until ie.ReadyState = READYSTATE_COMPLETE
End With
Application.Wait (Now + TimeValue("0:00:04"))
ie.Document.querySelector(".data .a_1_611").innerText
'Unload IE
Set ie = Nothing
End Sub
Here is source code:
They are class names not ids. A loop is perhaps required, with test of innerText value of node, if ordering changes but otherwise you want the first match for the example shown in image
.data .a_1_611
Which is
ie.document.querySelector(".data .a_1_611").click
nth-of-type is useful for fixed position selection but more expensive than class selectors.
I'm a newbie, attempting to web scrape aspect ratio details from the imdb.com website.
I've plundered some code on You Tube and adapted it using inspect element.
The code opens imdb and runs a search by title but returns a Run Time error 438.
Ideally I'd like it to return the html of the top result so I could perform a further click the top result to follow through to the page with tech details from where I could get the aspect ratio information and paste it into a cell.
Unfortunately I get a fail from my Click instruction - haven't even got to the point of extracting the aspect ratio info.
Can anyone see where I've gone wrong?
Many thanks,
Nick
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row = Range("Title").Row And Target.Column = Range("Title").Column Then
Dim ie As New InternetExplorer
ie.Visible = True
ie.navigate "https://www.imdb.com/find?ref_=nv_sr_fn&q=" & Range("Title").Value
Do
DoEvents
Loop Until ie.readyState = READYSTATE_COMPLETE
Dim doc As HTMLDocument
Set doc = ie.document
Dim sDD As String
doc.getElementsByTagName("a").Click
End If
End Sub
So, addressing your code
You can use a shorter version of Target.Address = Range("Title").Address
You don't want the first a tag element. You want the first search result a tag element.
You can use a CSS selector combination to get the first search result a tag element as shown below.
I use a CSS selector combination of .result_text a to target elements within parent class result_text with tag a. The . is a class selector.
This combination is known as a descendant selector.
Using search term in sheet of Red October this is what the CSS query first result is:
It is a relative link with base string https://www.imdb.com.
Applying via querySelector method means only first matched result is returned i.e. the top result.
VBA:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Target.Address = Range("Title").Address Then
Dim ie As New InternetExplorer
ie.Visible = True
ie.navigate "https://www.imdb.com/find?ref_=nv_sr_fn&q=" & Range("Title").value
Do
DoEvents
Loop Until ie.readyState = READYSTATE_COMPLETE
Dim doc As HTMLDocument
Set doc = ie.document
doc.querySelector(".result_text a").Click
'other code
End If
Application.EnableEvents = True
End Sub
This line of code:
doc.getElementsByTagName("a")
gives you the Collection of Hyperlinks in your HTML Document. That is, it gives you ALL the elements that match your given criteria, if any are available.
However, some issues may arrive:
There may not be any hyperlinks available - So there are no elements to click on.
You are not referencing any element to click. If you want the first one in the collection of found items, you could go with the index, as suggested. Else, you might look for another clicking criteria (such as what is its text or another given attribute).
Even still, a found element might not be clickable by your browser, if, for example, it is shadowed by another element.
I'm not too familiar with getting the elements from IE, but I've been successful when it's straight-forward. The website I'm working with now is confusing me.
I am launching a site and putting in the username & password, then I want to click the login button but I am failing to find the correct way to locate and click the button since it doesn't have an ID.
I have seen various posts on this site with similar questions and I have tried following the advice in those posts but still can't get it to work.
I will share my code and the element information from the site.
Dim IEapp As InternetExplorerMedium
Dim divClassLogin As Object
Set IEapp = New InternetExplorerMedium
With IEapp
.Navigate "http://ctdayppv02/PVE.aspx"
.Visible = True
.AddressBar = 0
.StatusBar = 0
.Toolbar = 0
.MenuBar = 0
.Height = 700
.Width = 950
End With
Do While IEapp.Busy: DoEvents: Loop
Do Until IEapp.ReadyState = READYSTATE_COMPLETE: DoEvents: Loop
IEapp.Document.all.Item("txtUserName").Value = "Name"
IEapp.Document.all.Item("txtPassword").Value = "Pass"
IEapp.Document.all.Item("btnLogin").Click
This is the IE Inspect Elements html.
This is the Chrome Inspect Elements html.
The posts I've referenced on this site are (amongst others):
Click button on login page
VBA to click on a button in IE with no ID, Name, ClassName
Use VBA to click on a button in IE
Can somebody help me identify what element I should be looking at to click login? I'm used to finding an ID or something that says "Submit" but I'm not seeing it on this site.
Thanks in advance.
As I cannot access the URL. I just come out with the code (without testing it) that I usually do and for me the most flexible way even though it quite long. Please try:
Dim ee as Variant, htmldoc
Set htmldoc= IEapp.document
For each ee in htmldoc.getElementsByTagName("span")
If ee.className = "dijitReset dijitInline dijitButtonNode" And InStr(ee.innerHTML, "btnLogin") > 0 Then 'not sure whether innerhtml or outerhtml you need tp check in your watches
ee.Click: DoEvents: Sleep 1000
''or u can try this
ee.FireEvent ("onclick"): DoEvents: Sleep 1000
Exit For
End If
Next ee