Unable to access Pop Up / iframe window using selenium python - python

I'm pretty new to selenium. I'm working on a autocheckout scrip using selenium python. Script executes very smooth till the final checkout page. However, I'm unable to access element on the final page('Razorpay Checkout'), which is a kind of pop up/iframe window.
Any help accessing the same would be highly appreciated.
Thanks in advance!
Below is the code I'm using
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
driver = webdriver.Chrome('C:/Users/hamhatre/Desktop/chromedriver.exe')
driver.get("https://shopatsc.com/collections/playstation-5/products/ps5-horizon-forbidden-west")
driver.maximize_window()
driver.implicitly_wait(20)
elem = driver.find_element_by_xpath('//*[#id="pincode_input"]')
elem.send_keys("400708")
driver.find_element_by_xpath('//*[#id="check-delivery-submit"]').click()
driver.find_element_by_xpath('/html/body/div[2]/main/div[1]/div/div/div/div[2]/div[1]/form/div[3]/div/button[2]').click()
driver.find_element_by_xpath('//*[#id="checkout_email"]').send_keys('abc#gmail.com')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_first_name"]').send_keys('abc')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_last_name"]').send_keys('xyz')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_address1"]').send_keys('Rd1, Flat no 2, Apt 1')
driver.find_element_by_xpath(('//*[#id="checkout_shipping_address_address2"]')).send_keys('Nothing')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_city"]').send_keys('Mumbai')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_province"]').send_keys('Maharashtra')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_zip"]').send_keys('400708')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_phone_custom"]').send_keys('9876543210')
driver.find_element_by_id('continue_to_shipping_button_custom').click()
driver.find_element_by_id('continue_button').click()
driver.find_element_by_xpath('/html/body/div/div/div/main/div[1]/div/form/div[3]/div[1]/button').click()
print(driver.title)
seq = driver.find_elements_by_tag_name('iframe')
print(seq)
print("No of frames present in the web page are: ", len(seq))
for index in range(len(seq)):
iframe = driver.find_elements_by_tag_name('iframe')[index]
driver.switch_to.frame(iframe)
driver.find_element_by_id('language-dropdown').click()
Below is the error
Traceback (most recent call last):
File "C:\Users\hamhatre\Desktop\Algotron\WebScrap_Sample.py", line 47, in <module>
driver.find_element_by_id('language-dropdown').click()
File "C:\Users\hamhatre\Anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File "C:\Users\hamhatre\Anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 976, in find_element
return self.execute(Command.FIND_ELEMENT, {
File "C:\Users\hamhatre\Anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "C:\Users\hamhatre\Anaconda3\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"[id="language-dropdown"]"}
(Session info: chrome=99.0.4844.84)

I am using chromedriver version 100. Your code throws a NoSuchElementException. Thats because your driver tries to find an element which does not exist. So, what you need to do is to put time.sleep(4) statements after your click() statements (Your browser needs time to open the window/s). If you are done using the driver, use driver.quit().
Followed code worked for me:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
driver = webdriver.Chrome('C:/Users/hamhatre/Desktop/chromedriver.exe')
driver.get("https://shopatsc.com/collections/playstation-5/products/ps5-horizon-forbidden-west")
driver.maximize_window()
driver.implicitly_wait(20)
elem = driver.find_element_by_xpath('//*[#id="pincode_input"]')
elem.send_keys("400708")
driver.find_element_by_xpath('//*[#id="check-delivery-submit"]').click()
driver.find_element_by_xpath('/html/body/div[2]/main/div[1]/div/div/div/div[2]/div[1]/form/div[3]/div/button[2]').click()
driver.find_element_by_xpath('//*[#id="checkout_email"]').send_keys('abc#gmail.com')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_first_name"]').send_keys('abc')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_last_name"]').send_keys('xyz')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_address1"]').send_keys('Rd1, Flat no 2, Apt 1')
driver.find_element_by_xpath(('//*[#id="checkout_shipping_address_address2"]')).send_keys('Nothing')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_city"]').send_keys('Mumbai')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_province"]').send_keys('Maharashtra')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_zip"]').send_keys('400708')
driver.find_element_by_xpath('//*[#id="checkout_shipping_address_phone_custom"]').send_keys('9876543210')
driver.find_element_by_id('continue_to_shipping_button_custom').click()
time.sleep(4)
driver.find_element_by_id('continue_button').click()
time.sleep(4)
driver.find_element_by_xpath('/html/body/div/div/div/main/div[1]/div/form/div[3]/div[1]/button').click()
time.sleep(4)
print(driver.title)
seq = driver.find_elements_by_tag_name('iframe')
print(seq)
print("No of frames present in the web page are: ", len(seq))
for index in range(len(seq)):
iframe = driver.find_elements_by_tag_name('iframe')[index]
driver.switch_to.frame(iframe)
driver.find_element_by_id('language-dropdown').click()

