florentbr / SeleniumBasic

A Selenium based browser automation framework for VB.Net, VBA and VBScript
BSD 3-Clause "New" or "Revised" License
430 stars 197 forks source link

Cannot find element in selenium VBA #260

Closed TorontoMapleLeaf closed 1 year ago

TorontoMapleLeaf commented 1 year ago

Hello, everyone,

I try to locate the text " Chrome is up to date" after Chrome is updated, but cannot with all tries. below is the code:

Sub ChromeDriverUpdate() Dim obj As WebDriver, By As New By Dim sUrl As String , sXpath as String Set obj = New WebDriver sUrl = "chrome://settings/help" sXpath = "//*[@id='updateStatusMessage']/div" obj.Start "Chrome", "" obj.Get sUrl Application.Wait (Now + TimeValue("00:00:03"))

Debug.Print obj.FindElementById("updateStatusMessage").Text  ' this does not work
Debug.Print obj.FindElementByXPath(XPath).Text   ' this does not work

End Sub

neither find element by ID or Xpath worked. it always showed that "NoSuchElementError"

can anybody help me out?

thank you, ken

GCuser99 commented 1 year ago

You have three shadow-roots in the dom tree path that you need to navigate around to get to that element. Unfortunately, I don't think SeleniumBasic has direct support for shadow-root dom, even though currently the Chrome/Edge drivers do support, and Firefox (geckodriver) is getting close.

So if you look at the full xpath to that element, you will see the shadow-root nodes indicated as "//" below:

/html/body/settings-ui//div[2]/settings-main//settings-about-page//settings-section[1]/div[2]/div[2]/div[1]/div

The only way I know to traverse that path in SeleniumBasic is something like this:

    Set webelem = driver.ExecuteScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-about-page').shadowRoot.querySelector('#updateStatusMessage')")
    Debug.Print  webelem.FindElement(By.Tag, "div").Text

Hope that helps...

TorontoMapleLeaf commented 1 year ago

thank you so much for your help. I am a hobby VBA Selenium user, write code for my routine task to save some time. it seems that I have to get around it by other means.

again thank you very much. there are some times I can't find element by Xpath, maybe due to that I am only using Selenium Basis.

On Sat., Nov. 26, 2022, 8:49 a.m. GCuser99, @.***> wrote:

You have a couple of shadow-roots in the dom tree path that you need to navigate around to get to that element. Unfortunately, I don't think SeleniumBasic has direct support for shadow-root dom, even though currently the Chrome/Edge drivers do support, and Firefox (geckodriver) is getting close.

So if you look at the full xpath to that element, you will see the shadow-root nodes indicated as "//" below:

/html/body/settings-ui//div[2]/settings-main//settings-about-page//settings-section[1]/div[2]/div[2]/div[1]/div

The only way I know to traverse that path in SeleniumBasic is something like this:

Set webelem = driver.ExecuteScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-about-page').shadowRoot.querySelector('#updateStatusMessage')")
Debug.Print  webelem.FindElement(By.Tag, "div").Text

Hope that helps...

— Reply to this email directly, view it on GitHub https://github.com/florentbr/SeleniumBasic/issues/260#issuecomment-1328050063, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOBAKZ47XFZCO7D3VJKG6J3WKIIP7ANCNFSM6AAAAAASLUMKXY . You are receiving this because you authored the thread.Message ID: @.***>

TorontoMapleLeaf commented 1 year ago

is there a Selenium professional, more powerful than Selenium Basic? where to get it? is there a reference book for Selenium?

thank you

On Sat., Nov. 26, 2022, 8:49 a.m. GCuser99, @.***> wrote:

You have a couple of shadow-roots in the dom tree path that you need to navigate around to get to that element. Unfortunately, I don't think SeleniumBasic has direct support for shadow-root dom, even though currently the Chrome/Edge drivers do support, and Firefox (geckodriver) is getting close.

So if you look at the full xpath to that element, you will see the shadow-root nodes indicated as "//" below:

/html/body/settings-ui//div[2]/settings-main//settings-about-page//settings-section[1]/div[2]/div[2]/div[1]/div

The only way I know to traverse that path in SeleniumBasic is something like this:

Set webelem = driver.ExecuteScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-about-page').shadowRoot.querySelector('#updateStatusMessage')")
Debug.Print  webelem.FindElement(By.Tag, "div").Text

Hope that helps...

— Reply to this email directly, view it on GitHub https://github.com/florentbr/SeleniumBasic/issues/260#issuecomment-1328050063, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOBAKZ47XFZCO7D3VJKG6J3WKIIP7ANCNFSM6AAAAAASLUMKXY . You are receiving this because you authored the thread.Message ID: @.***>

dornech commented 1 year ago

Hi there,

while I am not call myself a Selenium professional I think I am pretty experienced and do some stuff with Selenium and VBA. I devleopped some routines also one for accessing shadowDOM which I need to click away the data protection banners. You may refer to https://www.youtube.com/watch?v=phYGCGXGtEw https://titusfortner.com/2021/11/22/shadow-dom-selenium.html for further information as well. Please note that you need to use CSS Seelctors to find elements under a shadwow DOM root.

