Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Puppeteer - How to connect WSEndpoint using local IP address?

I have two Node.js scripts for puppeteer automation.

1) launcher.js

This Puppeteer script launches a chrome browser and disconnects the chrome so that it can be connected by using WSEndpoint.

const puppeteer = require('puppeteer');

module.exports = async () => {
    try {
        const options = {
            headless: false,
            devtools: false,
            ignoreHTTPSErrors: true,
            args: [
                `--no-sandbox`,
                `--disable-setuid-sandbox`,
                `--ignore-certificate-errors`
            ]
        };
        const browser = await puppeteer.launch(options);
        let pagesCount = await browser.pages();
        const browserWSEndpoint = await browser.wsEndpoint();
        // console  WSEndPoint say : "ws://127.0.0.1:42207/devtools/browser/dbb2525b-ce44-43c2-a335-ff15d0306f36"
        console.log("browserWSEndpoint----- :> ", browserWSEndpoint);
        await browser.disconnect();
        return browserWSEndpoint;
    } catch (err) {
        console.error(err);
        process.exit(1);
        return false;
    }
};

2) connector.js

Launches headless chrome and tries to connect chrome by WSEndPoint by various hostnames. If I ran this script with run command as node connector.js localhost, it tries to connect WSEndpint with localhost as the hostname.

const puppeteer = require('puppeteer');
const launcher = require('./launcher');

(async (host) => {
    try {
        let WSEndPoint = await launcher();
        WSEndPoint = WSEndPoint.replace('127.0.0.1', host);
        console.log("WSENDPOINT :", WSEndPoint);
        const browser = await puppeteer.connect({
            browserWSEndpoint: WSEndPoint,
            ignoreHTTPSErrors: true
        });
        let pagesCount = await browser.pages();
        console.log("Pages available :> ", pagesCount.length);
        // const browserWSEndpoint = await browser.wsEndpoint();
        await browser.disconnect();
        process.exit(1);
        return true;
    } catch (err) {
        console.error(err);
        process.exit(1);
        return false;
    }
})(process.argv[2]);

But I can't connect the WSEndpint of the chrome using my local IP address ( say 192.168.1.36). Why?

The error message is

{ Error: connect ECONNREFUSED 192.168.1.33:36693
    at Object._errnoException (util.js:992:11)
    at _exceptionWithHostPort (util.js:1014:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1186:14)
  code: 'ECONNREFUSED',
  errno: 'ECONNREFUSED',
  syscall: 'connect',
  address: '192.168.1.33',
  port: 36693 }
like image 212
NIKHIL C M Avatar asked Jul 22 '18 15:07

NIKHIL C M


1 Answers

You can proxy the websocket and connect to the proxy instead. I tested it on my server and it ran successfully.

Here is how we create a websocket server using http-proxy,

Server

const httpProxy = require("http-proxy");
const host = "0.0.0.0";
const port = 8080;
async function createServer(WSEndPoint, host, port) {
  await httpProxy
    .createServer({
      target: WSEndPoint, // where we are connecting
      ws: true,
      localAddress: host // where to bind the proxy
    })
    .listen(port); // which port the proxy should listen to
  return `ws://${host}:${port}`; // ie: ws://123.123.123.123:8080
}

Then when we run it, we create a proxy server and listen to the ws endpoint instead. I am not exporting it to keep the explanation simpler.

// your other codes
const pagesCount = (await browser.pages()).length; // just to make sure we have the same stuff on both place
const browserWSEndpoint = await browser.wsEndpoint();
const customWSEndpoint = await createServer(browserWSEndpoint, host, port); // create the server here
console.log({ browserWSEndpoint, customWSEndpoint, pagesCount });
// your other code here

When I run on the server, we get the following,

On the droplet,

➜  node index.js 
{ browserWSEndpoint: 'ws://127.0.0.1:45722/devtools/browser/df0ca6a9-48ba-4962-9a20-a3a536d403fa',
  customWSEndpoint: 'ws://0.0.0.0:8080',
  pagesCount: 1 }

Client

Then we connect it like this,

const puppeteer = require("puppeteer-core");
(async serverAddr => {
  const browser = await puppeteer.connect({
    browserWSEndpoint: `ws://${serverAddr}`,
    ignoreHTTPSErrors: true
  });
  const pagesCount = (await browser.pages()).length;
  const browserWSEndpoint = await browser.wsEndpoint();
  console.log({ browserWSEndpoint, pagesCount });
})(process.argv[2]);

On my guest computer,

➜  node index.js "123.123.123.123:8080"
Pages available :>  1
{ browserWSEndpoint: 'ws://123.123.123.123:8080' }

This way we can host on multiple server and route between them, scale away and more if needed.

Peace!

like image 52
Md. Abu Taher Avatar answered Oct 19 '22 02:10

Md. Abu Taher