Luiz Alves
Luiz Alves

Reputation: 2645

Using chrome and puppeteer with multiple browsers

I am using puppeteer. I need to load multiples pages and inject a javascript.

I am creating two browsers, with one page(tab) each one and the javascript injected.

I have a node server with routes to each page loaded.

I named a session to each page with '100' and '101'. Two userdata folders(100 and 101) are created after run the app. These sessions are also used to separate the routes.

The browsers are correctly created , without problem.

My problem is when I consume a route, node server allways return the same result to both pages:

If I test using Postman or an other chrome browser with the next:

http://localhost:3007/teste100/getMyNumber 
and    http://localhost:3007/teste101/getMyNumber 

They are returning the same value. But the values are differentes to each browser page. It seems the page is not been considered on request and It returns the same result to both pages. But, as I said the function "getMyNumber" should be returning differents values to each page. My sample function uses local storage but i have many others not using local storage and all have the same problem.

Please, what am I doing wrong?

I suspect about something I am not passing the correct browser page to route. But, I don´t find the error.

//server.js

const express = require('express')
const app = express()
const server = require('http').Server(app)
const port = 3001
const host = 'http://localhost'
const callbackUrl = `${host}:${port}`;

const browser_pages = {};
startUp = async (sessionId) => {
    if (browser_pages[sessionId]) return browser_pages[sessionId];
    let clientBrowser = require('./src/clientbrowser')({}, sessionId)
    let cb = await clientBrowser.startWhats(sessionId || "user_data");
    let page = cb.getPage();
    browser_pages[sessionId] = cb;
    const troutes = require('./src/routes/testroutes')(page)
    app.use('/teste' + sessionId, troutes)
}
startUp('100');
startUp('101');
server.listen(port, () => {
    console.log(`Listening on ${callbackUrl}...`);
});

//clientBrowser.js

const path = require('path');
const EventEmitter = require('events');
....
const puppeteer = require('puppeteer');

class ClientBrowser extends EventEmitter {
    constructor(options, sessionId) {
        super();
        this.options = fUtils.mergeDefault(DefaultOptions, options);
        this.app = app;
        this.pPage = null;
    }
    getPage = () => {
        return this.pPage;
    }
    createBrowser = async (sessionId) => {
        let browser = await puppeteer.launch({
            headless: false,
            userDataDir: path.join(process.cwd(), sessionId || 'session'),
            args: DEFAULT_CHROMIUM_ARGS,
            ignoreHTTPSErrors: true,
            devtools: false,
            defaultViewport: null
        });
        return browser;
    }


    LoadPageWhatsApp = async (page) => {
        page.setUserAgent(UserAgent);
        await page.setBypassCSP(true);
        await page.setViewport({
            width: 800,
            height: 900
        })
        await page.goto(WEB_WHATS_APP, {
            waitUntil: 'networkidle0',
            timeout: 0
        })
        return page;
    }

    initWhatsApp = async (sessionId) => {
        let browser = await this.createBrowser(sessionId);
        let pages = await browser.pages();
        let page = pages[0];
        await this.LoadPageWhatsApp(page);
        return page;
    }

    startWhats = async (sessionId) => {
        const page = await this.initWhatsApp(sessionId);
        this.pPage = page;
        let fpath = './web/teste.js';
        //inject test script
        await page.addScriptTag({ path: require.resolve(fpath) });
        console.log("Injected Script:" + path.basename(fpath));
        return this;
    }
}
module.exports = (params, sessionId) => { return new ClientBrowser(params, sessionId)}

//testroutes.js

const express = require('express');
const router = express.Router();
const path = require('path');

module.exports = function (page) {
    router.get('/getMyNumber', async (req, res) => {
        const cc = await page.evaluate(() => {
            return getMyNumber();
        });
        console.log(cc);
        res.send({ "data": cc });
    });

    return router;
}

//teste.js

function getMyNumber() {
    return localStorage.getItem('last-wid');
}

Upvotes: 0

Views: 1613

Answers (1)

user5481197
user5481197

Reputation:

This is what is causing the problems:

module.exports = function (page) {
    router.get('/getMyNumber', async (req, res) => {
        const cc = await page.evaluate(() => {
            return getMyNumber();
        });
        console.log(cc);
        res.send({ "data": cc });
    });

    return router;
}

You actually set this route twice. I know it looks like you set two different paths because of your app.use('/teste' + sessionId, troutes) line. But really you set two different paths to point to the same router. Your router object is the same for both because the object is coming from the same module require('./src/routes/testroutes')

Quick fix: Pass page and sessionId to make an unique url with route.get. For example: router.get('/getMyNumber'+ sessionId,.... or router.get('/'+ sessionId + '/getMyNumber',....

What your current code is sets up to do is make two middleware calls for /getMyNumber route. router.get actually passes a third parameter next to your callback. function. ('/getMyNumber', async (req, res, next). If you call next() in you function instead of res.send({...}) the other '/getMyNumber' will be called.

To clarify the last paragraph your code is acting like this:

router.get('/getMyNumber', [cbPage1, cbPage2])

UPDATE:

By creating the page when the route is called you won't have the page close problem. You can then save the result of your call to browser_pages[sessionId]. This change also will give you unique routes for each call. Also, by setting the route with app you don't have to deal with express.Router().

startUp = async(sessionId, app) => {
    app.get(baseUrl + sessionId +'/getMyNumber', async (req, res) => {
        let clientBrowser = require('./src/clientbrowser')({}, sessionId)
        let cb = await clientBrowser.startWhats(sessionId || "user_data");
        let page = cb.getPage();
        const cc = await page.evaluate(() => {
            return getMyNumber();
        });
        console.log(cc);
        browser_pages[sessionId] = cc; // save the result of the session
        res.send({ "data": cc });
    });
}

Upvotes: 1

Related Questions