Selenium仅在使用无头chrome(Python)时无法定位元素



我刚开始学习Selenium,需要在云中使用没有GUI的jenkins机器验证登录网页。我成功地在有UI的系统上运行了这个脚本。然而,当我将脚本修改为无头运行时,它失败了,说找不到元素。我的脚本如下:

#!/usr/bin/env python3
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
import time
import argparse

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--window-size=1120, 550')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--allow-running-insecure-content')
driver = webdriver.Chrome(ChromeDriverManager().install(), chrome_options=chrome_options)
driver.implicitly_wait(5)
lhip = '13.14.15.16'
user = 'username'
paswd = 'password'

parser = argparse.ArgumentParser()
parser.add_argument('-i', '--lh_ip',    type=str, metavar='', default=lhip,     help='Public IP of VM' )
parser.add_argument('-u', '--usr',      type=str, metavar='', default=user,     help='Username for VM')
parser.add_argument('-p', '--pwd',      type=str, metavar='', default=paswd,    help='Password for VM')
args = parser.parse_args()

lh_url = 'https://' + args.lh_ip + '/login/'
driver.get(lh_url)
try:
if driver.title == 'Privacy error':
driver.find_element_by_id('details-button').click()
driver.find_element_by_id('proceed-link').click()
except:
pass
driver.find_element_by_id('username').send_keys(args.usr)
driver.find_element_by_id('password').send_keys(args.pwd)
driver.find_element_by_id('login-btn').click()
driver.implicitly_wait(10)
try:
if driver.find_element_by_tag_name('span'):
print('Login Failed')
except:
print('Login Successful')
driver.close()

当不使用chrome_options时,python脚本在我的系统上运行良好。然而,当添加它们以无头模式运行时,它会失败,输出如下:

[WDM] - Current google-chrome version is 85.0.4183
[WDM] - Get LATEST driver version for 85.0.4183
[WDM] - Driver [/home/ramesh/.wdm/drivers/chromedriver/linux64/85.0.4183.87/chromedriver] found in cache
Traceback (most recent call last):
File "/home/ramesh/practice_python/test_headless.py", line 44, in <module>
driver.find_element_by_id('username').send_keys(args.usr)
File "/home/ramesh/.local/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 360, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File "/home/ramesh/.local/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 978, in find_element
'value': value})['value']
File "/home/ramesh/.local/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/home/ramesh/.local/lib/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="username"]"}
(Session info: headless chrome=85.0.4183.121)

由于我已经学习了大约一天的硒,我可能正在做一些相当愚蠢的事情,所以如果有人向我展示我做错了什么,我将不胜感激。我在谷歌上搜索了很多,尝试了很多东西,但都没用。还有为什么它说";css选择器"当我只使用id作为用户名时?

如果脚本在没有headless模式的情况下运行得很好,那么可能是窗口大小有问题。在指定--no sandbox选项的同时,尝试更改传递给网络驱动程序的窗口大小

chrome_options.add_argument('-窗口大小=1920180'(

这个窗户尺寸对我来说很管用。

即使这不起作用,你也可能需要添加之前回答的等待计时器,因为与UI模式下的浏览器相比,无头模式下的渲染工作方式不同。

无头模式下的渲染参考-https://www.toolsqa.com/selenium-webdriver/selenium-headless-browser-testing/

我也遇到了同样的问题,它最初是工作的,但在我们使用Selenium的网站更新后,它停止了无头模式下的工作,但继续以非无头模式工作。经过两天对网络最深和最黑暗的深度的研究和大量的尝试和错误,终于找到了问题所在。

我尝试了网上列出的所有方法,但直到我发现为止,都没有奏效。

在无头chrome模式下,用户代理是这样的:Mozilla/5.0(X11;Linux x86_64(AppleWebKit/537.36(KHTML,类似Gecko(HeadlessChrome/60.03112.50 Safari/537.36

服务提供商更新了他们的代码以识别HeadlessChrome部分,这将导致选项卡崩溃,进而破坏Selenium用户会话。

这导致了上述问题在其中一个例外中引发。

为了解决这个问题,我使用了一个名为fake_headers的插件(https://github.com/diwu1989/Fake-Headers):

from fake_headers import Headers
header = Headers(
browser="chrome",  # Generate only Chrome UA
os="win",  # Generate only Windows platform
headers=False # generate misc headers
)
customUserAgent = header.generate()['User-Agent']
options.add_argument(f"user-agent={customUserAgent}")

虽然这只是解决方案的一半,因为我只想要Windows和Chrome标头,而且fake_headers模块不包括最新的Chrome浏览器,并且列表中有很多旧版本的Chrome,如本文件所示https://github.com/diwu1989/Fake-Headers/blob/master/fake_headers/browsers.py.我运行Selenium的特定网站具有某些功能,这些功能只适用于较新版本的Chrome,因此当较旧版本的Chrome通过用户代理标头时,网站上的某些功能实际上会停止工作。因此,我需要更新fake_headers模块中的browsers.py文件,以便只包含我想要包含的Chrome版本。因此,我删除了所有较旧版本的Chrome,并创建了一个精选版本列表(每个版本都经过单独测试,可以在有问题的网站上运行,并删除了没有的版本(。最后列出了以下列表,我可以对其进行扩展,尽管目前还没有。

chrome_ver = [
'90.0.4430', '84.0.4147', '85.0.4183', '85.0.4183', '87.0.4280', '86.0.4240', '88.0.4324', '89.0.4389', '92.0.4515', '91.0.4472', '93.0.4577', '93.0.4577'
]

希望这能帮助人们避免两天的压力和混乱。

关于无头铬可检测性的一些更有用的信息:https://intoli.com/blog/making-chrome-headless-undetectable/

我也遇到过类似的情况。我在网上尝试了很多解决方案,比如指定分辨率,但直到现在都不起作用:

self.chrome_options.add_argument('user-agent="MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"')

因此,您似乎需要将UA添加到chrome选项中,这样硒驱动程序就不会在无头模式下崩溃。

chrome_options.add_argument('-窗口大小=1920180'(这对我有用感谢

我会以一种等待元素出现在网页上的方式重构代码:

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
WebDriverWait(wd, 10).until(EC.presence_of_element_located((By.ID, 'username'))).send_keys(args.usr)
WebDriverWait(wd, 10).until(EC.presence_of_element_located((By.ID,'password'))).send_keys(args.pwd)
WebDriverWait(wd, 10).until(EC.presence_of_element_located((By.ID, 'login-btn'))).click()

通常,CCD_ 1与某些条件相结合的使用应该比隐式等待或CCD_ 2更可取。下面详细解释一下原因。

要仔细检查的另一件事是元素是否具有用于搜索的ID,以及这些元素是否位于iframe中。

最新更新