Triggering <A> Element Without ID or Text - vba

While setting up an automation process for extracting data from a page, I came across a link where I am having trouble selecting it.
Here is the HTML code:
<a class="dt-button buttons-copy buttons-html5" tabindex="0" aria-controls="tblReport" href="#" title="Copy to Clipboard"><span><i class="fa fa-files-o fa-lg blue"></i></span></a>
My last attempt was using:
For Each m In objIE.document.getElementsByTagName("a")
If m.className = "dt-button buttons-copy buttons-html5" Then
m.Click
Exit For
End If
Next
With Dim m As HTMLElementCollection.
But nothing happens.
If triggered, a window will appear stating that the content has been copied to the clipboard.
Another approach was:
objIE.document.getElementsByClassName("dt-button buttons-copy buttons-html5")(0).Click
But I get the error message
Object variable or With block variable not set
objIE is set as:
Dim objIE As Object
Set objIE = CreateObject("InternetExplorer.Application")
I can't figure out what I am missing.

You need to ensure that your page is completely loaded PRIOR to setting your object.
If you are already doing this, sometimes webpages will say they're loaded when they are actually not. To circumvent this, you can loop your object waiting for it to become ready by doing this:
Do While objIE.document.getElementsByClassName("dt-button buttons-copy buttons-html5")(0) Is Nothing
DoEvents
Loop
Then when it's no longer Nothing, you can now click it:
objIE.document.getElementsByClassName("dt-button buttons-copy buttons-html5")(0).Click

Related

How to Click an href using an Excel VBA

I am very new to VBA and had a question regarding how to click an href link in Internet Explorer. There are multiple href's on the source page. I have never encountered this and it has been giving me a hard time! I have looked on this website searching for answers but decided to ask here.
Below I have listed the code I have, up to the point where I encounter the problem, as well as the Source Code on Internet Explorer.
I commented out what I have tried and listed the error I received.
Code Below:
Sub ()
Dim i As Long
Dim URL As String
Dim IE As Object
Dim objElement As Object
Dim objCollection As Object
User = "User"
Pwd = "Pwd"
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
URL = "URL.com"
IE.Navigate URL
Do While IE.ReadyState <> 4
DoEvents
Loop
IE.Document.getElementById("txtUsername").Value = User
IE.Document.getElementById("txtPassword").Value = Pwd
IE.Document.getElementById("btnSubmit").Click
'IE.getElementByClassName("txtTerms").Click - Runtime Error 438
'IE.getElementByTagName("Claims Management").Click - Runtime Error 438
'Set HREF = IE.Document.getElementsByClassName("txtTerms")
'For Each HREF In IE.Document.getElementsByTagName("Claims").Click - No error occurs, nothing happens.
End Sub
Internet Explorer Source Code:
<table id="tblContent">
<tr>
<td class="txtTerms"><a href='href url 1'>Claims</a>
<br>Download<br>Create<br><a class='terms' href='href url 2'
target='terms'>Terms</a><br><br></td>
</tr>
My question would be, how to get VBA to click only on 'href url 1'?
Let me know if any additional information is needed. I apologize for my level of VBA but I am excited to learn more!
Thanks for the help!
In HTML, href is a property of the type <a> (link) which contains an absolute or relative path.
For example:
Questions
... will show as "Questions" and, if you click it, will bring you to www.stackoverflow.com/questions/. Note that "www.stackoverflow.com" has been added automatically since the path is relative.
Facebook
... will show as "Facebook" and, if you click it, will bring you to www.facebook.com. In this case, the path is absolute.
Although your HTML code is incomplete, I guess that all the links you want to navigate are contained in the table having id="tblContent". If that's the case, then you can get all the links (tagName == 'a') in that table and store the values in a collection:
Dim allHREFs As New Collection
Set allLinks = IE.Document.getElementById("tblContent").getElementsByTagName("a")
For Each link In allLinks
allHREFs.Add link.href
Next link
You can then decide to navigate them and do what you have to do one by one:
For j = 1 To allHREFs.Count
IE.Navigate URL + allHREFs(j) '<-- I'm assuming hrefs are relative.
'do your stuff here
Next href

Clicking a button in IE using VBA

