selenium.common.exceptions.ElementNotInteractableException:消息:使用 Selenium Python 单击元素时元素不可交互

Posted

技术标签:

【中文标题】selenium.common.exceptions.ElementNotInteractableException:消息:使用 Selenium Python 单击元素时元素不可交互【英文标题】:selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable when clicking on an element using Selenium Python 【发布时间】:2019-08-09 15:33:00 【问题描述】:

我知道有人问过这个问题,但我需要解决这个错误:

 Traceback (most recent call last):
 File "goeventz_automation.py", line 405, in <module>
if login(driver) is not None:
File "goeventz_automation.py", line 149, in login
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[@track-element='header-login']"))).click()
File "/usr/local/lib/python3.6/dist-packages/selenium/webdriver/support/wait.py", line 80, in until
raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message:

这是出现错误的代码:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import TimeoutException
import urllib.request as request
import urllib.error as error
from PIL import Image
from selenium.webdriver.chrome.options import Options
import datetime as dt
import time
from common_file import *
from login_credentials import *

def login(driver):
global _email, _password
if waiter(driver, "//a[@track-element='header-login']") is not None:
    #login = driver.find_element_by_xpath("//a[@track-element='header-login']")
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[@track-element='header-login']"))).click()
    #login.click()
    if waiter(driver,"//input[@id='user_email']") is not None:
        email = driver.find_element_by_xpath("//input[@id='user_email']")
        password = driver.find_element_by_xpath("//input[@id='password']")
        email.send_keys(_email)
        password.send_keys(_password)
        driver.find_element_by_xpath("//button[@track-element='click-for-login']").click()
        return driver
    else:
        print("There was an error in selecting the email input field. It may be the page has not loaded properly.")
        return None
else:
    print("There was an error in selecting the header-login attribute on the page.")
    return None

if __name__ == '__main__':
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--no-sandbox')
    chrome_options.add_argument('--disable-dev-shm-usage')

    driver = webdriver.Chrome('/usr/bin/chromium/chromedriver',chrome_options=chrome_options)
    #d.get('https://www.google.nl/')
    #driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get('https://www.goeventz.com/')
    if login(driver) is not None:
        print(create_event(driver))

我认为Keys.ENTER 有一些问题,但我不知道如何解决。我已经尝试了所有可能的解决方案......

【问题讨论】:

我认为包含名为“waiter”的函数的代码是明智的,因为它与您编辑要显示的问题的错误有关。很高兴看到您所做的所有相关导入,这样我们就可以正确排除任何线索或导致您的问题的原因。 确保您的 DOM 中没有任何 iframe,还有一个名为 isEnabled 的方法使用该方法并确保该元素已启用,然后尝试单击它。 【参考方案1】:

您应该使用 selenium click() 方法,而不是使用 login.send_keys(Keys.ENTER),这对您来说很好。

您可以先检查元素是否可点击,然后您可以点击它。 喜欢:

WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[@track-element='header-login']"))).click()

【讨论】:

改成这个方法后还是报同样的错误 此代码在本地运行良好,但在服务器上出现问题 @Nandan 更新了我的答案。请尝试更新的答案。 你不需要使用login = driver.find_element_by_xpath("//a[@track-element='header-login']")你可以使用我在答案中使用的语句。 我已删除代码并添加了此代码,但仍面临问题【参考方案2】:

此错误消息...

selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable

...暗示当您尝试在其上调用 click() 时,所需的元素不是可交互的

几个事实:

当您初始化 Chrome 浏览器时,浏览器始终处于最大化模式。 您可以禁用扩展。 您还需要禁用信息栏

我使用了与您构建的相同的 xpath,您可以使用以下解决方案:

代码块:

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

options = webdriver.ChromeOptions()
options.add_argument("start-maximized");
options.add_argument("disable-infobars")
options.add_argument("--disable-extensions")
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
driver.get("https://www.goeventz.com/")
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//a[@track-element='header-login']"))).click()

浏览器快照:

【讨论】:

【参考方案3】:

概述

