I'm trying to locate a specific HTML element via class name but it's not finding anything. I've looked into it for a while but I'm unable to identify the issue
HTML snippet: div's class name is fl-l score
My Python Code:
# Throws Timeout Exception because element unable to be located.
WebDriverWait(self.driver, 5).until(ec.presence_of_element_located((By.CLASS_NAME, "fl-l score")))
score_block = self.driver.find_element_by_class_name("fl-l score")
I should also note that I tried finding it using XPath, which worked, but it's not a viable solution because the website is dynamic.
Instead of finding element by class name, you can change the locator by css selector for multiple class names:
WebDriverWait(self.driver, 5).until(ec.presence_of_element_located((By.CSS_SELECTOR, ".fl-l.score")))
score_block = self.driver.find_element_by_css_selector(".fl-l.score")
The above code hits the page twice, to be more efficient you should compress it into one line, like so:
score_block = WebDriverWait(self.driver, 5).until(ec.presence_of_element_located((By.CSS_SELECTOR, ".fl-l.score")))
In Selenium we do not have support for multiple class name, so basically we are left with only css and xpath in this kinda situation.
Since xpath is not viable solution in your case. try css.
You can combine multiple classes by removing the spaces in between, and simply putting . in that place.
Also, WebdriverWait will always return a common exception, and it's hard to figure out what exactly went wrong, so try using driver.find_element in case you want to have the proper error stack trace.
But for just that matter you should not remove WebdriverWait.
Try this :
score_block = self.driver.find_element_by_class_name("div.fl-l.score")
should work for you. if it works then replace with WebDriverWait
Related
I'm trying to use relative locators in selenium 4, but I'm not having much luck with it.
I found an example here, but even though I'm able to find the first element, the second line doesn't work and it seems to be stuck there (I cannot close the browser automatically afterwards).
decision_div = browser.find_element(By.CLASS_NAME, "decisions")
conclusion_div = browser.find_element(locate_with(By.TAG_NAME, "div").below(decision_div))
How can I get it to find the next div right below the one with the specified class name?
As you are able to find the first element, I don't see any issues in your code as such:
decision_div = browser.find_element(By.CLASS_NAME, "decisions")
conclusion_div = browser.find_element(locate_with(By.TAG_NAME, "div").below(decision_div))
You just need to ensure that the the element with the value of class attribute as decisions is above the desired <div> element as follows:
<sometagname class="decisions" ...></div>
<div class="some class" ...></div>
Note : You have to add the following imports :
from selenium.webdriver.support.relative_locator import locate_with
References
You can find a couple of relevant detailed discussions in:
How to get the count of likes from a Twitter post using Selenium?
Selenium 4 relative locators are dealing with pair of web elements with the similar size and adjacent positions, not what you are trying to do here.
In this case the div element you are trying to locate is similarly nested below the parent element located by decisions class name.
So, you can simply locate the conclusion_div element with this code line:
conclusion_div = browser.find_element(By.XPATH, "//div[#class='decisions']//div")
But since the locator above gives 13 matches and I don't know which of them you want to locate it could be:
conclusion_div = browser.find_element(By.XPATH, "//div[#class='decisions']//div")
Or maybe
conclusion_div = browser.find_element(By.XPATH, "//*[#class='decisions']//div[contains(#class,'carousel')]")
Or maybe
conclusion_div = browser.find_element(By.XPATH, "//*[#class='decisions']//div[#class='decision-image']")
The picture attached show the structure of the HTML page that I am trying to scrape:
First I retrieve the element league-item and then I am looking for the i item with class name : 'ds-icon-material league-toggle-icon'
Selenium is telling me that it cannot find any item with such name.
Here is my code:
path = r"""chromedriver.exe"""
driver = webdriver.Chrome(executable_path=path)
driver.get(_1bet)
time.sleep(5)
#a = driver.find_element_by_class_name('box-content.box-bordered.box-stick.box-bordered-last')
league1 = driver.find_elements_by_class_name('league-list')[0]
league1.find_element_by_class_name("ds-icon-material league-toggle-icon")
Can you please help me? I dont understand why it isn't working.
Thanks
NB: The website I'm scraping is: https://1bet.com/ca/sports/tennis?time_range=all
I can't access that web page so I can only guess what is going there.
I can figure 2 problems here:
To select element inside element it's better to use XPath starting with a dot .
The element you trying to access having 2 class names. You should use css selector or XPath to locate element according to multiple class names.
So I suggest you trying this:
league1 = driver.find_elements_by_class_name('league-list')[0]
league1.find_element_by_xpath(".//i[#class='ds-icon-material league-toggle-icon']")
Selenium expects single class name - and it adds dot at the beginning to create CSS selector.
But "ds-icon-material league-toggle-icon" is two classes and it will add dot befor first class but not before second class and this makes proble.
You may use directly css selector with all dots
.find_element_by_css_selctor(".ds-icon-material.league-toggle-icon")
or you have to trick Selenium and add missing dots between classes
.find_element_by_class_name("ds-icon-material.league-toggle-icon")
I can't connect with this page to confirm that this is all.
I'm trying to get text using Selenium WebDriver and here is my code. Please note that I don't want to use XPath, because in my case the ID gets changed on every relaunch of the web page.
My code:
driver.find_element_by_class_name("05uR6d").text
HTML:
<div class="O5uR6d">to fasten stuff</div>
Error:
selenium.common.exceptions.InvalidSelectorException: Message: invalid selector: An invalid or illegal selector was specified (Session info: chrome=88.0.4324.150)
Error is specific to the line of code I mentioned above.
How can I fix this?
Use this xpath:
driver.find_element_by_xpath("//div[contains(text(),'to fasten stuff')]")
Or this CSS:
driver.find_element_by_css_selector(".O5uR6d")
If both won't work, improve your question by adding more data of HTML you are looking at.
It can be done using multiple ways let me try to explain most of them.
Get element by class name.
this is the most easiest solution to get any element by class name you can simply do is:
driver.find_element_by_class_selector('foo');
Get Element by xpath
This is a bit tricky one, you can apply xpath either the class name, title, id or whatever remains same. it also works even if there's a text inside your div. For example:
driver.find_element_by_xpath("//tagname[#attribute='value']")
or in your case:
driver.find_element_by_xpath("//div['class='O5uR6d']")
or you can do something like #vitaliis said
driver.find_element_by_xpath("//div[contains(text(),'to fasten stuff')]")
You can read more about xpath and how to find it on this link
Get Elements by ID:
You can also get the element from id if there's any that's static:
driver.find_element_by_id('baz')
Get Elements by Name:
Get Elements by name using the following syntax:
driver.find_element_by_name('bazz')
Using CSS Selectors:
You can also use the css selectors to find the elements. Consider a following tag that has some attributes:
<p class="content">Site content goes here.</p>
You can get this element by:
driver.find_element_by_css_selector('p.content')
You can read more about it over here
I'm using Selenium to fill out this HTML form, but when it comes to inputting the data it says 'element not interactable'. I am able to click on the element however actually sending a string produces an error. How can I fix this?
driver.get('https://www.masmovil.es/cobertura-fibra-optica-campos/')
prov = Select(driver.find_element_by_xpath('//*[#id="province"]'))
prov.select_by_index(32)
driver.find_element_by_xpath('//*[#id="town"]').send_keys('1')
Thank you!
In the page you are accessing there are 2 elements that are returned with the selector by_xpath('//*[#id="town"]'), one is a "mm-ui-autocomplete", the other one is an "input".
the "mm-ui-autocomplete" is not visible nor interactable to a real user, that's probably what's throwing the exception you're having, and selenium always takes the first match when there's more than one element returned by the selector, so, assuming you want to type something on the "Localidad" field, it is selecting the wrong element.
Try changing your selector to by_xpath('//input[#id="town"]') and see if it works.
Hope it helps.
Can you try with this css selector :
input[id='town']
code :
driver.find_element_by_css_selector("input[id='town']").send_keys('1')
The xpath (//*[#id="town"]) you have used has two entries :
one with mm-ui-autocomplete tag and one with input tag.
Always give preference to css selector over xpath. It's more stable then xpath.
In case you would not want to use css selector, then you can use xpath like this :
//input[#id='town']
Code :
driver.find_element_by_xpath("//input[#id='town']").send_keys('1')
In my case, it happens that the find_element was not working before the frontend finished loading.
I solved this by adding sleep(2) before the find_element_by_xpath. You will need to import the function by from time import sleep.
I'm writing a Python program that uses Selenium to navigate to and enter information into search boxes on an advanced search page. This website uses Javascript, and the IDs and Names for each search box change slightly each time the website is loaded, but the Class Names remain consistent. Class names are frequently reused though, so my goal is to use find_elements_by_class_name(classname) and then index through that list.
One box, for example, has the class name x-form-text x-form-field x-form-num-field x-form-empty-field, but I can't use this because selenium considers it a compound class name and throws an error. If I use just a portion of it, such as x-form-text, it can't find the element. My hope is to either find a way to allow the spaces or, if that can't be done, find a way to search for all elements whose class name contains a section of text without spaces, such as x-form-text.
Any help or thoughts would be greatly appreciated!
Edit:
I tried this code:
quantminclass = 'x-form-text.x-form-field.x-form-num-field.x-form-empty-field'
quantmin = '25'
browser.find_elements_by_css_selector(quantminclass)[0].send_keys(quantmin)
But got an error that the list index was out of range, implying that it can't find anything. I inspected the element and that is definitely its class name, so I'm not sure how to proceed.
Those are multiple classes, not a single class with spaces, just use all the classes together.
driver.find_element_by_css_selector('.class1.class2.class3')
In CSS selector a dot . is a class, you can concatenate any number class names
Try converting class name to a CSS selector.
With a CSS selector, a class named x-form-text x-form-field x-form-num-field
turns into .x-form-text.x-form-field.x-form-num-field
So basically just replace spaces with dots and you're good to go.
Since Selenium 4 find_element_by_* is depricated, so you need to use
find_element() [Selenium-doc]
from selenium.webdriver.common.by import By
# By CLASS_NAME
driver.find_element(By.CLASS_NAME, "x-form-text.x-form-field.x-form-num-field.x-form-empty-field")
# By CSS_SELECTOR
driver.find_element(By.CSS_SELECTOR, ".x-form-text.x-form-field.x-form-num-field.x-form-empty-field")
# By XPATH
driver.find_element(By.XPATH, "//*[#class='x-form-text x-form-field x-form-num-field x-form-empty-field']")
If you have class name (or another attrs) with spaces, for example:
<div class="target with space or maybe another-long-text">Test 123</div>
This will work:
driver.find_element_by_xpath("//div[#class='target with space or maybe another-long-text']")