Skip to content
Advertisement

Can’t launch selenium drivers while in Electron renderer process

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
})()

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement