How to navigate through links in differents levels selenium vba - vba

Actually, im trying to navigate to a block that has 3 levels.
First level im clicking to open the tree
Second level is an category with Href
Third level sometimes has subcategory with href too
So im trying to navigate through second and third level if exists.
My code works fine at level 1, it clicks all the items from level 1, but for the second level is not working properly.
What can be wrong at second level and how I can do to reach the third one?
driver.Get "https://www.tecnoglobal.cl/tiendaonline/webapp/ofertas/"
driver.Window.Maximize
Set categories = driver.FindElementsByXPath(".//*[#id='acordeon-productos-subcat']")
driver.FindElementByXPath(".//*[#id='js-productos']").Click
For Each category In categories
Application.Wait Now + TimeValue("00:00:01")
category.FindElementByXPath("ancestor::div/a/span").Click
Set categorylinks = driver.FindElementsByXPath(".//*[#id='acordeon-productos-subcat']")
For Each categorylink In categorylinks
linkcategory = categorylink.FindElementByXPath("descendant::div/descendant::span").Text
Thanks in advance.

The links are already present on page load so you don't need to click on products or navigate through tree. Simply gather an initial collection of the final nodes using a css attribute = value selector based on the ng-if attribute value. From that webElements collection extract the href attributes into an array, loop that array and .Get to each one.
Saving the links into an array avoids stale elements exceptions/element not found bubbling up when you navigate away from source page.
There are two patterns specified with Or "," syntax so as to match on 2nd Subcategoria and 3rd Subsubcategorias links.
Dim targets As WebElements, links(), link As webElement, i As Long
Set targets = driver.FindElementsByCss("[ng-if='!Subcategoria.leaf'],[ng-if='!Subsubcategorias.leaf']")
ReDim links(1 To targets.Count)
For Each link In targets
i = i + 1
links(i) = link.Attribute("href")
Next
For i = LBound(links) To UBound(links)
driver.Get links(i)
'do something on page
Next

Related

How to get sub div in the loop in Selenium?

