简体   繁体   English

没有这样的元素:无法在生产环境中使用chromedriver和Selenium定位元素

[英]no such element: Unable to locate element using chromedriver and Selenium in production environment

I have a problem with selenium chromedriver which I cannot figure out what's causing it. 我有硒chromedriver的问题,我无法弄清楚是什么导致它。 Some weeks ago everything was working OK, and suddenly this error started to show up. 几周前一切正常,但突然出现这个错误。 The problem is coming from the following function. 问题来自以下功能。

 def login_(browser):
    try:
        browser.get("some_url")
        # user credentials
        user = browser.find_element_by_xpath('//*[@id="username"]')
        user.send_keys(config('user'))
        password = browser.find_element_by_xpath('//*[@id="password"]')
        password.send_keys(config('pass'))
        login = browser.find_element_by_xpath('/html/body/div[1]/div/button')
        login.send_keys("\n")
        time.sleep(1)
        sidebar = browser.find_element_by_xpath('//*[@id="sidebar"]/ul/li[1]/a')
        sidebar.send_keys("\n")
        app_submit = browser.find_element_by_xpath('//*[@id="sidebar"]/ul/li[1]/ul/li[1]/a')
        app_submit.send_keys("\n")
    except TimeoutException or NoSuchElementException:
        raise LoginException

This function works with no problem in the development environment (macOS 10.11), but throws the following error in the production environment: 此功能在开发环境(macOS 10.11)中没有问题,但在生产环境中引发以下错误:

Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id="sidebar"]/ul/li[1]/a"}
(Session info: headless chrome=67.0.3396.79)
(Driver info: chromedriver=2.40.565383 (76257d1ab79276b2d53ee97XXX),platform=Linux 4.4.0-116-generic x86_64)

I already updated both Chrome and chromedriver (v67 & 2.40, respectively) in each environment. 我已经在每个环境中更新了Chrome和chromedriver(分别为v67和2.40)。 I also gave it more time.sleep(15) . 我也给了它更多的时间。 time.sleep(15) But the problem persists. 但问题仍然存在。 My latest guess is that maybe the initialization of the webdriver is not working properly: 我最新的猜测是,webdriver的初始化可能无法正常工作:

def initiate_webdriver():
   option = webdriver.ChromeOptions()
   option.binary_location = config('GOOGLE_CHROME_BIN')
   option.add_argument('--disable-gpu')
   option.add_argument('window-size=1600,900')
   option.add_argument('--no-sandbox')
   if not config('DEBUG', cast=bool):
       display = Display(visible=0, size=(1600, 900))
       display.start()
       option.add_argument("--headless")
   else:
       option.add_argument("--incognito")
   return webdriver.Chrome(executable_path=config('CHROMEDRIVER_PATH'), chrome_options=option)

Because, if the Display is not working, then there may not be the mentioned sidebar but some other button. 因为,如果Display不工作,那么可能没有提到的sidebar而是其他一些按钮。

So my questions are: does anybody have had a similar issue? 所以我的问题是:有没有人有类似的问题? Is there a way to know what is the page showing at the time the driver is looking for such an element? 有没有办法知道驱动程序在寻找这样一个元素时显示的页面是什么?

It's report that the element not found error after you supplying the login , so I think the login failed and the page redirected to somewhere. 报告提供登录后找不到元素错误,因此我认为登录失败,页面重定向到某处。 You can use screenshot option to take a screenshot of the page and then see which page the driver load. 您可以使用屏幕截图选项获取页面的屏幕截图,然后查看驱动程序加载的页面。

driver.save_screenshot("path to save screen.jpeg")

Also you can save the raw html code and inspect the same page. 您还可以保存原始html代码并检查同一页面。

Webdriver Screenshot Webdriver截图

Using Selenium in Python to save a webpage on Firefox 在Python中使用Selenium在Firefox上保存网页

A couple of things as per the login_(browser) method: 根据login_(browser)方法的一些事情:

  • As you have identified the Login button through: 正如您已通过以下方式确定登录按钮:

     login = browser.find_element_by_xpath('/html/body/div[1]/div/button') 

    I would suggest rather invoking send_keys("\\n") take help of the onclick() event through login.click() to mock the clicking of Login button as follows: 我建议宁可调用send_keys("\\n")通过login.click()来帮助onclick()事件来模拟点击Login按钮 ,如下所示:

     login = browser.find_element_by_xpath('/html/body/div[1]/div/button') login.click() 
  • Next when you identify the sidebar induce WebDriverWait for the element to be clickable as follows: 接下来,当您确定侧边栏时,可以通过以下方式触发WebDriverWait以使元素可单击

     WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="sidebar"]/ul/li[1]/a'))).click() 
  • As you mentioned your code code block works perfect in macOS 10.11 environment but throws the following error in the production environment (Linux) it is highly possible that different browsers renders the HTML DOM differently in different OS architecture. 正如您所提到的, 您的代码块在macOS 10.11环境中运行良好,但在生产环境(Linux)中抛出以下错误 ,不同的浏览器很可能在不同的OS体系结构中呈现不同的HTML DOM So instead of absolute xpath you must use relative xpath as follows: 因此,您必须使用相对xpath ,而不是绝对 xpath ,如下所示:

     WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[@attribute='value']"))).click() 

A couple of things as per the initiate_webdriver() method: 根据initiate_webdriver()方法的一些事情:

  • As per Getting Started with Headless Chrome the argument --disable-gpu is applicable only for Windows but not a valid configuration for Linux OS . 根据Headless Chrome入门,参数--disable-gpu仅适用于Windows,但不适用于Linux OS的有效配置。 So need o remove: 所以需要删除:

     option.add_argument('--disable-gpu') 

Note : You have to add the following imports : 注意 :您必须添加以下导入:

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

Whenever I encounter strange issues in Selenium like this, I prefer retrying to find the particular element which is causing intermittent troubles. 每当我在这样的Selenium中遇到奇怪的问题时,我更愿意重试找到导致间歇性故障的特定元素。 One way is to wrap it around a try-except block: 一种方法是将它包装在try-except块周围:

try:
   sidebar = browser.find_element_by_xpath('//*[@id="sidebar"]/ul/li[1]/a')
except NoSuchElementException:
   time.sleep(10)
   print("Unable to find element in first time, trying it again")
   sidebar = browser.find_element_by_xpath('//*[@id="sidebar"]/ul/li[1]/a')

You could also put the try code in a loop with a suitable count variable to make the automation code work. 您还可以将try代码放在一个带有合适计数变量的循环中,以使自动化代码正常工作。 (Check this ). (检查一下 )。 In my experience with JAVA, this idea has resolved multiple issues. 根据我对JAVA的经验,这个想法解决了多个问题。

You need to wait until the element is visible or else you will get this error. 您需要等到元素可见,否则您将收到此错误。 Try something like this: 尝试这样的事情:

from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support.expected_conditions import visibility_of_element_located
from selenium.webdriver.common.by import By
TIMEOUT = 5

...
xpath = '//*[@id="sidebar"]/ul/li[1]/a'
WebDriverWait(self.selenium, TIMEOUT).until(visibility_of_element_located((By.XPATH, xpath)))
browser.find_element_by_xpath(xpath)
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM