【问题标题】:How to uniquely identify puppeteer browser instances?如何唯一标识 puppeteer 浏览器实例?
【发布时间】:2021-12-15 01:35:21
【问题描述】:

我正在使用 puppeteer 在 Node.js 中开发自动化 API。当调用 API 时,会创建一个 puppeteer 无头浏览器实例,并启动一些自动化过程,如登录,并登录到调用中传递的用户配置文件。但是,如果我正在执行自动化的网站检测到机器人行为。它会在电子邮件中发送登录代码,以便发送对该 API 调用的响应,要求提供登录代码。当登录代码在另一个 API 调用中提交时,它只是转到该页面并放置代码。因此我们登录了。当我只有一个浏览器实例时,这件事完美无缺。但是当多个浏览器实例正在运行时,登录代码 API 不会获得所需的页面。它跳转到最后创建的浏览器实例,该实例可能正在执行其他进程,而不是需要登录代码的目标实例。

我的问题是如何唯一标识浏览器实例,以便我可以将登录代码放在该实例上,而不是为不同用户执行不同进程的其他实例。

启动浏览器

let browser;

let page;

async function startBrowser() {

    if(proxyUrl == '' || proxyUn == '' || proxyPw == ''){
        browser = await puppeteer.launch({

            //slowMo: 30, // to slowdown the process

            headless: false,    //  set as false to open a chromium
    
            ignoreDefaultArgs: ["--enable-automation"],
    
            defaultViewport: null,
    
            args: ["--no-sandbox",
    
                "--disable-setuid-sandbox",
    
                "--start-maximized",
    
                '--window-size=1920,1080',
    
                "--disable-gpu",
    
                "--disable-dev-profile",
    
            ]
    
        });

    }else{

        //proxy Chain for proxy application
    
        const oldProxyUrl = `http://${proxyUn}:${proxyPw}@${proxyUrl}`;

        const newProxyUrl = await proxyChain.anonymizeProxy(oldProxyUrl);

            browser = await puppeteer.launch({

                //slowMo: 30, // to slowdown the process
    
                headless: false,    //  set as false to open a chromium
    
                ignoreDefaultArgs: ["--enable-automation"],
    
                defaultViewport: null,
    
                args: ["--no-sandbox",
    
                    "--disable-setuid-sandbox",
    
                    "--start-maximized",
    
                    '--window-size=1920,1080',
    
                    "--disable-gpu",
    
                    "--disable-dev-profile",
    
                    `--proxy-server=${newProxyUrl}`,
    
                ]
    
            });

        


    }   
    browser.on('disconnected', function(){
        browser = '';
    }); 
    page = await browser.newPage();

    await page.setViewport({ width: 1920, height: 1080 });

    page.setUserAgent(

        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"

    );

}

播放测试

async function playTest(url, res) {

    try {
            try{

                await startBrowser();

                await page.setDefaultNavigationTimeout(32400000);
            
            }catch(e){

                proxyFailedFlag = true;

                console.error(new Date().toLocaleString() + ': ', e);

                return res.status(400).json({ status: 'failure', info: 'Invalid Proxy' }).end();
            
            }

            try{

                console.log(new Date().toLocaleString() + ': ', 'connecting login page ...');
                
                await page.goto(url);

            }catch(e){

                proxyFailedFlag = true;

                await closeBrowser(browser);

                console.error(new Date().toLocaleString() + ': ', e);

                return res.status(400).json({ status: 'failure', info: 'Invalid Proxy' }).end();
            
            }

            await waitTillHTMLRendered(page);

            await page.setViewport({

                width: 1400,

                height: 966

            });

            await playing(res);

    } catch (e) {

        console.error(new Date().toLocaleString() + ': ', e);
        
    }

}

播放

const playing = async (res) => {

    console.log(new Date().toLocaleString() + ': ', 'waiting for login form ...');

    if (await page.$(ACCEPT_COOKIES_SELECTOR) !== null) {

        const accept_elm = await page.$(ACCEPT_COOKIES_SELECTOR);

        await accept_elm.click({ clickCount: 1 });

    }

    await page.waitForSelector(USERNAME_SELECTOR, {

        visible: true,

    });
    

    await page.click(USERNAME_SELECTOR);

    await page.keyboard.type(email);

    await page.click(PASSWORD_SELECTOR);

    await page.keyboard.type(password);


    const m_login_elm = await page.$(M_LOGIN_SELECTOR);

    await m_login_elm.click({ clickCount: 1 });


    console.log(new Date().toLocaleString() + ': ', 'logging in ...');


    try {

        await page.waitForNavigation();

        let pageURL = page.url();

        console.log("page url: ", pageURL)

        if (pageURL === 'https://www.targetwebsite.com/feed/') {

            loginFailedFlag = false;

            let accountElm = await page.$(PROFILE_NAME_SELECTOR);

            accountName = await page.evaluate(accountElm => accountElm.textContent, accountElm);

            accountName = accountName.trim();

            console.log("Login success", accountName);

        } else if (pageURL === "https:/www.targetwebsite.com/login-submit") {

            console.log("Exception Login Submit Form!");

            if (await page.$(NOT_REMEMBER_BTN_SELECTOR) !== null) {

                const notRememberBtn = await page.$(NOT_REMEMBER_BTN_SELECTOR);

                await notRememberBtn.click({ clickCount: 1 });


            } else {

                throw new Error('Login fail!');

            }

        } else {

            pageURL = pageURL.split("challenge");

            if(pageURL[0]==="https://www.targetwebsite.com/captcha/"){

                loginFailedFlag = true;

                return res.status(400).json({ status: 'failure', info: 'Captcha' }).end();

            }

            loginFailedFlag = false;

            console.log("Pin code is required");

        }


    } catch (error) {
        loginFailedFlag = true;
        return res.status(400).json({ status: 'failure', info: 'Invalid Login' }).end();
    }



    if (await page.$(PIN_INPUT_SELECTOR) !== null) {



        console.log("pin code required")

        warnFlag = true

        warnmsg = 'Awaiting IP Code';

    } else {



        warnFlag = false

        console.log('not found Pin Code step');

        await waitTillHTMLRendered(page);

        if (await page.$(RE_ACCEPT_COOKIES_SELECTOR) !== null) {

            const accept_elm = await page.$(RE_ACCEPT_COOKIES_SELECTOR);

            await accept_elm.click({ clickCount: 1 });

        }

        await getCookies();

    }

}

在第二次 API 调用中提交登录代码时

async function handleIpProcess(ip_email, ip_code) {

        await waitTillHTMLRendered(page);

        await page.click(PIN_INPUT_SELECTOR);

        await page.keyboard.type(ip_code);
    
        await page.waitForSelector(PIN_SUBMIT_SELECTOR, {
    
            visible: true,
    
        });
    
        await page.click(PIN_SUBMIT_SELECTOR);
    
        await getCookies();

}

【问题讨论】:

    标签: node.js express puppeteer


    【解决方案1】:

    我通过使用 uuid 为每个实例创建一个对象并将其推送到数组来解决此问题。

    browser = {
      uuid: email, //used email because it was most suitable in my case
      pass: password,
      instance: undefined,
      page: undefined
    }
    
    browserInstances.push(browser); //browserInstances is an array initialized earlier in the code
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多