首页 > 解决方案 > 使用 Selenium 登录网站时出现问题

问题描述

我正在尝试学习如何使用 Selenium 登录网站:Ingram-Micro。我制作了一个脚本,它在不同的页面上运行:https://news.ycombinator.com/login.

现在我试图将同样的东西应用到 Ingram-Micro 上,但我被卡住了,我不知道还能尝试什么。我遇到的问题是一条错误/消息,指出提交元素不可点击,页面底部有一个接受 cookie 按钮,这似乎是导致问题的原因。

我试图解释它,但我总是收到错误说该元素不存在。但是,如果我不尝试单击接受 cookie 元素,我会收到原始错误,即提交按钮不可单击。这是我的代码:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException 
import time

chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')

url = "https://usa.ingrammicro.com/_layouts/CommerceServer/IM/Login.aspx? 
returnurl=//usa.ingrammicro.com/"
driver = webdriver.Chrome(options=chrome_options)
driver.get(url)

def login():
    USERNAME = 'email'
    PASSWORD = 'password'         
    element = driver.find_element_by_link_text('I ACCEPT')
    if element.is_displayed():
        print("Element found")
        element.click()
    else:
        print("Element not found")

driver.find_element_by_id('okta-signin-username').send_keys(USERNAME)
driver.find_element_by_id('okta-signin-password').send_keys(PASSWORD)
driver.find_element_by_id('okta-signin-submit').click()      

login()

try:   
    me = driver.find_element_by_id("login_help-about")  
    print(f"{me.text} Element found")

except NoSuchElementException:
    print('Not found')

driver.quit()

这是我得到的错误:

selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element <input class="button button-primary" type="submit" value="Log in" id="okta-signin-submit" data-type="save"> is not clickable at point (365, 560). Other element would receive the click: <p class="cc_message">...</p>

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate 
element: {"method":"link text","selector":"I ACCEPT"}
(Session info: headless chrome=84.0.4147.125)

标签: pythonseleniumselenium-webdrivernosuchelementexception

解决方案


您面临的挑战是围绕脚本进行同步。

该站点上的事件链是 1) 页面已加载,2) 它启动了 javascript,3) 将 cookie 窗口滑动到视图中......

但是,页面加载后,selenium 不知道脚本,所以它认为它是好的。它试图在按钮出现之前点击它,并因为找不到它而感到不安。( NoSuchElementException)

有不同的同步策略 - 这里的工作是 webdriverwait 告诉 selenium 等待(没有错误),直到您的对象达到指定的预期条件。

您可以在此处阅读有关等待和预期条件的更多信息

试试这个代码。对于cookie“我接受”按钮,我将标识符更改为xpath(因为我喜欢xpaths)并将其包装在webdriverwait中,等待对象可点击......

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException 
import time

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


chrome_options = Options()
#chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')

url = "https://usa.ingrammicro.com/_layouts/CommerceServer/IM/Login.aspx?returnurl=//usa.ingrammicro.com/"
driver = webdriver.Chrome(options=chrome_options)
driver.get(url)

def login():
    USERNAME = 'email'
    PASSWORD = 'password'  

    element = WebDriverWait(driver, 30).until(EC.element_to_be_clickable((By.XPATH, '//a[text()="I ACCEPT"]')))       
    if element.is_displayed():
        print("Element found")
        element.click()
    else:
        print("Element not found")

    driver.find_element_by_id('okta-signin-username').send_keys(USERNAME)
    driver.find_element_by_id('okta-signin-password').send_keys(PASSWORD)
    driver.find_element_by_id('okta-signin-submit').click()      

login()

请注意,我必须删除无头以检查它是否有效,并且顶部还有 3 个额外的导入。


当您没有很多复杂的对象或具有不同等待条件的对象时,Webdriverwait 非常有用。

另一种同步和(在我看来更容易)是在脚本开始时设置一个隐式等待 ONCE - 这会配置驱动程序对象。

driver.implicitly_wait(10)

正如之前的链接所说:

隐式等待告诉 WebDriver 在尝试查找任何不立即可用的元素(或多个元素)时轮询 DOM 一段时间。默认设置为 0。一旦设置,就会在 WebDriver 对象的生命周期内设置隐式等待。

您可以像这样使用它.. 不做所有代码,只需在创建驱动程序并且代码工作后添加这一行:

.....
url = "https://usa.ingrammicro.com/_layouts/CommerceServer/IM/Login.aspx?returnurl=//usa.ingrammicro.com/"
driver = webdriver.Chrome(options=chrome_options)
driver.get(url)
driver.implicitly_wait(10) # seconds

def login():
    USERNAME = 'email'
    PASSWORD = 'password'  

    element = driver.find_element_by_link_text('I ACCEPT')
    if element.is_displayed():
        print("Element found")
        element.click()
    else:
        print("Element not found")
........

推荐阅读