A. L
A. L

Reputation: 12649

puppeteer - how to set download location

I was able to successfully download a file with puppeteer, but it was just saving it to my /Downloads folder. I've been looking around and can't find anything in the api or forums to set this location.

My downloads are basically just go going to the link:

await page.goto(url);

Upvotes: 25

Views: 34392

Answers (8)

Muhammad Uzair
Muhammad Uzair

Reputation: 484

All given solutions weren't working for me in the newer version of puppeteer 15.5.0

using puppeteer-extra with puppeteer-extra-plugin-user-preferences plugin did the trick.

// make sure puppeteer-extra & puppeteer-extra-plugin-user-preferences are installed

const UserPreferencesPlugin = require("puppeteer-extra-plugin-user-preferences");

const downloadImageDirectoryPath = process.cwd()

puppeteer.use(
  UserPreferencesPlugin({
    userPrefs: {
      download: {
        prompt_for_download: false,
        open_pdf_in_system_reader: true,
        default_directory: downloadImageDirectoryPath,
      },
      plugins: {
        always_open_pdf_externally: true,
      },
    },
  })
);

Upvotes: 1

Chandan Singh
Chandan Singh

Reputation: 1

For firefox in node js

const reportsFolder = join(__dirname, "data");
const browser = await puppeteer.launch({
    browser: "firefox",
    args: [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--ignore-certificate-errors",
    ],
    headless: true,
    acceptInsecureCerts: true,
    extraPrefsFirefox: {
      "network.stricttransportsecurity.preloadlist": false,
      "security.enterprise_roots.enabled": true,
      "security.cert_pinning.enforcement_level": 0,
      "security.ssl.errorReporting.enabled": false,
      "security.ssl.enable_ocsp_stapling": false,
      "security.ssl.enable_ocsp_must_staple": false,
      "security.ssl.enable_revocation_checking": false,
      "security.OCSP.enabled": 0,
      "browser.helperApps.neverAsk.saveToDisk":
        "application/pdf,application/octet-stream",
      "browser.download.folderList": 2, // 2 means custom location
      "browser.download.dir": reportsFolder, // Set the download directory here
      "browser.download.useDownloadDir": true,
      "pdfjs.disabled": true,
    },
  });

Upvotes: 0

Md. Abu Taher
Md. Abu Taher

Reputation: 18826

Update for newer Puppeteer versions (~June 2022):

As mentioned by @Daniel here, you have to create the CDP session yourself:

const client = await page.target().createCDPSession()
await client.send('Page.setDownloadBehavior', {
  behavior: 'allow',
  downloadPath: './myAwesomeDownloadFolder',
})

Original Answer

This is how you can set the download path in latest puppeteer v0.13.

await page._client.send('Page.setDownloadBehavior', {behavior: 'allow', downloadPath: './myAwesomeDownloadFolder'});

The behaviour is experimental, it might be removed, modified, or changed later.

Pst, you can try more tricks listed here, on your own risk :).

Upvotes: 42

Eric Y
Eric Y

Reputation: 1

Finally, I run the program in docker container with chrome installed

FROM node:18-slim

