Catching anchor element using SHDocVw.InternetExplorer - vba

I want to catch the anchor element in website via vba.
I tried both as an MSHTML.IHTMLAnchorElement and MSHMTL.IHTMLBUttonELement but either way gives an error on Set line. Can anyone describe what's wrong with code below?
Sub goToWhtSpp()
Dim ie As New SHDocVw.InternetExplorer
ie.Visible = True
ie.navigate "https://cooperatordirectory.com/"
Do While ie.readyState <> READYSTATE_COMPLETE Or ie.Busy
Loop
Dim doc As MSHTML.HTMLDocument
Set doc = ie.document
Application.Wait 3000
URL = "https://cooperatordirectory.com/search_results?location_value=Florida&adm_lvl_1_sn=FL&stateSearchLN=Florida&country_sn=US&location_type=administrative_area_level_1&stateSearch=FL&swlat=24.396308&nelat=31.000968&swlng=-87.634896&nelng=-79.974306&lat=27.6648274&lng=-81.5157535&faddress=Florida%2C+USA&place_id=ChIJvypWkWV2wYgR0E7HW9MTLvc"
ie.navigate URL
Dim aelement As MSHTML.IHTMLAnchorElement
Set aelement = doc.getElementsByClassName("btn btn-primary btn-block") ' err line
Dim btn As MSHTML.IHTMLButtonElement
Set btn = doc.getElementsByClassName("btn btn-primary btn-block") ' err line
Debug.Print btn.Value
End Sub
<a class="btn btn-primary btn-block" href="/pro/20220324090906/connect">Send Message</a>

You want a page load wait after each .navigate. In this case you only need the one .navigate and wait.
getElementsByClassName() returns a collection not a single node. So both your type declaration, subsequent SET attempt to this type, and later attempt to view the .value attribute will fail. .value is a property of a single node.
If you want the first "button" href then index into a correctly typed variable and call .item(0), or, more efficiently, use the querySelector() method of ie.document and pass in a single class of the multi-valued class (the one which still correctly identifies the target element).
Dim anchors As IHTMLElementCollection
Set anchors = .document.getElementsByClassName("btn-primary")
Dim anchor As IHTMLAnchorElement
Set anchor = .document.getElementsByClassName("btn-primary").Item(0)
Option Explicit
Public Sub PrintMessageUrl()
Const URL As String = "https://cooperatordirectory.com/search_results?location_value=Florida&adm_lvl_1_sn=FL&stateSearchLN=Florida&country_sn=US&location_type=administrative_area_level_1&stateSearch=FL&swlat=24.396308&nelat=31.000968&swlng=-87.634896&nelng=-79.974306&lat=27.6648274&lng=-81.5157535&faddress=Florida%2C+USA&place_id=ChIJvypWkWV2wYgR0E7HW9MTLvc"
Dim ie As SHDocVw.InternetExplorer
Set ie = New SHDocVw.InternetExplorer
With ie
.Visible = True
.navigate URL
Do While .readyState <> READYSTATE_COMPLETE Or .Busy: DoEvents: Loop
Debug.Print .document.querySelector(".btn-primary").href
.Quit
End With
End Sub

Related

VBA Object doesn't support property or method when filling webform

