DEV Community

Cover image for Practical Puppeteer: How to upload a file programatically
Sony AK
Sony AK

Posted on

Practical Puppeteer: How to upload a file programatically

Hi everybody! Today I will share about how to upload file using Puppeteer. If you don't know about Puppeteer yet, here is the brief explanation.

Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium. Go to https://pptr.dev for more details.

During automation using Puppeteer sometimes we want to simulate upload a file and now I will show it with real scenario.

The scenario is we will upload a file to website called Easyupload.io at https://easyupload.io. We can upload a file without need for login and they will by default keep the file for 7 days and they will give us the URL of uploaded file. Quite simple and perfect sample.

Alt Text Easyupload.io, the website for our scenario

Let's start.

Preparation

Install Puppeteer

npm i puppeteer
Enter fullscreen mode Exit fullscreen mode

The API to upload file is elementHandle.uploadFile(...filePaths). We will prepare the file to upload called test_to_upload.jpg and pass to uploadFile method.

The code

const puppeteer = require('puppeteer');

(async () => {
    // set some options (set headless to false so we can see 
    // this automated browsing experience)
    let launchOptions = { headless: false, args: ['--start-maximized'] };

    const browser = await puppeteer.launch(launchOptions);
    const page = await browser.newPage();

    // set viewport and user agent (just in case for nice viewing)
    await page.setViewport({width: 1366, height: 768});
    await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36');

    // go to the target web
    await page.goto('https://easyupload.io/');

    // get the selector input type=file (for upload file)
    await page.waitForSelector('input[type=file]');
    await page.waitFor(1000);

    // get the ElementHandle of the selector above
    const inputUploadHandle = await page.$('input[type=file]');

    // prepare file to upload, I'm using test_to_upload.jpg file on same directory as this script
    // Photo by Ave Calvar Martinez from Pexels https://www.pexels.com/photo/lighthouse-3361704/
    let fileToUpload = 'test_to_upload.jpg';

    // Sets the value of the file input to fileToUpload
    inputUploadHandle.uploadFile(fileToUpload);

    // doing click on button to trigger upload file
    await page.waitForSelector('#upload');
    await page.evaluate(() => document.getElementById('upload').click());

    // wait for selector that contains the uploaded file URL
    await page.waitForSelector('#upload-link');
    await page.waitFor(5000);

    // get the download URL
    let downloadUrl = await page.evaluate(() => {
        return document.getElementById('upload-link').value;
    });

    // display the result on console
    console.log({'file': fileToUpload,
                 'download_url': downloadUrl});

    // close the browser
    await browser.close();
})();
Enter fullscreen mode Exit fullscreen mode

The code is full of comment, I hope you can understand. I set the headless option to false so we can see the browser in action.

In the code I also put some page.waitFor() to avoid race condition during scraping this scenario.

Run it

node upload_file.js
Enter fullscreen mode Exit fullscreen mode

If everyting OK it will display the result in console similar like below.

{
  file: 'test_to_upload.jpg',
  download_url: 'https://easyupload.io/ffbvzk'
}
Enter fullscreen mode Exit fullscreen mode

You can go to the download_url above and you will get your uploaded image. It means our upload automation with Puppeteer works perfectly. I have test it using headless mode and headful mode, all are working well.

That's it. Thank you and I hope you enjoy it.

Source code of this sample is available at GitHub https://github.com/sonyarianto/upload-file-with-puppeteer.git.

Reference

Credits

Top comments (10)

Collapse
 
sovanyio profile image
Brian Bolton

FYI: this call should have an await

    // Sets the value of the file input to fileToUpload
    inputUploadHandle.uploadFile(fileToUpload);
Enter fullscreen mode Exit fullscreen mode

Just spent an hour debugging an automatic upload form due to this :P

Collapse
 
ashiqcseworld profile image
Ashiqur Rahman • Edited

can you please write an article about, how to, make a puppeteer extra plugin?

I want to make a plugin so that, whenever any interactions (click on a button, navigate to a page, etc..) it will take a screenshot automatically before and after the interaction. so that I don't have to call page.screenshot manually every time!

Collapse
 
dynamitebud profile image
Rudra

hey, i am starting a new project with puppeteer. Do you want to work ?

Collapse
 
sonyarianto profile image
Sony AK

Hi Ashiqur, wow nice use case, I still don't have any experience for writing plugin for Puppetter but I will note it for this nice use case.

Collapse
 
csandman profile image
Christopher Sandvik

This is great, except I'm stuck at one part. What would you do if there is no upload button, and the upload is normally automatically trigerred when the file is uploaded? For some reason nothing happens when I call the uploadFile function, I would expect it to continue automatically.

Collapse
 
sonyarianto profile image
Sony AK

Hi Chris,
Thanks, but sorry I am still don't understand your use case, do you have any sample of code or target web to do that? What do you mean by "no upload button". Basically we just target the <input type="file"> and call the uploadFile method for the file input selector. Tell me more and maybe I can help you.

Collapse
 
olizh profile image
Oliver Zhang • Edited

Hi Sony, first of all, thanks for a very useful post. This works perfect on my Mac. But when I deploy the code on Heroku, the file doesn't really upload. It looks like Pupeteer on Heroku couldn't find the file in the following line, thus the submit resulting in no file upload:

inputUploadHandle.uploadFile(fileToUpload);

The file exists in that path on Heroku's server because I'm able to send that file as an email attachment using Node Mailer. I'v been scratching my head for two days in a row. I wonder if you happen to have tried this on a Heroku app.

Collapse
 
sonyarianto profile image
Sony AK

Hi Oliver, sorry for super late reply, maybe file path is wrong? or try by using full path to the file.

Collapse
 
harshajayaweeraxhj profile image
harshajayaweeraXHJ

Thanks Sony, Great article!
Can you please look into this issue. i'm struggling with it and stuck for days now.

github.com/puppeteer/puppeteer/iss...

It is about uploading an image
Thanks in advance.

Collapse
 
sonyarianto profile image
Sony AK

Hi Harshajayaweera, sorry for the late reply, I think I miss this, already got solution for your problem?