Selenium (Python) - 在启用后单击禁用按钮

Selenium (Python) - click on disabled button after it is enabled

我将 Selenium 与 Python 结合使用来自动执行上传文件的过程。有一个“上传”按钮,默认情况下是禁用的,只有在选择要上传的文件时才可以点击。

禁用按钮的 HTML 是 -

<button type="button" id="upload-button" data-bi-id="upload-button" class="ms-Button ms-Button--primary is-disabled root-296" disabled="" aria-label="Upload" aria-disabled="true" data-is-focusable="false">

按钮变成可点击后的 HTML 是 -

<button type="button" id="upload-button" data-bi-id="upload-button" class="ms-Button ms-Button--primary root-437" aria-label="Upload" data-is-focusable="true" tabindex="0">

我正在使用-

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.ID,"upload-button"))).click()

但是它不起作用。我相信这是点击禁用按钮(即使选择了文件并且按钮已变为可点击)。我也试过 -

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.CLASS_NAME,"ms-Button ms-Button--primary root-437"))).click()

但这给出了 TimeOut Exception。那么这个按钮变成可点击后怎么办才能点击呢。我尝试了一些来自 Internet 的解决方案,但其中 none 似乎有效。

您似乎使用了错误的 ID 值。

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.ID,"upload-button"))).click()

或者使用这个 css 选择器

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.CSS_SELECTOR,"#upload-button[data-is-focusable='true']"))).click()

关于您的代码的当前版本,我认为您可能是正确的,它在真正启用之前单击了按钮。你有

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.ID,"upload-button"))).click()

您正在等待此元素成为 clickable。我想尝试弄清楚这到底是什么意思,所以我查看了源代码。 element_to_be_clickable满意As soon as the element is "visible" and "enabled".

据我所知,可见性定义为 DOM 和 height/width 均 > 0。根据您的描述,听起来您的按钮立即可见。所以一旦“启用”,element_to_be_clickable就满足了,等待就会结束。

这就引出了一个问题,到底是什么决定了一个元素是否“启用”?我发现selenium的is_enabled(在源代码中需要element_to_be_clickable才能通过),本质上是对W3C specification for disabled()的否定。它归结为这一行,它表示如果 The element is a button, input, select, textarea, or form-associated custom element, and the disabled attribute is specified on this element (regardless of its value).

元素被“禁用”

就是这样。您的元素确实具有“已禁用”属性,但它还有一些其他可能导致它被禁用的东西——class 名称包含 is-disabled,它有 aria-disabled="true" 以及data-is-focusable="false",所有这些都会在按钮完全可点击时发生变化。我想知道 disabled 属性是否先于其他也会导致元素被禁用的东西消失,所以就像你说的那样,也许你的点击在按钮准备好之前就已经注册了。为了调试这个,我会尝试在执行 WebDriverWait 之后和单击按钮之前临时添加一个硬等待,几秒钟。

为了你的 class 名字,

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.CLASS_NAME,"ms-Button ms-Button--primary root-437"))).click()

我怀疑这是一个动态的 class 名称,特别是 root-437 部分,所以也许这就是它不起作用的原因。

最后,您是否打算通过单击按钮从您的文件系统上传?因为它只能与您的网络浏览器交互,而不能在您的 OS 上浏览 window,所以这是行不通的。上传文件有一种特殊的方式——您必须识别文件输入元素,并使用 send_keys().

将您要上传的文件的绝对路径发送到该元素

如您所见,按钮元素在仍处于禁用状态时包含 class is-disabled 和属性 disabled,而在启用时不包含这些属性。
所以预期的条件是定位到下面定义的元素 xpath:

//button[@id='upload-button' and(not(contains(@class,'is-disabled'))) and(not(@disabled))]

换句话说,您应该使用以下内容:

WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.XPATH, "//button[@id='upload-button' and(not(contains(@class,'is-disabled'))) and(not(@disabled))]")))

您也可以根据缺少上述两个属性之一来定位启用的按钮。

尝试使用隐式单击而不显式等待:

driver.implicitly_wait(15)
driver.find_element_by_xpath('//button[@data-is-focusable="true"]').click()

driver.implicitly_wait(15)
driver.find_element_by_xpath('//button[@data-is-focusable="true" and @tabindex="0"]').click()

如果这没有帮助,请在您的问题中添加更多详细信息。