【问题标题】:Using chrome and puppeteer with multiple browsers在多个浏览器中使用 chrome 和 puppeteer
【发布时间】:2020-02-26 04:09:30
【问题描述】:

我正在使用 puppeteer。 我需要加载多个页面并注入一个 javascript。

我正在创建两个浏览器,每个浏览器都有一个页面(选项卡)并注入了 javascript。

我有一个节点服务器,其中包含到加载的每个页面的路由。

我用“100”和“101”为每个页面命名了一个会话。运行应用程序后会创建两个 userdata 文件夹(100 和 101)。这些会话也用于分隔路由。

浏览器已正确创建,没有问题。

我的问题是当我使用路由时,节点服务器总是向两个页面返回相同的结果:

如果我使用 Postman 或其他 chrome 浏览器进行测试:

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

它们返回相同的值。 但是每个浏览器页面的值都不同。 似乎没有根据请求考虑该页面,并且它向两个页面返回相同的结果。但是,正如我所说,函数“getMyNumber”应该向每个页面返回不同的值。我的示例函数使用本地存储,但我还有许多其他函数不使用本地存储,并且都有相同的问题。

请问,我做错了什么?

我怀疑我没有传递正确的浏览器页面来路由。 但是,我没有发现错误。

//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');
}

【问题讨论】:

    标签: node.js puppeteer


    【解决方案1】:

    这是导致问题的原因:

    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;
    }
    

    你实际上设置了两次这条路线。我知道由于您的 app.use('/teste' + sessionId, troutes) 行,您似乎设置了两条不同的路径。但实际上你设置了两条不同的路径指向同一个router。您的路由器对象对于两者都是相同的,因为该对象来自同一个模块require('./src/routes/testroutes')

    快速修复:传递页面和 sessionId 以使用 route.get 创建一个唯一的 url。 例如:router.get('/getMyNumber'+ sessionId,....router.get('/'+ sessionId + '/getMyNumber',....

    您当前的代码设置为对/getMyNumber 路由进行两次中间件调用。 router.get 实际上将第三个参数next 传递给您的回调。 function. ('/getMyNumber', async (req, res, next)。如果你在你的函数中调用 next() 而不是 res.send({...}) 另一个 '/getMyNumber' 将被调用。

    为了澄清最后一段,您的代码如下所示:

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

    更新:

    通过在调用路由时创建页面,您将不会遇到页面关闭问题。然后,您可以将调用结果保存到browser_pages[sessionId]。 此更改还将为您提供每次呼叫的唯一路线。此外,通过使用app 设置路由,您不必处理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 });
        });
    }
    

    【讨论】:

    • @123 不,这不是导致相同结果的原因。我有其他函数并且都返回相同的值。例如,我有一个从 whatsapp 获取所有联系人的功能。我每页使用两部手机。当我注入脚本时,我总是得到相同的结果。手机有不同的联系人列表。所以,问题不在于本地存储。
    • @123,谢谢,我会试试的。但是,现在我必须重复 sessionId 两次才能访问该路线。我必须使用 localhost:/3007/test100/getMyNumber/100。它很丑。你觉得有什么可以让它变得更好的吗?
    • @123 非常感谢您的帮助。我接受你的回答。
    • @123 请再问一个问题。你解决的第一个。在我的代码中,我使用“const troutes = require('./src/routes/testroutes')(page)”,但有时“页面”会关闭并失效。然后我创建一个新的“页面”并再次使用“const troutes = require('./src/routes/testroutes')(page)”。但是路线记得旧页面关闭并且路线不起作用。为了避免它,我必须做些什么吗?
    • 有没有办法删除旧路由并使用带有正确页面参数的新路由?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-15
    • 2018-08-20
    • 1970-01-01
    • 2020-05-09
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    相关资源
    最近更新 更多