How to catch a download with playwright?

Viewed 5561

I'm trying to download a file from a website using Playwright. The button that triggers the download does some js and then the download starts.

Clicking the button using the .click function triggers a download but it shows an error: Failed - Download error.

enter image description here

I've tried using the devtools protocol Page.setDownloadBehavior, but this doesn't seem to do anything.

    const playwright = require("playwright");
    const { /*chromium,*/ devices } = require("playwright");
    const iPhone = devices["iPad (gen 7) landscape"];

    (async () => {
        const my_chromium = playwright["chromium"];
        const browser = await my_chromium.launch({ headless: false });
        const context = await browser.newContext({
            viewport: iPhone.viewport,
            userAgent: iPhone.userAgent
        });
        const page = await context.newPage();
        const client = await browser.pageTarget(page).createCDPSession();
        console.log(client);
        await client.send("Page.setDownloadBehavior", {
            behavior: "allow",
            downloadPath: "C:/in"
        });
        //...and so on
        await page.click("#download-button");
        browser.close();
    })();

Full file here

There is a proposal for a better download api in Playwright, but I can't find the current API. There was a suggestion that something to do with the downloadWillBegin event would be useful, but I've no idea how to access that from Playwright.

I'm open to the suggestion that I should use Puppeteer instead, but I moved to playwright because I couldn't work out how to download a file with Pupeteer either, and the issue related to it suggested that the whole team had moved to Playwright.

4 Answers

Take a look at the page.on("download")

const browser = await playwright.chromium.launch({});
const context = await browser.newContext({ acceptDownloads: true });
const page = await context.newPage();
await page.goto("https://somedownloadpage.weburl");
await page.type("#password", password);
await page.click("text=Continue");
const download = await page.waitForEvent("download");
console.log("file downloaded to", await download.path());

Embarassingly, I was closing the browser before the download had started.

It turns out that the download error was caused by the client section. However that means that I have no control over where the file is saved.

The download works when headless: false but not when headless: true.

If anyone has a better answer, that'd be great!

You can use waitForTimeout.

I tried with {headless: true} & await page.waitForTimeout(1000);

it's working fine. you can check same here

To download file (also its buffer) i highly recomend this module: Got node module. Its much easier, clean and light.

(async () => {
const response = await got('https://sindresorhus.com')
    .on('downloadProgress', progress => {
        // Report download progress
    })
    .on('uploadProgress', progress => {
        // Report upload progress
    });

    console.log(response);
})();
Related