代码之家  ›  专栏  ›  技术社区  ›  Alex

Python Selenium查找无法单击的可单击元素

  •  2
  • Alex  · 技术社区  · 6 年前

    我在用 python-selenium

    基本上,我试图做的是在DOM中找到一些元素,当它变得可点击时,然后点击它。代码如下:

    ....
    what = (By.XPATH, '//button/span[contains(text(), "Load")]')
    element = WebDriverWait(bspdriver.webdriver, 60).\
                    until(EC.element_to_be_clickable(what))
    element.click()
    ....
    

    然而 click 方法几乎立即失败,并显示以下错误消息:

    ElementClickInterceptedException: Message: Element <button class="ivu-btn ivu-btn-primary ivu-btn-long ivu-btn-small" type="button"> is not clickable at point (1193.3332901000977,522) because another element <div class="ivu-modal-wrap vertical-center-modal circuit-loading-modal"> obscures it
    

    可点击 ! 我以为 EC.element_to_be_clickable 就是这个意思。但事实并非如此。这是硒的一个缺陷吗?

        mustend = time.time() + 60
        while time.time() < mustend:
            try:
                WebDriverWait(bspdriver.webdriver, 60).\
                    until(EC.element_to_be_clickable(what)).click()
                break
            except (TimeoutException, NoSuchElementException,
                    StaleElementReferenceException,
                    ElementClickInterceptedException) as e:
                time.sleep(1.0)
    

    我觉得不太好。有办法改进代码吗?硒里有虫子吗?如果是的话,我可以报告。。。

    使用的包:

    • 硒3.8.0和3.11.0
    • 壁虎河0.19.1
    • 蟒蛇2.7.12
    • py.试验3.6.1

    ....
    >       element.click()
    selenium/test_pair_recording.py:66: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    ../venvs/linux_selenium/local/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py:80: in click
        self._execute(Command.CLICK_ELEMENT)
    ../venvs/linux_selenium/local/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py:501: in _execute
        return self._parent.execute(command, params)
    ../venvs/linux_selenium/local/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py:311: in execute
        self.error_handler.check_response(response)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x7fe69694fd90>
    response = {'status': 400, 'value': '{"value":{"error":"element click intercepted","message":"Element <button class=\"ivu-btn ivu...gate@chrome://marionette/content/listener.js:414:13\nclickElement@chrome://marionette/content/listener.js:1220:5\n"}}'}
    
        def check_response(self, response):
            """
                Checks that a JSON response from the WebDriver does not have an error.
    
                :Args:
                 - response - The JSON response from the WebDriver server as a dictionary
                   object.
    
                :Raises: If the response contains an error message.
                """
            status = response.get('status', None)
            if status is None or status == ErrorCode.SUCCESS:
                return
            value = None
            message = response.get("message", "")
            screen = response.get("screen", "")
            stacktrace = None
            if isinstance(status, int):
                value_json = response.get('value', None)
                if value_json and isinstance(value_json, basestring):
                    import json
                    try:
                        value = json.loads(value_json)
                        if len(value.keys()) == 1:
                            value = value['value']
                        status = value.get('error', None)
                        if status is None:
                            status = value["status"]
                            message = value["value"]
                            if not isinstance(message, basestring):
                                value = message
                                message = message.get('message')
                        else:
                            message = value.get('message', None)
                    except ValueError:
                        pass
    
            exception_class = ErrorInResponseException
            if status in ErrorCode.NO_SUCH_ELEMENT:
                exception_class = NoSuchElementException
            elif status in ErrorCode.NO_SUCH_FRAME:
                exception_class = NoSuchFrameException
            elif status in ErrorCode.NO_SUCH_WINDOW:
                exception_class = NoSuchWindowException
            elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
                exception_class = StaleElementReferenceException
            elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
                exception_class = ElementNotVisibleException
            elif status in ErrorCode.INVALID_ELEMENT_STATE:
                exception_class = InvalidElementStateException
            elif status in ErrorCode.INVALID_SELECTOR \
                    or status in ErrorCode.INVALID_XPATH_SELECTOR \
                    or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
                exception_class = InvalidSelectorException
            elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
                exception_class = ElementNotSelectableException
            elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
                exception_class = ElementNotInteractableException
            elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
                exception_class = InvalidCookieDomainException
            elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
                exception_class = UnableToSetCookieException
            elif status in ErrorCode.TIMEOUT:
                exception_class = TimeoutException
            elif status in ErrorCode.SCRIPT_TIMEOUT:
                exception_class = TimeoutException
            elif status in ErrorCode.UNKNOWN_ERROR:
                exception_class = WebDriverException
            elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
                exception_class = UnexpectedAlertPresentException
            elif status in ErrorCode.NO_ALERT_OPEN:
                exception_class = NoAlertPresentException
            elif status in ErrorCode.IME_NOT_AVAILABLE:
                exception_class = ImeNotAvailableException
            elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
                exception_class = ImeActivationFailedException
            elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
                exception_class = MoveTargetOutOfBoundsException
            elif status in ErrorCode.JAVASCRIPT_ERROR:
                exception_class = JavascriptException
            elif status in ErrorCode.SESSION_NOT_CREATED:
                exception_class = SessionNotCreatedException
            elif status in ErrorCode.INVALID_ARGUMENT:
                exception_class = InvalidArgumentException
            elif status in ErrorCode.NO_SUCH_COOKIE:
                exception_class = NoSuchCookieException
            elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
                exception_class = ScreenshotException
            elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
                exception_class = ElementClickInterceptedException
            elif status in ErrorCode.INSECURE_CERTIFICATE:
                exception_class = InsecureCertificateException
            elif status in ErrorCode.INVALID_COORDINATES:
                exception_class = InvalidCoordinatesException
            elif status in ErrorCode.INVALID_SESSION_ID:
                exception_class = InvalidSessionIdException
            elif status in ErrorCode.UNKNOWN_METHOD:
                exception_class = UnknownMethodException
            else:
                exception_class = WebDriverException
            if value == '' or value is None:
                value = response['value']
            if isinstance(value, basestring):
                if exception_class == ErrorInResponseException:
                    raise exception_class(response, value)
                raise exception_class(value)
            if message == "" and 'message' in value:
                message = value['message']
    
            screen = None
            if 'screen' in value:
                screen = value['screen']
    
            stacktrace = None
            if 'stackTrace' in value and value['stackTrace']:
                stacktrace = []
                try:
                    for frame in value['stackTrace']:
                        line = self._value_or_default(frame, 'lineNumber', '')
                        file = self._value_or_default(frame, 'fileName', '<anonymous>')
                        if line:
                            file = "%s:%s" % (file, line)
                        meth = self._value_or_default(frame, 'methodName', '<anonymous>')
                        if 'className' in frame:
                            meth = "%s.%s" % (frame['className'], meth)
                        msg = "    at %s (%s)"
                        msg = msg % (meth, file)
                        stacktrace.append(msg)
                except TypeError:
                    pass
            if exception_class == ErrorInResponseException:
                raise exception_class(response, message)
            elif exception_class == UnexpectedAlertPresentException and 'alert' in value:
                raise exception_class(message, screen, stacktrace, value['alert'].get('text'))
    >       raise exception_class(message, screen, stacktrace)
    E       ElementClickInterceptedException: Message: Element <button class="ivu-btn ivu-btn-primary ivu-btn-long ivu-btn-small" type="button"> is not clickable at point (1193.3332901000977,522) because another element <div class="ivu-modal-wrap vertical-center-modal circuit-loading-modal"> obscures it
    
    ../venvs/linux_selenium/local/lib/python2.7/site-packages/selenium/webdriver/remote/errorhandler.py:237: ElementClickInterceptedException
    
    1 回复  |  直到 6 年前
        1
  •  3
  •   Andersson    6 年前

    失败的原因是 ElementToBeClickable 正在等待元素被启用,它并没有真正检查元素是否可单击,它假设元素是可单击的如果元素被启用,它是真的,但它在这里失败了,因为即使另一个元素覆盖了所需的元素,元素也被启用。

    所以写这段代码让覆盖层消失

    WebDriverWait(bspdriver.webdriver,10).until(EC.invisibility_of_element_located((By.XPATH, "//div[@class='ivu-modal-wrap vertical-center-modal circuit-loading-modal']")));
    

    然后你写你的代码

    what = (By.XPATH, '//button/span[contains(text(), "Load")]')
    element = WebDriverWait(bspdriver.webdriver, 60).\
                    until(EC.element_to_be_clickable(what))
    element.click()