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
错误原因分析
- CSS_Selector函数变量未定义:函数中使用了未声明的变量
sCSS,导致XPath转CSS选择器失败,最终无法定位到元素,返回Nothing,调用SendKeys时触发"Object Required"错误。 - 登录后元素加载延迟:点击登录按钮后,密码输入框所在的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
相关产品推荐
相关产品推荐

