You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VBA Selenium 操作Shadow Root遇Object Required错误求助

含Shadow Root页面交互时的"Object Required"错误修复

花费数小时研究如何与含Shadow Root的HTML页面进行交互,已实现用户名输入和登录按钮点击功能,但密码输入段代码无法正常运行,抛出‘Object Required’错误。以下是原代码:

Sub Test()
    Dim sUserFullPath As String, sLoginFullPath As String, oUserElement As Object, oLoginElement As Object
    Dim ShadowHost As Selenium.WebElement
    Dim ShadowRoot As Object
    Set bot = New Selenium.ChromeDriver
    With bot
        .Get "https://onlinebanking.ebank.com.eg/?bank_id=01"
        .Window.Maximize
        .Wait 2000
        Rem User
        sUserFullPath = "/html/body/div/iron-pages/div[1]/ev-login//div/div/div[3]/div[2]/div[2]/div[1]/div[1]/div/oe-input//paper-input-container/iron-input/input"
        Set oUserElement = FindElementByFullXPath(bot, sUserFullPath)
        oUserElement.SendKeys "yyyyyy"
        .Wait 1000
        Rem Login
        sLoginFullPath = "/html/body/div/iron-pages/div[1]/ev-login//div/div/div[3]/div[2]/div[2]/div[2]/div[1]/div/paper-button/oe-i18n-msg"
        Set oLoginElement = FindElementByFullXPath(bot, sLoginFullPath)
        oLoginElement.Click
        
        Rem This part doesn't work as the previous
        Dim sPassFullPath As String
        sPassFullPath = "/html/body/div/iron-pages/div[1]/ev-login//div/div/div[3]/div[2]/div[2]/div[1]/div[2]/div[1]/div[1]/div/oe-input//paper-input-container/iron-input/input"
        Dim oPassElement As Object
        Set oPassElement = FindElementByFullXPath(bot, sPassFullPath)
        oPassElement.SendKeys "kkkkkk"
    End With
End Sub

Function FindElementByFullXPath(ByVal bot As Selenium.ChromeDriver, ByVal sFullXPath As String) As Object
    Dim x
    x = SplitXPathByShadowRoots(sFullXPath)
    Set FindElementByFullXPath = FindElementAcrossShadows(bot, x)
End Function

Function SplitXPathByShadowRoots(ByVal sFullXPath As String)
    Dim x, i As Long
    x = Split(sFullXPath, "//")
    ReDim result(UBound(x))
    For i = 0 To UBound(x)
        If i = 0 Then result(i) = "/" & x(i) Else result(i) = x(i)
    Next i
    SplitXPathByShadowRoots = result
End Function

Function FindElementAcrossShadows(ByVal bot As Selenium.ChromeDriver, ByVal x) As Object
    Dim oElement As Object, i As Long
    Set oElement = bot.FindElementByXPath(x(0))
    For i = 1 To UBound(x)
        Set oElement = bot.ExecuteScript("return arguments[0].shadowRoot", oElement)
        Set oElement = bot.ExecuteScript("return arguments[0].querySelector('" & CSS_Selector(x(i)) & "')", oElement)
        If oElement Is Nothing Then Debug.Print "Element Not Found": Exit Function
    Next i
    Set FindElementAcrossShadows = oElement
End Function

Function CSS_Selector(ByVal myXPath As String) As String
    CSS_Selector = Replace(myXPath, "/", " > ")
    CSS_Selector = Replace(sCSS, "[", ":nth-child(")
    CSS_Selector = Replace(sCSS, "]", ")")
End Function

错误原因分析

  1. CSS_Selector函数变量未定义:函数中使用了未声明的变量sCSS,导致XPath转CSS选择器失败,最终无法定位到元素,返回Nothing,调用SendKeys时触发"Object Required"错误。
  2. 登录后元素加载延迟:点击登录按钮后,密码输入框所在的Shadow Root可能尚未完全渲染,直接查找元素会导致定位失败。

修复后的代码

