Selenium cannot find class [duplicate] - python

I'm trying to automate a process on this page, and according to its html code, after clicking the wallet button located at the top right corner of that page, it deploys 4 main wallets to choose to log in to the page.
All of those wallets share the same class which is elements__StyledListItem-sc-197zmwo-0 QbTKh, and I wrote the code below in order to try to get their button names (Metamask, Coinbase wallet...), here:
driver = webdriver.Chrome(service=s, options=opt) #execute the chromedriver.exe with the previous conditions
driver.implicitly_wait(10)
driver.get('https://opensea.io/') #go to the opensea main page.
WebDriverWait(driver, 3).until(EC.element_to_be_clickable((By.XPATH, '//*[#id="__next"]/div/div[1]/nav/ul/div[2]/li/button'))) #wait for the wallet button to be enabled for clicking
wallet_button = driver.find_element(By.XPATH, '//*[#id="__next"]/div/div[1]/nav/ul/div[2]/li/button')
wallet_button.click() #click that wallet button
wallet_providers = driver.find_elements(By.CLASS_NAME, "elements__StyledListItem-sc-197zmwo-0 QbTKh") #get the list of wallet providers
for i in wallet_providers:
print(i)
After compiling the code above, I noticed that it didn't print anything, and it was due to the empty array of wallet_providers, which is very weird because I understand that by calling find_elements(By.CLASS_NAME, "the_class_name") it will then return an array containing the elements that share the same class, but it didn't do that in this case.
So, I would appreciate if someone could explain me what did I do wrong? In the end, I just wanted to manage to click on the Metamask button which doesn't always stay at the same location, sometimes it's the first element of that list, sometimes the second...

You are using this CLASS_NAME elements__StyledListItem-sc-197zmwo-0 QbTKh which has space in it.
In Selenium, a class name having space will not be parsed and will throw the error.
The reason why you did not get the error is cause you are using find_elements that will either return a list of web element or nothing.
So how to resolve this?
remove the space and put a . instead to make a CSS_SELECTOR
try this:
wallet_providers = driver.find_elements(By.CSS_SELECTOR, ".elements__StyledListItem-sc-197zmwo-0.QbTKh") #get the list of wallet providers
to be honest we can have better locator than this, cause it seems these values 197zmwo-0.QbTKh are generated dynamically.
I would rather use this CSS:
li[class^='elements__StyledListItem'] span[font-weight]
or this xpath:
//li[starts-with(#class,'elements__StyledListItem')]//descendant::span[#font-weight]
Also, you should print it like this: (this is one way but there are others as well):
Code:
driver.get("https://opensea.io/")
WebDriverWait(driver, 3).until(EC.element_to_be_clickable((By.XPATH, '//*[#id="__next"]/div/div[1]/nav/ul/div[2]/li/button'))) #wait for the wallet button to be enabled for clicking
wallet_button = driver.find_element(By.XPATH, '//*[#id="__next"]/div/div[1]/nav/ul/div[2]/li/button')
wallet_button.click() #click that wallet button
wallet_providers = driver.find_elements(By.CSS_SELECTOR, "li[class^='elements__StyledListItem'] span[font-weight]") #get the list of wallet providers
for i in wallet_providers:
print(i.get_attribute('innerText'))
Console output:
WalletConnect
MetaMask
Coinbase Wallet
Fortmatic
Process finished with exit code 0

The locators you are using are not relative enough, and on my first inspection, I somehow didn't locate them in the DOM. So, refactored code with relative locators to make the code work.
driver.get('https://opensea.io/') #go to the opensea main page.
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//*[#title='Wallet']"))).click()
wallets = WebDriverWait(driver, 10).until(EC.visibility_of_all_elements_located((By.XPATH, "//*[#data-testid='WalletSidebar--body']//li")))
for wallet in wallets:
print(wallet.text)
Output:
WalletConnect
MetaMask
Popular
Coinbase Wallet
Fortmatic
Process finished with exit code 0

You use the class name elements__StyledListItem-sc-197zmwo-0 QbTKh which has space in it to find the elements. Actually, in Selenium we can't use the class name to locate an element/elements which have space in it. You can use CSS-Selector instead of the class name and in CSS-Selector you need to replace the spaces of the class with a (.) dot.
OR
You can use the parent class and then tags to point to the desired elements.
div[class='Blockreact__Block-sc-1xf18x6-0.eOSaGo'] > ul > li

Related

Switch (internal) tab using Selenium

