Skip to content

Instantly share code, notes, and snippets.

@SadSack963
Created June 21, 2024 22:09
Show Gist options
  • Save SadSack963/25470daf6bc28677dec0e4b200ec9bbf to your computer and use it in GitHub Desktop.
Save SadSack963/25470daf6bc28677dec0e4b200ec9bbf to your computer and use it in GitHub Desktop.
Day 52 Instagram Follower Bot
import os
from dotenv import load_dotenv
from selenium import webdriver, common
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from time import sleep
import random
load_dotenv("D:/Python/EnvironmentVariables/.env")
USERNAME = os.getenv("Username_Instagram")
PASSWORD = os.getenv("Password_Instagram")
BASE_URL = "https://www.instagram.com/"
INTERESTING_ACCOUNT = "buzzfeedtasty" # "pythonclubb"
class InstaFollower:
def __init__(self):
options = Options()
options.add_experimental_option("detach", True)
# ==========================================================================================
# Use a Chrome profile to look more like a human :)
# Specify path to Chrome User Data Folder
options.add_argument(r'--user-data-dir=C:\Users\John\AppData\Local\Google\Chrome\User Data')
# This creates the new user I have called SeleniumProfile
options.add_argument('--profile-directory=SeleniumProfile')
# NOTE. Since we are using a profile, if the script crashes or is interrupted, then we remain logged in.
# When the script opens the URL again, we will still be logged in and at the page your were previously on.
# Make sure you log out before starting the script again to have a clean run!
# ==========================================================================================
self.driver = webdriver.Chrome(options=options)
self.xpath = "xpath_1" # Default XPATH used for the "Follow" buttons
def find_element(self, xpath, comment="", retries=1):
print(comment)
print(f"Finding {xpath}")
while retries:
retries -= 1 # Allows for slow page loading
try:
element = self.driver.find_element(by=By.XPATH, value=xpath)
print("Element found.")
return element
except common.exceptions.ElementNotInteractableException:
print("Element Not Interactable Exception")
except common.exceptions.NoSuchElementException:
print("No Such Element Exception")
finally:
sleep(1)
def login(self, url):
self.driver.get(url)
# Click modal button to allow essential cookies
# Only required the first time if you use a profile
element = self.find_element(
xpath='/html/body/div[2]/div/div/div[2]/div/div/div[1]/div/div[2]/div/div/div/div/div[2]/div/button[1]',
comment='Click modal button to allow essential cookies',
)
if element:
element.click()
# Input Username / Password and Login
element = self.find_element(
xpath='//*[@id="loginForm"]/div/div[1]/div/label/input',
comment='Input Username / Password and Login',
)
if element:
element.send_keys(
USERNAME + Keys.TAB +
PASSWORD + Keys.ENTER
)
# Click modal button again to allow essential cookies
# Only required the first time if you use a profile
# We must use the Full XPATH - the id changes every time the page is loaded
element = self.find_element(
xpath='/html/body/div[2]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div/div/div[2]/div/div/div[3]/div[3]/div/div[1]/div',
comment='Click modal button again to allow essential cookies',
)
if element:
element.click()
# Don't save passwords
element = self.find_element(
xpath='//*[@id="react-root"]/section/main/div/div/div/div/button',
comment='Don\'t save passwords',
)
if element:
element.click()
# Dismiss Notifications
element = self.find_element(
# xpath='/html/body/div[4]/div/div/div/div[3]/button[2]'
xpath='/html/body/div[3]/div[1]/div/div[2]/div/div/div/div/div[2]/div/div/div[3]/button[2]',
comment='Dismiss Notifications',
)
if element:
element.click()
def find_followers(self, url):
self.driver.get(url)
sleep(5) # Wait for page to load
# Click on the "followers" text link to bring up the Followers Modal Pop-up
element = self.find_element(
xpath='/html/body/div[2]/div/div/div[2]/div/div/div[1]/div[2]/div/div[2]/section/main/div/header/section[3]/ul/li[2]/div/a',
comment='Followers Modal Pop-up',
)
if element:
element.click()
sleep(5) # Allow the modal to load
# Find the first "Follow" button in the modal area
xpath_1 = "/html/body/div[6]/div[2]/div/div/div[1]/div/div[2]/div/div/div/div/div[2]/div/div/div[2]/div[2]/div/div[1]/div/div/div/div[3]/div/button"
xpath_2 = "/html/body/div[6]/div[2]/div/div/div[1]/div/div[2]/div/div/div/div/div[2]/div/div/div[3]/div[1]/div/div[1]/div/div/div/div[3]/div/button"
element = self.find_element(
xpath=xpath_1,
comment='Find the first "Follow" button in the modal area - xpath_1',
)
self.xpath = "xpath_1"
if not element:
element = self.find_element(
xpath=xpath_2,
comment='Find the first "Follow" button in the modal area - xpath_2',
)
self.xpath = "xpath_2"
# Make the first few followers visible (scroll the modal contents down)
if element:
for _ in range(2):
element.send_keys(Keys.END)
sleep(2) # Allow the list to update
def follow(self):
count = 1
while True:
if self.xpath == "xpath_1":
xpath = f"/html/body/div[6]/div[2]/div/div/div[1]/div/div[2]/div/div/div/div/div[2]/div/div/div[2]/div[2]/div/div[{count}]/div/div/div/div[3]/div/button"
else:
xpath = f"/html/body/div[6]/div[2]/div/div/div[1]/div/div[2]/div/div/div/div/div[2]/div/div/div[3]/div[1]/div/div[{count}]/div/div/div/div[3]/div/button"
element = self.find_element(
xpath=xpath,
comment=f'Find "Follow" button {count} in the modal area',
)
if not element:
break
if element.text == "Follow":
print(f"{count} followed")
# element.click()
sleep(random.randint(1, 4))
count += 1
# if count > 3: # <----- Limit actually following for testing purposes
# break
# TESTED Working - 20/06/2024
# ===========================
insta_follower = InstaFollower()
if insta_follower.driver is None:
print('Cannot load webdriver.')
quit()
insta_follower.login(url=BASE_URL)
insta_follower.find_followers(url=BASE_URL + INTERESTING_ACCOUNT)
insta_follower.follow()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment