当前位置: 首页 > 知识库问答 >
问题:

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

郑佐
2023-03-14

我刚开始学习Selenium,需要使用云中的jenkins机器验证登录网页,该机器没有GUI。我成功地在有UI的系统上运行了脚本。然而,当我将脚本修改为运行headless时,它无法表示无法定位元素。我的脚本如下:

#!/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)

由于我对Selenium有大约一天的学习时间,我可能正在做一些相当愚蠢的事情,所以如果有人告诉我我做错了什么,我会非常感激。我用谷歌搜索了很多东西,尝试了很多东西,但都不起作用。当我只使用id作为用户名时,为什么它会显示“css选择器”?

共有3个答案

锺离德庸
2023-03-14

我会重构代码,直到元素出现在网页上:

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()

通常,与隐式等待或时间相比,最好将WebDriverWait与某些条件结合使用。sleep()。这里详细解释了原因。

其他需要仔细检查的事情是元素是否具有用于搜索的ID,以及这些元素是否位于iframe中。

柯树
2023-03-14

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

我尝试了网络上列出的所有方法以及更多方法,但直到我找到这个方法,一切都不起作用。

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

服务提供商更新了他们的代码以识别Headless Chrome部分,并会导致选项卡崩溃,进而破坏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模块中的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/

慕容念
2023-03-14

如果脚本在没有无头模式的情况下运行良好,则可能是窗口大小有问题。在指定--no-sandbox选项的同时,尝试更改传递给webdriver的窗口大小

chrome_options.add_argument

这个窗口大小在我的情况下起作用。

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

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

 类似资料:
  • 问题内容: 我正在尝试搜寻房地产网站上的商品。它有一个aspx表单,必须在提交之前填写。 http://www.cbre.us/PropertyListings/Pages/Properties-for- Sale.aspx 我只关心俄勒冈州的多户家庭财产。所以这是我的第一次尝试: 当我运行此脚本时,出现错误“找不到元素“ ForSalePropertyType”。在这里我在做什么错? 问题答案:

  • 我对selenium WebDriver非常陌生,我试图自动化一个页面,它有一个名为“删除日志文件”的按钮。使用FireBug我了解到,HTML被描述为 css选择器也使用firepath定义为“#DeletelogButton” 请帮助我解决这个问题。

  • 我有一个粘性导航栏,它有几个列表元素,每个元素都包含href元素。当我试图定位元素时,我得到了错误。以下是我的HTML代码: 我想通过Webdriver定位Academic,我遇到这样的错误无法定位元素。

  • 我想在selenium中找到我的文本字段,但我不知道如何找到(我第一次使用sellenium)。 我试过: 或者通过xPath和cssSseltor String在dev工具中由chrome生成。 请帮助我,我将感谢解释。 这是html:

  • 因此,我一直在尝试使用selenium在python上定位用户名输入框。我尝试了xpath、id、类名等。 我还知道显式等待元素加载。然而,尽管如此,没有运气。我检查了元素是否在我忽略的iframe中,但找不到它。 这是用户输入框元素。 下面是我为定位元素而编写的代码。