A few things you could do in your next project:
Use WebDriverWait to allow enough time for elements to be loaded
Use switch_to.default_content() before switching to another frame
Use time.sleep() while you switch frames
Try using relative xpaths (ex: //div[#id="user_address"]). It's easy to right click and copy the absolute xpath for an element from the inspect window, however if there's another element added in between, your xpath would no longer point to the desired element. Moreover, relative xpaths would empower you with a deeper understanding allowing you to easily find elements.
This code should work:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import StaleElementReferenceException
import time
driver = webdriver.Chrome('D://chromedriver/100/chromedriver.exe')
driver.get("https://shopatsc.com/collections/playstation-5/products/ps5-horizon-forbidden-west")
driver.maximize_window()
wait = WebDriverWait(driver, 20)
wait.until(EC.presence_of_element_located((By.XPATH, '//input[#id="pincode_input"]'))).send_keys('400708')
wait.until(EC.presence_of_element_located((By.XPATH, '//span[#id="check-delivery-submit"]'))).click()
wait.until(EC.presence_of_element_located((By.XPATH, '//button[normalize-space(text())="Buy Now"]'))).click()
wait.until(EC.presence_of_element_located((By.XPATH, '//input[#id="checkout_email"]'))).send_keys('abc#gmail.com')
wait.until(EC.presence_of_element_located((By.XPATH, '//input[#id="checkout_shipping_address_first_name"]'))).send_keys('abc')
wait.until(EC.presence_of_element_located((By.XPATH, '//input[#id="checkout_shipping_address_last_name"]'))).send_keys('xyz')
wait.until(EC.presence_of_element_located((By.XPATH, '//input[#id="checkout_shipping_address_address1"]'))).send_keys('Rd1, Flat no 2, Apt 1')
wait.until(EC.presence_of_element_located((By.XPATH, '//input[#id="checkout_shipping_address_address2"]'))).send_keys('Nothing')
wait.until(EC.presence_of_element_located((By.XPATH, '//input[#id="checkout_shipping_address_city"]'))).send_keys('Mumbai')
wait.until(EC.presence_of_element_located((By.XPATH, '//select[#id="checkout_shipping_address_province"]'))).send_keys('Maharashtra')
wait.until(EC.presence_of_element_located((By.XPATH, '//input[#id="checkout_shipping_address_zip"]'))).send_keys('400708')
wait.until(EC.presence_of_element_located((By.XPATH, '//input[#id="checkout_shipping_address_phone_custom"]'))).send_keys('9876543210')
wait.until(EC.presence_of_element_located((By.XPATH, '//button[#id="continue_to_shipping_button_custom"]'))).click()
wait.until(EC.presence_of_element_located((By.XPATH, '//button[#id="continue_button"]'))).click()
wait.until(EC.presence_of_element_located((By.XPATH, '//span[normalize-space(text())="Complete order"]/parent::button'))).click()
print(driver.title)
# finding all iframes
iframes = wait.until(EC.presence_of_all_elements_located((By.TAG_NAME, 'iframe')))
print(f'No. of iframes: {len(iframes)}')
print('Looping through frames to check language dropdown')
found = False
frameno = 0
tries = 1
maxtries = 5
# Attempt at least 5 times to click on the language dropdown
while not found and frameno < len(iframes) and tries <= maxtries:
try:
print(f"Frame# {frameno} \t {tries} of {maxtries} tries")
print('Switching to frame')
driver.switch_to.frame(iframes[frameno])
time.sleep(2)
wait.until(EC.presence_of_element_located((By.XPATH, '//div[#id="language-dropdown"]/div/div'))).click()
found = True
print('Found and clicked')
except StaleElementReferenceException:
print("Exception occured. Capturing iframes again")
driver.switch_to.default_content()
iframes = wait.until(EC.presence_of_all_elements_located((By.TAG_NAME, 'iframe')))
except Exception as ex:
print("Couldn't find/click on the language dropdown")
frameno += 1
finally:
print('Switching to default content')
driver.switch_to.default_content()
time.sleep(2)
tries += 1

Related

Unable to close a pop up using Selenium with Python

So here is my code so far that isn't faring to well:
url = 'https://americanbarbell.com/products/american-barbell-cast-kettlebell'
path = "C:\Program Files (x86)\msedgedriver.exe"
driver = webdriver.Edge(path)
driver.get(url)
time.sleep(5)
driver.find_element(By.XPATH,'//*[#id="closeIconSvg"]').click()
But I keep getting this back:
Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[#id="closeIconSvg"]"}
I'm not seeing anything about an iFrame? I saw a lot of other people with this problem but have yet to find a working solution.
Thanks in advance
Switch to the modal window and wait until it loads.
iframe = driver.find_element(By.XPATH, '//*[#id="attentive_creative"]')
driver.switch_to.frame(iframe)
wait = WebDriverWait(driver, 10)
status_message = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "#closeIconContainer"))
driver.find_element(By.ID, "closeIconContainer").click()
)
You will need to import a couple of methods.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
A super simple work around ended up being
driver.refresh()
Thanks!
Pls, show line where this id is
and probably you may use such solution:
url = 'https://americanbarbell.com/products/american-barbell-cast-kettlebell'
path = "C:\Program Files (x86)\msedgedriver.exe"
driver = webdriver.Edge(path)
driver.get(url)
time.sleep(5)
try:
element = driver.find_element(By.XPATH,'//*[#id="closeIconSvg"]')
element.click()
except NoSuchElementException: # Error catch here
print('Error.')