I am using Excel VBA to try click a button on a site, here's the code from the site using inspect element:
<button class="_ah57t _84y62 _frcv2 _rmr7s">ClickHere</button>
And here's what i'm doing in VBA:
Sub testcode()
Dim ie As InternetExplorer
Dim html As HTMLDocument
Set ie = New InternetExplorer
ie.Visible = True
ie.Navigate "somesite.com"
Do While ie.READYSTATE <> READYSTATE_COMPLETE
DoEvents
Loop
Dim e
Set e = ie.Document.getElementsByClassName("_ah57t _84y62 _frcv2 _rmr7s")
e.Click
End Sub
Using the debug I found that the code seems to be storing something called "[object]" in the variable e and and then gives a Runtime error '438' when it gets to e.click. I have even tried using .Focus first, but get the same error. Any ideas?
The getElementsByClassName() function returns a collection not a single element. You need to specify an index on the returned collection in order to return a single element. If there is only one element within the class you can simply use:
ie.Document.getElementsByClassName("_ah57t _84y62 _frcv2 _rmr7s")(0).Click
The (0) specifies the index of the element within the collection returned from the class.
Its easy to tell whether a function returns a collection or single element:
getElementBy... - Returns a single element.
getElementsBy... - Returns a collection of elements.

Exception 0x800A01B6 using getElementById after the first load

I have created a ribbon for Powerpoint with visual studio XML ribbon. This ribbon has a button that, simplifying, does this:
opens an IE browser
search an element (hiddenfield) in the code by his id
get the value of this element
Print the value in the actual slide
It works correctly the first time I click the button of my ribbon, but it throws an Exception 0x800A01B6 the following times I click the button.
This is the code executed when I click the button:
Dim oType As Type = Type.GetTypeFromProgID("InternetExplorer.Application")
If oType IsNot Nothing Then
Dim ie As SHDocVw.InternetExplorer
ie = Nothing
ie = TryCast(Activator.CreateInstance(oType), SHDocVw.InternetExplorer)
If ie IsNot Nothing Then
Dim oEmpty As Object = [String].Empty
Dim oURL As Object = targetURL
ie.AddressBar = False
ie.MenuBar = False
ie.ToolBar = 0
ie.Visible = True
ie.Height = 800
ie.Width = 1100
ie.Navigate(oURL, oEmpty, oEmpty, oEmpty, oEmpty)
End If
Do While (ie.Busy Or ie.ReadyState <> READYSTATE.READYSTATE_COMPLETE)
Sleep(1000)
Application.DoEvents()
Loop
Sleep(10000) ' 10 seconds for testing purpose
Dim str As String = String.Empty
Dim hdnstring As HTMLInputElement = ie.Document.getElementById("hdnstring")
str = hdnstring.value
DoSomething(str)
ie.Quit()
ie = Nothing
End If
This is the code of the website that opens (targetURL), the code remains identical in every load and only the hidden value changes:
<html>
<body>
<form name="form1" id="form1">
<input type="hidden" name="hdnstring" id="hdnstring" value="Get This String" />
</form>
</body>
</html>
The second time (and following) I execute the function: the IE opens, the website fully loads, it waits 10 seconds and then I get an error in the line:
Dim hdnstring As HTMLInputElement = ie.Document.getElementById("hdnstring")
with Exception 0x800A01B6 message.
The most strange thing is that if I click viewsource in the IE contextual menu while the 10 seconds delay (the ones for testing purpose), it works perfect every time I click the button; but if I don't, the Exception 0x800A01B6 appers.
Any idea of what I'm doing wrong?
Error details image:
The type of the Document property is only resolved at run-time, so it's an Object until then. This is why calling any methods in it results in the so-called late binding - you do not yet know if the getElementById method exists or not, so that has to be determined a run-time.
You most likely get the error because the Document is not of the IHTMLDocument3 type, which is the only document type that includes the getElementById method.
What you can try is casting the Document to an IHTMLDocument3 interface. Since it inherits IHTMLDocument and IHTMLDocument2 you can cast between them even if the document is actually one of the earlier types.
DirectCast(ie.Document, IHTMLDocument3).getElementById("hdnstring")

click link using getelementsbyclassname vba 7 using access 2007

