Extract Data with Selenium and VBA - vba

I'm new using selenium. I have a site that is not more compatible with the IE, so i decided to try this new technique, but can't see what is wrong on my code. Any help will be apreciated.
Sub ExtractPrice()
Dim bot As WebDriver, myproducts As WebElements, myproduct As WebElement
Set bot = New WebDriver
bot.Start "chrome"
bot.Get "https://www.veadigital.com.ar/prod/72060/lechuga-capuchina-por-kg"
' Application.Wait Now + TimeValue("00:00:20")
Set myproducts = bot.FindElementsByClass("datos-producto-container")
'
For Each myproduct In myproducts
If myproduct.FindElementByClass("product-price").Text <> "" Then
'Debug.Print myproducts.FindElementByClass("product-price").Text
Worksheets("VEA").Range("b2").Value = myproducts.FindElementsByClass("product-price").Text
End If
Next
MsgBox ("complete")
End Sub

Issue is in this line :
Worksheets("VEA").Range("b2").Value = myproducts.FindElementsByClass("product-price").Text
Remember FindElements, returns a list of webelements rather than webelement. Instaead use the line you have used in if condition.
Worksheets("VEA").Range("b2").Value=myproduct.FindElementByClass("product-price").Text
Note : With above line of code you will get your price, but it will come as $379 instead of $3.79. As there is no . in price on page. Better way to store price is :
Dim intValue = myproduct.FindElementByClass("product-price").Text
Dim decValue= myproduct.findElementByXPath(".//div[#class='product-price']//span").Text
Worksheets("VEA").Range("b2").Value = Replace(intValue , decValue, "."&decValue)
Above will assign $3.79.

Related

How to check the visibility of the element in Edge Browser using VBA Selenium and alternative to Obj.Wait

Unable to check the visibility of the element. Please guide
At present using Obj.Wait to wait so that Site is loaded fully. Is there any other way which can check the Edge Browser has loaded fully before execution of next code
In the instant case
Obj.Wait 580000
If Obj.IsElementPresent(By.XPath("//*[#id='downloadReport']/div")) = True Then
I have a following VBA code + Selenium which is opening a website, populate data from Excel and displays the record.
Dim Obj As New WebDriver
Sub EdgeAutoSF1CRA0()
Set Obj = New Selenium.EdgeDriver
Dim By As New Selenium.By
Obj.SetCapability "ms:edgeOptions", "{""excludeSwitches"":[""enable-automation""]}"
Obj.Start "edge", ""
Obj.Get "https://************
Obj.Window.Maximize
Obj.FindElementByName("croreAccount").SendKeys ("Search")
Obj.FindElementByXPath("//*[#id='loadSuitFiledDataSearchAction']/div[1]/div[3]/div[4]/img").Click
Obj.FindElementById("borrowerName").SendKeys (ThisWorkbook.Sheets("Sheet1").Range("C5").Value)
Obj.FindElementByXPath("//*[#id='search-button']/ul/li[1]/div/input").Click
Obj.Wait 580000
If Obj.IsElementPresent(By.XPath("//*[#id='downloadReport']/div")) = True Then
Obj.FindElementByXPath("//*[#id='downloadReport']/div").Click
Else
Obj.FindElementByXPath("//*[#id='three-icons']/ul/li[3]/a/div").Click
End If
'Call EdgeAutoSF25LA0
End Sub
If match is found, then element
XPath("//*[#id='downloadReport']/div")
is visible. The code at site is
'a href="downloadStatusReport" id="downloadReport">Download</a
If no match is found, then element
XPath("//*[#id='downloadReport']/div")
is not visible. The code at site is
'a href="downloadStatusReport" id="downloadReport" style="display: none;">Download</a

I want to fill data with javascript in selenium vba