I've been trying to access elements of a website using Selenium but keep getting this message :
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
The problem I'm having seems to be that the website uses the same classes' name between two tabs, and just changes the visibility of one to display the other. For instance, when the first tab is displayed the first div's visibility is visible and the second is hidden. If the second tab is displayed, then the second div is visible, and the first hidden.
For the first tab, I have no problem accessing the desired elements. However, if the second tab is displayed, I get the above error message.
Is there a way to switch between to div like one would do between two iframe ?
This is what my code looks like for the moment :
driver.get(url) #get url
driver.find_element(By.XPATH, "//input[#id='ctl00_cphMaster_ConsultationCitoyenCriteresRecherche_CritereRechercheTabContainer_RechercheSimpleTabPanel_RechercheSimpleControl_MotsClesTextBox']").send_keys(string) #enter searched term
driver.find_element(By.XPATH, "//input[#id='ctl00_cphMaster_ConsultationCitoyenCriteresRecherche_CritereRechercheTabContainer_RechercheSimpleTabPanel_RechercheSimpleControl_PorteeRadioButtonList_1']").click()
driver.find_element(By.XPATH, "//input[#class='Bouton BoutonRechercher']").click() #click the search button
WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH,"//div[#class='Header']")))
driver.find_element(By.XPATH, '//*[#id="__tab_ctl00_cphMaster_ConsultationCitoyenResultatsRecherche_ResultatsRechercheTabContainer_RechercheLETabPanel"]').click() #switch tab
WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH,"//div[#class='Header']")))
while True:
listings = driver.find_elements_by_class_name("InscriptionSummaryValue")
c = 1
for i in listings:
page = int(driver.find_element(By.XPATH, "//span[#class='CurrentPage']").text) #can't find the element because it seems to be located in the first div

I'm unable to locate the element to perform actions on it

I'm facing an issue locating the element on screen when there are no unique identifiers like ID, text etc. As it opens URL, I need to scroll down and click on button - 'Get Started' to proceed!...
Below is my code:
global driver
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.maximize_window()
driver.get("https://My URL")
driver.implicitly_wait(10)
screen = driver.find_element(By.XPATH, '//div[#class="swiper-wrapper"]')
screen.click() (- This step doesnt through any error, i tried using this to scroll down the screen)
element = driver.find_element(By.XPATH, '//span[contains(text(),"Get Started")]')
driver.execute_script("arguments[0].scrollIntoView(true);", element )
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//span[contains(text(),"Get Started")]'))).click()
or
element.click()
Please help me in determining how to locate the element.
enter image description here
In this case you are trying to find span which is inside #shadow-root, Selenium won't be able to click elements inside #shadow-root in easy way. Look here: How to click button inside #shadow-root (closed) using Selenium and Python
But in your case you probably don't need/want to click this specific span, becouse you have custom element ion-button, which has some click event listener attached to it.
You can check XPATH value in browser devtools. If you go to Elements tab, you can right click desired element and choose option Copy>Copy Xpath. Also make sure your element is not inside iframe tag, it could cause problem as well.

Not able to select and click dropdown search query result with Selenium webdriver

