#node.js #express #puppeteer
Вопрос:
Я разрабатываю API автоматизации в Node.js с кукловодом. Когда API вызывается, создается экземпляр браузера без головы кукловода, и запускается какой-то процесс автоматизации, такой как вход в систему, и он входит в профиль пользователя, переданный при вызове. Но если веб — сайт, на котором я выполняю автоматизацию, обнаруживает поведение бота. Он отправляет код входа в систему по электронной почте, поэтому отправляется ответ на этот вызов 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); } }
Playing
const playing = async (res) =gt; { 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 =gt; 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(); }
Ответ №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