Function findElementsShadowDOM(ByRef objSelenium As Selenium.WebDriver, ByVal s_XPath_ShadowHost As String, ByVal s_CSS_Elements As String) As Selenium.WebElements

Dim objShadowHost As Selenium.WebElement, objShadowRoot As Object Set objShadowHost = objSelenium.FindElementByXPath(s_XPath_ShadowHost) If Not objShadowHost Is Nothing Then Set objShadowRoot = objShadowHost.ExecuteScript("return arguments[0].shadowRoot", objShadowHost) If (TypeName(objShadowRoot) <> "Dictionary") Then ' Selenium 3 with Chrome-webdriver chromedriver.exe before 96.x If objShadowRoot Is Nothing Then Stop End If Set findElementsShadowDOM = objShadowRoot.FindElementsByCss(s_CSS_Elements) Else ' Selenium 3 with Chrome-webdriver chromedriver.exe 96.x ' on error to catch error if subnode to shadowRoot not existing any more On Error Resume Next Set findElementsShadowDOM = objShadowHost.ExecuteScript("return arguments[0].shadowRoot.querySelectorAll(arguments[1])", Array(objShadowHost, s_CSS_Elements)) On Error GoTo 0 End If End If

Set objShadowHost = Nothing Set objShadowRoot = Nothing

End Function

However, due to unsecure future of SeleniumVBA I moved my stuff to Python. Python is a great platform and can be combined nicely with the COM technology using PyWin32 package by Mark Hammond.

Best regards dornech

TorontoMapleLeaf commented 1 year ago

thank you so much for your prompt. I will take time to digest them to improve my skill.

have a great weekend. sincerely, Ken

On Sun., Nov. 27, 2022, 10:03 a.m. dornech, @.***> wrote:

Hi there,

while I am not call myself a Selenium professional I think I am pretty experienced and do some stuff with Selenium and VBA. I devleopped some routines also one for accessing shadowDOM which I need to click away the data protection banners. You may refer to https://www.youtube.com/watch?v=phYGCGXGtEw https://titusfortner.com/2021/11/22/shadow-dom-selenium.html for further information as well. Please note that you need to use CSS Seelctors to find elements under a shadwow DOM root.

Function findElementsShadowDOM(ByRef objSelenium As Selenium.WebDriver, ByVal s_XPath_ShadowHost As String, ByVal s_CSS_Elements As String) As Selenium.WebElements

Dim objShadowHost As Selenium.WebElement, objShadowRoot As Object Set objShadowHost = objSelenium.FindElementByXPath(s_XPath_ShadowHost) If Not objShadowHost Is Nothing Then Set objShadowRoot = objShadowHost.ExecuteScript("return arguments[0].shadowRoot", objShadowHost) If (TypeName(objShadowRoot) <> "Dictionary") Then ' Selenium 3 with Chrome-webdriver chromedriver.exe before 96.x If objShadowRoot Is Nothing Then Stop End If Set findElementsShadowDOM = objShadowRoot.FindElementsByCss(s_CSS_Elements) Else ' Selenium 3 with Chrome-webdriver chromedriver.exe 96.x ' on error to catch error if subnode to shadowRoot not existing any more On Error Resume Next Set findElementsShadowDOM = objShadowHost.ExecuteScript("return arguments[0].shadowRoot.querySelectorAll(arguments[1])", Array(objShadowHost, s_CSS_Elements)) On Error GoTo 0 End If End If

Set objShadowHost = Nothing Set objShadowRoot = Nothing

End Function

However, due to unsecure future of SeleniumVBA I moved my stuff to Python. Python is a great platform and can be combined nicely with the COM technology using PyWin32 package by Mark Hammond.

Best regards dornech

— Reply to this email directly, view it on GitHub https://github.com/florentbr/SeleniumBasic/issues/260#issuecomment-1328265196, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOBAKZ6K5P3AFVTO2GBXOBLWKNZ53ANCNFSM6AAAAAASLUMKXY . You are receiving this because you authored the thread.Message ID: @.***>

TorontoMapleLeaf commented 1 year ago

hi, there,

what's the difference between Selenium basis and Selenium 3/4? are 3/4 also free?

thanks, Ken

On Sun., Nov. 27, 2022, 10:03 a.m. dornech, @.***> wrote:

Hi there,

while I am not call myself a Selenium professional I think I am pretty experienced and do some stuff with Selenium and VBA. I devleopped some routines also one for accessing shadowDOM which I need to click away the data protection banners. You may refer to https://www.youtube.com/watch?v=phYGCGXGtEw https://titusfortner.com/2021/11/22/shadow-dom-selenium.html for further information as well. Please note that you need to use CSS Seelctors to find elements under a shadwow DOM root.

Function findElementsShadowDOM(ByRef objSelenium As Selenium.WebDriver, ByVal s_XPath_ShadowHost As String, ByVal s_CSS_Elements As String) As Selenium.WebElements