I'm trying to use the Excel VBA to fill a web form and then scrape some data.
I am stuck on how to put in the value that I want to search for.
In the source code, there is no id or name that I can use.
I tried with a class name but it is not working.
" Source code:
<input type="text" style="height: 28px; width: 170px; padding-left: 5px;" ng-model="model.FieldValue" placeholder="Enter a Value" ng-show="model.searchOptions.length && model.searchOptions != 'SQE Quote Id'" class="ng-pristine ng-valid ng-touched">
Sub Macro1()
Dim i As Long
Dim URL As String
Dim IE As Object
Dim objElement As Object
Dim objCollection As Object
Dim html As HTMLDocument
Set IE = New InternetExplorerMedium
'Set IE.Visible = True to make IE visible, or False for IE to run in the background
IE.Visible = True
'Define URL
URL = "xxxx"
'Navigate to URL
IE.Navigate URL
' Statusbar let's user know website is loading
Application.StatusBar = URL & " is loading. Please wait..."
' Wait while IE loading...
'IE ReadyState = 4 signifies the webpage has loaded (the first loop is set to avoid inadvertently skipping over the second loop)
Do While IE.ReadyState = 4: DoEvents: Loop 'Do While
Do Until IE.ReadyState = 4: DoEvents: Loop 'Do Until
'
Set html = IE.Document
IE.Document.getElementById("searchOptions").Click (2)
IE.Document.getElementById("searchOptions").Value = "Access Qref"
IE.Document.getelemenetbyclassname("ng-pristine ng-valid ng-touched").Value = "00000"
'
End Sub
Try to put '.' between class names like below is working on my side.
IE.Document.querySelector("input.ng-pristine.ng-valid.ng-touched").Value = "00000"
Modified example:
Sub Macro1()
Dim i As Long
Dim URL As String
Dim IE As Object
Dim objElement As Object
Dim objCollection As Object
Dim html As HTMLDocument
Set IE = New InternetExplorerMedium
'Set IE.Visible = True to make IE visible, or False for IE to run in the background
IE.Visible = True
'Define URL
URL = "D:\Backup20190913\tests\353.html"
'Navigate to URL
IE.Navigate URL
' Statusbar let's user know website is loading
Application.StatusBar = URL & " is loading. Please wait..."
' Wait while IE loading...
'IE ReadyState = 4 signifies the webpage has loaded (the first loop is set to avoid inadvertently skipping over the second loop)
Do While IE.ReadyState = 4: DoEvents: Loop 'Do While
Do Until IE.ReadyState = 4: DoEvents: Loop 'Do Until
Set html = IE.Document
IE.Document.querySelector("input.ng-pristine.ng-valid.ng-touched").Value = "00000"
End Sub
Output:
The error is as it says. The method you are trying does not exist for that node. You are fine using a multi-valued class (more than one class name for the element; denoted by several strings separated by spaces within the class attribute of the element) inside of the correct method getElementsByClassName, rather than getelemenetbyclassname then you need to index into the returned collection in order to exercise the .click method.
IE.Document.getElementsByClassName("ng-pristine ng-valid ng-touched")(0).Value = "00000" '0 for first node
However, as in other answer, if using querySelector/querySelectorAll to match by css class selector then a multi-valued class must have the spaces between replaced with ".". Better still, try to select as few of those class names inside the multi-value as possible and the most selective which still match on the required node(s)
And please, I write this a lot on SO, use a proper page load wait:
While IE.busy Or IE.readystate <> 4: DoEvents: Wend

VBA Macro for Internet Explorer - code run well on debugging 1 by 1 command but didn't work if i run the whole program

