3

So what I am trying to do is to open puppeteer window with my google profile, but what I want is to do it multiple times, what I mean is 2-4 windows but with the same profile - is that possible? I am getting this error when I do it:

(node:17460) UnhandledPromiseRejectionWarning: Error: Failed to launch the browser process!
[45844:13176:0410/181437.893:ERROR:cache_util_win.cc(20)] Unable to move the cache: Access is denied. (0x5)
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless:false,
    '--user-data-dir=C:\\Users\\USER\\AppData\\Local\\Google\\Chrome\\User Data',
  );
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({ path: 'example.png' });
        
  await browser.close();
})();
theDavidBarton
  • 7,643
  • 4
  • 24
  • 51
DUMBUSER
  • 491
  • 7
  • 22
  • 3
    You have syntax problems in that `launch` object – charlietfl Apr 10 '21 at 15:26
  • i just wrote a quick one since mine is huge, it's just an example – DUMBUSER Apr 10 '21 at 15:28
  • 1
    Ok. but people will focus on that because lots and lots of questions here are just syntax typos. At least make it syntactically correct to avoid any confusion. You can [edit] the question at any time to improve or clarify it – charlietfl Apr 10 '21 at 15:30
  • 2
    Also double check that the error actually still is the same with the shortened sample code you show. – Tomalak Apr 13 '21 at 08:47
  • i tried it that away, i can't even open it if the main browser is opened – DUMBUSER Apr 13 '21 at 10:07

1 Answers1

7

Note: It is already pointed in the comments but there is a syntax error in the example. The launch should look like this:

const browser = await puppeteer.launch({
  headless: false,
  args: ['--user-data-dir=C:\\Users\\USER\\AppData\\Local\\Google\\Chrome\\User Data']
});

The error is coming from the fact that you are launching multiple browser instances at the very same time hence the profile directory will be locked and cannot be moved to reuse by puppeteer.

You should avoid starting chromium instances with the very same user data dir at the same time.

Possible solutions

  • Make the opened windows sequential, can be useful if you have only a few. E.g.:
const firstFn = async () => await puppeteer.launch() ...
const secondFn = async () => await puppeteer.launch() ...

(async () => {
  await firstFn()
  await secondFn()
})();
  • Creating copies of the user-data-dir as User Data1, User Data2 User Data3 etc. to avoid conflict while puppeteer copies them. This could be done on the fly with Node's fs module or even manually (if you don't need a lot of instances).
  • Consider reusing Chromium instances (if your use case allows it), with browser.wsEndpoint and puppeteer.connect, this can be a solution if you would need to open thousands of pages with the same user data dir.
    Note: this one is the best for performance as only one browser will be launched, then you can open as many pages in a for..of or regular for loop as you want (using forEach by itself can cause side effects), E.g.:
const puppeteer = require('puppeteer')
const urlArray = ['https://example.com', 'https://google.com']

async function fn() {
  const browser = await puppeteer.launch({
    headless: false,
    args: ['--user-data-dir=C:\\Users\\USER\\AppData\\Local\\Google\\Chrome\\User Data']
  })
  const browserWSEndpoint = await browser.wsEndpoint()

  for (const url of urlArray) {
    try {
      const browser2 = await puppeteer.connect({ browserWSEndpoint })
      const page = await browser2.newPage()
      await page.goto(url) // it can be wrapped in a retry function to handle flakyness

      // doing cool things with the DOM
      await page.screenshot({ path: `${url.replace('https://', '')}.png` })
      await page.goto('about:blank') // because of you: https://github.com/puppeteer/puppeteer/issues/1490
      await page.close()
      await browser2.disconnect()
    } catch (e) {
      console.error(e)
    }
  }
  await browser.close()
}
fn()
theDavidBarton
  • 7,643
  • 4
  • 24
  • 51
  • if it's possible to do a code example of usage of browser.wsEndpoint, thank you for the answer – DUMBUSER Apr 17 '21 at 13:07
  • Here you are @DUMBUSER. Note, that there are many other possible solutions. This is only one. You could build solutions where `forEach` works as well, but that is a bit more complex than putting it here as a snippet. There are good tutorials and/or npm packages for similar purposes. e.g. https://www.npmjs.com/package/puppeteer-cluster – theDavidBarton Apr 17 '21 at 13:17
  • 1
    You should be specifying the user data dir through https://pptr.dev/api/puppeteer.browserlaunchargumentoptions.userdatadir instead of args. If you use args, Puppeteer will still pass in a randomized-name temp dir user data folder as well, and Chrome doesn't behave as expected with two user data dirs specified. – loxx Oct 09 '22 at 06:10
  • 1
    @theDavidBarton You really saved my bacon with this one!! Our company has been having issues with Puppeteer performance and runaway / orphaned Chromium processes for years, using what I thought was the straightforward approach of launching a singleton browser instance on app startup and then requesting pages with it. Using your alternative approach of generating new browser instances that "connect" to the singleton browser instance and then requesting pages with those connected browser instances, our system is absolutely flying and no more stranded Chromium processes!!! – Justin Feb 08 '23 at 21:37