Cannot get dynamical element with python selenium - python

There is site, that streams youtube videos. I want to get playlist with them. So I use selenium webdriver to get the needed element div with class-name ytp-title-text where youtube link is located.
It is located here for example, when I use browser console to find element:
<div class="ytp-title-text"><a class="ytp-title-link yt-uix-sessionlink" target="_blank" data-sessionlink="feature=player-title" href="https://www.youtube.com/watch?v=VyCY62ElJ3g">Fears - Jono McCleery</a><div class="ytp-title-subtext"><a class="ytp-title-channel-name" target="_blank" href=""></a></div></div>
I wrote simple script for testing:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
driver = webdriver.Firefox()
driver.get('http://awsmtv.com')
try:
element = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CLASS_NAME, "ytp-title-text"))
)
finally:
driver.quit()
But no element is found and timeout exception is thrown. I cannot understand, what actions selenium needs to perform to get the full page source.

Required link is hidden and also located inside an iframe. Try below to locate it:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it("tvPlayer_1"))
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "ytp-title-link")))
print(element.get_attribute('href'))
finally:
driver.quit()

Just saw this element is inside iframe... You need to switch to the iframe first -> find it by ClassName -> ifame = ...(By.CLASS_NAME, "player") then switch to it driver.switch_to_frame(iframe) and you should be able now to get the wanted element :)
The XPath locator like this one will work (or your locator) -> "//a[#class='ytp-title-link yt-uix-sessionlink']".
You then need via the element to get the property href for the youtube video url or the text of the element for the song title.
If still not working I can suggest to get the page source - html = driver.page_source which will give you the source of the page and via some regex to get the info you want eventually.

Related

How do I resolve this error in Selenium : ERROR: Couldn't read tbsCertificate as SEQUENCE, ERROR: Failed parsing Certificate

I'm trying to execute a selenium program in Python to go to a new URL on click of a button in the current homepage. I'm new to selenium and any help regarding this would be appreciated. Here's my code
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
url = 'https://nmit.ac.in'
driver = webdriver.Chrome()
driver.get(url)
try:
# wait 10 seconds before looking for element
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(By.LINK_TEXT, "Parent Portal")
)
except:
print()
driver.find_element(By.LINK_TEXT, "Parent Portal").click()
I have tried to increase the wait time as well as using all forms of the supported located strategies under the BY keyword, but to no avail. I keep getting this error.
As far as I know, you shouldn't be worried by those errors. Although, I proved your code and it's not finding any element in the web page. I can recommend you use the xpath of the element you want to find:
# wait 10 seconds before looking for element
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "/html//div[#class='wsmenucontainer']//button[#href='https://nmitparents.contineo.in/']"))
)
element.click()
#wait for the new view to be loaded
time.sleep(10)
driver.quit()
Psdt: you can use the extention Ranorex Selocity to extract a good and unique xpath of any element in a webpage and also test it!!
image

Unable to click and "Accept Cookies" pop up in python Selenium

I'm trying to scrape some information on prices from a website and get find the different prices for different states and cities. However, an "Accept Cookies" pop up shows up, and I need to click it for my code to be successful, but I am struggling to get Selenium to locate anything to click at all
here is the website www.kettlebellkings.com
here is the html for the button:
<button role="button" data-testid="uc-accept-all-button" class="sc-eDvSVe hSwgIR" style="margin: 0px 6px;">Accept All</button>
I've been using Expected conditions but it just times out every time. Here is my code:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
path = "C:\Program Files (x86)\msedgedriver.exe"
driver = webdriver.Edge('www.kettlebellkings.com')
driver.get(url)
element_present = EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-testid="uc-accept-all-button"]'))
WebDriverWait(driver, 30).until(element_present)
try:
driver.find_element(By.CSS_SELECTOR, 'button[data-testid="uc-accept-all-button"]').click()
except:
clicker = driver.find_element(By.CSS_SELECTOR, 'button[data-testid="uc-accept-all-button"]')
driver.execute_script("arguments[0].click();", clicker)
But it just times out. If I leave out the expected conditions:
path = "C:\Program Files (x86)\msedgedriver.exe"
driver = webdriver.Edge('www.kettlebellkings.com')
driver.get(url)
driver.find_element(By.CSS_SELECTOR, 'button[data-testid="uc-accept-all-button"]').click()
Returns:
Message: no such element: Unable to locate element: {"method":"css selector","selector":"button[data-testid="uc-accept-all-button"]"}
It doesn't appear to be in an iframe either - what am I missing here?
'Accept All' cookies button is inside the Shadow Dom, try the below code:
shadow_root = driver.find_element(By.CSS_SELECTOR, "#usercentrics-root").shadow_root
shadow_root.find_element(By.CSS_SELECTOR, "button[data-testid='uc-accept-all-button']").click()
You can refer how to handle shadow dom elements from the below links:
https://www.lambdatest.com/blog/shadow-dom-in-selenium/
https://www.seleniumeasy.com/selenium-tutorials/accessing-shadow-dom-elements-with-webdriver
you could try setting a cookie that would stop the pop up
just accept cookies on your normal browser, set them in the program and the website will recognize it as you/your account
driver.add_cookie({"name": "key", "value": "value"})

Selenium driver can't find any element after logging into a website [Python]

