Charlie Z
Charlie Z

Reputation: 9

Find element by XPath in Selenium with Python can not catch an exception

I want to play videos automatically through this page by click the Next bottom. However, at the end of each chapter, there is an exercise page without a video, and I want to skip it.

The skip-to-next-chapter button element is on every page, just not visible.

(1) on exercise page, wait for the page to be loaded

(2) find the skip-to-next-chapter button and click on it

(3) on the video page, skip-to-next-chapter is not visible, so skip this block

However, I can not catch any exceptions, so the process got stuck at the next_ = driver.find_element_by_xpath('//*[foo]') line. This line doesn’t return anything and run forever. And it won’t throw a Timeout exception.

How can I debug this?

try:
    myElem = WebDriverWait(driver, delay).until(EC.presence_of_element_located((By.ID, 'myID')))
    next_ = driver.find_element_by_xpath('//*[foo]')
    next_.click()
except (NoSuchElementException ,ElementNotVisibleException,TimeoutException):
    print('skip this')

changed to

    try:
        WebDriverWait(driver, 1).until(
        EC.element_to_be_clickable((By.XPATH, '//*[contains(concat( " ", @class, " " ), concat( " ", "skip-to-next-chapter", " " ))]'))
    ).click()
    except TimeoutException:
        pass

But it still does not work.

Debug final stop point from PyCharm:

Screenshot

When stepping into EC.element_to_be_clickable((By.XPATH, '//*[contains(concat( " ", @class, " " ), concat( " ", "skip-to-next-chapter", " " ))]')) line, it goes to wait.py >>

    def until(self, method, message=''):
    """Calls the method provided with the driver as an argument until the \
    return value is not False."""
    screen = None
    stacktrace = None

    end_time = time.time() + self._timeout
    while True:
        try:
            value = method(self._driver)# <<<< stopped here!!
            if value:
                return value
        except self._ignored_exceptions as exc:
            screen = getattr(exc, 'screen', None)
            stacktrace = getattr(exc, 'stacktrace', None)
        time.sleep(self._poll)
        if time.time() > end_time:
            break
    raise TimeoutException(message, screen, stacktrace)

Upvotes: 0

Views: 2467

Answers (2)

Charlie Z
Charlie Z

Reputation: 9

I still don't know what’s wrong with my code. Why doesn’t WebDriver return anything when it can not find the element? Anyway, I walk way from this by another way.

  1. Use Beautiful Soup to parse the page source

  2. Check if the button exists

  3. if exist → driver, click it

if not → skip

src = driver.page_source
soup = BeautifulSoup(src, 'lxml')

next_chap = soup.find('button',class_="btn btn-link skip-to-next-chapter ga")

if(next_chap!=None):
    try:
        driver.find_element_by_css_selector('.btn.btn-link.skip-to-next-chapter.ga').click()
    except Exception as e:
        print(e)
else:
    print("button not exists ,skip")

Upvotes: 0

undetected Selenium
undetected Selenium

Reputation: 193208

You have to take care of a couple of things in your code block. In your code block as you have tried to handle three exceptions and among them NoSuchElementException and ElementNotVisibleException looks as a pure overhead to me for the following reasons:

  • First of all, I am still trying to understand the logic behind waiting for an elementA (i.e. (By.ID, 'myID')), but moving ahead and clicking on elementB, i.e., find_element_by_xpath('//*[foo]')

  • If your code block is generating NoSuchElementException, definitely we have to look at the Locator Strategy which you have adapted if it uniquely identifies an element and also cross-check that the element is within the Viewport.

  • If your code block is generating ElementNotVisibleException, we have to consider this factor as well when we pick up the EC clause, e.g., presence_of_element_located.

  • Finally, as moving forward you are attempting to invoke the click() method on the element, instead of the EC clause as presence_of_element_located, you should be using element_to_be_clickable(locator)

  • So to wait for an element and moving ahead to click it, your code block will be like:

     try:
         WebDriverWait(driver, delay).until(EC.element_to_be_clickable((By.ID, 'myID'))).click()
     except (TimeoutException):
         print('skip this')
    

Upvotes: 1

Related Questions