HTML selenium ChromeDriver ExecuteScript

S.Br.

Board Regular
Joined
Oct 5, 2012
Messages
94
Office Version
  1. 365
  2. 2016
  3. 2013
  4. 2011
  5. 2010
  6. 2007
Dear Mr.Excel;
please help with resolving the 'JavaScript error: circular reference' error in the following macro (using Excel 2010, VBA 7.0):

VBA Code:
Option Explicit 'VBA 7.0
Sub Macro1()
  Dim ChrmDrv As ChromeDriver
  Dim objBody As Object, objChildNodes As Object
  Dim nKids As Integer
  Set ChrmDrv = New ChromeDriver
  If ChrmDrv Is Nothing Then Exit Sub
  With ChrmDrv
    .Start "CHROME"
    .Get "file://F:\TEST.HTML"
  End With
  Set objBody = ChrmDrv.ExecuteScript("return document.getElementsByTagName('body')[0];")
  If objBody Is Nothing Then Exit Sub
  nKids = ChrmDrv.ExecuteScript("return arguments[0].childNodes.length;", objBody)
  MsgBox nKids 'shows 3
  Set objChildNodes = ChrmDrv.ExecuteScript("return arguments[0].childNodes;", objBody) 'JavaScript error: circular reference
  Set objChildNodes = Nothing
  Set objBody = Nothing
  ChrmDrv.Quit
  Set ChrmDrv = Nothing
End Sub

where the F:\TEST.HTML file looks like this:

HTML:
<!DOCTYPE html>
<html>
  <head>   </head>
  <body>
<!-- Just an HTML comment... -->
  </body>
</html>

Thanks in advance,
S.Br.
 

Excel Facts

How to calculate loan payments in Excel?
Use the PMT function: =PMT(5%/12,60,-25000) is for a $25,000 loan, 5% annual interest, 60 month loan.
What are you trying to do? Selenium deals with HTML elements, not nodes, so I don't think you can read childNodes as a collection.

You can read children, because they are elements (Selenium WebElements data type):

VBA Code:
    Dim objChildren As Object
    Set objChildren = Edge.ExecuteScript("return arguments[0].children;", objBody)
    Debug.Print objChildren.Count '0 because there are no elements within <body>

For childNodes you can read their individual properties like this:

VBA Code:
    nKids = ChrmDrv.ExecuteScript("return arguments[0].childNodes.length;", objBody)
    Debug.Print nKids 'shows 3
    Dim c As Long, nv As String, nt As Long
    For c = 0 To nKids - 1
        nv = ChrmDrv.ExecuteScript("return arguments[0].childNodes[" & c & "].nodeValue;", objBody)
        nt = ChrmDrv.ExecuteScript("return arguments[0].childNodes[" & c & "].nodeType;", objBody)
        Debug.Print c; "nodeType " & nt
        Debug.Print "nodeValue >" & nv & "<"
    Next
Output:
Code:
 3
 0 nodeType 3
nodeValue >
<
 1 nodeType 8
nodeValue > Just an HTML comment... <
 2 nodeType 3
nodeValue >
<
 
Upvote 1
thank you, John; I agree with most of you're saying, but
Selenium deals with HTML elements, not nodes, so I don't think you can read childNodes as a collection.
I do not declare objChildNodes as Collection. Secondly, if I remove the comment line from the F:\TEST.HTML file then that same script does not throw an exception, which tells me that there is nothing wrong with the VBA script per se, but rather something is going on inside the underlying JavaScript engine.
BTW, the whole idea of this project is using XL VBA to retrieve HTML comments generated by JS.
Regards,
<S.Br./>
 
Upvote 0
I didn't mean a VBA Collection; I used 'collection' in the general sense of a group of items, which could be an array, Collection, or Dictionary, etc.

I investigated the F:\TEST.HTML file with the comment line deleted and it does seem that Selenium's JavaScript engine is not processing the script part of Set objChildNodes = ChrmDrv.ExecuteScript("return arguments[0].childNodes;", objBody) correctly. For a start, objChildNodes is returned as a List data type with 1 item. List is not a VBA data type. The 1 item in the objChildNodes List is a Dictionary with 66 items which starts with the constants for the different node types, followed by the properties, methods and events of the DOM Node interface. All this is shown by the following macro which outputs to the active sheet:

