Loop through span elements in selenium python, Att

2019-08-16 14:40发布

This question already has an answer here:

I want to loop through a list of span elements and make Selenium click all span elements available. Currently I'm getting an AttributeError: 'list' object has no attribute 'click'. See code snippets below for more details.

I made have a BasePage as super class where I define most of my selenium methods:

from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait


class BasePage(object):

    def __init__(self, driver):
        self.driver = driver

    def _visit(self, url):
        self.driver.get(url)

    def _find(self, locator):
        return self.driver.find_element(locator["by"], locator["value"])

    def _find_all(self, locator):
        return self.driver.find_elements(locator["by"], locator["value"])

    def _click(self, locator):
        self._find(locator).click()

    def _click_all(self, locator):
        self._find_all(locator).click()

    def _type(self, locator, input_text):
        self._find(locator).send_keys(input_text)

    def _clear(self, locator):
        self._find(locator).clear()

I have also made a page object where I define all the locators and actions of a page.

from selenium.webdriver.common.by import By

from .base_page import BasePage


class RelatiePage(BasePage):

    _open_actieve_polis = {"by": By.CSS_SELECTOR, "value": "td:nth-
    child(2)"}

    def __init__(self, driver):
        super(BasePage, self).__init__()
        self.driver = driver


    def relatie_tabs_(self):
        self._click(self._open_actieve_polissen_tab)
        self._click_all(self._open_actieve_polis)
        self.driver.back()

these are the html selectors i want to loop through:

tbody > tr:nth-child(2) > td:nth-child(2) > span > a
tbody > tr:nth-child(3) > td:nth-child(2) > span > a
tbody > tr:nth-child(4) > td:nth-child(2) > span > a
tbody > tr:nth-child(5) > td:nth-child(2) > span > a
tbody > tr:nth-child(6) > td:nth-child(2) > span > a

the error i'm currently receiving:

line 46, in relatie_tabs_
    self._click_all(self._open_actieve_polis), self.driver.back()

 line 24, in _click_all
    self._find_all(locator).click()

AttributeError: 'list' object has no attribute 'click'

1条回答
迷人小祖宗
2楼-- · 2019-08-16 14:59

Here is your problem: method self._find_all(self, locator) returns a list of elements, so instead of use it as

def _click_all(self, locator):
    self._find_all(locator).click()

you should do

def _click_all(self, locator):
    for element in self._find_all(locator):
        element.click()

Also note that if clicking target element triggers page refresh/navigation to new page, you will get StaleElementReferenceException, so _click_all() might be applied to list of elements that performs some actions on static page

Update

from selenium.webdriver.support.ui import WebDriverWait as wait

def _click_all(self, locator):
    counter = len(self._find_all(locator))
    for index in range(counter):
        self._find_all(locator)[index].click()
        self.driver.back()
        wait(self.driver, 10).until(lambda driver: len(self._find_all(locator)) == counter)
查看更多
登录 后发表回答