I have a connection to an internet explorer webpage but i cannot seem to "click" a specific link using vba7 in access. I've tried loads of options like getelementsbyclassname. Here's the source code from the webpage:
<tr>
<td valign=bottom class="formbutton" align=center colspan=2>
view
</td>
</tr>
As you can see it has no name nor a usable hyperlink and the purpose of this link is to submit the filled-out form and give it a unique number on a new web page.
Can you please help me in VBA 7 for Access 2007 to come up with a vba code that works?
Many thanks!
The following should work assuming you have a pointer to the InternetExplorer object already.
Public Sub ClickElement()
'Assuming you already have an IE object
Dim Elements As Object
Dim Element As Object
'get all 'A' tags, which the hyperlink is part of
Set Elements = IE.Document.getElementsByTagName("a")
For Each Element In Elements
'I believe the element you want to click appears as 'View' on screen
If Element.InnerText = "View" Then
'Usually a good idea to give the element focus and
'possibly fire the OnClick event, but sometimes not needed
Element.Focus
Element.Click
Element.FireEvent ("OnClick")
Exit For
End If
Next
End Sub

VBA to change dropdown value in internet explorer

I am looking to automate internet explorer using Excel VBA to extract football results from a website and am really struggling with getting the data to update when I change the dropdown value.
The website is: http://www.whoscored.com/Regions/250/Tournaments/30/Seasons/3871/Stages/8209/Fixtures/Europe-UEFA-Europa-League-2013-2014
I am looking to change the value of the 'stages' dropdown and scrape the match results.
My code works fine for opening IE, changing the value of the 'scrape' dropdown but I can't get the data to update. Whilst I am comfortable with VBA I know very little about HTML and Javascript although I can guess what some lines are doing. From what I can see there is javascript code that handles the change event, I just can't see how to get it to run - I have tried firing the 'onchange' event in my code as suggested from my searches but I can't get it to work.
This is the code I can see that controls the drop down (I have deleted a lot of the dropdown values for other dropdowns as it made this post even longer:
<div id="breadcrumb-nav">
.
.
<span><select id="stages" name="stages"><option selected="selected" value="/Regions/250/Tournaments/30/Seasons/3871/Stages/8209">Europa League Group Stages</option>
<option value="/Regions/250/Tournaments/30/Seasons/3871/Stages/7816">Europa League Qualification</option>
<option value="/Regions/250/Tournaments/30/Seasons/3871/Stages/8158">Europa League Grp. A</option>
<option value="/Regions/250/Tournaments/30/Seasons/3871/Stages/8159">Europa League Grp. B</option>
.
.
<option value="/Regions/250/Tournaments/30/Seasons/3871/Stages/8466">Europa League</option>
</select></span>
</div>
<script type="text/javascript">
$('#breadcrumb-nav select').change(function () {
NG.GA.trackEvent('BreadcrumbNav', this.id);
window.location.href = this.value;
// TODO: Disable all selects?
});
</script>
my code:
Sub ScrapeData()
Dim ie As InternetExplorer
Dim URL As String
URL = "http://www.whoscored.com/Regions/250/Tournaments/30/Seasons/3871/Stages/8466/Fixtures/Europe-UEFA-Europa-League-2013-2014"
Set ie = New InternetExplorer
ie.Visible = True
ie.navigate (URL)
Do
DoEvents
Loop Until ie.readyState = 4
SelectValue ie, "/Regions/250/Tournaments/30/Seasons/3871/Stages/7816"
SelectValue ie, "/Regions/250/Tournaments/30/Seasons/3871/Stages/8209"
End Sub
Sub SelectValue(ByVal ie As InternetExplorer, ByVal value As String)
Dim htmlDoc As HTMLDocument
Dim ddStages As HTMLSelectElement
Dim idBreadCrumb As Object
Set htmlDoc = ie.document
With ie.document
Set idBreadCrumb = .getelementbyid("breadcrumb-nav")
Set ddStages = .getelementbyid("stages")
End With
ddStages.value = value
ddStages.FireEvent ("onchange")
'fireevent on ddStages didn't work so tried here too
idBreadCrumb.FireEvent ("onchange")
Do
DoEvents
Loop Until ie.readyState = 4
End Sub
Any help would be really appreciated.
There must be some JavaScript executing on the event "the select element has changed its value". My suggestion, much easier than executing the JavaScript, is to just navigate the link (because what the JS does here is just changing the HTML page you are seeing, and not the elements within the same webpage).
So, for example, I would just replace this:
SelectValue ie, "/Regions/250/Tournaments/30/Seasons/3871/Stages/7816"
with this
ie.Navigate "http://www.whoscored.com/" & "/Regions/250/Tournaments/30/Seasons/3871/Stages/7816"
to get the exactly same result.