I have a web form of pre populated data which i have to fill. I want to do this with javascript. I am not sure to write the code .
Public Sub ABC()
Dim document As HTMLDocument
Dim bot As New WebDriver
Dim cSCRIPT,m
m=58
bot.Start "chrome", ""
bot.Get "https://XYZ"
cSCRIPT = "document.getElementByXPath("//td[contains(text(),'XXXX')]/following-sibling::td[5]").value='" & m & "'"
bot.ExecuteScript cSCRIPT
But my code do not work. How can I code in selenium VBA with the help of XPath to fill data in Web table.
I can't test this in VBA but have translated from python which worked. I use evaluate to handle the xpath matching.
The function Document.evaluate() has the following definition:
var xpathResult = document.evaluate(
xpathExpression,
contextNode,
namespaceResolver,
resultType,
result
);
The first argument is the xpath expression. Then contextNode is basically the node to apply the xpath to i.e. document in this case. namespaceResolver is null as no namespace prefixes are used (it's an html document). I specify resultType as XPathResult.ANY_TYPE so as to get the natural type from the expression. For result argument I pass null so as to create a new XPathResult.
The return type is object. I use iterateNext to get to the input element and then assign the visual value with input.value = "abc"; and the actual with input.setAttribute('value', 'xyz');.
I am using a testable example but you would amend as per your html which means your xpath would be
//td[contains(text(),'XXXX')]/following-sibling::td[5]/input
VBA:
Dim s As String
s = "var td = document.evaluate(""//tr[contains(td/text(), 'Angelica Ramos')]/td[2]/input"", document, null, XPathResult.ANY_TYPE, null);" & _
"var input = td.iterateNext();" & _
"input.value = 'abc';" & _
"input.setAttribute('value', 'xyz');"
bot.Get 'https://datatables.net/examples/api/form.html'
bot.ExecuteScript s
Python original:
bot.get('https://datatables.net/examples/api/form.html')
s = '''var td = document.evaluate("//tr[contains(td/text(), 'Angelica Ramos')]/td[2]/input", document, null, XPathResult.ANY_TYPE, null);
var input = td.iterateNext();
input.value = 'abc';
input.setAttribute('value', 'xyz');
'''
bot.execute_script(s)
References:
https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate
https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate#Result_types
https://javascript.info/object
https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/singleNodeValue
https://developer.mozilla.org/en-US/docs/Web/API/XPathResult/iterateNext
It's tough to debug the XPath without seeing the table and underlying HTML for the webpage, but typically if a table is tough to access, I just use a macro tool like AppRobotic to leverage screen X,Y coordinates of the table to click into it and fill in the necessary info, sometimes navigating using keyboard strokes while in the table works well also:
Set Waiter = CreateObject("Selenium.Waiter")
Set Assert = CreateObject("Selenium.Assert")
Set bot = CreateObject("Selenium.FirefoxDriver")
Set x = CreateObject("AppRobotic.API")
Sub ABC
' Open webpage
bot.Get "https://www.google.com"
' Wait a couple of seconds
x.Wait(2000)
' Type in the Search box
bot.FindElementByName("q").SendKeys "test"
bot.Keys.Return
' Or use coordinates if an element is difficult to find
' Use UI Item Explorer to get X,Y coordinates of Search box and move cursor
x.MoveCursor(438, 435)
' click inside Search box
x.MouseLeftClick
x.Type("test")
x.Type("{ENTER}")
While Waiter.Not(Instr(bot.Title, "test")): Wend
x.MessageBox("Click OK to quit the browser"):
bot.Quit
End Sub

How to click the date picker selenium VBA?

I'd like to use selenium VBA to download some data from Yahoo Finance KOSPI COmposite Index.
I got the difficulty when click the date picker arrow to get the mini window to select the end date as today. I tried to record the marco through selenium IDE in chrome, but IDE does not record the step when I click the arrow of the Time period to get the date picker visible.
Below is my code in VBA.
Public Function seleniumKorea(bot As WebDriver)
Dim url As String
url = "https://finance.yahoo.com/quote/%5EKS11/history?period1=1484018309&period2=1515554309&interval=1d&filter=history&frequency=1d"
bot.Start "chrome", url
bot.Get "/"
'Not sure how to add date picker here
bot.FindElementByName("endDate").Clear
bot.FindElementByName("endDate").SendKeys (Date)
bot.FindElementByXPath("(.//*[normalize-space(text()) and normalize-space(.)='End Date'])[1]/following::button[1]").Click
Application.Wait (Now + TimeValue("0:01:00"))
bot.FindElementByXPath("(.//*[normalize-space(text()) and normalize-space(.)='As of'])[1]/following::div[4]").Click
Application.Wait (Now + TimeValue("0:01:00"))
bot.FindElementByXPath("(.//*[normalize-space(text()) and normalize-space(.)='Currency in KRW'])[1]/following::span[2]").Click
Application.Wait (Now + TimeValue("0:01:00"))
End Function
I tried to use the ByXPath to get the svg class but failed.
Thanks in advance.
I would use the following which submits the OATH consent if required and scrolls the date picker into the viewport
Option Explicit
Public Sub DatePicking()
Dim d As WebDriver
Set d = New ChromeDriver
Const URL = "https://finance.yahoo.com/quote/%5EKS11/history?period1=1484018309&period2=1515554309&interval=1d&filter=history&frequency=1d/"
With d
.get URL
If .Title = "Yahoo is now part of Oath" Then
.FindElementByCss("form").submit
End If
With .FindElementByCss("[data-test='date-picker-full-range']")
.ScrollIntoView
.Click
End With
With .FindElementByCss("[name=startDate]")
.Clear
.SendKeys "05/10/2017"
End With
With .FindElementByCss("[name=endDate]")
.Clear
.SendKeys "05/10/2017"
End With
Stop '<==Delete me later
.Quit
End With
End Sub
Check this out. It should serve the purpose. I used xpath to solve the issue.
Sub CustomizeDate()
Const Url$ = "https://finance.yahoo.com/quote/%5EKS11/history?period1=1484018309&period2=1515554309&interval=1d&filter=history&frequency=1d"
Dim driver As New ChromeDriver
With driver
.get Url
.FindElementByXPath("//input[#data-test='date-picker-full-range']", timeout:=5000).Click
.FindElementByXPath("//input[#name='startDate']").Clear.SendKeys ("01/05/2017")
.FindElementByXPath("//input[#name='endDate']").Clear.SendKeys ("01/08/2017")
.FindElementByXPath("//button/span[.='Done']", timeout:=5000).Click
.FindElementByXPath("//button/span[.='Apply']", timeout:=5000).Click
End With
End Sub
Don't use hardcoded delay for any item to appear. Use Explicit Wait instead. The script will wait upto 5000, meaning 5 seconds for that item to be available.

Cannot Login with Excel VBA Selenium

So I am tryin to create a Script that will automatically login for me on this website:
https://teespring.com/login
This is my script so far:
Sub openBrowser()
'Open new browser
Set driver = New Selenium.ChromeDriver
'Navigate to Website
urlWebsite = "https://teespring.com/login"
driver.Get urlWebsite
So I have tried to enter my username with the following lines of code:
driver.FindElementByCss("").sendKeys Username
But I got an error saying element not visible
Is there any way I can still automate the login process?
thanks for your help and if you need further information I will try my best to as I am still learning how to handle vba selenium :-)
It is not visible because it is inside a form.
You need to access via form:
Option Explicit
Public Sub EnterInfo()
Dim d As WebDriver
Set d = New ChromeDriver
Const URL = "https://teespring.com/login"
With d
.Start "Chrome"
.get URL
With .FindElementByClass("js-email-login-form")
.FindElementByCss("input[name=email]").SendKeys "myEmail"
.FindElementByCss("input[name=password]").SendKeys "myPassWord"
.FindElementByCss("input[type=submit]").Click
End With
Stop '<== Delete me after inspection
.Quit
End With
End Sub