Selenium not waiting for element to be visible causing error: invalid element state

Error: Element is not currently interactable and may not be manipulated.
So I have selenium requesting a page and then filling out a few input boxes then clicking a button to submit the form.
The issue I'm having is that selenium isn't waiting for the element to be visible so I have to manually place a time.sleep(2) to fix that but I would prefer to use a wait until they show up in case it takes longer or less time to load or if they don't load at all.
I have it setup like this currently to request the page, find the input field, check if the element exists and type the text into it, I get this error at the element.clear() part which doesn't happen when I include a time.sleep(2) after requesting the url:
error
Traceback (most recent call last):
File "C:\Users\example\AppData\Roaming\JetBrains\PyCharmCE2021.2\scratches\example.py", line 125, in <module>
completeForm(
File "C:\Users\example\AppData\Roaming\JetBrains\PyCharmCE2021.2\scratches\example.py", line 89, in completeForm
typeText(Field, text)
File "C:\Users\example\AppData\Roaming\JetBrains\PyCharmCE2021.2\scratches\example.py", line 50, in typeText
element.clear()
File "C:\Users\example\Desktop\selenium-program\venv\lib\site-packages\selenium\webdriver\remote\webelement.py", line 92, in clear
self._execute(Command.CLEAR_ELEMENT)
File "C:\Users\example\Desktop\selenium-program\venv\lib\site-packages\selenium\webdriver\remote\webelement.py", line 693, in _execute
return self._parent.execute(command, params)
File "C:\Users\example\Desktop\selenium-program\venv\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 400, in execute
self.error_handler.check_response(response)
File "C:\Users\example\Desktop\selenium-program\venv\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 236, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.InvalidElementStateException: Message: invalid element state: Element is not currently interactable and may not be manipulated
(Session info: chrome=93.0.4577.63)
Code
from seleniumwire.undetected_chromedriver.v2 import Chrome, ChromeOptions
from selenium.common.exceptions import TimeoutException
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.webdriver import ActionChains
import random
import time
#Setup selenium chrome browser with options
def setupBrowser():
global driver
options = {}
chrome_options = ChromeOptions()
driver = Chrome(seleniumwire_options=options, options=chrome_options)
#Type like a human
def typeText(element, text):
success = False
if doesElementExist(element):
while success == False:
actions = ActionChains(driver)
actions.move_to_element(element)
actions.click()
element.clear()
for character in text:
actions.send_keys(character)
actions.perform()
time.sleep(random.uniform(0.13, 0.4))
if element.get_attribute("data-initial-value") == text:
success = True
#check if element exists, times out after some time and returns error
def doesElementExist(element):
timeout = 10
try:
element_present = EC.visibility_of_element_located(element)
WebDriverWait(driver, timeout).until(element_present)
except TimeoutException:
print("Error: Timed out after {} seconds waiting for element to load!".format(timeout))
return False
finally:
return True
driver.get(url)
driver.implicitly_wait(60)
Field = driver.find_element_by_xpath('//*[#id="mG61Hd"]/div[2]/div/div[2]/div[1]/div/div/div[2]/div/div[1]/div/div[1]/input')
text = "exampletexttowrite123"
typeText(Field, text)
Your typeText needs corrections. It does not have .perform() so what happens is all the item will get stored in Actioncahins queue and the moment you write .perform() they will be release one by one.
Code :
def typeText(element, text):
success = False
if doesElementExist(element):
while success == False:
actions = ActionChains(driver)
actions.move_to_element(element).perform()
element.click()
element.clear()
for character in text:
actions.send_keys(character).perform()
time.sleep(random.uniform(0.13, 0.4))
if element.get_attribute("data-initial-value") == text:
success = True
PS :
this method is directly accepting a web element, make sure the web element should be rendered properly.
Update :
driver = webdriver.Chrome(driver_path)
driver.maximize_window()
#driver.implicitly_wait(50)
driver.get("https://docs.google.com/forms/d/e/1FAIpQLSfMJRFOPF0qeJG3DHrbzbDR7nETPF0qE2D-r_F3kjjqdP9B1w/viewform")
wait = WebDriverWait(driver, 20)
ActionChains(driver).move_to_element(wait.until(EC.visibility_of_element_located((By.XPATH, "//div[text()='Your answer']/preceding-sibling::input")))).perform()
wait.until(EC.visibility_of_element_located((By.XPATH, "//div[text()='Your answer']/preceding-sibling::input"))).send_keys('cruise')

Can't fetch titles from some box-like containers

I've written a script in python in association with selenium to click on some dots available on a map in a web page. When a dot is clicked, a small box containing relevant information pops up.
Link to that site
I would like to parse the title of each box. When I execute my script, it throws an error while clicking on a dot. How can I make a go successfully?
This is the script:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
link = "replace with above link"
driver = webdriver.Chrome()
driver.get(link)
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mapDiv_zoom_slider .esriSimpleSliderIncrementButton"))).click()
for item in wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR,"#NWQMC_VM_directory_June2016_3915_0_layer circle"))):
item.click()
Error I'm having:
line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: Element <circle fill="rgb(237, 81, 81)" fill-opacity="1" stroke="rgb(153, 153, 153)" stroke-opacity="1" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" cx="720" cy="430" r="4" transform="matrix(1.00000000,0.00000000,0.00000000,1.00000000,0.00000000,0.00000000)" fill-rule="evenodd" stroke-dasharray="none" dojoGfxStrokeStyle="solid"></circle> is not clickable at point (720, 430). Other element would receive the click: <circle fill="rgb(20, 158, 206)" fill-opacity="1" stroke="rgb(153, 153, 153)" stroke-opacity="1" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" cx="720" cy="430" r="4" transform="matrix(1.00000000,0.00000000,0.00000000,1.00000000,0.00000000,0.00000000)" fill-rule="evenodd" stroke-dasharray="none" dojoGfxStrokeStyle="solid"></circle>
(Session info: chrome=67.0.3396.99)
(Driver info: chromedriver=2.36.540470 (e522d04694c7ebea4ba8821272dbef4f9b818c91),platform=Windows NT 6.1.7601 SP1 x86)
This is how a box gets popped up:
#Andrei Suvorkov was really close (+1)
Try below code to get required output:
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get(link)
wait = WebDriverWait(driver, 5)
driver.maximize_window()
items = wait.until(EC.presence_of_all_elements_located((By.XPATH, "//*[name()='svg']//*[name()='circle']")))
for item in items:
ActionChains(driver).move_to_element(item).click(item).perform()
popup = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "contentPane")))
print(popup.text)
wait.until(EC.visibility_of_element_located((By.XPATH, "//div[contains(#class, 'close')]"))).click()
To answer your particular question you cannot interact with svg elements like usual. For that you have to use xPath like I have provided in the example. Also you cannot click on these elements like usual, but you can use ActionChains.
wait = WebDriverWait(driver, 5)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mapDiv_zoom_slider .esriSimpleSliderIncrementButton"))).click()
time.sleep(3)
items = driver.find_elements_by_xpath("//*[name()='svg']//*[name()='circle']")
i = 0
for item in items:
try:
time.sleep(1)
ActionChains(driver).move_to_element(item).click(item).perform()
except Exception:
print("Can't click")
This code works and every element will be clicked until the map will be zoomed in. At one of the elements the map zooms in and it doesn't work after that. Why? I didn't found out yet, but you can find it from yourself or ask another question and we will try to help you.
Note: you have to add some imports:
from selenium.webdriver.common.action_chains import ActionChains
import time
EDIT: I have found the problem, you have to close every popup after click and then it works. The working code is below:
wait = WebDriverWait(driver, 5)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#mapDiv_zoom_slider .esriSimpleSliderIncrementButton"))).click()
time.sleep(3) # wait until all elements will be ready
items = driver.find_elements_by_xpath("//*[name()='svg']//*[name()='circle']")
for item in items:
time.sleep(0.5) # small pause before each iteration
ActionChains(driver).move_to_element(item).click(item).perform()
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#title = 'Close']"))).click()
I didn't find a way to avoid time.sleep(), probably in this particular case it is not possible.