您似乎在查找“提交”按钮时遇到了 XPATH 问题,或者您的提交按钮不可点击,或者您的提交按钮附加了一些客户端事件(javascript/etc),这些事件是必需的有效地提交页面。

在大多数情况下调用 pw.submit() 方法应该消除等待提交按钮变为可点击的需要,并避免在大多数情况下定位按钮时出现任何问题。在许多其他网站上,一些必要的后端流程由实际单击“提交”按钮后执行的客户端活动启动(尽管在旁注中,这不是最佳实践,因为它使网站不太容易访问,等等,我离题了)。最重要的是,观察您的脚本执行并确保您没有在网页上看到有关您提交的凭据的任何明显错误,这一点很重要。

此外,一些网站要求您在输入用户名、密码和提交页面之间添加一定的最短时间,以便将其视为有效的提交过程。我什至遇到过要求您一次使用 send_keys 1 作为用户名和密码的网站,以避免他们使用的一些反抓取技术。在这些情况下,我通常在调用之间使用以下内容:

from random import random, randint

def sleepyTime(first=5, second=10):
    # returns the value of the time slept (as float)
    # sleeps a random amount of time between the number variable in first
    # and the number variable second (in seconds)
    sleepy_time = round(random() * randint(first, second), 2)
    sleepy_time = sleepy_time if sleepy_time > first else (first + random())
    sleep(sleepy_time)
    return sleepy_time

我看不出您将 _email 和 _password 变量设为全局变量有什么用,除非它们在登录函数中的某处被更改,并且您希望将该更改沉淀到其他范围。

我将如何尝试解决它

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException, TimeoutException

TIME_TIMEOUT = 20 # Twenty-second timeout default

def eprint(*args, **kwargs):
    """ Prints an error message to the user in the console (prints to sys.stderr), passes
    all provided args and kwargs along to the function as usual. Be aware that the 'file' argument
    to print can be overridden if supplied again in kwargs.
    """
    print(*args, file=sys.stderr, **kwargs)


def login(driver):
    global _email, _password
    try:
        email = WebDriverWait(driver, TIME_TIMEOUT).until(EC.presence_of_element_located((By.XPATH, "//input[@id='user_email']")))
        pw = WebDriverWait(driver, TIME_TIMEOUT).until(EC.presence_of_element_located((By.XPATH, "//input[@id='password']"))
        pw.submit()
        # if this doesn't work try the following:
        # btn_submit = WebDriverWait(driver, TIME_TIMEOUT).until(EC.element_to_be_clickable((By.XPATH, "//button[@track-element='click-for-login']"))
        # btn_submit.click() 
        # if that doesn't work, try to add some random wait times using the 
        # sleepyTime() example from above to add some artificial waiting to your email entry, your password entry, and the attempt to submit the form.

except NoSuchElementException as ex:
    eprint(ex.msg())

except TimeoutException as toex:
    eprint(toex.msg)

if __name__ == '__main__':
    driver = webdriver.Chrome('/usr/bin/chromium/chromedriver',chrome_options=chrome_options)
    #d.get('https://www.google.nl/')
    #driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get('https://www.goeventz.com/')
    if login(driver) is not None:
        print(create_event(driver))

【讨论】:

【参考方案4】:

对于无头 chrome 浏览器,您还需要在 chrome 选项中提供窗口大小。对于无头浏览器 selenium 无法知道您的窗口大小。试试,让我知道。

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('window-size=1920x1480')

【讨论】:

在 Heroku 上运行无头 Chrome 时,这对我有用,谢谢。 @KunduK 我全屏显示它并且一切正常,突然停止,您的解决方案通过设置特定的窗口大小来帮助,这是为什么呢?【参考方案5】:

复制完整的 xpath,而不是复制仅 xpath。它会工作

【讨论】:

因此卡了几个小时,谢谢!

以上是关于selenium.common.exceptions.ElementNotInteractableException:消息:使用 Selenium Python 单击元素时元素不可交互的主要内容,如果未能解决你的问题,请参考以下文章