How can I scroll down a webpage using Selenium with VBA

I've written a script using VBA in combination with selenium to get all the company links from a webpage which doesn't display all the links until scrolled downmost. However, when I run my script, I get only 20 links but there are 1000 links in total. I've heard that it is possible to accomplish this type of task executing javascript function between the code. At this point, I can't get any idea how can I place that within my script. Here is what I've tried so far:
Sub Testing_scroll()
Dim driver As New WebDriver
Dim posts As Object, post As Object
driver.Start "chrome", "http://fortune.com/fortune500"
driver.get "/list/"
driver.execute_script ("window.scrollTo(0, document.body.scrollHeight);") --It doesn't support here
Set posts = driver.FindElementsByXPath("//li[contains(concat(' ', #class, ' '), ' small-12 ')]")
For Each post In posts
i = i + 1
Cells(i, 1) = post.FindElementByXPath(".//a").Attribute("href")
Next post
End Sub
According to the examples included with SeleniumBasic you should be using
driver.ExecuteScript("window.scrollTo(0, document.body.scrollHeight);")
not "driver.execute_script", which is the python equivalent from the previous solution I gave you :) You are going to have to loop that in the same way until you've got all 1000 links on the page.
This works for me. It scrolls incrementally down the page until it reaches the end. I found that scrolling directly to the end didn't load all of the in-between elements. This example is Selenium VBA for a Chrome driver.
Sub scrollToEndofPage(dr As WebDriver)
Dim aCH As WebActionChain, scrPOS As Long, oldPOS As Long
scrPOS = dr.ExecuteScript("return window.pageYOffset;")
Set aCH = dr.ActionChain
oldPOS = -1
Do While scrPOS > oldPOS
oldPOS = scrPOS
aCH.ScrollBy 0, 100: aCH.Perform
scrPOS = dr.ExecuteScript("return window.pageYOffset;")
DoEvents
Loop
End Sub