0

I am building an API that requires users to login in a website and I'm handling this with Puppeteer.

The problem here is when two users using the API at the same time (Or in the same browser session), I get an error saying that the user is already logged in and I think this happened because it is the same session.

Here is my current code:

import express from "express";
import puppeteer from "puppeteer";

const myRoutes = express.Router();

myRoutes.get("/login", async (request, response) => {
  const loginAuth = request.body;

  try {
    const browser = await MyBrowser.initialize();
    const page = await browser.newPage();

    await page.goto("https://website.com/login");
    await page.waitForNetworkIdle({ idleTime: 3000 });

    await page.$eval("#userName", (el, value) => (el.value = value), loginAuth.userName);
    await page.$eval("#password", (el, value) => (el.value = value), loginAuth.password);

    await page.$eval("#loginBtn", (el) => el.click());

    await page.$eval("#loginBtn", (el) => el.click());

    // MyBrowser.closeBrowser();
  } catch (err) {
    console.log("ERRORR OCCURED...");
    console.log(err);
  }

  response.end("No message");
});

class MyBrowser {
  static #browser;

  static async initialize() {
    if (!MyBrowser.#browser?.isConnected())
      MyBrowser.#browser = await puppeteer.launch({ args: ["--no-sandbox"] });
  }

  static async closeBrowser() {
    if (MyBrowser.#browser?.isConnected()) await MyBrowser.#browser.close();
  }
}

export { myRoutes };

when I send 2 requests at the same time, I get the following error:
Error: Error: failed to find element matching selector "#userName" at ElementHandle.$eval

This error is occurring because the first request user has already logged in and the element is no longer present on the page for the second request.

So I want to make sure that if two or more users using the API, they each will have their own session.

I know that I could use another puppeteer.launch() but it may require a large amount of memory and I want to avoid that...

I have also tried to close the browser using MyBrowser.closeBrowser() before the end of the request, but I encountered this error when I tried to send two requests at the same time:
Error: Protocol error (Runtime.callFunctionOn): Session closed. Most likely the page has been closed. at CDPSessionImpl.send

It works fine if I wait some times before each request.

Obaadz
  • 1
  • 2
  • Here are two examples of sharing one browser across all requests (each request gets its own page): [1](https://stackoverflow.com/a/67910262/6243352), [2](https://stackoverflow.com/questions/52225461/puppeteer-unable-to-run-on-heroku/67596057#67596057). – ggorlen Jan 08 '23 at 16:11
  • Thanks for sharing those examples, they were really helpful for other issues that I had, but it looks like they are using the same `puppeteer.launch()` function for every user's requests. This means that if there are multiple requests at the same time, it creates a new browser session for each request, which is something I'm trying to avoid. Do you have any other suggestions that might help me solve this issue? – Obaadz Jan 08 '23 at 20:02
  • Please review them again. Neither of the examples create a new browser for each request. They create a new page per request and share a single browser. Run it headfully locally and play with it if you're not yet convinced. – ggorlen Jan 08 '23 at 20:07
  • I would consider to use puppeteer-cluster with specified user directories. – sametcodes Jan 08 '23 at 22:18
  • @ggorlen Yes! I just gave this examples a second look and they do well. I apologize for misunderstanding earlier. It works perfectly for my needs. Thank you so much for your help, I really appreciate it. I'm convinced now, thanks again. – Obaadz Jan 08 '23 at 22:31
  • 1
    @sametcodes Thanks for the suggestion, I will keep it in mind and consider using it if needed. Appreciate your help. – Obaadz Jan 08 '23 at 22:36

0 Answers0