VBA Code:
Sub Macro4()

    Dim ChrmDrv As ChromeDriver
    Dim objBody As Object, objChildNodes As Object
    Set ChrmDrv = New ChromeDriver
    
    If ChrmDrv Is Nothing Then Exit Sub
    With ChrmDrv
        .Start
        .Get "F:\TEST2.html" 'HTML comment deleted
    End With
    
    Set objBody = ChrmDrv.ExecuteScript("return document.getElementsByTagName('body')[0];")
    If objBody Is Nothing Then Exit Sub
    
    Set objChildNodes = ChrmDrv.ExecuteScript("return arguments[0].childNodes;", objBody) 'No JavaScript error
    Debug.Print TypeName(objChildNodes), "Count = " & objChildNodes.Count 'objChildNodes is a List data type with 1 item
    
    Dim dict As Object 'Scripting.Dictionary
    Dim dict2 As Object 'Scripting.Dictionary
    Dim key As Variant
    Dim list As Object 'List - unknown data type
    Dim we As Object 'WebElement
    Dim s As String
    Dim i As Long, r As Long
    Dim ws As Worksheet
    
    Set dict = objChildNodes(1)  'the 1 item is a Dictionary
    Debug.Print TypeName(dict), "Count = " & dict.Count  'the Dictionary has 66 items
    
    Set ws = ActiveSheet
    ws.Cells.Delete
    r = 1
    ws.Cells(r, 1).Resize(, 2).Value = Array(TypeName(dict), "Count = " & dict.Count)

    i = 0
    On Error Resume Next
    For Each key In dict.Keys
        i = i + 1
        With ws
            r = r + 1
            .Cells(r, 1).Resize(, 3).Value = Array(i, key, TypeName(dict(key)))
            Debug.Print i, key, TypeName(dict(key))
            Select Case TypeName(dict(key))
                Case Is = "Dictionary"
                    Set dict2 = dict(key)
                    .Cells(r, 4).Value = "Count = " & dict2.Count
                Case Is = "List"
                    Set list = dict(key)
                    .Cells(r, 4).Value = "Count = " & list.Count
                Case Is = "WebElement"
                    Set we = dict(key)
                    'Read a property, e.g. tagname and see if an error occurs
                    s = we.tagname
                    If Err.Number > 0 Then
                        .Cells(r, 4).Resize(, 3).Value = Array("Count = " & list.Count, "Error " & Err.Number, Err.Description)
                    Else
                        .Cells(r, 4).Value = s
                    End If
                Case Else
                    .Cells(r, 4).Value = dict(key)
            End Select
            Err.Clear
        End With
    Next
    On Error GoTo 0
    
    ws.Cells.WrapText = False
    ws.Cells.HorizontalAlignment = xlLeft
    ws.Range("A1:C1").EntireColumn.AutoFit
    
    Set objChildNodes = Nothing
    Set objBody = Nothing
    ChrmDrv.Quit
    Set ChrmDrv = Nothing
    
End Sub

If you want to read HTML comments the easiest approach is with the Microsoft HTML Object Library (MSHTML), like this:

VBA Code:
Option Explicit

Public Sub HTML_Nodes()

    Dim HTMLfile As String
    Dim HTML As String
    Dim HTMLdoc As Object
    
    HTML = ReadFile("F:/TEST1.html")
    
    Set HTMLdoc = CreateObject("HTMLfile")
    HTMLdoc.Open
    HTMLdoc.write HTML
    HTMLdoc.Close
    Do
        DoEvents
    Loop Until HTMLdoc.readyState = "complete"

    ScanNodes HTMLdoc.body.parentElement
        
End Sub


Private Sub ScanNodes(node As Object)
    
    Const NODE_COMMENT = 8
    Dim child As Object
    
    If node.NodeType = NODE_COMMENT Then
        Debug.Print node.NodeValue
    End If
    
    'Traverse child nodes
        
    If node.childNodes.Length > 0 Then
        For Each child In node.childNodes
            ScanNodes child
        Next
    End If
    
End Sub


Private Function ReadFile(file As String) As String
    If Dir(file) <> vbNullString Then
        Open file For Binary Access Read As #1
        ReadFile = Space$(LOF(1))
        Get #1, , ReadFile
        Close #1
    End If
End Function
 
Upvote 0
I didn't mean a VBA Collection; I used 'collection' in the general sense of a group of items, which could be an array, Collection, or Dictionary, etc.

I investigated the F:\TEST.HTML file with the comment line deleted and it does seem that Selenium's JavaScript engine is not processing the script part of Set objChildNodes = ChrmDrv.ExecuteScript("return arguments[0].childNodes;", objBody) correctly. For a start, objChildNodes is returned as a List data type with 1 item. List is not a VBA data type. The 1 item in the objChildNodes List is a Dictionary with 66 items which starts with the constants for the different node types, followed by the properties, methods and events of the DOM Node interface. All this is shown by the following macro which outputs to the active sheet:

