Reputation: 193298
I'm trying to retrieve the value of navigator.plugins
from a Selenium driven ChromeDriver initiated google-chrome Browsing Context.
Using google-chrome-devtools I'm able to retrieve navigator.userAgent
and navigator.plugins
as follows:
But using Selenium's execute_script()
method I'm able to extract the navigator.userAgent
but navigator.plugins
raises the following circular reference error:
Code Block:
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
driver = webdriver.Chrome(options=options, executable_path=r'C:\WebDrivers\chromedriver.exe')
driver.get("https://www.google.com/")
print("userAgent: "+driver.execute_script("return navigator.userAgent;"))
print("plugins: "+driver.execute_script("return navigator.plugins;"))
Console Output:
userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Traceback (most recent call last):
File "C:\Users\Soma Bhattacharjee\Desktop\Debanjan\PyPrograms\navigator_properties.py", line 19, in <module>
print("vendor: "+driver.execute_script("return navigator.plugins;"))
File "C:\Python\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 636, in execute_script
'args': converted_args})['value']
File "C:\Python\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "C:\Python\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.JavascriptException: Message: javascript error: circular reference
(Session info: chrome=83.0.4103.116)
I've been through the following discussions on circular reference and I understand the concept. But I am not sure how should I address the issue here.
Can someone help me to retrieve the navigator.plugins
please?
Upvotes: 1
Views: 3654
Reputation: 193298
A circular reference occurs if two separate objects pass references to each other. Circular referencing implies that the 2 objects referencing each other are tightly coupled and changes to one object may need changes in other as well.
NavigatorPlugins.plugins returns a PluginArray object, listing the Plugin objects describing the plugins installed in the application. plugins
is PluginArray
object used to access Plugin
objects either by name or as a list of items. The returned value has the length property and supports accessing individual items using bracket notation (e.g. plugins[2]
), as well as via item(index)
and namedItem("name")
methods.
To extract the navigator.plugins
properties you can use the following solutions:
To get the list of names of the plugins
:
print(driver.execute_script("return Array.from(navigator.plugins).map(({name}) => name);"))
Console Output:
['Chrome PDF Plugin', 'Chrome PDF Viewer', 'Native Client']
To get the list of filename of the plugins
:
print(driver.execute_script("return Array.from(navigator.plugins).map(({filename}) => filename);"))
Console Output:
['internal-pdf-viewer', 'mhjfbmdgcfjbbpaeojofohoefgiehjai', 'internal-nacl-plugin']
To get the list of description of the plugins
:
print(driver.execute_script("return Array.from(navigator.plugins).map(({description}) => description);"))
Console Output:
['Portable Document Format', '', '']
Upvotes: 1
Reputation: 1067
There might be a serialization issue when you query a non-primitive data structure from a browser realm.
By closely inspecting the hierarchy of a single plugin, we can see it has a recursive structure which is an issue for the serializer.
If you need a list of plugins, try returning just a serialized, newline-separated string and then split it by a newline symbol in the Python realm.
For example:
plugins = driver.execute_script("return Array.from(navigator.plugins).map(({name}) => name).join('\n');").split('\n')
Upvotes: 3
Reputation: 25730
I'm assuming it has something to do with the fact that navigator.plugins
returns a PluginArray.
The PluginArray
page lists the methods and properties that are available and with that I wrote this code that returns the list of names. You can adapt it to whatever you need.
print("plugins: " + driver.execute_script("var list = [];for(var i = 0; i < navigator.plugins.length; i++) { list.push(navigator.plugins[i].name); }; return list.join();"))
Upvotes: 2