On the Sofascore.com site, I will automatically take the link in cell A1 at https://www.sofascore.com/tr/football/2022-11-16 or similar, and run it in the for next loop and print some information of the matches on my table. In order to print the information, I first have to click on each match one by one. I also do this with CSS.Click. But since I'm going to do this over and over, I definitely need a loop. CSS links are very similar to each other, only 1 number changes for each match. The first thing that comes to my mind is a next loop for CSSs that automatically picks up the next CSS code, but I don't have enough knowledge. I want to consult experts, thanks in advance.
I am open to all suggestions.
Sub sofascore()
Dim x As New Selenium.ChromeDriver, i, sonsat As Integer
x.SetProfile "C:\Users\Oğuzhan\AppData\Local\Google\Chrome\User Data"
x.AddArgument ("user-data-dir=C:\Users\xyz\AppData\Local\Google\Chrome\User Data\System Profile")
x.Start "chrome", "https://www.sofascore.com/"
x.Window.Maximize
Set ks = New Selenium.Keys
sonsat = Sheets("veri").Range("A10000").End(xlUp).Row
For i = 2 To sonsat
On Error Resume Next
x.Get Range("A" & i).Value
'CLICK THE SHOW ALL MATCHES ON THE SITE.
x.FindElementByCss("#__next > div > main > div.sc-
hLBbgP.dRtNhU.sc-cabffeca-0.QpfGa > div.sc- hLBbgP.sc-eDvSVe.gjJmZQ.fEHohf.sc-cabffeca-1.iITCqu > div.sc-hLBbgP.tYcjv.sc-cabffeca-2.loALSf > div > div.sc-hLBbgP.sc-eDvSVe.bdzsxu.hryjgv > button > div > span").Click
x.SendKeys ks.Home
x.Wait 200
'CLICK ON MATCH 1 ON THE LIST
x.FindElementByCss("#__next > div > main > div.sc-hLBbgP.dRtNhU.sc-cabffeca-0.QpfGa > div.sc-hLBbgP.sc-eDvSVe.gjJmZQ.fEHohf.sc-cabffeca-1.iITCqu > div.sc-hLBbgP.tYcjv.sc-cabffeca-2.loALSf > div > div:nth-child(2) > div > div > div:nth-child(2) > a > div > div > div.sc-hLBbgP.dRtNhU.sc-9199a964-1.kusmLq").Click
x.Wait 1500
'THE FOLLOWING CODES PRINT THE MATCH DATA INTO THE COLUMNS.
codes..
..
'THIS IS IMPORTANT NOW. FOR MATCH 2, THE LOOP STARTS AGAIN AND WITH THE EXACT SAME CODES. HERE I HAVE TO MANUALLY WRITE THE 2nd CSS CODE :(
x.FindElementByCss("#__next > div > main > div.sc-hLBbgP.dRtNhU.sc-cabffeca-0.QpfGa > div.sc-hLBbgP.sc-eDvSVe.gjJmZQ.fEHohf.sc-cabffeca-1.iITCqu > div.sc-hLBbgP.tYcjv.sc-cabffeca-2.loALSf > div > div:nth-child(2) > div > div > div:nth-child(3) > a > div > div > div.sc-hLBbgP.dRtNhU.sc-9199a964-1.kusmLq").Click
x.Wait 1500
'Same codes upper
....
...
...
Next
End Sub
I've tried many ways but probably nonsense. Expert comments will enlighten me.
Related
I'm trying to scape data from a website via Excel VBA. I have a web page which has different data depending on a button selection, but the button sits withing a ul list. I can find the element by class using:
.FindElementByClass("shared-filter-button-list_navItem__ZiG2J")
But I can seem to work out how to switch the focus between 'This season' and 'All time' to change to displayed data on the page. Any ideas would be gratefully received. The html is:
<ul class="shared-filter-button-list_navContainer__3hJmS"><li class="shared-filter-button-list_navItem__ZiG2J is-active"><button class="tag-button_btn__1B2dI tag-button__purple__3SyTF shared-filter-button_wrap__3OgbA is-active" value="This season" type="button">This season</button></li><li class="shared-filter-button-list_navItem__ZiG2J"><button class="tag-button_btn__1B2dI tag-button__purple__3SyTF shared-filter-button_wrap__3OgbA " value="All time" type="button">All time</button></li></ul>
It would help to see the page, but if you just want to click the "this season" or "all time" button, just find the buttons inside the list you already have and click one?
update
I misread the provided HTML (its all in one line) and thought that shared-filter-button-list_navItem__ZiG2J was the container ul not the list items, and also that selenium uses 1-based indexes not 0-based.
The code below finds all buttons that match the query and prints their index and text to the debug window.
Private Driver As Selenium.ChromeDriver
Sub Main()
Set Driver = New Selenium.ChromeDriver
Driver.Get "https://www.euroleaguebasketball.net/eurocup/players/lukas-meisner/011187/"
Dim List As Selenium.WebElements
' get a list of button that are children of li with specified class name
Set List = Driver.FindElementsByXPath("//li[contains(#class, 'shared-filter-button-list_navItem__ZiG2J')]/button", 0, 5000)
If List Is Nothing Then
Debug.Print "failed to get list"
Exit Sub
End If
For Index = 1 To List.Count
Debug.Print Index & " -> " & List(Index).Text
Next Index
End Sub
Expected result from this code is:
1 -> This season
2 -> All time
3 -> Regular Season
If you wanted to click the This season button
List(1).Click
I have a case where I am trying to scrape multiple pages, but I noticed that the desired part to scrape is different sometimes and this makes me to use IF statements to check for the existence of object like that
Set obj = html.querySelector("div > blockquote > p > span > strong")
If obj Is Nothing Then
Set obj = html.querySelector("div > blockquote > p > strong > span")
If obj Is Nothing Then
Set obj = html.querySelector("div > blockquote:nth-child(14) > p > strong")
If obj Is Nothing Then
Set obj = html.querySelector("div > blockquote:nth-child(13) > p > strong")
If obj Is Nothing Then
Set obj = html.querySelector("div > blockquote:nth-child(12) > p > strong")
End If
End If
End If
End If
Is there an alternative and more reliable way to solve such a problem?
You have to know there are more cases for the element
Without actual html to work with unsure if there are additional alternatives such as writing simpler/more transferable css selector lists.
That said, here are two options I would consider. Option 1: For very long css selector lists. Reduce the complexity of your code and have the one level of nesting. Option 2: For shorter css selector lists, use OR syntax to test for alternate patterns.
Having each alternate list on its own line, in one place, should aid with code maintenance over time.
Dim tests() As Variant, test As Long
tests = Array( _
"div > blockquote > p > span > strong", _
"div > blockquote > p > strong > span", _
"div > blockquote:nth-child(14) > p > strong", _
"div > blockquote:nth-child(13) > p > strong", _
"div > blockquote:nth-child(12) > p > strong")
'-------------------------
'Option 1: Single nested testing for longer selector list
For test = LBound(tests) To UBound(tests)
Set obj = HTML.querySelector(tests(test))
If Not obj Is Nothing Then Exit For
Next
'Option 2: CSS OR syntax for shorter selector list
Dim selectorList As String
selectorList = Join$(tests, ",")
Set obj = HTML.querySelector(selectorList)
'--------------- then continue -------
If Not obj Is Nothing Then
' do something
End If
If going with Option 1 I might then go on to consider using a flag boolean variable
Dim found As Boolean
For test = LBound(tests) To UBound(tests)
Set obj = html.querySelector(tests(test))
found = Not obj Is Nothing
If found Then Exit For
Next
If found Then
'do something
End If
All,
I am using cheerio package for web scraping,
cheerio tr selector as below. i want to find length of x to iterate
body > table > tbody > tr:nth-child(x) > th:nth-child(2)
Below is my score card html, i want to calculate the total marks of subjects.
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"/><title>Student Score Card</title><h3>Score card</h3>
<table>
<tr><th>Subject</th><th>Marks</th></tr>
<tr><th>English</th><th>78</th></tr>
<tr><th>Maths</th><th>98</th></tr>
<tr><th>Science</th><th>83</th></tr>
<tr><th>Lab</th><th>80</th></tr>
<tr><th>Physical</th><th>75</th></tr>
</table></html>
here i know the row count as 6, so hard coded the value. however it may change in future. so not able to find the max value via code, looking for help here.
Sample logic
const $ = cheerio.load(scorecard.html);
let total = 0;
for(i=0;i<6;i++){
total += parseInt($("body > table > tbody > tr:nth-child("+i+") > th:nth-child(2)").text().valueOf());
}
console.log(total);
If I understand correctly what you are trying to do, then this should help.
const selectors = Array.from($("body > table > tbody > tr"));
let total = 0;
for (let i = 0; i < selectors.length; i++) {
total += parseInt($(selectors[i]).find("th:nth-child(2)").text());
}
console.log(total);
I have an element with this html
<span id="ContentPlaceHolder1_Label2" designtimedragdrop="1319" style="display:inline-block;color:Firebrick;font-size:Medium;font-weight:bold;width:510px;"></span>
and after clicking Save button on the page this part changes to that
<span id="ContentPlaceHolder1_Label2" designtimedragdrop="1319" style="display:inline-block;color:Firebrick;font-size:Medium;font-weight:bold;width:510px;">تم حفظ التعديل بنجاح</span>
You would notice this value تم حفظ التعديل بنجاح ..
After that I should click another button but the problem appears when the internet connection is slow. I got the other button clicked before saving
How can I wait for the appearance of the value تم حفظ التعديل بنجاح and then after the appearance of that text >> move to the another button
Thanks advanced for help
I have tried this solution and it worked well for me
This was with the help of Ziggus' suggestion
Do Until .FindElementById("ContentPlaceHolder1_Label2").Text = "تم حفظ التعديل بنجاح"
Application.Wait Now() + TimeValue("00:00:01")
Loop
I would re-write this as you risk an infinite loop. Make it a timed loop and add in a DoEvents.
Dim result As String, testElement As Object, t As Date
Const MAX_WAIT_SEC As Long = 10 '<==adjust time here
t = Timer
Do
DoEvents
On Error Resume Next
Set testElement = .FindElementById("ContentPlaceHolder1_Label2")
result = testElement.Text
If Timer - t > MAX_WAIT_SEC Then Exit Do
On Error GoTo 0
Loop While result <> "تم حفظ التعديل بنجاح"
So I've got this program that opens a PDF that I want to save. I thought I'd circumvented this SaveAs dialog box using SetPreferences, and yet here's the dialog box again. Anyone have any success getting SetPreferences to turn off the SaveAs dialog?
Am I trying to set these preferences in the wrong place in the program? My understanding was it happens before the bot is started.
Sub CompanyName()
Dim bot As New Selenium.WebDriver
MyFolder = ThisWorkbook.Path
bot.SetPreference "download.default_directory", MyFolder
bot.SetPreference "download.directory_upgrade", True
bot.SetPreference "download.prompt_for_download", False
bot.Start "Chrome", "https://www.intacct.com/ia/acct/login.phtml?[![enter image description here][1]][1]_ga=2.13247287.1007588550.1536894830-1229002215.1536894830"
bot.Get "/"
bot.FindElementById("company").SendKeys "Company ID"
bot.Wait 500
bot.FindElementById("login").SendKeys "Username"
bot.Wait 500
bot.FindElementById("passwd").SendKeys "Password"
bot.Wait 500
bot.FindElementById("retbutton").Click
Stop
'bot.SwitchToParentFrame
Dim menuitem As WebElement
Set menuitem = bot.FindElementByCss("#mainmenu > div > div:nth-child(7) > div.iamenutitlewrapper > span")
bot.Actions.MoveToElement(menuitem).Perform
bot.FindElementByXPath("//span[#class='iamenutitle'][contains(text(),'Accounts Payable')]").Click
bot.FindElementByCss("#mainmenu > div > div:nth-child(7) > div.iamenu.mega.setup-closed > div > div > table > tbody > tr:nth-child(5) > td:nth-child(2) > span:nth-child(2)").Click
bot.SwitchToFrame "iamain"
bot.FindElementByName("F_RECORDID").SendKeys "123"
bot.SendKeys bot.Keys.Enter
bot.Wait 500
bot.FindElementByLinkText("View").Click
bot.Wait 500
bot.FindElementByCss("span.buttons.view_attachment").Click
bot.SwitchToNextWindow
bot.SendKeys bot.Keys.Control, "s"
The code seems to be ok!
Maybe the reason can be the Selenium Driver version.
Try to update enr driver on official link here chromedriver.
I hope it helps you.
Best Regards,
Pedro Azzam.