Sub Test()
    Dim sUserFullPath As String, sLoginFullPath As String, oUserElement As Object, oLoginElement As Object
    Dim ShadowHost As Selenium.WebElement
    Dim ShadowRoot As Object
    Set bot = New Selenium.ChromeDriver
    With bot
        .Get "https://onlinebanking.ebank.com.eg/?bank_id=01"
        .Window.Maximize
        .Wait 2000
        Rem User
        sUserFullPath = "/html/body/div/iron-pages/div[1]/ev-login//div/div/div[3]/div[2]/div[2]/div[1]/div[1]/div/oe-input//paper-input-container/iron-input/input"
        Set oUserElement = FindElementByFullXPath(bot, sUserFullPath)
        oUserElement.SendKeys "yyyyyy"
        .Wait 1000
        Rem Login
        sLoginFullPath = "/html/body/div/iron-pages/div[1]/ev-login//div/div/div[3]/div[2]/div[2]/div[2]/div[1]/div/paper-button/oe-i18n-msg"
        Set oLoginElement = FindElementByFullXPath(bot, sLoginFullPath)
        oLoginElement.Click
        
        Rem 等待密码框所在区域加载完成
        .Wait 3000 ' 根据实际加载时间调整
        
        Rem 密码输入
        Dim sPassFullPath As String
        sPassFullPath = "/html/body/div/iron-pages/div[1]/ev-login//div/div/div[3]/div[2]/div[2]/div[1]/div[2]/div[1]/div[1]/div/oe-input//paper-input-container/iron-input/input"
        Dim oPassElement As Object
        Set oPassElement = FindElementByFullXPath(bot, sPassFullPath)
        If Not oPassElement Is Nothing Then
            oPassElement.SendKeys "kkkkkk"
        Else
            Debug.Print "密码输入框未找到"
        End If
    End With
End Sub

Function FindElementByFullXPath(ByVal bot As Selenium.ChromeDriver, ByVal sFullXPath As String) As Object
    Dim x
    x = SplitXPathByShadowRoots(sFullXPath)
    Set FindElementByFullXPath = FindElementAcrossShadows(bot, x)
End Function

Function SplitXPathByShadowRoots(ByVal sFullXPath As String)
    Dim x, i As Long
    x = Split(sFullXPath, "//")
    ReDim result(UBound(x))
    For i = 0 To UBound(x)
        If i = 0 Then result(i) = "/" & x(i) Else result(i) = x(i)
    Next i
    SplitXPathByShadowRoots = result
End Function

Function FindElementAcrossShadows(ByVal bot As Selenium.ChromeDriver, ByVal x) As Object
    Dim oElement As Object, i As Long
    On Error Resume Next ' 临时捕获错误,避免中途退出
    Set oElement = bot.FindElementByXPath(x(0))
    If Err.Number <> 0 Then
        Debug.Print "初始元素未找到: " & x(0)
        Exit Function
    End If
    On Error GoTo 0
    
    For i = 1 To UBound(x)
        Set oElement = bot.ExecuteScript("return arguments[0].shadowRoot", oElement)
        If oElement Is Nothing Then
            Debug.Print "Shadow Root未找到,索引: " & i
            Exit Function
        End If
        
        Dim cssSel As String
        cssSel = CSS_Selector(x(i))
        Set oElement = bot.ExecuteScript("return arguments[0].querySelector('" & cssSel & "')", oElement)
        If oElement Is Nothing Then
            Debug.Print "元素未找到,CSS选择器: " & cssSel
            Exit Function
        End If
    Next i
    Set FindElementAcrossShadows = oElement
End Function

Function CSS_Selector(ByVal myXPath As String) As String
    CSS_Selector = Replace(myXPath, "/", " > ")
    ' 替换未定义的sCSS为当前已赋值的CSS_Selector
    CSS_Selector = Replace(CSS_Selector, "[", ":nth-child(")
    CSS_Selector = Replace(CSS_Selector, "]", ")")
    ' 移除开头多余的空格(如果XPath以/开头)
    CSS_Selector = LTrim(CSS_Selector)
End Function

关键修复点

  • 修正CSS_Selector函数中的变量错误,将未定义的sCSS替换为CSS_Selector本身,确保XPath到CSS选择器的转换正确。
  • 在登录后添加等待时间,确保密码输入框所在的Shadow Root完全渲染。
  • 在FindElementAcrossShadows函数中添加错误捕获和调试输出,便于定位具体哪一步失败。
  • 添加对象非空判断,避免在元素未找到时调用SendKeys触发错误。

内容的提问来源于stack exchange,提问作者YasserKhalil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 05:10:53