Im trying to perform select and click action from the search box result dropdown for testing purpose. Though i dont get ant error but i'm stuck and not able to do so, search results came then disappeared immediately. Please any one help me out. Im using Python script to automate webdriver. Here is the screenshot below for reference.
. I have tried webdriverwait for same action but it gives Timeout exception error. If there is any child actions from CSS to perform let me know. Here is what i tried
search = driver.find_element_by_id('searchInput')
search.send_keys("flowers")
dropdown = WebDriverWait(driver, 4).until(
EC.presence_of_element_located((By.XPATH, "//li[text()='flowers']")))
Apart from this snippet, i want to rather just perform enter key operation, where i get query result for 'flower' on this ecomm. website.
Here is the website URL- https://paytmmall.com
Once you type flower in the input field, there are multiple options appearing based on the input provided. They are in li tags and under b tag.
Code :
driver = webdriver.Chrome(driver_path)
driver.maximize_window()
#driver.implicitly_wait(30)
wait = WebDriverWait(driver, 30)
driver.get("https://paytmmall.com/")
search = wait.until(EC.visibility_of_element_located((By.ID, "searchInput")))
search.send_keys("flowers")
time.sleep(3)
wait.until(EC.visibility_of_element_located((By.XPATH, "(//li)[4]/descendant::b[contains(text(),'flowers')]"))).click()
time.sleep is just for visibility purpose. you can remove that as well.
Also this xpath (//li)[4]/descendant::b[contains(text(),'flowers')] is based on xpath indexing , since I think you wanna select the 4th option which is flower itself. In case you wanna select a different option, you would have to write the different xpath.
In case you are looking to just select the searched item, it's better to pass enter key once you type flower in the input field.
You can use the below code for that :
search = wait.until(EC.visibility_of_element_located((By.ID, "searchInput")))
search.send_keys("flowers")
time.sleep(3)
search.send_keys(Keys.RETURN)
The suggested options are not containing the text directly in li elements, they are inside child elements inside li elements.
Try this instead:
search = driver.find_element_by_id('searchInput')
search.send_keys("flowers")
dropdown = WebDriverWait(driver, 4).until(
EC.visibility_of_element_located((By.XPATH, "//li//*[text()='flowers']")))

Web-element is visible and enabled but .click() fails in python selenium with phantomJS

I want to click on the Next-button at https://free-proxy-list.net/. The XPATH selector is //*[#id="proxylisttable_next"]/a
I do this with the following piece of code:
element = WebDriverWait(driver, 2, poll_frequency = 0.1).until
(EC.visibility_of_element_located((By.XPATH, '//*[#id="proxylisttable_next"]/a')))
if (element.is_enabled() == True) and (element.is_displayed() == True):
element.click()
print "next button located and clicked" # printed in case of success
Subsequently, I get all the IPs from the table like this:
IPs = WebDriverWait(driver, 2, poll_frequency = 0.1).until
(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ':nth-child(n) > td:nth-child(1)')))
Although the CSS_selector is the same for all tabs, and although I get a next button located and clicked, the IPs output is the same for both tabs (i.e. it seems like the Next-button never was clicked). Additionally, there is no Exception thrown.
Therefore, there must be something fundamentally wrong with my approach.
How to click on visible & enabled buttons correctly in phantomJS using python/selenium?
For your understanding, here is the html of the page section I am referring to:
As far as I see there could be two possible causes:
The click was not registered, though this is highly unlikely. You can look at other ways to click like JavascriptExecutor's click.
(Most likely) The find elements are queried right after the click is performed and before the Page 2 results are loaded. Since elements is visible from page 1, it exits immediately with the list of elements from page 1. An ideal way of doing this would be (using psuedocode as I am not familiar with python)
a. Get the current page number
b. Get all the IPs from the current page
c. Click Next
d. Check if (Current page + 1 ) page has become active (class 'active' is added to the Number 2)
e. Get all the elements from the current page
I am the OP and for anyone coming across a similar problem - The Next element was no longer attached to the DOM following its selection, which caused StaleElementReferenceException when printing element.is_enabled() or when clicking it - a detailed solution can be found here

Selenium (python): can't switch to iframe (name is dynamically generated)

I'm having problem selecting the iframe and accessing the different elements inside it. The iframe name is dynamically generated (e.g. frame11424758092173 or frame0005809321 or frame32138092173). The problem is that Selenium can't find the iframe no matter what i do....
switching to most recent frame doesn't work:
iframe = driver.find_elements_by_tag_name('iframe')[0]
driver.switch_to_frame(iframe)
Waiting for frame gets a timeout exception:
try:
iframe = WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it(By.TAG_NAME('iframe')))
except:
logger.error(traceback.format_exc())
The following lines of code also times out:
try:
iframe = WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.TAG_NAME, u"iframe")))
driver.switch_to_frame(iframe)
except:
logger.error(traceback.format_exc())
I have also tried iterating through the frames but it can't find it. The returned list is empty
iframes = driver.find_elements_by_tag_name('iframe')
#iframes is empty
really need some help...
Have you tried locating the iframe by its XPath and using the contains method?:
iframe = driver.find_element_by_xpath('//iframe[contains(#name, "frame")]')
driver.switch_to_frame(iframe)
Now you can access elements within the iframe.
To exit the iframe use:
driver.switch_to_default_content()
The contains method lets you get an element by a partial attribute value. Pretty useful for dynamically generated IDs, names, etc. You can search by other attributes as well using XPath. For example, say your iframe element has the attribute value = "3". You could use:
iframe = driver.find_element_by_xpath('//iframe[contains(#name, "frame")][#value = "3"]')
driver.switch_to_frame(iframe)
This approach can be used with any number of attributes as well.
You could also try getting the element by its selector. Keep in mind that this limits what you can do with it:
driver.execute_script('document.querySelector("INSERT SELECTOR HERE").doSomething();')
To get the Selector and/or XPath you're going to want to inpect the element using your browser (Chrome in my case). Right click on the element. Click Inspect. Then right click on the HTML element and click Copy > Copy Xpath or Copy > Copy Selector.
If that doesn't work for me, my last resort is to go the url of the iframe.To get that, you need to right-click on the area of the webpage where the iframe exists and click View Frame Source. It'll then lead you to a new page. The url of that page will be shown in the top of the browser after view-source:. You can then simply navigate to that url:
driver.get('insert url of iframe here')
And now you have access to the elements within the iframe. I do not recommend this approach if you are manipulating elements within the iframe and then exiting the iframe. Your changes will get lost. This will only work if you are scraping info off of that iframe, NOT if you are manipulating the elements within. Finding the iframe element and switching into it is usually better and safer.

Categories