Finding Unfollowers on Instagram with Selenium

08 September 2023

1. Introduction

Instead of giving our login information to 3rd party applications to find the unfollowers on Instagram, we can perform the analysis we want using the web scraping method with Selenium. As a first step, let's import the necessary libraries.

import os\nimport random\nimport time\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.service import Service\nfrom selenium.webdriver.common.by import By

2. The Instagram Class

The Instagram class contains the methods and attributes we will use for follower analysis. In the class's constructor, Firefox browser is initializing for Selenium. It is important to set a real user agent when initializing the Firefox browser so that Instagram does not notice that we are a robot. If you want to use the Firefox Driver, you can download it from here, create a folder called FirefoxDriver in the same place as your Python file, and put the geckodriver in it.

class Instagram:\n\tdef __init__(self, username: str, password: str):\n\t\toptions = webdriver.FirefoxOptions()\n\t\toptions.set_preference("general.useragent.override",\n\t\t\t\t\t"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0")\n\t\tservice = Service(executable_path="FirefoxDriver/geckodriver")\n\t\tself.__browser = webdriver.Firefox(options=options, service=service)\n\t\tself.__url = "https://www.instagram.com/"\n\t\tself.__loginUrl = "https://www.instagram.com/"\n\t\tself.__username = username\n\t\tself.__password = password\n\t\tself.followers = []\n\t\tself.followings = []\n\t@staticmethod\n\tdef __sleep_randomly(minimum_interval: int = 1):\n\t\tpass\n\tdef __write_file(self, items: list):\n\t\tpass\n\tdef login(self):\n\t\tpass\n\tdef __enter_verification_code(self):\n\t\tpass\n\tdef pick_nonfollowers(self, profile_url: str):\n\t\tpass\n\tdef __get_followings(self, profile_url: str):\n\t\tpass\n\tdef __get_followers(self, profile_url: str):\n\t\tpass\n\tdef __pick_items(self, mode) -> list:\n\t\tpass

3. Utility Methods

The sleep_randomly method is used to wait for a period of time in range of [minimum_interval, minimum_interval + 1) seconds. Again, it is necessary to add some randomness so that it is not understood that we are a robot.

@staticmethod\ndef __sleep_randomly(minimum_interval: int = 1):\n\tinterval = (random.random() + minimum_interval)\n\ttime.sleep(interval)

The write_file method is used to write the data we collect to the nonfollowers.txt file.

def __write_file(self, items: list):\n\tfile = open("nonfollowers.txt", "w+")\n\tfile.write("Followings:" + os.linesep)\n\tfor item in self.followings:\n\t\tfile.write(item + os.linesep)\n\tfile.write("Followers:" + os.linesep)\n\tfor item in self.followers:\n\t\tfile.write(item + os.linesep)\n\tfile.write("Nonfollowers:" + os.linesep)\n\tfor item in items:\n\t\tfile.write(item + os.linesep)

4. Login

The login method is used to enter the username and password in the class attributes into the required input fields and click the login button.

def login(self):\n\tself.__browser.get(self.__loginUrl)\n\tself.__sleep_randomly(15)\n\tusername_input = self.__browser.find_element(by=By.CSS_SELECTOR, value="input[name=username]")\n\tpassword_input = self.__browser.find_element(by=By.CSS_SELECTOR, value="input[name=password]")\n\tlogin_button = self.__browser.find_element(by=By.CSS_SELECTOR, value="button[type=submit]")\n\tusername_input.send_keys(self.__username)\n\tself.__sleep_randomly()\n\tpassword_input.send_keys(self.__password)\n\tself.__sleep_randomly()\n\tlogin_button.click()\n\tself.__sleep_randomly(20)\n\tself.__enter_verification_code()
Username input element
Password input element
Login button

5. 2 Factor Authentication

If two-step verification is enabled on your account, this method is used to send the 2FA code which is entered from the console into the input field and submit it .

def __enter_verification_code(self):\n\tverification_code_input = self.__browser.find_element(by=By.CSS_SELECTOR,\n\t\t\t\t\t\t\t\t\t value="input[name=verificationCode]")\n\tsubmit_button = self.__browser.find_element(by=By.CSS_SELECTOR, value="button[type=button]")\n\tverification_code = input("Enter 2FA code: ")\n\tverification_code_input.send_keys(verification_code)\n\tself.__sleep_randomly()\n\tsubmit_button.click()\n\tself.__sleep_randomly(20)
Verification code input element
Verification code send button

6. Finding Unfollowers

The pick_nonfollowers method first collects the accounts we follow and then our followers and finds out which accounts we follow are not in our follower list.

def pick_nonfollowers(self, profile_url: str):\n\tnonfollowers = []\n\tself.__get_followings(profile_url)\n\tself.__get_followers(profile_url)\n\tfor item in self.followings:\n\t\tif item not in self.followers:\n\t\t\tnonfollowers.append(item)\n\t\t\tprint(item)\n\tself.__write_file(nonfollowers)
def __get_followings(self, profile_url: str):\n\tself.__browser.get(profile_url + "/following/")\n\tself.__sleep_randomly(20)\n\tself.followings = self.__pick_items("followings")
def __get_followers(self, profile_url: str):\n\tself.__browser.get(profile_url + "/followers/")\n\tself.__sleep_randomly(20)\n\tself.followers = self.__pick_items("followers")
The pick_items method, which is the most important method of the program, collects the addresses of the profiles from the opened following or follower list. The element with overflow-y: scroll style is scrolled down until no new user is added.
def __pick_items(self, mode) -> list:\n\tlinks = []\n\telements = []\n\twhile True:\n\t\telements = self.__browser.find_elements(by=By.CSS_SELECTOR, value="div[role=dialog] a[href]")\n\t\telement_count = len(elements)\n\t\tif mode == "followings":\n\t\t\tself.__browser.execute_script(\n\t\t\t"document.querySelectorAll('div[role=dialog]')[1].childNodes[0].childNodes["\n\t\t\t"0].childNodes[3].scrollTop += 1500")\n\t\telse:\n\t\t\tself.__browser.execute_script(\n\t\t\t"document.querySelectorAll('div[role=dialog]')[1].childNodes[0].childNodes["\n\t\t\t"0].childNodes[2].scrollTop += 1500")\n\t\tself.__sleep_randomly(5)\n\t\telements = self.__browser.find_elements(by=By.CSS_SELECTOR, value="div[role=dialog] a[href]")\n\t\tif len(elements) == element_count:\n\t\t\tbreak\n\tfor element in elements:\n\t\tlinks.append(element.get_attribute("href"))\n\treturn list(set(links))
Selected element to scroll followings
Selected element to scroll followers
Selected element for user profile link

7. Usage

To run the program, it is enough to create an instance of the Instagram class with your username and password, run the login method, and then run the pick_nonfollowers method with the profile address to analyze the unfollowers.

if __name__ == '__main__':\n\tinstagram = Instagram("mert_ozgen", "enter_your_password_here")\n\tinstagram.login()\n\tinstagram.pick_nonfollowers("https://www.instagram.com/mert_ozgen")