简体   繁体   中英

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? Eg, 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.

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

b) use xpath - the most reliable. Moreover you can take the xpath as a standard throughout all your scripts and create functions as above mentions for universal use.

UPDATE : I wrote the initial answer over 4 years ago and at the time I thought xpath would be the best option. Now I recommend to use css selectors . I still recommend not to mix/use "by id", "by name" and etc and use one single approach instead.

None of the solutions provided seemed at all easiest to me, so I'd like to add my own way.

Basically, you get the list of the elements instead of just the element and then count the results; if it's zero, then it doesn't exist. Example:

if driver.find_elements_by_css_selector('#element'):
    print "Element exists"

Notice the "s" in find_elements_by_css_selector to make sure it can be countable.

EDIT : I was checking the len( of the list, but I recently learned that an empty list is falsey, so you don't need to get the length of the list at all, leaving for even simpler code.

Also, another answer says that using xpath is more reliable, which is just not true. See What is the difference between css-selector & Xpath? which is better(according to performance & for cross browser testing)?

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 2 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.

solution 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 it's 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

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

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

https://sqa.stackexchange.com/questions/3481/quicker-way-to-assert-that-an-element-does-not-exist

So 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)

你也可以更简洁地使用

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

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

What we need is :

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

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

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

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

you could use is_displayed() like below

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

如果数组的长度等于 0 元素不存在,您可以通过可用的方法查找元素并检查响应数组长度。

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

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)
  

You can check by find_elements, if the result is null, that element is not exist

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

A) Use .is_displayed() as explained at

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

# After navigating to the url
# Get boolean value for is element display
is_button_visible = driver.find_element(By.CSS_SELECTOR, "[name='login']").is_displayed()

continue your Code logic using "is_button_visible" for branching.

B) refer to @Sam Woods's accepted answer

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

doc

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM