Chrome无头模式下Selenium能否使用element.click()?解决元素不可点击问题
问题描述
我正在用Python的Selenium结合Chrome驱动写脚本,用来批量下载网站上的文件。但每次程序开新标签或者点下载按钮时,浏览器都会弹出来抢焦点,这实在太烦了,所以想改用无头模式。结果一用无头模式就报错:
WebDriverException: Message: unknown error: Element ... is not clickable at point (435, 575). Other element would receive the click:
...
(Session info: headless chrome=66.0.3359.139) (Driver info: chromedriver=2.37.544337 (8c0344a12e552148c185f7d5117db1f28d6c9e85),platform=Mac OS X 10.13.4 x86_64)
之前非无头模式下也碰到过同样的错误,但用driver.maximize_window()最大化窗口后就好了,这说明Chrome里元素得在屏幕可见区域才能被点击。可无头模式下按钮好像一直处于隐藏状态,导致没法点击。有没有办法让无头模式下按钮也能正常点击呢?
我的相关代码如下,最后一行触发了错误:
def login(driver, url, username, password): driver.get(url) uname = driver.find_element_by_name("login") uname.send_keys(username) passw = driver.find_element_by_name("password") passw.send_keys(password) submit_button = driver.find_element_by_class_name("button") action = webdriver.ActionChains(driver) action.move_to_element(submit_button) submit_button.click()
解决方案
针对无头模式下元素不可点击的问题,你可以试试这几个实用方法:
1. 给无头浏览器设置合适的窗口尺寸
无头模式下Chrome默认的窗口尺寸很小,很多元素会处于可视区域外,这时候调用maximize_window()可能也不生效,不如直接指定一个足够大的窗口尺寸,比如常见的1920x1080:
from selenium import webdriver options = webdriver.ChromeOptions() options.add_argument('--headless') # 指定窗口大小,确保元素落在可视区域内 options.add_argument('--window-size=1920,1080') driver = webdriver.Chrome(options=options)
这样设置后,元素大概率会落在可视区域内,就能正常点击了。
2. 用JavaScript直接点击元素
如果设置窗口大小还是不行,可以绕开Selenium的可见性检查,直接用JavaScript来触发点击事件——这种方法不管元素是否在可视区域都能生效:
把你代码里的submit_button.click()替换成:
driver.execute_script("arguments[0].click();", submit_button)
完整修改后的login函数大概是这样:
def login(driver, url, username, password): driver.get(url) uname = driver.find_element_by_name("login") uname.send_keys(username) passw = driver.find_element_by_name("password") passw.send_keys(password) submit_button = driver.find_element_by_class_name("button") # 用JS点击绕开可视性检查 driver.execute_script("arguments[0].click();", submit_button)
3. 增加显式等待,确保元素完全加载可点击
有时候无头模式下页面加载速度和非无头模式有差异,可能元素还没完全准备好就去点击了,这时候可以用显式等待,等待元素处于可点击状态再操作:
from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def login(driver, url, username, password): driver.get(url) uname = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.NAME, "login")) ) uname.send_keys(username) passw = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.NAME, "password")) ) passw.send_keys(password) # 等待按钮完全可点击后再操作 submit_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CLASS_NAME, "button")) ) submit_button.click()
这种方法能避免因为页面加载不完整导致的点击失败问题,结合前面的窗口尺寸设置,效果会更好。
内容的提问来源于stack exchange,提问作者Blaszard

