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.
Easyupload.io, the website for our scenario
Let's start.
Preparation
Install Puppeteer
npm i puppeteer
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();
})();
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
If everyting OK it will display the result in console similar like below.
{
file: 'test_to_upload.jpg',
download_url: 'https://easyupload.io/ffbvzk'
}
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
- https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#elementhandleuploadfilefilepaths
- https://pptr.dev
- https://easyupload.io
Credits
- test_to_upload.jpg is taken from photo by Ave Calvar Martinez from Pexels https://www.pexels.com/photo/lighthouse-3361704/
- Cover image is taken from photo by Brett Stone from Pexels https://www.pexels.com/photo/photo-of-a-person-using-a-gray-laptop-computer-2874782/
Top comments (10)
FYI: this call should have an
await
Just spent an hour debugging an automatic upload form due to this :P
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!
hey, i am starting a new project with puppeteer. Do you want to work ?
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.
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.
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.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.
Hi Oliver, sorry for super late reply, maybe file path is wrong? or try by using full path to the file.
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.
Hi Harshajayaweera, sorry for the late reply, I think I miss this, already got solution for your problem?