Selenium Explicit Wait 无法等待可点击性

问题描述 投票:0回答:1

我遇到了硒显式等待按钮可点击的问题。当按钮 web 元素由

返回时
self.driver_wait.until(
            expected_conditions.element_to_be_clickable((By.ID, 'login-btn'))
            )

我收到阻塞错误:

selenium.common.exceptions.ElementClickInterceptedException: Message: Element <a id="login-btn" class="fm-btn fm-btn-ghost-white account"> is not clickable at point (886,96) because another element <div id="ot-pc-content" class="ot-pc-scrollbar"> obscures it

讽刺的是,它明确指出,该元素不可点击,尽管显式等待指令应该完全等待我的理解......

我尝试等到阻碍元素不再可见,但这没有帮助:

    self.driver_wait.until(
        expected_conditions.invisibility_of_element((By.ID, 'ot-pc-content'))
        )
    button_login_1 = self.driver_wait.until(
        expected_conditions.element_to_be_clickable((By.ID, 'login-btn'))
        )

我想使用这个最小示例可以重现这种行为,其中包括类定义所需的所有内容:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
import time
import datetime as dt
from typing import Union

class Session_FLM:
    def __init__(self,
                 url: str = 'https://www.freelancermap.de/',
                 browser: str = "FireFox",
                 session_time: Union[None, dt.datetime] = None,
                 use_fixed_wait_default: bool = False,
                 default_wait_time_fixed: float = 1,
                 default_explicit_wait_max: float = 10,
                 implicit_wait_max: float = 10
                 ):
        self.browser: str = browser
        if session_time:
            self.session_time = session_time
        else:
            self.session_time = dt.datetime.now()
        self.url: str = url
        self.cookies: bool = False
        self.default_explicit_wait_max: float = default_explicit_wait_max
        self.use_fixed_wait_default: bool = use_fixed_wait_default
        self.default_wait_time_fixed: float = default_wait_time_fixed
        self.implicit_wait_max: float = implicit_wait_max
        self.driver: Union[
            webdriver.firefox.webdriver.WebDriver,
            webdriver.chrome.webdriver.WebDriver,
            None] = None    
        self.driver_wait: Union[WebDriverWait, None] = None     
        self.headers: dict = {
            'User-Agent': 'Mozilla/5.0'
            }
     
    def init_webdriver(
            self,
            url: Union[str, None] = None,
            use_fixed_wait: Union[bool, None] = None,
            wait_time_fixed: Union[float, None] = None,
            activate_implicit_wait: bool = False,
            implicit_wait_max: Union[float, None] = None,
            explicit_wait_max: Union[float, None] = None
            ) -> None:

        if not url:
            url = self.url
        if not use_fixed_wait:
            use_fixed_wait = self.use_fixed_wait_default
        if not wait_time_fixed:
            wait_time_fixed = self.default_wait_time_fixed
        if not implicit_wait_max:
            implicit_wait_max = self.implicit_wait_max
        if not explicit_wait_max:
            explicit_wait_max = self.default_explicit_wait_max

        if self.browser == 'Chrome':
            driver_options = webdriver.ChromeOptions()
            driver_options.page_load_strategy = 'normal'        # wait for entire page content to be loaded
            self.driver = webdriver.Chrome(options=driver_options)
        elif self.browser == 'FireFox':
            driver_options = webdriver.FirefoxOptions()
            driver_options.page_load_strategy = 'normal'        # wait for entire page content to be loaded
            self.driver = webdriver.Firefox(options=driver_options)

        self.driver_wait = WebDriverWait(self.driver, explicit_wait_max)

        if activate_implicit_wait:
            self.driver.implicitly_wait(implicit_wait_max)
        self.driver.get(url=url)
        if use_fixed_wait:
            time.sleep(wait_time_fixed)

    def cookies_handling(
            self,
            accept_cookies: bool = False,
            use_fixed_wait: Union[bool, None]  = None,
            wait_time_fixed: Union[float, None] = None
            ) -> None:
        """
        Handle freelancermap cookies.

        Args:
            accept_cookies (bool, optional): True: Accept all cookies; False: Enter cookie details and only accept obigatory cookies.
            use_fixed_wait: (Union[bool, None], optional): Only use fixed wait if True
            wait_time_fixed (Union[float, None], optional): Fixed waiting time, which is used whenever "Selenium Implicit Wait" is set to be inactive; overrides "Session_FLM" objects default fixed waiting time.
        """     

        if not use_fixed_wait:
            use_fixed_wait = self.use_fixed_wait_default
        if not wait_time_fixed:
            wait_time_fixed = self.default_wait_time_fixed

        if accept_cookies:
            button_accept_cookies = self.driver_wait.until(
                expected_conditions.element_to_be_clickable((By.ID, 'onetrust-accept-btn-handler'))
            )
            button_accept_cookies.click()
        else:
            button_settings_cookies = self.driver_wait.until(
                expected_conditions.element_to_be_clickable((By.ID, 'onetrust-pc-btn-handler'))
                )
            button_settings_cookies.click()
            if use_fixed_wait:
                time.sleep(wait_time_fixed)
            button_accept_selected_cookies = self.driver_wait.until(
                expected_conditions.element_to_be_clickable((By.CLASS_NAME, 'save-preference-btn-handler'))
                )
            button_accept_selected_cookies.click()

        if use_fixed_wait:
            time.sleep(wait_time_fixed)

    def login(
            self,
            email: str,
            password: str,
            use_fixed_wait: Union[bool, None]  = None,
            wait_time_fixed: Union[float, None] = None
            ) -> None:
        """
        Login with an existing freelancermap account.

        Args:
            email (str): Account email
            password (str): Account password
            use_fixed_wait: (Union[bool, None], optional): Only use fixed wait if True
            wait_time_fixed(Union[float, None], optional): Fixed waiting time, which is used whenever "Selenium Implicit Wait" is set to be inactive; overrides "Session_FLM" objects default fixed waiting time.
        """          

        if not wait_time_fixed:
            wait_time_fixed = self.default_wait_time_fixed
            
        if use_fixed_wait:
            time.sleep(wait_time_fixed)
        self.driver_wait.until(
            expected_conditions.invisibility_of_element((By.ID, 'ot-pc-content'))
            )
        button_login_1 = self.driver_wait.until(
            expected_conditions.element_to_be_clickable((By.ID, 'login-btn'))
            )
        button_login_1.click()
        if use_fixed_wait:
            time.sleep(wait_time_fixed)
        input_field_email = self.driver.find_element(
            By.ID,
            "login"
        )
        input_field_email.send_keys(email)
        input_field_pw = self.driver.find_element(
            By.ID,
            "password"
        )
        input_field_pw.send_keys(password)
        button_login_2 = self.driver_wait.until(
            expected_conditions.element_to_be_clickable((By.CSS_SELECTOR, 'button.fm-btn-primary:nth-child(1)'))
            )
        button_login_2.submit()
        self.driver_wait.until(
            expected_conditions.url_to_be('https://www.freelancermap.de/mein_account.html')
            )
        if use_fixed_wait:
            time.sleep(wait_time_fixed)
        self.driver.back()
        if use_fixed_wait:
            time.sleep(wait_time_fixed)