First of all if a similar topic occurred earlier I'm sorry but I couldn't find any problem like mine.
I would like to create a simple script which enters an e-mail website, log into my account and finds the amount of unread messages.
This is the part with logging in
from selenium import webdriver
from time import sleep
class sMailBot():
def __init__(self):
self.driver = webdriver.Chrome()
def login(self):
self.driver.get('website.com')
sleep(2)
btn_login = self.driver.find_element_by_xpath('//*[#id="username"]')
btn_login.send_keys('my_username')
btn_password = self.driver.find_element_by_xpath('//*[#id="password"]')
btn_password.send_keys('my_password')
btn_logintoaccount = self.driver.find_element_by_xpath('//*[#id="button"]')
btn_logintoaccount.click()
sleep(5)
It works really well. After logging into my mail account comments like driver.title or driver.current_url work.
Now I would like to scrape this part of html code:
<b>some_important_string_which_stores_the_amount_of_unread_mails</b>
I tried to do this using it's path
driver.find_element_by_xpath('//*[#id="MS_act1"]/span)
However it does not work. Moreover I can't find any other elements from this side.
I would like to highlight that I waiting even more than 10 seconds for the page to load.
The error which occurred
NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[#id="MS_act1"]/span/b"}
(Session info: chrome=80.0.3987.87)
As you asked I add some surrounding HTML code
<span style="float: right">
<b>some_important_string_which_stores_the_amount_of_unread_mails</b>
</span>
Please, don't use sleep, it's not a good choice for selenium.
Instead, use selenium waits:
driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
finally:
driver.quit()
https://selenium-python.readthedocs.io/waits.html
First of all I will avoid using sleep. You may try using WebDriverWait instead. This will pause the browser until a given condition is satisfied.
e.g. as follows
WebDriverWait(self.driver, 60).until(EC.presence_of_element_located((By.XPATH, "//button[text()='Login']")))
This will wait for 60 sec maximum for the element (button with text Login) to occur in the page.
After logging into your mail account commands like driver.title and driver.current_url works but they are not part of the DOM Tree.
The relevant HTML would have helped us to construct a canonical answer. However to extract the desired text, you have to induce WebDriverWait for the visibility_of_element_located() and you can use either of the following Locator Strategies:
Using CSS_SELECTOR and get_attribute("innerHTML"):
print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "[id^='MS_act'] span>b"))).get_attribute("innerHTML"))
Using XPATH and text attribute:
print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//*[starts-with(#id, 'MS_act')]//span/b"))).text)
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

python selenium element not visible exception

import webbrowser
from selenium import webdriver
browser = webdriver.Chrome()
browser.maximize_window()
browser.get('https://www.suntrust.com/')
browser.implicitly_wait(15)
elem = browser.find_element_by_css_selector('input#sign-on-3A69E29D-79E0-
403E-9352-5261239ADD89-user')
elem.click().send_keys('your-username')
element not visible exception error message:
I'm trying to sign into the login/password field automatically, but I keep getting this error message.
I have tried various "find_element_by" locators, but this one was recommended, so I don't think the css selector is the problem. What am I doing wrong?
It happens usually because the dom wouldn't have loaded and the Selenium script tries to find that element .. Make sure this element is not inside an Iframe . Use the selenium explicit wait until the element loads and then perform action on that button . You have to do something like this in python . The below code is just creating a wait object and then waiting for the element to load and perform next step
from selenium.webdriver.support.ui import WebDriverWait
myElem = WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'IdOfMyElement')))
print "Page is ready!"
except TimeoutException:
print "Loading took too much time!"
Here is the Answer to your Question:
The css_selector you constructed was not unique and was matching to 2 elements on the HTML DOM. The first match was invisible while the second match was our expected element. Selenium was trying to click the first element. Hence the error. Here is your own code with the modified css_selector which works well at my end:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("start-maximized")
options.add_argument("disable-infobars")
options.add_argument("--disable-extensions")
browser = webdriver.Chrome(chrome_options=options, executable_path="C:\\Utility\\BrowserDrivers\\chromedriver.exe")
browser.get('https://www.suntrust.com/')
browser.implicitly_wait(15)
elem = browser.find_element_by_css_selector('section[role="main"] input[id="sign-on-3A69E29D-79E0-403E-9352-5261239ADD89-user"]')
elem.send_keys('your-username')
Let me know if this Answers your Question.

Selenium Python: How to wait for a page to load after a click?

I want to grab the page source of the page after I make a click. And then go back using browser.back() function. But Selenium doesn't let the page fully load after the click and the content which is generated by JavaScript isn't being included in the page source of that page.
element[i].click()
#Need to wait here until the content is fully generated by JS.
#And then grab the page source.
scoreCardHTML = browser.page_source
browser.back()
As Alan mentioned - you can wait for some element to be loaded. Below is an example code
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Firefox()
element = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.ID, "element_id")))
you can also use seleniums staleness_of
from selenium.webdriver.support.expected_conditions import staleness_of
def wait_for_page_load(browser, timeout=30):
old_page = browser.find_element_by_tag_name('html')
yield
WebDriverWait(browser, timeout).until(
staleness_of(old_page)
)
You can do it using this method of a loop of try and wait, an easy to implement method
from selenium import webdriver
browser = webdriver.Firefox()
browser.get("url")
Button=''
while not Button:
try:
Button=browser.find_element_by_name('NAME OF ELEMENT')
Button.click()
except:continue
Assuming "pass" is an element in the current page and won't be present at the target page.
I mostly use Id of the link I am going to click on. because it is rarely present at the target page.
while True:
try:
browser.find_element_by_id("pass")
except:
break

Categories