How do I fix the TypeError raised when trying to find an element using Selenium?

I am trying to scrape all the links from a web page. I am using Selenium WebDriver to scroll and click the load more button present in the web page. The code which I am trying is as shown below:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import ElementNotVisibleException
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException
from bs4 import BeautifulSoup
def fetch_links(url):
chrome_path = r"D:\nishant_pc_d_drive\nishant_pc\d_drive\update_engine\myntra_update\chromedriver.exe"
driver = webdriver.Chrome(chrome_path)
driver.get(url)
while True:
try:
scrollcount=1
while scrollcount<5:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
WebDriverWait(driver, 5)
scrollcount+=1
WebDriverWait(driver, 10).until(EC.presence_of_element_located(driver.find_elements_by_css_selector('.load_more .sbt-button, .load_more_order .sbt-button')))
driver.find_element_by_id("loadmore").click()
except (ElementNotVisibleException,NoSuchElementException) as e:
print "done"
x = driver.page_source
soup2 = BeautifulSoup(x, 'html.parser')
linkcount=0
for each in soup2.find_all('a',attrs={"class":"thumb searchUrlClass"}):
print "https://www.shoppersstop.com/"+each.get('href')
linkcount+=1
print linkcount
# thumb searchUrlClass
fetch_links("https://www.shoppersstop.com/women-westernwear-tops-tees/c-A206020")
But unfortunately it is giving me an error, as shown below:
Traceback (most recent call last):
File "D:/INVENTORY/shopperstop/fetch_link.py", line 36, in <module>
fetch_links("https://www.shoppersstop.com/women-westernwear-tops-tees/c-A206020")
File "D:/INVENTORY/shopperstop/fetch_link.py", line 21, in fetch_links
WebDriverWait(driver, 10).until(EC.presence_of_element_located(driver.find_element_by_class_name('sbt-button')))
File "C:\Python27\lib\site-packages\selenium\webdriver\support\wait.py", line 71, in until
value = method(self._driver)
File "C:\Python27\lib\site-packages\selenium\webdriver\support\expected_conditions.py", line 63, in __call__
return _find_element(driver, self.locator)
File "C:\Python27\lib\site-packages\selenium\webdriver\support\expected_conditions.py", line 328, in _find_element
return driver.find_element(*by)
TypeError: find_element() argument after * must be an iterable, not WebElement
How can I fix this error? Thanks!
The error text is legitimately confusing.
Basically, some Expected Conditions (EC) methods use locators, while some use elements. The one you used only accepts a locator, but you provided an element instead.
The difference is sort of explained in the Selenium API docs here:
element is a WebElement object.
locator is a tuple of (by, path).
A practical example of a locator is (By.ID, 'someid') (You'll need to import Selenium's "By" class)
So, here's the initial code that incorrectly provides an element:
WebDriverWait(driver, 10).until(
EC.presence_of_element_located(driver.find_element_by_class_name('sbt-button'))
)
It should be updated to provide a locator instead:
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, 'sbt-button'))
)
Notice the double parens. That's a tuple being passed to the EC method.
Note: In your case, it also looks like you want multiple elements, so you also need to use EC.presence_of_all_elements_located() instead of EC.presence_of_element_located().
from selenium.webdriver.common.by import By
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)

