Python Selenium find element which contains specific text - python

I have a problem. I want to find the login page of several websites using Selenium. To do this, I try to go to the page and click the button with text such as "sign in", "login", and so on. This worked for Netflix. Example:
Code Website: Netflix.com
Sign In
My Code to detect the button:
result = "https://www.microsoft.com"
driver.get(result)
elem = driver.find_element_by_link_text('Sign In').click
print(driver.current_url) # returns the website: https://www.netflix.com/de-en/login
Now I try this with the website Microsoft.com. Website code as image:
If I now change my contains query to:
driver.find_element_by_link_text('Sign in').click # small "in"
Selenium does not find any element. I have tried many different options that Selenium offers such as:
find_element_by_id
find_element_by_name
find_element_by_link_text
...
eg: [https://selenium-python.readthedocs.io/locating-elements.html]
My goal is to use the textual information like "sign in, login" etc. to find the button and press it.
I would be very grateful for your help

See the issue here is with Netflix.com , you have a HTML like this :
Sign In
see the tag, it is a, which is an anchor tag in HTML.
find_element_by_link_text, or find_element_by_partial_link_text look for text between anchor tag.
But when you go to Microsoft.com
<div class="mectrl_header_text mectrl_truncate">Sign in</div>
Sign in is wrapped inside div. so find_element_by_link_text or find_element_by_partial_link_text will not work.
instead you can try with below xpath :-
//div[text()='Sign in']
in code :-
driver.find_element_by_xpath("//div[text()='Sign in']").click()
or you can give it a try with Explicit waits as well :-
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[text()='Sign in']"))).click()

As described by cruisepandey for these two particular cases, find_element_by_link_text will work in some cases but in some other cases will not.
While locating element by it's text will work for all these case.
So I never use find_element_by_link_text or by partial text methods, just using find_element_by_xpath method based on element's text and it works fine.
In your case you can use
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[text()='Sign in']"))).click()
This will be more simple, stable and reliable.

Related

Clicking on a button with changing xpath

I just started working with Selenium webdriver to try automate clicking a button in a discord chat based on preconditions. The problem I am having is being able to classify this button.
For starters, the HTML code is as follows:
<div tabindex="0" class="reactionInner-15NvIl" aria-label="♥️, press to react" aria-pressed="false" role="button"><img src="/assets/1afd3c799f3e158662a70498e83e2a87.svg" alt="♥️" draggable="false" class="emoji"><div class="reactionCount-2mvXRV" style="min-width: 9px;">1</div></div>
What I first tried to do was to find_element_by_xpath:
driver.find_element_by_xpath('/html/body/div/div[1]/div/div[2]/div/div/div/div[2]/div[2]/div[2]/div[1]/div[1]/div/div/div[48]/div[1]/div[2]/div[2]/div[1]/div/div').click()
But, when a new opportunity for this reaction comes up, the xpath changes:
/html/body/div/div[1]/div/div[2]/div/div/div/div[2]/div[2]/div[2]/div[1]/div[1]/div/div/div[50]/div[1]/div[2]/div[2]/div[1]/div/div
Notice the only part changing it the div[48] to div[50]
The next thing I tried was to find_element_by_class_name:
element = driver.find_element_by_class_name('reactionInner-15NvIl')
driver.execute_script("arguments[0].click();", element)
The reason I did this was because I was having a problem with simply doing:
driver.find_element_by_class_name('reactionInner-15NvIl').click()
That code would give me an error saying Message: element click intercepted: Element <div tabindex="0" class="reactionInner-15NvIl" aria-label="💗, press to react" aria-pressed="false" role="button">...</div> is not clickable at point (405, 94). Other element would receive the click: <span id="NewMessagesBarJumpToNewMessages_122" class="span-3ncFWM">...</span> and the code wouldn't run. The program runs with the execute_script but it just isn't doing anything, the button is not being clicked. So if anyone has any idea how to be able to click this button, any help would be appreciated!
You can use xpath in a better way than navigate between the divs, like you did the first time.
First of all, if you can change the HTML to use id, or name, thats better.
In this case, you could use this xpath:
//div[#class = "reactionInner-15NvIl"]
When searching by class, this could return multiple results, so use the function find_elements_by_xpath, and then choose the exactly one
Induce WebDriverWait and wait for element_to_be_clickable() and following css selector.
WebDriverWait(driver,20).until(EC.element_to_be_clickable((By.CSS_SELECTOR,"div[class*='reactionInner-'][role='button']"))).click()
You need to import following libraries.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
Update:
Induce Javascript Executor to click.
driver.execute_script("arguments[0].click();", WebDriverWait(driver,20).until(EC.element_to_be_clickable((By.CSS_SELECTOR,"div[class*='reactionInner-'][role='button']"))))

How to click on "Not Now" button within Instagram through Selenium and Python

I am trying to login to Instagram with an "instagram bot" that I am currently coding. I have gotten it past the login screen, past the "get the app" screen and how it want's to turn on notifications. The two option are "Turn on" and "not now". I am trying to use the same method as before to click "not now" but it wont work. The code (using inspect element on firefox) says
<button class="aOOlW HoLwm " tabindex="0">Not Now</button>
I have tried using the class code with
notNowButton = driver.find_element_by_xpath("//a[#class='aOOlW HoLwm']")
# or
notNowButton = driver.find_element_by_xpath("//a[#tabindex='0']")
but that doesn't work either. Any help?
the notification:
using WebDriverWait and Xpath match text Not Now
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
notNowButton = WebDriverWait(driver, 15).until(
lambda d: d.find_element_by_xpath('//button[text()="Not Now"]')
)
notNowButton .click()
so this somehow worked for me.i have tested it like 10 times but this is probably not the best way.
#we just set a simple sleep time.it's not complicated we just wait for 5 seconds to make sure the page is fully loaded
sleep(5)
#since it's a button we just write //button and then it has to search for the described class which in this scenario it is aOOlW HoLwm and then it just clicks on it
not_now_notif=browser.find_element_by_xpath("//button[#class='aOOlW HoLwm ']")
not_now_notif.click()
btw you can check here.i do believe this might be helpful too
https://www.edureka.co/community/575/need-wait-until-page-completely-loaded-selenium-webdriver
Seems you were pretty close.
In you first code trial:
driver.find_element_by_xpath("//a[#class='aOOlW HoLwm']")
The <tag> is not <a> tag but <button> tag. So changing it as following would have worked.
driver.find_element_by_xpath("//button[#class='aOOlW HoLwm ']")
Now the desired element is JavaScript enabled element so you have to induce WebDriverWait for the element to be clickable and the following line would have worked perfecto:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//button[#class='aOOlW HoLwm ']"))).click()
As an alternative you could have also used cssSelector as follows:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.aOOlW.HoLwm"))).click()
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome('/Users/username/Documents/WebDriver/chromedriver')
browser.find_elements_by_xpath("//button[contains(text(), 'Not Now')]")[0].click()
You must first use copy css selector to Copy the path
Notnow = driver.find_element_by_css_selector("body > div.RnEpo.Yx5HN > div > div > div.mt3GC > button.aOOlW.HoLwm")
Notnow.click()
First, find the element by its text and assign it to not_now_button:
not_now_button = driver.find_element_by_xpath("//*[text()='Not Now']")
Then click the button:
not_now_button.click()

Angular JS: Selenium cannot click a button by python code on mac

I have a button, i can successfully find it and capture it's text. However click is not working. Can someone help.
<button class="yellow labeled icon button no-margin" type="button">
<div class="icon my_class"></div>
<span class="ttt">Add new student</span>
</button>
This works:
return driver.find_element(By.XPATH, 'xpath').text
But this does not work and "no exception". Code pass but click not done.
driver.find_element(By.XPATH, 'xpath').click()
You can try clicking it with javascript :
element = driver.find_element(By.XPATH, 'xpath')
driver.execute_script("arguments[0].click();", element)
Of-coarse invoking .text and click() relates to two different states of a WebElement.
Your code block return driver.find_element(By.XPATH, 'xpath').text succeeds as the text Add new student gets rendered within the HTML DOM when you lookout for it. This doesn't guarantees that the WebElement is also interactable by that time. There is a possibility of a JavaScript/Ajax at work rendering the button at that point of time.
It is worth to mention that rendering of the text Add new student resembles to the expected_conditions clause of text_to_be_present_in_element where as interactability (i.e. clickability) resembles to the expected_conditions clause of element_to_be_clickable
Solution
As you mentioned it's an AngularJS based site/element and the click is not getting executed you have to induce WebDriverWait in-conjunction with expected_conditions clause set as element_to_be_clickable as follows :
WebDriverWait(self.driver, 30).until(EC.element_to_be_clickable((By.XPATH, "xpath"))).click()

Access nested elements in HTML using Python Selenium

I am trying to automate logging into a website (http://www.phptravels.net/) using Selenium - Python on Chrome. This is an open website used for automation tutorials.
I am trying to click an element to open a drop-down (My Account button at the top navbar) which will then give me the option to login and redirect me to the login page.
The HTML is nested with many div and ul/li tags.
I have tried various lines of code but haven't been able to make much progress.
driver.find_element_by_id('li_myaccount').click()
driver.find_element_by_link_text(' Login').click()
driver.find_element_by_xpath("//*[#id='li_myaccount']/ul/li[1]/a").click()
These are some of the examples that I tried out. All of them failed with the error "element not visible".
How do I find those elements? Even the xpath function is throwing this error.
I have not added any time wait in my code.
Any ideas how to proceed further?
Hope this code will help:
from selenium import webdriver
from selenium.webdriver.common.by import By
url="http://www.phptravels.net/"
d=webdriver.Chrome()
d.maximize_window()
d.get(url)
d.find_element(By.LINK_TEXT,'MY ACCOUNT').click()
d.find_element(By.LINK_TEXT,'Login').click()
d.find_element(By.NAME,"username").send_keys("Test")
d.find_element(By.NAME,"password").send_keys("Test")
d.find_element(By.XPATH,"//button[text()='Login']").click()
Use the best available locator on your html page, so that you need not to create xpath of css for simple operations
You may be having issues with the page not being loaded when you try and find the element of interest. You should use the WebDriverWait class to wait until a given element is present in the page.
Adapted from the docs:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Set up your driver here....
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, 'li_myaccount'))
)
element.click()
except:
#Handle any exceptions here
finally:
driver.quit()

