Search code examples
node.jsseleniumselenium-webdriverautomationinstagram

Upload an image to Instagram on Windows without API


This is a knowledge sharing inspired by : Posting (Uploading) an image to Instagram using Selenium not using an API

Most of the answer from internet only has Python version, so I am here to publish a JavaScript version in node.js


Solution

  • This solution only works under Windows OS.

    Below code reads photos with .jpg format from upload folder and post one by one with caption.

    1. Download the autoit module from :

    https://github.com/xhawk18/node-autoit/issues/15

    1. Update package.json with below dependencies:
    "dependencies": {
        "selenium-webdriver": "^4.0.0-beta.4",
        "autoit": "file:autoit-2.0.1.tgz"   
    },
    
    1. Run npm install

    2. Run the actual code :

    const fs = require('fs');
    const { Builder, By, Key } = require('selenium-webdriver');
    const au = require('autoit');
    const chrome = require('selenium-webdriver/chrome');
    
    const instagramUrl = 'https://www.instagram.com/';
    const account = 'YOUR_INSTAGRAM_ACCOUNT';
    const password = 'YOUR_INSTAGRAM_PASSWORD';
    const instagramLoginUrl = instagramUrl + 'accounts/login/';
    const instagramAccountUrl = instagramUrl + account;
    
    const waitTime = 2000;
    const uploadFolder = 'uploadFolderName'
    const mobileDeviceName = 'iPhone X';
    const loginAlert = '//*[@id="slfErrorAlert"]';
    const newPostButton = '//div[@data-testid="new-post-button"]';
    const nextButton = '//button[text()="Next"]';
    const captionTextArea = '//textarea[@aria-label="Write a caption…"]';
    const shareButton = '//button[text()="Share"]';
    
    let readFileNames = () => {
     let filenames = [];
     fs.readdirSync(uploadFolder).forEach(file => {
       let filename = file.split('.');
       if (filename[1] == 'jpg') {
         filenames.push(file);
       }
     })
     return filenames;
    }
    
    let filenames = readFileNames();
    
    (async function example() {
     let driver = await new Builder()
       .forBrowser('chrome')
       .setChromeOptions(new chrome.Options()
         .setMobileEmulation({ deviceName: mobileDeviceName }))
       .build();
     try {
       // Go to Login page 
       await driver.get(instagramLoginUrl);
       await driver.sleep(waitTime);
       // Login
       await driver.findElement(By.name('username')).sendKeys(account);
       await driver.findElement(By.name('password')).sendKeys(password, Key.RETURN);
       await driver.sleep(waitTime);
       // Redirect to Profile Home Page
       await driver.get(instagramAccountUrl);
       await driver.sleep(waitTime);
       //Read Local Photos
       for (let file of filenames) {
         //Create New Post
         await driver.findElement(By.xpath(newPostButton)).click();
         await driver.sleep(waitTime);
         let imagePath = `${__dirname}\\${uploadFolder}\\${file}`;
         console.log(imagePath);
         // Handle Windows Upload Photo Dialog
         let handle = "[TITLE:Open]";
         au.Init();
         au.WinWait(handle);
         au.Send(imagePath);
         au.ControlClick(handle, "", "Button1");
         await driver.sleep(waitTime);
         // Hit Next
         await driver.findElement(By.xpath(nextButton)).click();
         await driver.sleep(waitTime);
         // Fill The Captions
         await driver.findElement(By.xpath(captionTextArea)).sendKeys("Your caption");
         await driver.sleep(waitTime);
         // Share New Post
         await driver.findElement(By.xpath(shareButton)).click();
         await driver.sleep(waitTime);
         // Back To Home Page
         await driver.get(instagramAccountUrl);
       }
     }
     catch (err) {
       console.error(err);
     }
     finally {
       await driver.quit();
     }
    })();