How to handle the timeout exception in python

I am writing a bot that will follow the users on www.quora.com . following is the part of code I am using where I get timeout exception:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import urllib
driver = webdriver.Firefox()
driver.get('http://www.quora.com/')
time.sleep(10)
wait = WebDriverWait(driver, 10)
form = driver.find_element_by_class_name('regular_login')
time.sleep(10)
#add explicit wait
username = form.find_element_by_name('email')
time.sleep(10)
#add explicit wait
username.send_keys('abc#gmail.com')
time.sleep(30)
#add explicit wait
password = form.find_element_by_name('password')
time.sleep(30)
#add explicit wait
password.send_keys('def')
time.sleep(30)
#add explicit wait
password.send_keys(Keys.RETURN)
time.sleep(30)
#search = driver.find_element_by_name('search_input')
search = wait.until(EC.presence_of_element_located((By.XPATH, "//form[#name='search_form']//input[#name='search_input']")))
search.clear()
search.send_keys('Kevin Rose')
search.send_keys(Keys.RETURN)
link = wait.until(EC.presence_of_element_located((By.LINK_TEXT, "Kevin Rose")))
link.click()
#Wait till the element is loaded (Asynchronusly loaded webpage)
handle = driver.window_handles
driver.switch_to.window(handle[1])
#switch to new window
element = WebDriverWait(driver, 2).until(EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, "Followers")))
time.sleep(30)
element.click()
#goes to Kevin Rose followers page
time.sleep(30)
button = driver.find_elements_by_xpath("//a[contains(text(), 'Follow')]")
#Locate follow button on the page
no_of_followers = len(button)
#total number of unfollowed users
print no_of_followers
while(no_of_followers > 0):
# execute only if there are unfollowed users on page
count = 1
while(count < no_of_followers):
time.sleep(30)
link = wait.until(EC.presence_of_element_located((By.LINK_TEXT, "Follow")))
time.sleep(30)
link.click()
time.sleep(30)
print count
count = count + 1
time.sleep(30)
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(30)
button = driver.find_elements_by_xpath("//a[contains(text(), 'Follow')]")
time.sleep(30)
no_of_followers = len(button)
After executing the code i am getting "TimeoutException" error in the inner loop after successful execution once.
How can I solve this?
Traceback:
Traceback (most recent call last): File "C:\Python27\quorabot7",
line 72, in
link = wait.until(EC.presence_of_element_located((By.LINK_TEXT, "Follow"))) File
"C:\Python27\lib\site-packages\selenium\webdriver\support\wait.py",
line 71, in until
raise TimeoutException(message) TimeoutException: Message: ''
You're getting a TimeoutException because Selenium can't find that element within the time that you've set as your wait. This means that your locator strategy is incorrect.
I have not tested your other locators, but if it is truly the inner loop that is failing... my solution is below.
After looking through the DOM on Kevin Hart's page, I can see that the button you're interested in is:
<a class="follow_button with_count" href="#" action_click="UserFollow" id="__w2_Mab4s9V_follow_user">Follow<span class="count">43.8k</span></a>
You should try this:
link = wait.until(EC.presence_of_element_located(\
(By.className, "follow_button with_count")))
or this:
link = wait.until(EC.presence_of_element_located(\
(By.XPATH, '//a[#action_click="UserFollow"]')))
The correct is By.CLASS_NAME, not By.ClassName

Categories