Use selenium to click and view more text

I'm very new to Selenium.
I'm crawling data from this page. I need to scroll down the page and click on "Load More Arguments" to get more text. This is the location to click on.
<a class="debate-more-btn" href="javascript:void(0);" onclick="loadMoreArguments('15F7E61D-89B8-443A-A21C-13FD5EAA6087');">
Load More Arguments
</a>
I have tried this code but it does not work. Should I need more code to locate to that (I think the 1 has already tell the location to click). Do you have any recommendation? Thank you in advance.
[1] btn_moreDebate = driver.find_elements_by_class_name("debate-more-btn")
[2] btn.click()
Find the link by link text, move to the element and click:
from selenium.webdriver.common.action_chains import ActionChains
link = driver.find_element_by_link_text('Load More Arguments')
ActionChains(browser).move_to_element(link).perform()
link.click()
If you get an exception while finding an element, you may need to use an Explicit Wait:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
link = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.LINK_TEXT, "Load More Arguments")))
ActionChains(browser).move_to_element(link).perform()
link.click()
If I understand your code correctly, I can see a few things wrong.
1. You're using find_elements_by_class_name. I'd recommend using find_element_by_class_name instead. elements returns a list, which isn't needed in a case where there is only one element.
2. You're using btn_moreDebate as the holder for the results of your find_elements, but then interacting with btn.
You should be able to perform the find and click in one action:
driver.find_element_by_class_name("debate-more-btn").click()

Categories