Dim objShadowHost As Selenium.WebElement, objShadowRoot As Object Set objShadowHost = objSelenium.FindElementByXPath(s_XPath_ShadowHost) If Not objShadowHost Is Nothing Then Set objShadowRoot = objShadowHost.ExecuteScript("return arguments[0].shadowRoot", objShadowHost) If (TypeName(objShadowRoot) <> "Dictionary") Then ' Selenium 3 with Chrome-webdriver chromedriver.exe before 96.x If objShadowRoot Is Nothing Then Stop End If Set findElementsShadowDOM = objShadowRoot.FindElementsByCss(s_CSS_Elements) Else ' Selenium 3 with Chrome-webdriver chromedriver.exe 96.x ' on error to catch error if subnode to shadowRoot not existing any more On Error Resume Next Set findElementsShadowDOM = objShadowHost.ExecuteScript("return arguments[0].shadowRoot.querySelectorAll(arguments[1])", Array(objShadowHost, s_CSS_Elements)) On Error GoTo 0 End If End If

Set objShadowHost = Nothing Set objShadowRoot = Nothing

End Function

However, due to unsecure future of SeleniumVBA I moved my stuff to Python. Python is a great platform and can be combined nicely with the COM technology using PyWin32 package by Mark Hammond.

Best regards dornech

— Reply to this email directly, view it on GitHub https://github.com/florentbr/SeleniumBasic/issues/260#issuecomment-1328265196, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOBAKZ6K5P3AFVTO2GBXOBLWKNZ53ANCNFSM6AAAAAASLUMKXY . You are receiving this because you authored the thread.Message ID: @.***>

dornech commented 1 year ago

3/4 refers to the language bindings for Python etc. It is not related to SeleniumBasic

TorontoMapleLeaf commented 1 year ago

so if I want to switch to Python, I will have to use 3/4?

On Mon, 28 Nov 2022 at 02:23, dornech @.***> wrote:

3/4 refers to the language bindings for Python etc. It is not related to SeleniumBasic

— Reply to this email directly, view it on GitHub https://github.com/florentbr/SeleniumBasic/issues/260#issuecomment-1328649999, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOBAKZ3V4NPYSDEMT2XSAE3WKRMVJANCNFSM6AAAAAASLUMKXY . You are receiving this because you authored the thread.Message ID: @.***>

TorontoMapleLeaf commented 1 year ago

Hello,

I ran your code this morning, and get what I need("Chrome is up to date"). I am so excited, as I was struggling for a long time with this issue. .

Set webelem = driver.ExecuteScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-about-page').shadowRoot.querySelector('#updateStatusMessage')") Debug.Print webelem.FindElement(By.Tag, "div").Text

thank you so much, Ken

On Sat, 26 Nov 2022 at 08:49, GCuser99 @.***> wrote:

You have a couple of shadow-roots in the dom tree path that you need to navigate around to get to that element. Unfortunately, I don't think SeleniumBasic has direct support for shadow-root dom, even though currently the Chrome/Edge drivers do support, and Firefox (geckodriver) is getting close.

So if you look at the full xpath to that element, you will see the shadow-root nodes indicated as "//" below:

/html/body/settings-ui//div[2]/settings-main//settings-about-page//settings-section[1]/div[2]/div[2]/div[1]/div

The only way I know to traverse that path in SeleniumBasic is something like this:

Set webelem = driver.ExecuteScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-about-page').shadowRoot.querySelector('#updateStatusMessage')")
Debug.Print  webelem.FindElement(By.Tag, "div").Text

Hope that helps...

— Reply to this email directly, view it on GitHub https://github.com/florentbr/SeleniumBasic/issues/260#issuecomment-1328050063, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOBAKZ47XFZCO7D3VJKG6J3WKIIP7ANCNFSM6AAAAAASLUMKXY . You are receiving this because you authored the thread.Message ID: @.***>

dornech commented 1 year ago

Happy to hear I could help.

Starting Python would mean you start with Python 3.10 or 3.11 probably. And the latest version of the packages which is 4.6.1 for the Python Selenium bindings (given you are working with a pretty late Chrome version).

TorontoMapleLeaf commented 1 year ago

thank you.

On Mon, 28 Nov 2022 at 13:32, dornech @.***> wrote:

Happy to hear I could help.

Starting Python would mean you start with Python 3.10 or 3.11 probably. And the latest version of the packages which is 4.6.1 for the Python Selenium bindings (given you are working with a pretty late Chrome version).

— Reply to this email directly, view it on GitHub https://github.com/florentbr/SeleniumBasic/issues/260#issuecomment-1329557085, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOBAKZ3DJTQFIHB3JM7V24TWKT3DPANCNFSM6AAAAAASLUMKXY . You are receiving this because you authored the thread.Message ID: @.***>

TorontoMapleLeaf commented 1 year ago

with the help from Dornech, I got the solution to fix the issue .