VBA Code:
Sub Macro4()

    Dim ChrmDrv As ChromeDriver
    Dim objBody As Object, objChildNodes As Object
    Set ChrmDrv = New ChromeDriver
   
    If ChrmDrv Is Nothing Then Exit Sub
    With ChrmDrv
        .Start
        .Get "F:\TEST2.html" 'HTML comment deleted
    End With
   
    Set objBody = ChrmDrv.ExecuteScript("return document.getElementsByTagName('body')[0];")
    If objBody Is Nothing Then Exit Sub
   
    Set objChildNodes = ChrmDrv.ExecuteScript("return arguments[0].childNodes;", objBody) 'No JavaScript error
    Debug.Print TypeName(objChildNodes), "Count = " & objChildNodes.Count 'objChildNodes is a List data type with 1 item
   
    Dim dict As Object 'Scripting.Dictionary
    Dim dict2 As Object 'Scripting.Dictionary
    Dim key As Variant
    Dim list As Object 'List - unknown data type
    Dim we As Object 'WebElement
    Dim s As String
    Dim i As Long, r As Long
    Dim ws As Worksheet
   
    Set dict = objChildNodes(1)  'the 1 item is a Dictionary
    Debug.Print TypeName(dict), "Count = " & dict.Count  'the Dictionary has 66 items
   
    Set ws = ActiveSheet
    ws.Cells.Delete
    r = 1
    ws.Cells(r, 1).Resize(, 2).Value = Array(TypeName(dict), "Count = " & dict.Count)

    i = 0
    On Error Resume Next
    For Each key In dict.Keys
        i = i + 1
        With ws
            r = r + 1
            .Cells(r, 1).Resize(, 3).Value = Array(i, key, TypeName(dict(key)))
            Debug.Print i, key, TypeName(dict(key))
            Select Case TypeName(dict(key))
                Case Is = "Dictionary"
                    Set dict2 = dict(key)
                    .Cells(r, 4).Value = "Count = " & dict2.Count
                Case Is = "List"
                    Set list = dict(key)
                    .Cells(r, 4).Value = "Count = " & list.Count
                Case Is = "WebElement"
                    Set we = dict(key)
                    'Read a property, e.g. tagname and see if an error occurs
                    s = we.tagname
                    If Err.Number > 0 Then
                        .Cells(r, 4).Resize(, 3).Value = Array("Count = " & list.Count, "Error " & Err.Number, Err.Description)
                    Else
                        .Cells(r, 4).Value = s
                    End If
                Case Else
                    .Cells(r, 4).Value = dict(key)
            End Select
            Err.Clear
        End With
    Next
    On Error GoTo 0
   
    ws.Cells.WrapText = False
    ws.Cells.HorizontalAlignment = xlLeft
    ws.Range("A1:C1").EntireColumn.AutoFit
   
    Set objChildNodes = Nothing
    Set objBody = Nothing
    ChrmDrv.Quit
    Set ChrmDrv = Nothing
   
End Sub

If you want to read HTML comments the easiest approach is with the Microsoft HTML Object Library (MSHTML), like this:

VBA Code:
Option Explicit

Public Sub HTML_Nodes()

    Dim HTMLfile As String
    Dim HTML As String
    Dim HTMLdoc As Object
   
    HTML = ReadFile("F:/TEST1.html")
   
    Set HTMLdoc = CreateObject("HTMLfile")
    HTMLdoc.Open
    HTMLdoc.write HTML
    HTMLdoc.Close
    Do
        DoEvents
    Loop Until HTMLdoc.readyState = "complete"

    ScanNodes HTMLdoc.body.parentElement
       
End Sub


Private Sub ScanNodes(node As Object)
   
    Const NODE_COMMENT = 8
    Dim child As Object
   
    If node.NodeType = NODE_COMMENT Then
        Debug.Print node.NodeValue
    End If
   
    'Traverse child nodes
       
    If node.childNodes.Length > 0 Then
        For Each child In node.childNodes
            ScanNodes child
        Next
    End If
   
End Sub


Private Function ReadFile(file As String) As String
    If Dir(file) <> vbNullString Then
        Open file For Binary Access Read As #1
        ReadFile = Space$(LOF(1))
        Get #1, , ReadFile
        Close #1
    End If
End Function
many thanks, John; very useful information, appreciate. I wish it would explain the 'JavaScript error: circular reference' I'm getting.
Regards,
S.Br.
 
Upvote 0

Forum statistics

Threads
1,223,886
Messages
6,175,198
Members
452,616
Latest member
intern444

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top