I am attempting to scrape the website
https://justjoin.it/
I want to get all texts inside every job offer.
To get links to job offers I am using Xpath:
Dim elems as Selenium.WebElements
Set elems = mw.FindElementsByXPath("//div[contains(#class,'css-ic7v2w')]/div/div/div/a)
For Each webele In elems
Debug.Print webele.Attribute("href")
Debug.Print webele.Text
Next webele
and it is working fine.
The issue is that I want to go deeper into each specific div (3 divs after) and get the "alt" attribute which is the job offer name.
How to make this work? I suppose it will be some kind of sibling element?
I tried to loop through each webelement and get the siblings of it but I failed.
So what i want to get is to find specific div and loop through next nested divs inside.

findelementsbycss in vba with selenium

i can't manage to extract certain links from a website with css.
i don't really know css yet either and am just finding my way around it.
i have 2 questions one specific how to find the element, and at the end again how to examine the element in css.
1.
Inspection of the site with markers
i am trying to get the two links marked in green, as marker i would like to use either the red marked link text or above it.
my attempted code:
Set Elements = GC.FindElementsByCss("table.TABLE tbody tr td p iframe ")
a = 0
For Each Element In Elements
ReDim Preserve href(a) As String
href(a) = Element.Attribute("innerText")
a = a + 1
Next Element
can i somehow examine the elements in vba?
if i know what is stored in them, i could search for the desired value under Value and then use the expression.
I think under Watches I once had the possibility to see all the different values for an element like innerText, href, outerhtml, innerhtml and so on.
In VBA Watches at the moment i only see a small overview

VBA automation can't get innerText (innerHTML, value)

So, i've gotten innertext many times. This time, it's simply not working. Tried many alternatives.
First of All
I'm using Selenium on VBA to use chromedriver.
The source website is "[http://www.fazenda.df.gov.br/area.cfm?id_area=1536]" This website operates on a Iframe. After half an hour trying to get the inner text from it, i figured that the link in its code works just as fine: "[http://publica.agnet.fazenda.df.gov.br/FichaImovel/#/FichaCadastral]". This last one seems to operate on someting call "Angular".
The menu with the innertext i required is a dropdown one. As a dummy value, you can use 50868748. The dropdown text that it generates is composed by 15 lines and one table. The info that i need is on the 15th line, "Nome do Responsável", or in the column 2 line 2 on the table.
I managed to place the code and generate the dropdown list, but i can't manage to get the inner text.
Here is my code:
Dim iptu As String
Dim driver As New ChromeDriver
With driver
.Start
iptu = 50868748 'dummy
.Get "http://publica.agnet.fazenda.df.gov.br/FichaImovel/#/FichaCadastral"
.FindElementById("inscricaoImovel").Clear
.FindElementById("inscricaoImovel").SendKeys iptu
.FindElementsById("btnCadastro")(2).Click
.Wait (300)
'until here, everything works fine
Dim label As Object
Dim name As String
Set label = .FindElementsByClass("ng-binding")(91)
'as you can see, i end up using this class(91) to get the value on the table, but i can get from the 15th line too
name = label.getAttribute("innerText") 'Error is here
'i've tried .innerText, .innerHTML and others. The error is always "object does not accept property or method" Error 438.
end with
The chrome driver is up to date. Also, the page source does not cointain the info i need.
Anyone can help me out?
To get InnerText of the element, You need to call Text method
Set label = .FindElementsByClass("ng-binding")(91)
name = label.Text
To get inner Html,
name = label.Attribute("innerHTML")
Sometimes I have found that I have to execute javascript to get what I'm after. You can try
name=driver.ExecuteScript("document.getElementsByClassName('ng-binding')[91].innerText;")

Can we Traverse on another page when executing foreach loop?

There is Table on the page, I do need to retrieve information row by row. That is handle by for-each. Execution on same page for retrieving information is working fine.
But, Can we handle Detail page of particular Row ? Here "Test 1" has its own detail page. There are some operation which need to handle on detail page. How can we manage it and get back to actual execution.
As of now I am dealing it with for-each loop, and getting StaleElementReferenceException which is correct as webElement lost its actual ListElement<WebElement>
List<WebElement> findList = driver.findElements(By.xpath("//a[#class='*****']));
for (WebElement webElement : findList) {
...
//detail page is access by clicking webElement
webElement.click();
findList = driver.findElements(By.xpath("//a[#class='*****']));
}
If there is any way, Please suggest. Thanks.
You can do something like this :
List<WebElement> findList = driver.findElements(By.xpath("//a[#class='*****']));
for(int i = 1 ; i<=findList.size() ; i++){
driver.findElement(By.xpath("(//a[#class='***'])[" + i + "]")).click();
// extract some data from next page which is invoked by clicking on Test1 hyperlink.
}
in this way every time you are looking for //a[#class='***'][i] web element i , starting from 1 and till the end point.
P.S : You need to check this in devtool //a[#class='***'][1], whether it indicates the Test1 hyperlink or not.
Hope this helps.
Try to collect urls to detail pages of all and then open them.
There are two scenarios i can think of :
Clicking the link e.g. Test1 opens a new tab :
In this case you can just switch to new tab inside your loop , finish your operation on this tab and finally close the second tab / switch to first tab before continuing with your next iteartion. This should also not cause StaleElementException.
Clicking the link e.g. Test1 redirects to some other url in same tab :
For each iteration of loop, click on target link , perform some operation on new page.Before you continue with next iteration , Navigate to page containing your table again and lookup all the row elements again. Now , for next iteration you won't get StaleElementException. You will want to use the for loop so that you can maintain the index outside instead of a foreach variant.
findList = driver.findElements(By.xpath("//a[#class='*****']))
I would recommend the first option since that would be more clean and you can perform a shift + click on your link e.g. Test1 to force it open in a new tab instead of redirecting in same page. You can perform a shift + click using "Actions api" available in Selenium.

How to check all the links dynamically?

The following thing I have to do using VBScript in QTP 10/11:
The VBScript opens one login page. After the login it counts the number of links in that page and then prints all the links. Afterwards it opens every link one by one.
I am having issues with finding all the dynamic links.
You can get all the links on a page by using the Page's (or Frame's) ChildObject method.
Set desc = Description.Create()
desc("html tag").Value = "a"
Set links = Browser("B").Page("P").ChildObjects(desc)
For i = 0 to links.Count - 1
Print links(i).GetRoProperty("inner_text") & " => " & links(i).GetRoProperty("href")
Next
As for clicking them, that's a bit more complicated since after clicking a link you cause a navigation that invalidates the links object, you should either perform the ChildObjects each time (while keeping track of the index) or open the links in a different browser/tab.