Building a Python Selenium Instagram Bot

Python Selenium Instagram Bot

Building a Python Selenium Instagram Bot

    Hello friends, in today's post, we will develop a simple bot for Instagram using the python selenium module. To develop this bot, you need to have at least an average level of Python or programming knowledge, otherwise you may have difficulty understanding some parts; at the very least, you need to know about Python classes, functions, and the self structure.

Check out this article for installing Selenium and downloading the Web Driver.

Let's Add Libraries

 Now, let's slowly start writing our code. First, let's begin by adding the libraries we will use in our project.

from time import sleep ## Library needed to perform second-based delays
from selenium.common.exceptions import NoSuchElementException ## Library required for Selenium error handling
from selenium.webdriver.common.keys import Keys ## Library that allows us to simulate the keyboard with Selenium
from selenium import webdriver ## Selenium web driver library
tarayiciDriverKonum = "C:\\Users\\ahmet\\Desktop\\Python\\Selenium\\geckodriver.exe" ## Web driver location

**You need to adjust the code according to the browser you use as the Web Driver. I am writing this bot based on Firefox.

Let's Create a Class and Write Our First Function

Now that we've added the libraries, let's continue. Now, let's create a class named Instagram and start writing our functions inside the class.

class Instagram:
    def __init__(self, tarayiciKonum, url="https://www.urhoba.net", kullaniciAdi="kullanıcı adı", sifre="şifre"):
        self.tarayici = webdriver.Firefox(executable_path=tarayiciDriverKonum)
        self.url = url
        self.girisurl = "https://www.instagram.com/accounts/login/"
        self.kullaniciAdi = kullaniciAdi
        self.sifre = sifre
        self.girisYapilmismi = False
        self.tumTakipciler = []
        self.tumTakipEdilenler = []

Here, our first function is "def __init__ (self, a,b,c)". I would like to briefly explain this function here.

The __init__ function in python allows us to assign variables specific to the class and create variables that we can change or add when calling the class.

While preparing the bot for Instagram, we will define some variables here with __init__ so we can pull the required information from here directly inside the functions we will write later without asking the user.

I can say that the most important part of the __init__ section when writing this bot is actually the self.tarayici part, as we will perform all our actions with this browser variable.

Let's Write Our Functions to Open and Close the Browser

Now that we've roughly explained what the __init__ part does, let's create our necessary functions to open and close the browser under selenium control.

def TarayiciAc(self):
        try:            
            self.tarayici.get(self.url)
            print("Browser opened.")
            self.tarayici.implicitly_wait(10)
        except:
            print("A problem occurred while opening the browser!")

    def TarayiciKapat(self):
        self.tarayici.close()

You can see try and except command blocks in the browser opening function. These are commands we use to show error messages to the user in a conscious way instead of the system crashing when an error occurs.

In the Selenium library, after specifying our browser, the browser opens and navigates to the requested site via ".get('site address')", and with ".implicity_wait(duration)" a delay is introduced until the page is loaded.

With ".close()" the browser is closed. We put all of these into functions so that when our bot is fully finished, we can list all these functions one after another, making it much easier to use. 

Let's Write Our Function to Log Into the Instagram Account

Now let's write the code for logging into any Instagram account.

 def GirisYap(self, url):
        try:
            self.tarayici.get(url)
            self.tarayici.implicitly_wait(10)
            kullaniciAdiInput = self.tarayici.find_element_by_css_selector(
                "input[name='username']")
            sifreInput = self.tarayici.find_element_by_css_selector(
                "input[name='password']")
            girisButon = self.tarayici.find_element_by_xpath(
                "//button[@type='submit']")
            kullaniciAdiInput.send_keys(self.kullaniciAdi)
            sifreInput.send_keys(self.sifre)
            girisButon.click()
            print("Successfully logged into the account.")
            self.girisYapilmismi = True
            sleep(10)

        except:
            print("A problem occurred while logging into the account!")

