How to put XPath into optional mode - python

This XPath may available sometime or sometime not.
If reject is true then I am using if statement:
from selenium import webdriver
from selenium.webdriver.support.select import Select
from selenium.webdriver.firefox.options import Options
import time
import bs4
import requests
url="abc"
options = Options()
options.set_preference("dom.webnotifications.enabled", False)
driver=webdriver.Firefox(executable_path="C:\driver\geckodriver.exe",options=options)
driver.get(url)
driver.maximize_window()
reject = driver.find_element_by_xpath("/html/body/div/div/div/main/div/section/div[2]/div[2]/div/ul/a[1]/div[3]/label")
if reject:
driver.find_element_by_xpath("/html/body/div[1]/div/div/main/div/section/div[2]/div[2]/div/ul/a[1]/div[1]/span/i").click()
time.sleep(1)
driver.find_element_by_xpath("/html/body/div[1]/div/div/main/div/section/div[2]/div[2]/div/ul/a[1]/div[1]/div/ul/li[2]").click()
time.sleep(2)
driver.find_element_by_xpath("/html/body/div[3]/div/div/div[3]/button[1]").click()
time.sleep(5)
# Above code blocking to run below code (if reject is None).
neighbourhood= Select(driver.find_element_by_name("Locality"))
neighbourhood.select_by_value("5001641")
But the problem is if this reject variable XPath doesn't exist so it's showing error & blocking below code.
how to make this reject variable optional if XPath available then work if not then leave it & run below code.

You could catch the exception. Something like following:
...
try:
reject = driver.find_element_by_xpath("/html/body/div/div/div/main/div/section/div[2]/div[2]/div/ul/a[1]/div[3]/label")
except:
print("No element found")
if reject:
...
If you need this more often you could create a utility method for that.
def elementVisible(xpath):
try:
driver.find_element_by_xpath(xpath);
return true;
except:
return false;

try-except block will do the trick.
try:
reject = driver.find_element_by_xpath("/html/body/div/div/div/main/div/section/div[2]/div[2]/div/ul/a[1]/div[3]/label")
except:
print("An exception occurred")
Whenever the xpath is not found, the print statement is executed, and further code gets executed without an error like before.

Related

Is there a way for a program to keep running when it hits an error in Selenium Python

