A.B.E
A.B.E

Reputation: 77

Selenium webdriver not working in Electron build

I have an electron project that renders an html page with a button that when clicked calls a node js script (via IPC) which uses selenium to scrape webpages.

here’s my project structure:


    -app/
     --index.html
     --main.js
     --index.js
    -package.json

Here’s my package.json:

    {
        "name": "agencies-scraper",
        "version": "1.0.0",
        "main": "app/main.js",
        "devDependencies": {
            "electron": "^5.0.7",
            "electron-builder": "^21.1.1"
        },
        "scripts": {
            "start": "electron .",
            "pack": "electron-builder --dir",
            "dist": "electron-builder",
            "postinstall": "electron-builder install-app-deps"
        },
        "build": {
            "appId": "my.id",
            "files": [
                "app/**/*",
                "node_modules/**/*",
                "package.json"
            ],
            "mac": {
                "category": "your.app.category.type"
            },
        },
        "dependencies": {
            "csv-writer": "^1.5.0",
            "selenium-webdriver": "^4.0.0-alpha.4"
        }
    }

In index.html I have a button:


    <button id="test">Click to Scrape</button>

When clicked it fires the following chain of reactions:

  1. The linked index.js, send a signal to the “backchannel” ipc channel:

    const {ipcRenderer} = require("electron");
    const button = document.getElementById("test");
    button.addEventListener("click", () => {
      ipcRenderer.send("backchannel"); 
    }

  1. In main.js, I listen to “backchannel”, and when triggered, instantiate a selenium webdriver and open google.com in a separate chrome browser:
const {app, BrowserWindow, ipcMain} = require('electron')
const webdriver = require('selenium-webdriver')

ipcMain.on('backchannel', async (event, arg) => {
    const driver = new webdriver.Builder()
            .forBrowser('chrome')
            .build()
    try {
        await driver.get('https://google.com');
    } catch (error) {
        console.log(error)
    }
})
  1. The os asks if I want the electron app to accept incoming connections and I click “Allow” (selenium opens a browser regardless): Permission popup screenshot

This works perfectly when I work in development via npm start.

However, when I package the app either via npm run-script pack or npm run-script dist, the build version does not reach step 3. No permission window pops up and no browser opens. Selenium just doesn’t work there.

I am sure the IPC is working from index.js to main.js in the build version so the issue is not with that. What am I missing here?

Upvotes: 2

Views: 1803

Answers (1)

Mauricio Guzm&#225;n
Mauricio Guzm&#225;n

Reputation: 43

I had the same issue and this answer helped me to debug the issue

I'm quoting it in case it gets deleted

  1. In terminal type lldb path/to/build.app
  2. In the opened debugger type run --remote-debugging-port=8315. It should open a window of your app.
  3. Open Chrome at http://localhost:8315/
  4. Click on the name of the app. For example, Webpack App.
  5. If you don't see anything in the opened tab, focus on the window of your app.

Then in the terminal, check for this error:

The ChromeDriver could not be found on the current PATH. Please download the latest version of the ChromeDriver from http://chromedriver.storage.googleapis.com/index.html and ensure it can be found on your PATH.

if that is the case, then download the latest version of chromedriver and add the binaries to the root of your project.

Run the build again and it should work!

Edit: The problem you are facing is that binaries inside app.asar cannot be executed, so, a quick fix for this:

On your package.json, add the following property to the "build" object

"asar": false

it should look like this:

.
.
.
        "build": {
            "appId": "my.id",
            "asar": false,
            "files": [
                "app/**/*",
                "node_modules/**/*",
                "package.json"
            ],
            "mac": {
                "category": "your.app.category.type"
            },
        },
.
.
.

Edit #2:

Electron builder automatically unpacks executable binaries, so the following solution worked for me.

run npm install chromedriver

on the part you are building the chromedriver, change the way you build it to this:

const chromedriverPath = require('chromedriver').path.replace('app.asar', 'app.asar.unpacked');
const serviceBuilder = new ServiceBuilder(chromedriverPath);
let driver = new webdriver.Builder()
  .forBrowser("chrome")
  .setChromeService(serviceBuilder)
  .build();

This way, the driver gets the correct unpacked path to the chromedriver binary.

Upvotes: 2

Related Questions