if __name__ == '__main__':
    flm = Session_FLM(
        url='https://www.freelancermap.de/projektboerse.html',
        default_wait_time_fixed=2
        )
    flm.init_webdriver(activate_implicit_wait=False)
    flm.cookies_handling(
        accept_cookies=False,
        use_fixed_wait=False)
    flm.login(
        email='abc',
        password='123', 
        use_fixed_wait=False
        )
        
  • 当使用参数
    cookies_handling()
    调用
    use_fixed_wait=True
    时,单击按钮即可工作。
  • 当使用参数
    login()
    调用
    use_fixed_wait=True
    时,单击按钮即可工作。
  • 当使用参数
    cookies_handling()
    调用
    accept_cookies=False
    时,单击按钮有效,因为在这种情况下,阻碍元素根本不会出现。
  • 当所有这些参数都设置为
    False
    时,单击按钮会失败。

我真的很想了解我的方法有什么问题以及如何在不添加

time.sleep()
的情况下应对它。

python selenium-webdriver webdriverwait
1个回答
0
投票

这是您作为 MCVE 应该发布的内容,

url = 'https://www.freelancermap.de/projektboerse.html'
driver = webdriver.Chrome()
driver.maximize_window()
driver.get(url)

wait = WebDriverWait(driver, 10)
wait.until(EC.element_to_be_clickable((By.ID, "login-btn"))).click()

代码的其余部分与错误无关,只会造成混乱并混淆问题。

这段代码在我的机器上运行得很好。从点击拦截异常提供的 HTML 来看,您的代码所点击的似乎是 cookie 横幅。我的建议是首先接受或以其他方式关闭 cookie 横幅,然后继续执行其余代码,您应该不会遇到任何问题。

© www.soinside.com 2019 - 2024. All rights reserved.