I'm new with VBA Macro using for automate the internet explorer.
I've used it for creating bot to follow other online shopping follower (e-commerce).
Actually the code run well if I use debug 1 by 1 command, and it worked (can do the follow thing).
But if I run the whole program, the code just operate maybe several command & stopped (but it didn't error).
I used it for e-commerce (sho.ee).
The step is:
open IE for other shop's followers
grab all the link
open the new link in new IE
follow them, close the new IE
and looping.
If I run step by step it worked.
Hope you guys could help me which wrong with the code.
Here's the code => i changed the name of the shop by xxx
Sub Followers()
Dim objIE As InternetExplorer
Dim ieAnchors As Object
Dim Anchor As Object
Set objIE = New InternetExplorer
objIE.Visible = True
objIE.Navigate "https://shopee.co.id/shop/xxx/followers/"
Do While objIE.Busy = True Or objIE.ReadyState <> 4: DoEvents: Loop
Set ieAnchors = objIE.Document.getElementsByClassName("shop-href")
For Each Anchor In ieAnchors
result = Anchor
If result <> result_prev Then
Dim objIE_1 As InternetExplorer
Dim ieBtn As Object
Dim Btn As Object
Set objIE_1 = New InternetExplorer
objIE_1.Visible = True
objIE_1.Navigate Anchor
Do While objIE_1.Busy = True Or objIE_1.ReadyState <> 4: DoEvents: Loop
Set ieBtn = objIE_1.Document.getElementsByClassName("shopee-button-outline shopee-button-outline--complement shopee-button-outline--fill ")
For Each Btn In ieBtn
Btn.Click
Next Btn
objIE_1.Quit
result_prev = Anchor
End If
Next Anchor
End Sub
Sometimes pages load in parts, registering as complete before all elements have loaded. In these cases I use application.Wait to force the program to wait a set amount of time for page loads:
'wait five seconds
Application.Wait (Now + TimeValue("0:00:05"))
If it is a simple page, I will have a Do loop a check for ReadyState to avoid slowing the program down unnecessarily:
'wait for page to load
Do Until ie.ReadyState = READYSTATE_COMPLETE or ie.ReadyState = 4
DoEvents
Loop
yes it worked. by adding Application.Wait (Now + TimeValue("0:00:05"))
Sub Followers()
Dim objIE As InternetExplorer
Dim ieAnchors As Object
Dim Anchor As Object
Set objIE = New InternetExplorer
objIE.Visible = True
objIE.Navigate "https://shopee.co.id/shop/xxx/followers/"
Do While objIE.Busy = True Or objIE.ReadyState <> 4: DoEvents: Loop
Application.Wait (Now + TimeValue("0:00:02"))
Set ieAnchors = objIE.Document.getElementsByClassName("shop-href")
For Each Anchor In ieAnchors
result = Anchor
If result <> result_prev Then
Dim objIE_1 As InternetExplorer
Dim ieBtn As Object
Dim Btn As Object
Application.Wait (Now + TimeValue("0:00:02"))
Set objIE_1 = New InternetExplorer
objIE_1.Visible = True
objIE_1.Navigate Anchor
Do While objIE_1.Busy = True Or objIE_1.ReadyState <> 4: DoEvents: Loop
Set ieBtn = objIE_1.Document.getElementsByClassName("shopee-button-outline shopee-button-outline--complement shopee-button-outline--fill ")
For Each Btn In ieBtn
Btn.Click
Next Btn
objIE_1.Quit
result_prev = Anchor
End If
Next Anchor
End Sub

Script sometimes logs in a website but fails most of the times

I've created a vba script using Internet Explorer to log in a website using my credentials. The thing is the script sometimes works flawlessly but most of the times it fails while hitting the sign in button, meaning gets stuck there.
Sub SignIn()
Const Url$ = "https://member.angieslist.com/app/search?categoryName=Plumbing&isMisspelling=false&query=Plumbing&categorySearchType=legacy&category=107"
Dim IE As New InternetExplorer, HTML As HTMLDocument
Dim oPass As Object, oMail As Object, oButton As Object
With IE
.Visible = True
.navigate Url
While .Busy Or .readyState < 4: DoEvents: Wend
Set HTML = .document
With HTML
Do: DoEvents: Loop Until .querySelectorAll("#login--login-email").Length > 0
Set oMail = .querySelector("#login--login-email")
oMail.Focus
oMail.innerText = "useremail"
Do: DoEvents: Loop Until .querySelectorAll("#login--login-password").Length > 0
Set oPass = .querySelector("#login--login-password")
oPass.Focus
oPass.innerText = "password"
Do: DoEvents: Loop Until .querySelectorAll("#login--login-button").Length > 0
Set oButton = .querySelector("#login--login-button")
oButton.Focus
oButton.Click 'It gets here stuck most of the times
End With
End With
End Sub
How can I log in that site without fail?
This MIGHT work...50/50 shot.
Sub SignIn()
Const Url$ = "https://member.angieslist.com/app/search?categoryName=Plumbing&isMisspelling=false&query=Plumbing&categorySearchType=legacy&category=107"
Dim IE As New InternetExplorer, HTML As HTMLDocument
Dim oPass As Object, oMail As Object, objElement As Object, objCollection As Object
With IE
.Visible = True
.navigate Url
While .Busy Or .readyState < 4: DoEvents: Wend
Set HTML = .document
With HTML
Do: DoEvents: Loop Until .querySelectorAll("#login--login-email").Length > 0
Set oMail = .querySelector("#login--login-email")
oMail.Focus
oMail.innerText = "useremail"
Do: DoEvents: Loop Until .querySelectorAll("#login--login-password").Length > 0
Set oPass = .querySelector("#login--login-password")
oPass.Focus
oPass.innerText = "password"
Set ElementCol = IE.document.getElementsByClassName("btn btn-sm btn-primary btn-block btn-flat")
ElementCol.Item(0).Click
End With
End With
End Sub

Clicking link within a HTML List

I'm trying use Excel's IE automation tools to click a website link within a users profile of this site. Using the following in VBA:
ie.Document.getElementsByClassName("website")(0).getElementsByTagName("a")(0).Click
But keep getting the Runtime error '438' when ran. Any advice on how to fix this or if clicking this link is even possible please? Thanks.
EDIT (Full Code):
Dim ie As InternetExplorer
Dim html As HTMLDocument
Set ie = New InternetExplorer
ie.Visible = True
ie.Navigate "site"
Do While ie.READYSTATE <> READYSTATE_COMPLETE
DoEvents
Loop
Set objA = ie.Document.getElementsByClassName("website")(0) 'GETTIN ERROR HERE
objA.getElementsByTagName("a")(0).Click
End Sub
It would appear that there were a few minor issues here.
One being that .Click doesn't always function properly, I would suggest using .getAttribute("href") combined with ie.Navigate()
Another being that you seem to define html then never use it again.
The following code works:
Sub test()
Dim ie As InternetExplorer
Dim html As HTMLDocument
Set ie = New InternetExplorer
ie.Visible = True
ie.Navigate "http://beverlyhills.yourkwoffice.com/mcj/user/AssociateSearchSubmitAction.do?orgId=5058&lastName=&firstName=&rows=100"
Do While ie.READYSTATE <> READYSTATE_COMPLETE
DoEvents
Loop
Set html = ie.Document
Set objA = html.getElementsByClassName("website")(0).getElementsByTagName("a")(0)
ie.Navigate (objA.getAttribute("href"))
End Sub

VBA code not selecting a value from a dropdown that has a class but no id

I have some code which is meant to open an IE page and fill in the first drop-down to show "caravan". However my code is not selecting caravan from the drop-down.
The website is:
https://insurance.qbe.com.au/portal/caravan/form/estimate
When I right-click to inspect the source code of the drop-down I get directed to the following:
When I expand the source code below this, I see the following:
As you can see, the values associated with the drop-down are well below the source code I was initially directed to.
Here is the code I've been using to try and select 'caravan':
Sub GetQuote()
Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
IE.navigate ("https://insurance.qbe.com.au/portal/caravan/form/estimate")
IE.Visible = True
Do
DoEvents
Loop Until IE.readystate = 4
Dim lists, l
Set lists = IE.document.getElementsByTagName("select")(0)
For Each l In lists
If InStr(1, l.className, "form-control ng-pristine ng-untouched ng-valid", 1) Then
l.SelectedIndex = 0
End If
Next
Application.Wait (Now + TimeValue("00:00:03"))
End Sub
With the above code I was trying to select 'caravan' by referencing the very last bit of the source code I pasted above (i.e. by getting all select tags and then checking all items within the tag until an item whose class name contains "form-control ng-pristine ng-untouched ng-valid" is found, and then selecting index 0 for the value associated with this item. And this obviously didn't work - so here's other code I have tried, again with no luck (it's a slight modification of the code above, by simply referencing the source code that I was initially directed to when I inspected the drop-down, and that would be the very first source code I pasted):
For Each l In lists
If InStr(1, l.className, "ui-select-search ui-select-toggle ng-pristine ng-valid ng-touched", 1) Then
l.SelectedIndex = 0
Does this offer any help, not sure if it's your solution, but added here for formatting.
Sub test()
Dim ie As SHDocVw.InternetExplorer
Dim htmlDoc As MSHTML.HTMLDocument
Dim inputCollection As MSHTML.IHTMLElementCollection
Dim inputElement As MSHTML.HTMLInputElement
Set ie = New SHDocVw.InternetExplorer
ie.navigate ("https://insurance.qbe.com.au/portal/caravan/form/estimate")
Do While ie.Busy Or ie.readyState <> READYSTATE_COMPLETE
DoEvents
Loop
ie.Visible = 1
Set htmlDoc = ie.document
Set inputCollection = htmlDoc.getElementsByTagName("INput")
For Each inputElement In inputCollection
Debug.Print inputElement.className
Next inputElement
' or like this
Set inputElement = htmlDoc.getElementsByClassName("ui-select-search ui-select-toggle ng-pristine ng-valid ng-touched")(0)
End Sub