Months ago I built an electron app that scrapes data from a web page using selenium and then visualizes it inside the electron webpage and everything worked fine. After a few months of not using it, I’m having trouble because of many breaking changes inside electron and selenium themselves. The major breaking change is that is not possible to start selenium webdrivers from the renderer process anymore, but I can start it only in the main process.
This below is a minimal non-working example of what I’m trying to do:
// index.js - entry point of the program const electron = require("electron"); let app = electron.app let mainWin; app.on('ready', () => { mainWin = new electron.BrowserWindow({ width: 100, height: 100, frame: true, backgroundColor: '#222222', webPreferences: { nodeIntegration: true, contextIsolation: false }, }); mainWin.loadFile('./home.html'); mainWin.on('closed', function () { console.log('byebye') }); });
// home.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> hello </body> <script type="text/javascript">require('./home.js')</script> </html>
//home.js - script file for the home.html launched in the main process const { Builder, By } = require('selenium-webdriver'); process.env.PATH += `${__dirname};`; (async () => { let driver = await new Builder().forBrowser('chrome').build(); await driver.get('https://www.google.com'); let test = await driver.findElements(By.css('div')) console.log(test) })()
The program gets completely stuck on the build for chrome webdrivers. I am 100% sure that I am using the right chromedriver version and I never get an error or something useful, just empty, endless-running nothing.
Am I missing something (like webpreferences flags for the window) or this is a bug of electron/selenium?
It appears that this happens only when I’m using this on Linux.
Rebuilding the program to launch the drivers from the main process would mean rebuilding the program from scratch as it uses different windows and so on, and I can’t pass the driver or anything else from the main process to the renderer using IRC since it breaks the driver object itself.
Advertisement
Answer
Ok, I managed to make it work on Linux too. The tweak is to use a preload script that will initialize the driver instance and then pass it to the renderer process by polluting the window object (it is the recommended way as shown here https://www.electronjs.org/docs/latest/tutorial/security#how-1). In this way, it is possible to obtain a fully working driver instance in the renderer process in Linux with selenium and electron.
Below are the changes to make it work:
// index.js - entry point of the program const electron = require("electron"); let app = electron.app let mainWin; app.on('ready', () => { mainWin = new electron.BrowserWindow({ width: 100, height: 100, frame: true, backgroundColor: '#222222', webPreferences: { nodeIntegration: true, contextIsolation: false preload: path.join(__dirname,'preload.js') }, }); mainWin.loadFile('./home.html'); mainWin.on('closed', function () { console.log('byebye') }); });
//preload.js const { Builder, By } = require('selenium-webdriver'); (async () => { let driver = await new Builder().forBrowser('chrome').build(); window.pollutingDriver = driver })()
//home.js //retrieve the driver in this way const sleep = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)) } var driver = null ; (async () => { while(!driver) { driver = window.pollutingDriver await sleep(500) } //do the main work on the page })()