# ------------------------------------------
# install extension
# ------------------------------------------
RUN apt-get update -y && apt-get install -y \
    # chromium \
    # libnss3 lsb-release xdg-utils wget \
    wget gnupg \
    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
    && apt-get update \
    && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends \
    && rm -rf /var/lib/apt/lists/*

# ------------------------------------------
# set global config
# ------------------------------------------
ENV TZ Asia/Hong_Kong
# ------------------------------------------
# change the work directory
# ------------------------------------------
COPY source /root/source
WORKDIR /root/source

# ------------------------------------------
# upgrade npm
# ------------------------------------------
RUN npm install npm -g
RUN npm upgrade

# install node packages
RUN if test -e package-lock.json ; then npm ci ; else npm i ; fi
RUN npm run build
ENTRYPOINT ["npm", "run"]
CMD ["start"]

and

use await page.target().createCDPSession() as client for downloading the file ( ref: https://github.com/puppeteer/puppeteer/issues/1478#issuecomment-358826932 https://pptr.dev/api/puppeteer.cdpsession )

const downloadPath = `[YOU OWN DOWNLOAD PATH]`
const browser = await puppeteer.launch({
  headless: true,
  args: ['--no-sandbox', '--disable-setuid-sandbox'],
  executablePath: '/usr/bin/google-chrome-stable'
})

const page = await browser.newPage()
const client = await page.target().createCDPSession()
await client.send('Page.setDownloadBehavior', {
  behavior: 'allow',
  downloadPath
})

Upvotes: 0

KBoicourt
KBoicourt

Reputation: 31

The answer from Muhammad Uzair solved my similar issue of setting the Chromium user preference to enforce PDF file downloads, but I ran into an issue of setting things up since I am using Puppeteer, Jest, and Jest-Puppeteer, where Jest-Puppeteer handles the initial setup behind the scenes.

This Github post from Macil helped with how to apply the puppeteer-extra-plugin-user-preferences plugin within the jest-puppeteer.config.js file.

For example, this is my jest-puppeteer.config.js file:

const puppeteer = require('puppeteer-extra');
const UserPreferencesPlugin = require('puppeteer-extra-plugin-user-preferences');

const userPreferenceOptions = {
  userPrefs: {
    plugins: {
      always_open_pdf_externally: true,
    },
    download: {
      open_pdf_in_system_reader: false,
      prompt_for_download: false,
    },
  }
};
puppeteer.use(UserPreferencesPlugin(userPreferenceOptions));

require.cache[require.resolve('puppeteer')] = require.cache[require.resolve('puppeteer-extra')];

module.exports = {
  launch: {
    // https://github.com/puppeteer/puppeteer/blob/v13.3.2/docs/api.md#puppeteerlaunchoptions
    headless: true, // opens a browser instance
    slowMo: 25, // millis to slow each step
    devtools: false, // auto opens the devtools in the browser
    defaultViewport: {
      width: 1820,
      height: 980,
      deviceScaleFactor: 1,
      isMobile: false,
      isLandscape: true,
    },
    product: "chrome", // can also specify firefox
    browserContext: 'incognito',
    args: [
      // Chromium browser arguments: https://peter.sh/experiments/chromium-command-line-switches/
      '--ignore-certificate-errors',
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--window-size=1920,1080',
    ],
  },
};

Upvotes: 2

Patryk K
Patryk K

Reputation: 1

Update 30-07-2022: An update has been made and this feature has been removed from previous versions of the package as well, if you have downloaded the package before 10-06-2022 it should work. For me it is like that, but it is puzzling why also previous versions were changed ..

Upvotes: -1

Daniel Diekmeier
Daniel Diekmeier

Reputation: 3434

In newer versions of Puppeteer (I'm using v14.1), the Accepted Answer no longer works:

await page._client.send('Page.setDownloadBehavior', {behavior: 'allow', downloadPath: './myAwesomeDownloadFolder'});

> TypeError: page._client.send is not a function

Instead, I had to explicitely create a new CDPSession:

const client = await page.target().createCDPSession()
await client.send('Page.setDownloadBehavior', {
  behavior: 'allow',
  downloadPath: './myAwesomeDownloadFolder',
})

Upvotes: 22

ara6893
ara6893

Reputation: 79

I realize this is an old thread, but this thread popped up first for me when looking for how to set Puppeteer default download location. I was able to set the download location using the following code,

let customChrome = path.resolve(__dirname, './customChrome')
        let prefs = fs.readFileSync(customChrome+'/Default/Preferences');
        let obj = JSON.parse(prefs);
        obj.savefile.default_directory = path.resolve(__dirname, './downloads');
        obj.download.default_directory = path.resolve(__dirname, './downloads');
        fs.writeFileSync(customChrome+'/Default/Preferences', JSON.stringify(obj));
        const browser = await puppeteer.launch({
            userDataDir:customChrome,
            headless: false,                                                                                                                                                                                                                                                 
            args:['--disable-features=site-per-process','--no-sandbox']
        });

This will set the default download directory for files before the process starts. Essentially, Puppeteer creates a custom profile each time it runs, we can override that profile and define the download directory.

The first time you run the above code, you will have to comment out the fs.readFile to fs.writeFile as the UserDirDirectory is created if it does not exist the first time that Chrome is started.

All profile related data is then stored in the customChrome/Default folder. How to pass userDataDir profile folder to Puppeteer

Upvotes: 4

Related Questions