Here, we defined a function as "GirisYap(self, url)". With self, we can fetch variables inside __init__ and, in addition, I asked the user for a url because it would be better if the user adds Instagram's user login page here.

Selenium username Input


Afterwards, we created a variable named kullanıcıAdiInput and used the selenium property css selector to select the username input, did the same for password, and then for the login button.

To do these selections, press the F12 key on the Instagram login page, then right click on the input you want to select and press "inspect" (Edge), then right click on the area on the right and select whatever you want under "copy". Of course, remember to change your code according to the copying method you have chosen.

For example, if you chose xpath, don't forget to change css_selector to "self.tarayici.find_element_by_xpath".

Since we've selected the username and password inputs, with the ".send_keys("")" command, we can have them enter the username and password.

With girisButon.click(), we make it click the login button. Inside __init__ we set the logged in boolean to true. 

I should mention that I created this boolean for security, for actions like following or unfollowing in the future.

Let's Write the Follow and Unfollow Functions

We logged into the Instagram account, now let's start coding how to follow or unfollow any account.

    def TakipEt(self, kullaniciAdi):
        if self.girisYapilmismi == True:
            try:
                self.tarayici.get(self.url + kullaniciAdi)
                self.tarayici.implicitly_wait(10)
                takipEtButton = self.tarayici.find_element_by_css_selector(
                    'button')
                if takipEtButton.text == "Follow":
                    takipEtButton.click()
                    print(kullaniciAdi + " Followed")
                else:
                    print(kullaniciAdi + " Already following..")

            except:
                print(kullaniciAdi + " An error occurred while following!")
        else:
            print("Please log in with an account before following someone!")

    def TakiptenCik(self, kullaniciAdi):
        if self.girisYapilmismi == True:
            try:
                self.tarayici.get(self.url + kullaniciAdi)
                self.tarayici.implicitly_wait(10)
                takiptenCikButton1 = self.tarayici.find_element_by_xpath(
                    '//*[@id="react-root"]/section/main/div/header/section/div[1]/div[1]/div/div[2]/div/span/span[1]/button/div/span')
                takiptenCikButton1.click()
                self.tarayici.implicitly_wait(10)
                takiptenCikButton2 = self.tarayici.find_element_by_xpath(
                    '/html/body/div[4]/div/div/div/div[3]/button[1]')
                if takiptenCikButton2.text == "Unfollow":
                    takiptenCikButton2.click()
                    self.tarayici.implicitly_wait(10)
                    print(kullaniciAdi + " Unfollowed.")
            except:
                print(kullaniciAdi + "An issue occurred while unfollowing!")
        else:
            print("Please log in with an account before attempting to unfollow someone!")

In both of these functions, we have a common check with if to verify if any account has been logged in. Then we start catching errors with try and except, and then go to the profile of the person to follow or unfollow using the username.
For the follow part, we get the xpath position of the follow button and then if it says "Follow" we make it click the follow button, if it doesn't say "Follow" we print that you're already following.

For unfollowing, first, it clicks the button that appears before unfollow, then gets the position for the unfollow part with xpath and clicks the unfollow button.

Unfollow

Let's Write the Profile Analysis Function

 def ProfilAnaliz(self, kullaniciAdi):
        try:
            self.tarayici.get(self.url + kullaniciAdi)
            self.tarayici.implicitly_wait(10)
            gonderiSayisi = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/ul/li[1]/a/span')
            takipciSayisi = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/ul/li[2]/a/span')
            takipEdilenSayisi = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/ul/li[3]/a/span')
            kullaniciIsim = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/div[2]/h1')
            kullaniciBio = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/div[2]/span')
            kullaniciURL = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/div[2]/a')
            print("Account : " + kullaniciAdi + "\nName : " + kullaniciIsim.text + "\nBio : " + kullaniciBio.text + "\nURL : " + kullaniciURL.text +
                  "\nNumber of posts : " + gonderiSayisi.text + "\nNumber of followers : " + takipciSayisi.text + "\nNumber followed : " + takipEdilenSayisi.text)
        except:
            print(kullaniciAdi +
                  " An issue occurred while analyzing the profile!")