I'm using Selenium to extract data from a website. The HTML is usually the same for all the shows but for certain shows it's different. Most should have 27 elements but some have lower amounts so it spits out an error
So, I'm asking if there is a way to break out of the section of the code before the error stops the program?
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
Anime = input("Enter Anime:")
driver = webdriver.Chrome(executable_path=r"C:\Users\amete\Documents\chromedriver.exe")
driver.get("https://myanimelist.net/search/all?q=one%20piece&cat=all")
print(driver.title)
search = driver.find_element_by_xpath('//input[#name="q"]')
wait = WebDriverWait(driver, 20)
wait.until(EC.element_to_be_clickable((By.XPATH, '//input[#name="q"]')))
# Clears the field
search.send_keys(Keys.CONTROL, 'a')
search.send_keys(Keys.DELETE)
# The field is now cleared and the program can type whatever it wants
search.send_keys(Anime)
search.send_keys(Keys.RETURN)
#Accept the cookies
accept = driver.find_element_by_xpath('//*[#id="qc-cmp2-ui"]/div[2]/div/button[3]').click()
# Added this wait
wait.until(EC.element_to_be_clickable((By.XPATH, '//h2[#id="anime"]//ancestor::div[#class="content-left"]//article[1]/div[contains(#class, "list")][1]/div[contains(#class, "information")]/a[1]')))
link = driver.find_element_by_xpath('//h2[#id="anime"]//ancestor::div[#class="content-left"]//article[1]/div[contains(#class, "list")][1]/div[contains(#class, "information")]/a[1]').click()
#Extracting information
#English Title + Jap Title + Display Score
English_Title = driver.find_element_by_xpath('//*[#id="contentWrapper"]/div[1]').text
#Jap_Title = driver.find_element_by_xpath('//*[#id="contentWrapper"]/div[1]/div/div[1]/div/h1/strong').text
Score = driver.find_element_by_xpath('//*[#id="content"]/table/tbody/tr/td[2]/div[1]/table/tbody/tr[1]/td/div[1]/div[1]/div[1]/div[1]/div[1]/div').text
Episodes = driver.find_element_by_xpath('//*[#id="content"]/table/tbody/tr/td[1]/div/div[10]').text
print ("The English title :"+English_Title)
#print ("The Japanese title:"+Jap_Title)
print ("The Score of the Anime is:"+str(Score))
print (Episodes)
for i in range (7,28):
Info = driver.find_element_by_xpath('//*[#id="content"]/table/tbody/tr/td[1]/div/div['+str(i)+']').text
print (Info)
This is my code
The website I'm using is MyAnimeList
Yes it is use try, except :
Let's say you think that the few line of code will have some issue (risky code), try to put that into try clause, like below :
try:
for i in range (7,28):
Info = driver.find_element_by_xpath('//*[#id="content"]/table/tbody/tr/td[1]/div/div['+str(i)+']').text
print (Info)
except:
pass
Even if it fails in a for loop, it will go to except that just says pass.
This answers goes for any code in Python that causes an Exception.
To catch an exception so that the program continues to run, use the try and except block. Within the try block put the code that may cause an exception. If an exception does trigger then the except block will run.
For example:
try:
my_int = int(input("Enter a number: "))
except ValueError:
print("Please enter a number not a text")
In the above example the user may enter an integer in to the command line and the code will run smoothly, but if a user instead enters a character or a string such as hello world the int() function will raise a ValueError which will be caught by the except block which will print an error message but won`t stop the program.
If multiple exceptions may occur you can use multiple except block to catch different kinds of exceptions. You can also use an empty except block that will catch any exception (though this is generally unadvisable).
If you want to learn more about try ecxpet blocks and exception handling in general in python see here.

python script to open a page and click download

I am trying to open a page and click on download button. It works fine for the pages that have download element but for the pages which doesn't have that element it raises error
Code:
for i in data["allurl"]:
driver.get('{0}'.format(i))
if(driver.find_element_by_id('ContentPlaceHolder1_grdFileUpload_lnkDownload_0')):
button_element = driver.find_element_by_id('ContentPlaceHolder1_grdFileUpload_lnkDownload_0')
button_element.click()
else:
pass
It should pass instead of raising the error but when I run this it says:
NoSuchElementException: Message: no such element: Unable to locate
element:
{"method":"id","selector":"ContentPlaceHolder1_grdFileUpload_lnkDownload_0"}
How do I solve this?
driver.find_element_by_id() doesn't return True or False as your if-statement expects. Either change your if-statement, or use a try/except statement.
from selenium.common.exceptions import NoSuchElementException
for i in data["allurl"]:
driver.get('{0}'.format(i))
try:
button_element = driver.find_element_by_id('ContentPlaceHolder1_grdFileUpload_lnkDownload_0')
button_element.click()
except NoSuchElementException:
pass
Check the length count of the web element.If it is more than 0 then element available and click otherwise it will go to else condition.
for i in data["allurl"]:
driver.get('{0}'.format(i))
if len(driver.find_elements_by_id('ContentPlaceHolder1_grdFileUpload_lnkDownload_0'))>0:
button_element = driver.find_element_by_id('ContentPlaceHolder1_grdFileUpload_lnkDownload_0')
button_element.click()
else:
pass
from selenium.common.exceptions import NoSuchElementException
try:
button_element = driver.find_element_by_id('ContentPlaceHolder1_grdFileUpload_lnkDownload_0')
except NoSuchElementException:
pass
else:
button_element.click()
Note that even if it worked as you expected, it's inefficient because you perform search for the element twice.
EDIT: included the import statement for the exception
UPDATE: as a side note, assuming elements in data["allurl"] are url (i.e. strings) there is no need for string formatting. driver.get(i) would do. And i is poor choice for variable name - better use something more meaningful....

Continue when element is not found in selenium python

The following script follows a page in Instagram:
browser = webdriver.Chrome('./chromedriver')
# GO INSTAGRAM PAGE FOR LOGIN
browser.get('https://www.instagram.com/accounts/login/?hl=it')
sleep(2)
# ID AND PASSWORD
elem = browser.find_element_by_name("username").send_keys('test')
elem = browser.find_element_by_name("password").send_keys('passw')
# CLICK BUTTON AND OPEN INSTAGRAM
sleep(5)
good_elem = browser.find_element_by_xpath('//*[#id="react-root"]/section/main/div/article/div/div[1]/div/form/span/button').click()
sleep(5)
browser.get("https://www.instagram.com")
# GO TO PAGE FOR FOLLOW
browser.get("https://www.instagram.com/iam.ai4/")
sleep(28)
segui = browser.find_element_by_class_name('BY3EC').click()
If an element with class BY3EC isn't found I want the script to keep working.
When an element is not found it throws NoSuchElementException, so you can use try/except to avoid that, for example:
from selenium.common.exceptions import NoSuchElementException
try:
segui = browser.find_element_by_class_name('BY3EC').click()
except NoSuchElementException:
print('Element BY3EC not found') # or do something else here
You can take a look at selenium exceptions to get an idea of what each one of them is for.
surround it with try catches, than you can build a happy path and handle failures as well, so your test case will always work
Best practice is to not use Exceptions to control flow. Exceptions should be exceptional... rare and unexpected. The simple way to do this is to get a collection using the locator and then see if the collection is empty. If it is, you know the element doesn't exist.
In the example below we search the page for the element you wanted and check to see that the collection contains an element, if it does... click it.
segui = browser.find_elements_by_class_name('BY3EC')
if segui:
segui[0].click()

Python Selenium. How to use driver.set_page_load_timeout() properly?

from selenium import webdriver
driver = webdriver.Chrome()
driver.set_page_load_timeout(7)
def urlOpen(url):
try:
driver.get(url)
print driver.current_url
except:
return
Then I have URL lists and call above methods.
if __name__ == "__main__":
urls = ['http://motahari.ir/', 'http://facebook.com', 'http://google.com']
# It doesn't print anything
# urls = ['http://facebook.com', 'http://google.com', 'http://motahari.ir/']
# This prints https://www.facebook.com/ https://www.google.co.kr/?gfe_rd=cr&dcr=0&ei=3bfdWdzWAYvR8geelrqQAw&gws_rd=ssl
for url in urls:
urlOpen(url)
The problem is when website 'http://motahari.ir/' throws Timeout Exception, websites 'http://facebook.com' and 'http://google.com' always throw Timeout Exception.
Browser keeps waiting for 'motahari.ir/' to load. But the loop just goes on (It doesn't open 'facebook.com' but wait for 'motahari.ir/') and keep throwing timeout exception
Initializing a webdriver instance takes long, so I pulled that out of the method and I think that caused the problem. Then, should I always reinitialize webdriver instance whenever there's a timeout exception? And How? (Since I initialized driver outside of the function, I can't reinitialize it in except)
You will just need to clear the browser's cookies before continuing. (Sorry, I missed seeing this in your previous code)
from selenium import webdriver
driver = webdriver.Chrome()
driver.set_page_load_timeout(7)
def urlOpen(url):
try:
driver.get(url)
print(driver.current_url)
except:
driver.delete_all_cookies()
print("Failed")
return
urls = ['http://motahari.ir/', 'https://facebook.com', 'https://google.com']
for url in urls:
urlOpen(url)
Output:
Failed
https://www.facebook.com/
https://www.google.com/?gfe_rd=cr&dcr=0&ei=o73dWfnsO-vs8wfc5pZI
P.S. It is not very wise to do try...except... without a clear Exception type, is this might mask different unexpected errors.

How to check if element is on screen

I have a case when I need to find out what button is displayed now. I try it in this way first
{please don't mind on my helper functions. I thinks you can easy understand that Ui.find_el it is almost the same as driver.find_element_by....}:
if Ui.find_el(link.AuthorPopupNodes.LOGIN_EMAIL).is_displayed():
pass
else:
if Ui.find_el(link.HeaderNodes.LOGOUT_BUTTON).is_displayed():
self.log_out()
Ui.wait_for_element(link.HeaderNodes.LOGIN_BUTTON, "Timeout: Wait for Login button!")
Ui.click_el(link.HeaderNodes.LOGIN_BUTTON)
But then it start to fall errors that driver can't find element, so I cover it by try but it didn't work for me too.
try:
if Ui.find_el(link.AuthorPopupNodes.LOGIN_EMAIL).is_displayed():
pass
else:
if Ui.find_el(link.HeaderNodes.LOGOUT_BUTTON).is_displayed():
self.log_out()
Ui.wait_for_element(link.HeaderNodes.LOGIN_BUTTON, "Timeout: Wait for Login button!")
Ui.click_el(link.HeaderNodes.LOGIN_BUTTON)
except:
pass
For example if first IF fails, than it get out from try and I need to check if there is LOGOUT button. HIs it possible to check for element without try but also without selenium errors?
You can catch specific selenium errors, for example:
from selenium.common.exceptions import NoSuchElementException, ElementNotVisibleException
try:
Ui.find_el(link.AuthorPopupNodes.LOGIN_EMAIL)
except (NoSuchElementException, ElementNotVisibleException):
try:
Ui.find_el(link.HeaderNodes.LOGOUT_BUTTON)
self.log_out()
except (NoSuchElementException, ElementNotVisibleException):
pass
Ui.wait_for_element(link.HeaderNodes.LOGIN_BUTTON, "Timeout: Wait for Login button!")
Ui.click_el(link.HeaderNodes.LOGIN_BUTTON)

Categories

Resources