nonshatter
nonshatter

Reputation: 3517

Checking if an element exists with Python Selenium

I have a problem; I am using the Selenium (Firefox) web driver to open a webpage, click a few links, etc., and then capture a screenshot.

My script runs fine from the CLI, but when run via a cron job it is not getting past the first find_element() test. I need to add some debug, or something to help me figure out why it is failing.

Basically, I have to click a 'log in' anchor before going to the login page. The construct of the element is:

<a class="lnk" rel="nofollow" href="/login.jsp?destination=/secure/Dash.jspa">log in</a>

I am using the find_element By LINK_TEXT method:

login = driver.find_element(By.LINK_TEXT, "log in").click()

A) How do I check that the link is actually being picked up by Python? Should I use try/catch block?

B) Is there a better/more reliable way to locate the DOM element than by LINK_TEXT? E.g., in jQuery, you can use a more specific selector, $('a.lnk:contains(log in)').do_something();


I have solved the main problem and it was just finger trouble. I was calling the script with incorrect parameters - a simple mistake.

I'd still like some pointers on how to check whether an element exists. Also, an example/explanation of implicit / explicit Waits instead of using a crappy time.sleep() call.

Upvotes: 133

Views: 366524

Answers (14)

ВячикМячик
ВячикМячик

Reputation: 11

el = WebDriverWait(driver, timeout=3).until(lambda d: d.find_element(By.TAG_NAME,"p"))

doc

Upvotes: -1

Brian Leishman
Brian Leishman

Reputation: 8555

You can grab a list of elements instead of a single element. An empty list in python is falsey. Example:

if driver.find_elements(By.CSS_SELECTOR, '#element'):
    print "Element exists!"

You can also use By.ID and By.NAME, but that just turns your id or name into a css selector anyway. Source

Upvotes: 125

vmk
vmk

Reputation: 105

The same as Brian, but add to this answer from tstempko:

I tried and it works quickly:

driver.implicitly_wait(0)

if driver.find_element_by_id("show_reflist"):
    driver.find_element_by_id("show_reflist").find_element_by_tag_name("img").click()

After this, I restore my default value:

driver.implicitly_wait(30)

Upvotes: 7

TendaiM
TendaiM

Reputation: 313

A) Use .is_displayed() as explained at Information about web elements:

# After navigating to the URL,
# get the Boolean value for if this element is displayed
is_button_visible = driver.find_element(By.CSS_SELECTOR, "[name='login']").is_displayed()

Continue your Visual Studio Code logic using "is_button_visible" for branching.

B) Refer to Sam Woods's answer

Upvotes: 0

bao.le
bao.le

Reputation: 154

You can check by find_elements. If the result is null, that element does not exist.

if driver.find_elements(By.SOMETHING, "#someselector") == []:
    continue   # That element does not exist

Upvotes: 0

Lopi Dani
Lopi Dani

Reputation: 29

driver.find_element_by_id("some_id").size() is a class method.

We need:

driver.find_element_by_id("some_id").size which is a dictionary, so:

if driver.find_element_by_id("some_id").size['width'] != 0:
   print 'button exist'

Upvotes: 2

Alex Okrushko
Alex Okrushko

Reputation: 7372

For a):

from selenium.common.exceptions import NoSuchElementException
def check_exists_by_xpath(xpath):
    try:
        webdriver.find_element_by_xpath(xpath)
    except NoSuchElementException:
        return False
    return True

For b): Moreover, you can take the XPath expression as a standard throughout all your scripts and create functions as above mentions for universal use.

I recommend to use CSS selectors. I recommend not to mix/use "by id", "by name", etc. and use one single approach instead.

Upvotes: 185

Sam Woods
Sam Woods

Reputation: 1850

A) Yes. The easiest way to check if an element exists is to simply call find_element inside a try/catch.

B) Yes, I always try to identify elements without using their text for two reasons:

  1. the text is more likely to change and;
  2. if it is important to you, you won't be able to run your tests against localized builds.

The solution is either:

  1. You can use XPath to find a parent or ancestor element that has an ID or some other unique identifier and then find its child/descendant that matches or;
  2. you could request an ID or name or some other unique identifier for the link itself.

For the follow-up questions, using try/catch is how you can tell if an element exists or not and good examples of waits can be found here: http://seleniumhq.org/docs/04_webdriver_advanced.html

Upvotes: 71

Rajesh Selvaraj
Rajesh Selvaraj

Reputation: 431

You could use is_displayed() like below:

res = driver.find_element_by_id("some_id").is_displayed()
assert res, 'element not displayed!'

Upvotes: 1

Super Mario
Super Mario

Reputation: 939

A solution without try&catch and without new imports:

if len(driver.find_elements_by_id('blah')) > 0: # Pay attention: find_element*s*
    driver.find_element_by_id('blah').click # Pay attention: find_element

Upvotes: 29

Raoul
Raoul

Reputation: 2212

With the latest Selenium, you can now use you can now use .is_displayed():

https://www.selenium.dev/documentation/webdriver/elements/information/

Upvotes: 1

kiril
kiril

Reputation: 5202

When you know the element could not be there, the implicit wait could be a problem. I've created a simple context manager to avoid those waiting times

class PauseExplicitWait(object):
    """
    Example usage:

    with PauseExplicitWait(driver, 0):
        driver.find_element(By.ID, 'element-that-might-not-be-there')
    """
    def __init__(self, driver, new_wait=0):
        self.driver = driver
        self.original_wait = driver.timeouts.implicit_wait
        self.new_wait = new_wait
      
    def __enter__(self):
        self.driver.implicitly_wait(self.new_wait)
  
    def __exit__(self, exc_type, exc_value, exc_tb):
        self.driver.implicitly_wait(self.original_wait)
  

Upvotes: 2

WebLab - group
WebLab - group

Reputation: 19

You can find elements by available methods and check response array length if the length of an array equal the 0 element not exist.

element_exist = False if len(driver.find_elements_by_css_selector('div.eiCW-')) > 0 else True

Upvotes: 1

codeslord
codeslord

Reputation: 2368

You could also do it more concisely using

driver.find_element_by_id("some_id").size != 0

Upvotes: 6

Related Questions