A function we wrote to fetch information like any user's number of posts. Again, with xpath, we copy the locations of where these pieces of information appear and with selenium fetch and print the displayed data. 

Checking if the Account is Private

def HesapGizlimi(self, kullaniciAdi):
        try:
            self.tarayici.get(self.url + kullaniciAdi)
            self.tarayici.implicitly_wait(10)
            hesapGizlimi = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/div/article/div/div/h2')
            if hesapGizlimi.text == "This Account is Private":
                return True
            else:
                return False
        except NoSuchElementException:
            return False
        else:
            print("An issue occurred while checking if the account is private!")

Selenium generally lets us get text using address selection tools like xpath, and we use these fetched texts for whatever purpose we want. In the future, to view the followers of any account or analyze who doesn't follow you back, the profile must be public — that's why we check if the account is public or private by looking for the private profile message.

Let's Write the Function Showing Followers and Following


Yes, everything was quite simple up to this point. Actually, from here, it is also quite simple, but the process we will do here is a little more laborious compared to earlier steps. Viewing followers and those you follow are exactly the same, so I will explain via the followers.

Our code to find followers


  def TakipEdenleriGoster(self, kullaniciAdi, gosterGizle = False):
        if self.HesapGizlimi(kullaniciAdi):
            print("Can't see followers because the account is private!")
        else:
                self.tarayici.get(self.url + kullaniciAdi)
                self.tarayici.implicitly_wait(10)
                takipEdenlerLink = self.tarayici.find_element_by_xpath(
                "//*[@id='react-root']/section/main/div/header/section/ul/li[2]/a").click()
                self.tarayici.implicitly_wait(10)
                pencere = self.tarayici.find_element_by_css_selector("div[role=dialog] ul")
                takipEdenSayac = len(pencere.find_elements_by_css_selector("li"))
                print("You currently have "+ str(takipEdenSayac) +" followers.")

                self.action = webdriver.ActionChains(self.tarayici)
                pencere.click()
                
                while True:
                    self.action.key_down(Keys.END).key_up(Keys.SPACE).perform()
                    sleep(5)                    
                    yeniSayac = len(pencere.find_elements_by_css_selector("li"))

                    if takipEdenSayac != yeniSayac:
                        takipEdenSayac = yeniSayac
                        print("Total followers " + str(yeniSayac))
                        self.tarayici.implicitly_wait(15)
                    else: 
                        break                                      
                    
                takipciler = pencere.find_elements_by_css_selector("li")

                for akun in takipciler:
                    link = hesap.find_element_by_css_selector("a").get_attribute("href")
                    self.tumTakipciler.append(link)
                    if gosterGizle:
                        print(link)

In this function, we added a variable named gosterGizle for the future, to prevent printing followers, following, and non-followers all at once when showing non-followers. Because the future function that finds non-followers needs to be written after this one.

First, we check if the analyzed account is private, and if not, we open their profile in the browser, then click on the followers. After clicking followers, we scroll down to the end and transfer the names to an array.
If gosterGizle is true, it prints the follower names to the screen.

The different part here compared to other parts is "action.key_down(Keys.END)", which allows the page to scroll to the very bottom.
".key_up(Keys.SPACE)" is to go up one space unit after scrolling, to prevent the page from getting stuck.

Code for finding the ones you follow

 def TakipEttikleriniGoster(self, kullaniciAdi, gosterGizle = False):
        if self.HesapGizlimi(kullaniciAdi):
            print("Can't see following because the account is private!")
        else:
            self.tarayici.get(self.url + kullaniciAdi)
            self.tarayici.implicitly_wait(10)
            takipEttikleriLink = self.tarayici.find_element_by_xpath(
            "//*[@id='react-root']/section/main/div/header/section/ul/li[3]/a").click()
            self.tarayici.implicitly_wait(10)
            pencere = self.tarayici.find_element_by_css_selector("div[role=dialog] ul")
            takipEttikleriSayac = len(pencere.find_elements_by_css_selector("li"))
            print("You are currently following "+ str(takipEttikleriSayac) +" people.")

            self.action = webdriver.ActionChains(self.tarayici)
            pencere.click()

            while True:
                self.action.key_down(Keys.END).key_up(Keys.SPACE).perform()
                sleep(5)                    
                yeniSayac = len(pencere.find_elements_by_css_selector("li"))

                if takipEttikleriSayac != yeniSayac:
                    takipEttikleriSayac = yeniSayac
                    print("Total following " + str(yeniSayac))
                    self.tarayici.implicitly_wait(15)
                else: 
                    break                                      
                    
            takipedilenler = pencere.find_elements_by_css_selector("li")

            for hesap in takipedilenler:
                link = hesap.find_element_by_css_selector("a").get_attribute("href")
                self.tumTakipEdilenler.append(link)
                if gosterGizle:
                    print(link)

Finding Non-Followers

 def TakipEtmeyenler(self):
        if len(self.tumTakipEdilenler) != 0 and len(self.tumTakipciler) != 0:
            print("Non-Followers")
            for takipEdilenler in self.tumTakipEdilenler:
                if takipEdilenler not in self.tumTakipciler:
                    print(takipEdilenler)   
        else:
            print("Please show the followers and following first!")

To find the non-followers, after getting the following and followers, the difference of following followers is taken, and thus, after removing those who follow you from those you follow, the remaining ones are non-followers.

So how are we going to use this class we wrote?

Ins = Instagram(tarayiciDriverKonum, "https://instagram.com/", "username", "password")
Ins.TarayiciAc()
Ins.ProfilAnaliz("urhob")
Ins.GirisYap("https://www.instagram.com/accounts/login/")
Ins.TakipEdenleriGoster("urhoba",True)
Ins.TakipEttikleriniGoster("urhoba",True)
Ins.TakipEtmeyenler()
Ins.TakiptenCik("urhoba")
Ins.TakipEt("urhoba")
Ins.TarayiciKapat()

We will create a variable, then pull our class, enter the necessary information, and write the functions we want to use. There are a few conditions to pay attention to when writing the functions we want to use:

You must first call the login function in order to follow or unfollow someone.

To find non-followers of someone, you must first call the followers and following functions, then the non-followers function.

Note: If the console closes immediately after the operations are finished, add "print(input())" at the end of your code. That way, it will wait until you press any key in the console and send.

All the Code We Used

from time import sleep ## Library needed to perform second-based delays
from selenium.common.exceptions import NoSuchElementException ## Library required for Selenium error handling
from selenium.webdriver.common.keys import Keys ## Library that allows us to simulate the keyboard with Selenium
from selenium import webdriver ## Selenium web driver library
tarayiciDriverKonum = "C:\\Users\\ahmet\\Desktop\\Python\\Selenium\\geckodriver.exe" ## Web driver location

"""
Features

Follow
Unfollow
Followers
Following
Non-Followers
Profile Analysis

"""


class Instagram:
    def __init__(self, tarayiciKonum, url="https://www.urhoba.net", kullaniciAdi="username", sifre="password"):
        self.tarayici = webdriver.Firefox(executable_path=tarayiciDriverKonum)
        self.url = url
        self.girisurl = "https://www.instagram.com/accounts/login/"
        self.kullaniciAdi = kullaniciAdi
        self.sifre = sifre
        self.girisYapilmismi = False
        self.tumTakipciler = []
        self.tumTakipEdilenler = []

    def TarayiciAc(self):
        try:            
            self.tarayici.get(self.url)
            print("Browser opened.")
            self.tarayici.implicitly_wait(10)
        except:
            print("A problem occurred while opening the browser!")

    def TarayiciKapat(self):
        self.tarayici.close()

    def GirisYap(self, url):
        try:
            self.tarayici.get(url)
            self.tarayici.implicitly_wait(10)
            kullaniciAdiInput = self.tarayici.find_element_by_css_selector(
                "input[name='username']")
            sifreInput = self.tarayici.find_element_by_css_selector(
                "input[name='password']")
            girisButon = self.tarayici.find_element_by_xpath(
                "//button[@type='submit']")
            kullaniciAdiInput.send_keys(self.kullaniciAdi)
            sifreInput.send_keys(self.sifre)
            girisButon.click()
            print("Successfully logged into the account.")
            self.girisYapilmismi = True
            sleep(10)

        except:
            print("A problem occurred while logging into the account!")

    def TakipEt(self, kullaniciAdi):
        if self.girisYapilmismi == True:
            try:
                self.tarayici.get(self.url + kullaniciAdi)
                self.tarayici.implicitly_wait(10)
                takipEtButton = self.tarayici.find_element_by_css_selector(
                    'button')
                if takipEtButton.text == "Follow":
                    takipEtButton.click()
                    print(kullaniciAdi + " Followed")
                else:
                    print(kullaniciAdi + " Already following..")

            except:
                print(kullaniciAdi + " An error occurred while following!")
        else:
            print("Please log in with an account before following someone!")

    def TakiptenCik(self, kullaniciAdi):
        if self.girisYapilmismi == True:
            try:
                self.tarayici.get(self.url + kullaniciAdi)
                self.tarayici.implicitly_wait(10)
                takiptenCikButton1 = self.tarayici.find_element_by_xpath(
                    '//*[@id="react-root"]/section/main/div/header/section/div[1]/div[1]/div/div[2]/div/span/span[1]/button/div/span')
                takiptenCikButton1.click()
                self.tarayici.implicitly_wait(10)
                takiptenCikButton2 = self.tarayici.find_element_by_xpath(
                    '/html/body/div[4]/div/div/div/div[3]/button[1]')
                if takiptenCikButton2.text == "Unfollow":
                    takiptenCikButton2.click()
                    self.tarayici.implicitly_wait(10)
                    print(kullaniciAdi + " Unfollowed.")
            except:
                print(kullaniciAdi + "An issue occurred while unfollowing!")
        else:
            print("Please log in with an account before attempting to unfollow someone!")

    def ProfilAnaliz(self, kullaniciAdi):
        try:
            self.tarayici.get(self.url + kullaniciAdi)
            self.tarayici.implicitly_wait(10)
            gonderiSayisi = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/ul/li[1]/a/span')
            takipciSayisi = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/ul/li[2]/a/span')
            takipEdilenSayisi = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/ul/li[3]/a/span')
            kullaniciIsim = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/div[2]/h1')
            kullaniciBio = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/div[2]/span')
            kullaniciURL = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/div[2]/a')
            print("Account : " + kullaniciAdi + "\nName : " + kullaniciIsim.text + "\nBio : " + kullaniciBio.text + "\nURL : " + kullaniciURL.text +
                  "\nNumber of posts : " + gonderiSayisi.text + "\nNumber of followers : " + takipciSayisi.text + "\nNumber followed : " + takipEdilenSayisi.text)
        except:
            print(kullaniciAdi +
                  " An issue occurred while analyzing the profile!")

    def HesapGizlimi(self, kullaniciAdi):
        try:
            self.tarayici.get(self.url + kullaniciAdi)
            self.tarayici.implicitly_wait(10)
            hesapGizlimi = self.tarayici.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/div/article/div/div/h2')
            if hesapGizlimi.text == "This Account is Private":
                return True
            else:
                return False
        except NoSuchElementException:
            return False
        else:
            print("An issue occurred while checking if the account is private!")

    def TakipEdenleriGoster(self, kullaniciAdi, gosterGizle = False):
        if self.HesapGizlimi(kullaniciAdi):
            print("Can't see followers because the account is private!")
        else:
                self.tarayici.get(self.url + kullaniciAdi)
                self.tarayici.implicitly_wait(10)
                takipEdenlerLink = self.tarayici.find_element_by_xpath(
                "//*[@id='react-root']/section/main/div/header/section/ul/li[2]/a").click()
                self.tarayici.implicitly_wait(10)
                pencere = self.tarayici.find_element_by_css_selector("div[role=dialog] ul")
                takipEdenSayac = len(pencere.find_elements_by_css_selector("li"))
                print("You currently have "+ str(takipEdenSayac) +" followers.")

                self.action = webdriver.ActionChains(self.tarayici)
                pencere.click()
                
                while True:
                    self.action.key_down(Keys.END).key_up(Keys.SPACE).perform()
                    sleep(5)                    
                    yeniSayac = len(pencere.find_elements_by_css_selector("li"))

                    if takipEdenSayac != yeniSayac:
                        takipEdenSayac = yeniSayac
                        print("Total followers " + str(yeniSayac))
                        self.tarayici.implicitly_wait(15)
                    else: 
                        break                                      
                    
                takipciler = pencere.find_elements_by_css_selector("li")

                for hesap in takipciler:
                    link = hesap.find_element_by_css_selector("a").get_attribute("href")
                    self.tumTakipciler.append(link)
                    if gosterGizle:
                        print(link)

    def TakipEttikleriniGoster(self, kullaniciAdi, gosterGizle = False):
        if self.HesapGizlimi(kullaniciAdi):
            print("Can't see following because the account is private!")
        else:
            self.tarayici.get(self.url + kullaniciAdi)
            self.tarayici.implicitly_wait(10)
            takipEttikleriLink = self.tarayici.find_element_by_xpath(
            "//*[@id='react-root']/section/main/div/header/section/ul/li[3]/a").click()
            self.tarayici.implicitly_wait(10)
            pencere = self.tarayici.find_element_by_css_selector("div[role=dialog] ul")
            takipEttikleriSayac = len(pencere.find_elements_by_css_selector("li"))
            print("You are currently following "+ str(takipEttikleriSayac) +" people.")

            self.action = webdriver.ActionChains(self.tarayici)
            pencere.click()

            while True:
                self.action.key_down(Keys.END).key_up(Keys.SPACE).perform()
                sleep(5)                    
                yeniSayac = len(pencere.find_elements_by_css_selector("li"))

                if takipEttikleriSayac != yeniSayac:
                    takipEttikleriSayac = yeniSayac
                    print("Total following " + str(yeniSayac))
                    self.tarayici.implicitly_wait(15)
                else: 
                    break                                      
                    
            takipedilenler = pencere.find_elements_by_css_selector("li")

            for hesap in takipedilenler:
                link = hesap.find_element_by_css_selector("a").get_attribute("href")
                self.tumTakipEdilenler.append(link)
                if gosterGizle:
                    print(link)

    def TakipEtmeyenler(self):
        if len(self.tumTakipEdilenler) != 0 and len(self.tumTakipciler) != 0:
            print("Non-Followers")
            for takipEdilenler in self.tumTakipEdilenler:
                if takipEdilenler not in self.tumTakipciler:
                    print(takipEdilenler)   
        else:
            print("Please show the followers and following first!")


Ins = Instagram(tarayiciDriverKonum, "https://instagram.com/", "username", "password")
Ins.TarayiciAc()
Ins.ProfilAnaliz("urhob")
Ins.GirisYap("https://www.instagram.com/accounts/login/")
Ins.TakipEdenleriGoster("urhoba",True)
Ins.TakipEttikleriniGoster("urhoba",True)
Ins.TakipEtmeyenler()
Ins.TakiptenCik("urhoba")
Ins.TakipEt("urhoba")
Ins.TarayiciKapat()


print(input())

You can check out the source code of this project via GitHub.

Output