def unfollow(self, track: str, person: str, button: Union[WebElement, None]): """ Unfollow a user either from the profile or post page or dialog box """ # list of available tracks to unfollow in: ["profile", "post" "dialog] # check action availability if self.quota_supervisor.jump_unfollow(): return False, "jumped" if track in ["profile", "post"]: # Method of unfollowing from a user's profile page or post page if track == "profile": user_link = "https://www.instagram.com/{}/".format(person) if not check_if_in_correct_page(self, user_link): nf_go_to_user_page(self, person) for _ in range(3): following_status, follow_button = get_following_status( self, track, person) if following_status in ["Following", "Requested"]: nf_click_center_of_element(self, follow_button) sleep(3) confirm_unfollow(self) sleep(1) following_status, follow_button = get_following_status( self, track, person) if following_status in ["Follow", "Follow Back"]: break elif following_status in ["Follow", "Follow Back"]: self.logger.info( "Already unfollowed '{}' or is a private user that " "rejected your request".format(person)) return False, "already unfollowed" elif following_status == "Unblock": self.logger.warning( "Couldn't unfollow '{}', is blocked".format(person)) return False, "blocked" elif following_status == "UNAVAILABLE": self.logger.warning( "Couldn't unfollow '{}', is unavailable".format(person)) return False, "unavailable" elif following_status is None: sirens_wailing, emergency_state = emergency_exit(self) if sirens_wailing is True: return False, emergency_state else: self.logger.warning( "Couldn't unfollow '{}', unexpected failure".format( person)) return False, "unexpected failure" elif track == "dialog" and button is not None: # Method of unfollowing from a dialog box nf_click_center_of_element(self, button) sleep(4) confirm_unfollow(self) self.logger.info("Unfollowed '{}'".format(person)) self.quota_supervisor.add_unfollow() user, _ = InstaUser.objects.get_or_create(username=person) self.instauser.remove_following(user) return True, "success"
def get_following_status( self, track: str, person: str ) -> Tuple[str, Union[WebElement, None]]: # following_status, follow_button """ Verify if you are following the user in the loaded page """ if person == self.username: return "OWNER", None if track == "profile": user_link = "https://www.instagram.com/{}/".format(person) if not check_if_in_correct_page(self, user_link): nf_go_to_user_page(self, person) # check if the page is available valid_page = is_page_available(self) if not valid_page: self.logger.error( "Couldn't access the profile page of '{}', might have changed the" " username".format(person)) return "UNAVAILABLE", None # wait until the follow button is located and visible, then get it try: self.browser.find_element_by_xpath(XP.FOLLOW_BUTTON_XP) except NoSuchElementException: try: follow_button = self.browser.find_element_by_xpath( XP.FOLLOW_SPAN_XP_FOLLOWING) return "Following", follow_button except: return "UNAVAILABLE", None follow_button = explicit_wait(self, "VOEL", [XP.FOLLOW_BUTTON_XP, "XPath"], 7, False) if not follow_button: self.browser.execute_script(JS.RELOAD) self.quota_supervisor.add_server_call() follow_button = explicit_wait(self, "VOEL", [XP.FOLLOW_BUTTON_XP, "XPath"], 7, False) if not follow_button: # cannot find the any of the expected buttons self.logger.error( "Unable to detect the following status of '{}'".format(person)) return "UNAVAILABLE", None # get follow status following_status = follow_button.text return following_status, follow_button
def interact_with_post( self, link: str, user_validated: bool = False, ) -> Tuple[str, Interactions]: # msg, post_interactions interactions = Interactions() try: self.logger.debug("Checking post") if verify_liked_image(self): interactions.already_liked += 1 return "already liked", interactions else: inappropriate, user_name, is_video, image_links, reason, scope = check_post( self, link) if not inappropriate: sleep(1) if user_validated: valid = True details = "User already validated" else: self.logger.debug("Validating user") valid, details = nf_validate_user_call( self, user_name, self.quota_supervisor.LIKE, link) self.logger.info("'{}' is{} a valid user{}".format( user_name, "" if valid else " not", "" if valid else ": {}".format(details))) if not valid: interactions.not_valid_users += 1 return "Not valid user", interactions # try to like self.logger.debug("Liking post") sleep(1) like_state, msg = like_image(self, user_name) if like_state is True: interactions.liked_img += 1 # reset jump counter after a successful like self.jumps.likes = 0 checked_img = True temp_comments = [] commenting = random.randint( 0, 100) <= self.settings.comment_percentage following = random.randint( 0, 100) <= self.settings.follow_percentage interact = random.randint( 0, 100) <= self.settings.user_interact_percentage if self.settings.use_image_analysis and commenting: try: checked_img, temp_comments, image_analysis_tags = self.ImgAn.image_analysis( image_links, logger=self.logger) except Exception as err: self.logger.error( "Image analysis error: {}".format(err)) # comment if (self.settings.do_comment and checked_img and commenting and user_name not in self.settings.dont_include): comments = self.settings.comments comments.append(self.settings.video_comments if is_video else self.settings.photo_comments) # TODO: util_comment # success = process_comments(self, user_name, comments, temp_comments) # if success: # interactions.commented += 1 else: if self.settings.do_comment: self.logger.info("Not commented") sleep(1) # follow or interact only of user not previously validated to avoid recursion if not user_validated: # follow if (self.settings.do_follow and checked_img and following and user_name not in self.settings.dont_include and not is_follow_restricted(self, user_name)): self.logger.debug("Following user") follow_state, msg = follow_user( self, "post", user_name, None) if follow_state is True: interactions.followed += 1 elif msg == "already followed": interactions.already_followed += 1 sleep(1) # interact if self.settings.do_like and interact: self.logger.info( "Interacting with user '{}'".format(user_name)) user_link = "https://www.instagram.com/{}/".format( user_name) if not check_if_in_correct_page(self, user_link): nf_go_from_post_to_profile(self, user_name) interactions += like_loop( self, "Interact with user '{}'".format(user_name), user_link, self.settings.user_interact_amount, True) elif msg == "already liked": interactions.already_liked += 1 return msg, interactions elif msg == "block on likes": return msg, interactions elif msg == "jumped": # will break the loop after certain consecutive jumps self.jumps.likes += 1 return "success", interactions else: self.logger.info("Image not liked: {}\n{}".format(reason, scope)) interactions.inap_img += 1 return "inap_img", interactions except NoSuchElementException as err: self.logger.error("Invalid Page: {}".format(err)) return "Invalid Page", interactions except Exception as err: self.logger.error("Unexpected Exception: {}".format(err)) return "Unexpected Exception", interactions
def db_store_comments(self, posts: List[Post], post_link: str): """Stores all comments of open post then goes back to post page""" try: comments_button = self.browser.find_elements_by_xpath( '//article//div[2]/div[1]//a[contains(@href,"comments")]') if comments_button: nf_scroll_into_view(self, comments_button[0]) nf_click_center_of_element(self, comments_button[0]) sleep(2) comments_link = post_link + 'comments/' if not check_if_in_correct_page(self, comments_link): self.logger.error( "Failed to go to comments page, navigating there") # TODO: retry to get there naturally web_address_navigator(self.browser, comments_link) more_comments = self.browser.find_elements_by_xpath( '//span[@aria-label="Load more comments"]') counter = 1 while more_comments and counter <= 10: self.logger.info("Loading comments ({}/10)...".format(counter)) nf_scroll_into_view(self, more_comments[0]) self.browser.execute_script("arguments[0].click();", more_comments[0]) more_comments = self.browser.find_elements_by_xpath( '//span[@aria-label="Load more comments"]') counter += 1 comments = self.browser.find_elements_by_xpath( '/html/body/div[1]/section/main/div/ul/ul[@class="Mr508"]') for comment in comments: inner_container = comment.find_element_by_xpath( './/div[@class="C4VMK"]') username = inner_container.find_element_by_xpath( './/h3/div/a').text text, _ = deform_emojis( inner_container.find_element_by_xpath('.//span').text) post_date = inner_container.find_element_by_xpath( './/time').get_attribute('datetime') post_date = datetime.fromisoformat(post_date[:-1]) user = db_get_or_create_user(self, username) self.db.session.add(user) self.db.session.commit() for post in posts: comment = Comment( date_posted=post_date, text=text, user=user, post=post, ) self.db.session.add(comment) self.db.session.commit() else: self.logger.error("No comments found") except SQLAlchemyError: self.db.session.rollback() raise finally: self.db.session.commit() nf_find_and_press_back(self, post_link)
def follow_user_follow( self, follow: str, usernames: List[str], amount: int = 10, randomize: bool = False ): if self.aborting: return self valid = {"followers", "followings"} if follow not in valid: raise ValueError( "nf_follow_user_follow: follow must be one of %r." % valid) self.logger.info("Starting to follow user {}".format(follow)) for index, username in enumerate(usernames): state = { 'liked_img': 0, 'already_liked': 0, 'inap_img': 0, 'commented': 0, 'followed': 0, 'not_valid_users': 0, } self.logger.info("User [{}/{}]".format(index + 1, len(usernames))) self.logger.info("--> {}".format(username.encode("utf-8"))) nf_go_to_user_page(self, username) sleep(1) # TODO: get follow count follow_count = 10 actual_amount = amount if follow_count < amount: actual_amount = follow_count self.logger.info("About to go to {} page".format(follow)) nf_go_to_follow_page(self, follow, username) sleep(2) sc_rolled = 0 scroll_nap = 1.5 already_interacted_links = [] random_chance = 50 try: while state['followed'] in range(0, actual_amount): if self.quotient_breach: self.logger.warning( "--> Follow quotient reached its peak!" "\t~leaving Follow-User-Follow_ activity\n" ) break if sc_rolled > 100: self.logger.info("Scrolled too much! ~ sleeping 10 minutes") sleep(600) sc_rolled = 0 users = nf_get_all_users_on_element(self) # Interact with links instead of just storing them for user in users: link = user.get_attribute("href") if link not in already_interacted_links: msg = "" try: self.logger.info("about to scroll to user") sleep(1) nf_scroll_into_view(self, user) self.logger.info("about to click to user") sleep(1) nf_click_center_of_element(self, user) sleep(2) valid = False if ( user.text not in self.dont_include and not follow_restriction( "read", user.text, self.follow_times, self.logger and random.randint(0, 100) <= random_chance ) ): valid, details = nf_validate_user_call(self, user.text) self.logger.info("Valid User: {}, details: {}".format(valid, details)) if valid: self.logger.info("about to follow user") follow_state, msg = follow_user( self.browser, "profile", self.username, user.text, None, self.blacklist, self.logger, self.logfolder, ) if follow_state is True: state['followed'] += 1 self.logger.info("user followed") else: self.logger.info("--> Not following") sleep(1) if random.randint(0, 100) <= self.user_interact_percentage: self.logger.info( "--> User gonna be interacted: '{}'".format( user.text ) ) # disable re-validating user in like_by_users like_by_users( self, [user.text], None, True, ) else: state["not_valid_users"] += 1 finally: sleep(5) user_link = "https://www.instagram.com/{}".format(username) follow_link = "https://www.instagram.com/{}/{}".format(username, follow) nf_find_and_press_back(self, follow_link) sleep(3) if check_if_in_correct_page(self, user_link): nf_go_to_follow_page(self, follow, username) already_interacted_links.append(link) if msg == "block on follow": pass # TODO deal with block on follow break else: # For loop ended means all users in screen has been interacted with scrolled_to_bottom = self.browser.execute_script( "return window.scrollMaxY == window.scrollY" ) if scrolled_to_bottom and randomize and random_chance < 100: random_chance += 25 self.browser.execute_script( "window.scrollTo(0, 0);" ) update_activity(self.browser, state=None) sc_rolled += 1 sleep(scroll_nap) elif scrolled_to_bottom: # already followed all possibles users break # will scroll the screen a bit and reload for i in range(3): self.browser.execute_script( "window.scrollTo(0, document.body.scrollHeight);" ) update_activity(self.browser, state=None) sc_rolled += 1 sleep(scroll_nap) except Exception: raise sleep(4) self.logger.info("User [{}/{}]".format(index + 1, len(usernames))) self.logger.info("Liked: {}".format(state['liked_img'])) self.logger.info("Already Liked: {}".format(state['already_liked'])) self.logger.info("Commented: {}".format(state['commented'])) self.logger.info("Followed: {}".format(state['followed'])) self.logger.info("Inappropriate: {}".format(state['inap_img'])) self.logger.info("Not valid users: {}\n".format(state['not_valid_users'])) self.liked_img += state['liked_img'] self.already_liked += state['already_liked'] self.commented += state['commented'] self.followed += state['followed'] self.inap_img += state['inap_img'] self.not_valid_users += state['not_valid_users'] return self
def follow_by_list(self, follow_list: List[str], users_validated: bool = False): """ Follows users in 'follow_list' :param follow_list: list of usernames to follow :param users_validated: if users are already considered valid to follow them """ if self.aborting: return self interactions = Interactions() # for each username for index, username in enumerate(follow_list): # if aborting or quota was breached or its past time according to settings break the loop if self.aborting or self.quotient_breach or ( self.until_time and datetime.now() > self.until_time): break # if quotient was breached break the loop if self.jumps.check_follows(): self.logger.warning( "Follow quotient reached its peak, leaving Follow by List activity" ) self.jumps.follows = 0 self.quotient_breach = True break self.logger.info("Follow User [{}/{}] - started".format( index + 1, len(follow_list))) user_link = "https://www.instagram.com/{}".format(username) # skip to next in list if the user is follow restricted if is_follow_restricted(self, username): interactions.already_followed += 1 self.logger.info("Account {} already followed {} times".format( username, self.settings.follow_times)) continue # validate user if not considered valid if not users_validated: validation, details = nf_validate_user_call( self, username, self.quota_supervisor.FOLLOW) if not validation: self.logger.info( "--> Not a valid user: {}".format(details)) interactions.not_valid_users += 1 continue # follow user follow_state, msg = follow_user(self, "profile", username) if follow_state is True: interactions.followed += 1 self.logger.debug("user followed") elif msg == "already followed": interactions.already_followed += 1 elif msg == "jumped": # will break the loop after certain consecutive jumps self.jumps.follows += 1 # interact with user if self.settings.do_like and random.randint( 0, 100) <= self.settings.user_interact_percentage: self.logger.info("Interacting with user '{}'".format(username)) if not check_if_in_correct_page(self, user_link): nf_go_from_post_to_profile(self, username) interactions += like_loop( self, "Interact with user '{}'".format(username), user_link, self.settings.user_interact_amount, True) self.logger.info("Follow User [{}/{}] - ended".format( index + 1, len(follow_list))) self.logger.info(str(interactions)) self.interactions += interactions return self
def follow_user_follow(self, relation: str, usernames: List[str], amount: int = 10, randomize: bool = False, random_chance: int = 50): """ Follows 'amount' users of 'relation' ("following" or "followers") list of each user in usernames :param relation: what list to use, "following" or "followers" :param usernames: list of usernames to follow relations of :param amount: amount of users to follow for each user in 'usernames' :param randomize: if the bot will include a random factor to choose who to follow or follow the first 'amount' of usernames on the list :param random_chance: chance a user will be followed if using 'randomize' """ if self.aborting: return self valid = {"followers", "following"} if relation not in valid: self.logger.info( '{} is not a valid relation, using "followers"'.format( relation)) relation = "followers" self.logger.info("Starting to follow users {}".format(relation)) # for each username for index, username in enumerate(usernames): # if aborting or quota was breached or its past time according to settings break the loop if self.aborting or self.quotient_breach or ( self.until_time and datetime.now() > self.until_time): break interactions = Interactions() self.logger.info("Follow User {} [{}/{}]: {} - started".format( relation, index + 1, len(usernames), username)) user_link = "https://www.instagram.com/{}".format(username) follow_link = "https://www.instagram.com/{}/{}".format( username, relation) # navigate to user page if not check_if_in_correct_page(self, user_link): nf_go_to_user_page(self, username) sleep(1) # get followers & following counts and change amount if less than desired followers_count, following_count = get_relationship_counts( self, username) follow_count = following_count if relation == "following" else followers_count follow_count = follow_count if follow_count else 0 actual_amount = amount if follow_count < amount: actual_amount = follow_count # go to relation page nf_go_to_follow_page(self, relation, username) sleep(2) # follow users sc_rolled = 0 scroll_nap = 1.5 already_interacted_links = [] while interactions.followed in range(actual_amount): # if aborting or quota was breached or its past time according to settings break the loop if self.aborting or (self.until_time and datetime.now() > self.until_time): break # if quotient was breached break the loop if self.jumps.check_follows(): self.logger.warning( "Follow quotient reached its peak, leaving Follow User {} activity" .format(relation)) # reset jump counter before breaking the loop self.jumps.follows = 0 self.quotient_breach = True break # if scrolled too much sleep for 5-10 minutes if sc_rolled > 100: delay_random = random.randint(300, 600) self.logger.info( "Scrolled too much, sleeping {} minutes and {} seconds" .format(int(delay_random / 60), delay_random % 60)) sleep(delay_random) sc_rolled = 0 # get loaded usernames users = nf_get_all_users_on_element(self) # if no users were grabbed try to go back and load the relation page again while len(users) == 0: nf_find_and_press_back(self, user_link) in_user_page = check_if_in_correct_page(self, user_link) if not in_user_page: nf_go_to_user_page(self, username) nf_go_to_follow_page(self, relation, username) # get loaded usernames users = nf_get_all_users_on_element(self) # If after rechecking we are in the correct page there still no are users # the bot is most surely soft blocked from seeing relations, that block doesnt last long usually. # sleep for 5-10 minutes if len(users) == 0: delay_random = random.randint(300, 600) self.logger.info( "Soft block on see followers, " "sleeping {} minutes and {} seconds".format( int(delay_random / 60), delay_random % 60)) sleep(delay_random) self.logger.debug("Grabbed {} usernames".format(len(users))) # first one in the list is un-clickable by bad design on browser instagram, its behind the top bar for user in users[1:]: link = user.get_attribute("href") # try to follow first not already interacted user if link not in already_interacted_links: msg = "" try: user_text = user.text user_link2 = "https://www.instagram.com/{}".format( user_text) self.logger.info("Followed [{}/{}]".format( interactions.followed, actual_amount)) # Go to user page self.logger.info( "Trying user {}".format(user_text)) nf_scroll_into_view(self, user) sleep(1) nf_click_center_of_element(self, user, user_link2) sleep(2) # validate user valid = False if (user_text not in self.settings.dont_include and not is_follow_restricted(self, user_text) and random.randint(0, 100) <= random_chance): valid, details = nf_validate_user_call( self, user_text, self.quota_supervisor.FOLLOW) self.logger.info( "Valid User: {}, details: {}".format( valid, details)) # follow user if valid: follow_state, msg = follow_user( self, "profile", user_text) if follow_state is True: interactions.followed += 1 elif msg == "already followed": interactions.already_followed += 1 elif msg == "jumped": # will break the loop after certain consecutive jumps self.jumps.follows += 1 # interact with user if (self.settings.do_like and random.randint(0, 100) <= self.settings.user_interact_percentage ): self.logger.info( "Interacting with user '{}'".format( user_text)) if not check_if_in_correct_page( self, user_link2): nf_go_from_post_to_profile( self, user_text) interactions += like_loop( self, "Interact with user '{}'".format( user_text), user_link2, self.settings.user_interact_amount, True) else: interactions.not_valid_users += 1 except Exception as e: self.logger.error(e) finally: # go back to relation page and start the loop again sleep(1) nf_find_and_press_back(self, follow_link) in_follow_page = check_if_in_correct_page( self, follow_link) if not in_follow_page: in_user_page = check_if_in_correct_page( self, user_link) if not in_user_page: nf_go_to_user_page(self, username) nf_go_to_follow_page(self, relation, username) already_interacted_links.append(link) if msg == "block on follow": # raise SoftBlockedException(msg) pass # TODO: deal with block on follow break else: # For loop ended means all users in screen has been interacted with scrolled_to_bottom = self.browser.execute_script( JS.SCROLLED_TO_BOTTOM) # even if we are at the bottom if we were using randomize some users were ignored # so the bot can go back and look again with a higher random chance to foollow the users if scrolled_to_bottom and randomize and random_chance < 100: random_chance += 25 self.browser.execute_script(JS.SCROLL_TO_TOP) self.quota_supervisor.add_server_call() sc_rolled += 1 sleep(scroll_nap) elif scrolled_to_bottom: # already followed all possibles users break # if not at the bottom of the list # will scroll the screen a bit and look again for i in range(3): self.browser.execute_script(JS.SCROLL_SCREEN) self.quota_supervisor.add_server_call() sc_rolled += 1 sleep(scroll_nap) sleep(3) self.logger.info("Follow User {} [{}/{}] - ended".format( relation, index + 1, len(usernames))) self.logger.info(str(interactions)) self.interactions += interactions return self
def like_by_users(self, usernames: List[str], amount: int = None, users_validated: bool = False): """ Likes 'amount' (default bot settings 'user_interact_amount') images per given user, before it starts liking it may follow the user and after each like it may comment the post, according to bot settings :param usernames: list of usernames to like posts of :param amount: amount of post to like in each user feed :param users_validated: if users are already considered valid to like them """ if self.aborting: return self amount = amount or self.settings.user_interact_amount usernames = usernames or [] self.quotient_breach = False # for each username for index, username in enumerate(usernames): # if aborting or quota was breached or its past time according to settings break the loop if self.aborting or self.quotient_breach or ( self.until_time and datetime.now() > self.until_time): break # clean username username = username.strip() user_link = "https://www.instagram.com/{}/".format(username) interactions = Interactions() self.logger.info("Like by User [{}/{}]: {} - started".format( index + 1, len(usernames), username)) # navigate to user feed if not check_if_in_correct_page(self, user_link): nf_go_to_user_page(self, username) sleep(1) # validate user according to settings if not users_validated: valid, details = nf_validate_user_call( self, username, self.quota_supervisor.LIKE) self.logger.info("'{}' is{} a valid user{}".format( username, "" if valid else " not", "" if valid else ": {}".format(details))) if not valid: interactions.not_valid_users += 1 continue # follow user according to settings if (self.settings.do_follow and username not in self.settings.dont_include and random.randint(0, 100) <= self.settings.follow_percentage and not is_follow_restricted(self, username)): self.logger.debug("Following user") follow_state, msg = follow_user(self, "profile", username, None) if follow_state is True: interactions.followed += 1 elif msg == "already followed": interactions.already_followed += 1 sleep(1) # like images interactions += like_loop( self, "User [{}/{}]: {}".format(index + 1, len(usernames), username), user_link, amount, True) self.logger.info("Like by User [{}/{}]: {} - ended".format( index + 1, len(usernames), username)) self.logger.info(str(interactions)) self.interactions += interactions return self
def get_follow( self, username: str, follow: str ) -> Set[str]: # set of followers or following of given username valid = {"followers", "following"} if follow not in valid: raise ValueError("get_follow: follow must be one of %r." % valid) user_link = "https://www.instagram.com/{}/".format(username) if not check_if_in_correct_page(self, user_link): if self.username == username: go_to_bot_user_page(self) else: nf_go_to_user_page(self, username) if follow == 'followers': query = self.instauser.followers.all() else: query = self.instauser.following.all() usernames = set([instauser.username for instauser in query]) followers_count, following_count = get_relationship_counts(self, username) count = followers_count if follow == 'followers' else following_count if count == len(usernames): return usernames sleep(2) nf_go_to_follow_page(self, follow, username) sleep(2) sc_rolled = 0 scroll_nap = 1.5 seen_usernames = [] try: while True: if self.aborting or (self.until_time and datetime.now() > self.until_time): break if sc_rolled > 100: delay_random = random.randint(400, 600) self.logger.info( "Scrolled too much, sleeping {} minutes and {} seconds". format(int(delay_random / 60), delay_random % 60)) sleep(delay_random) sc_rolled = 0 users = nf_get_all_users_on_element(self) while len(users) == 0: nf_find_and_press_back(self, user_link) in_user_page = check_if_in_correct_page(self, user_link) if not in_user_page: nf_go_to_user_page(self, username) nf_go_to_follow_page(self, follow, username) users = nf_get_all_users_on_element(self) if len(users) == 0: delay_random = random.randint(200, 300) self.logger.info( "Soft block on see {}, " "sleeping {} minutes and {} seconds".format( follow, int(delay_random / 60), delay_random % 60)) sleep(300) for user in users[1:]: link = user.get_attribute("href") user_text = user.text if user_text not in seen_usernames: seen_usernames.append(user_text) if user_text not in usernames: add_follow_times(self, user_text) else: # For loop ended means all users in screen have been saved scrolled_to_bottom = self.browser.execute_script( JS.SCROLLED_TO_BOTTOM) if scrolled_to_bottom: # already saved all possibles users break # will scroll the screen a bit and grab usernames again for i in range(3): self.browser.execute_script(JS.SCROLL_SCREEN) self.quota_supervisor.add_server_call() sc_rolled += 1 sleep(scroll_nap) if scrolled_to_bottom: # already saved all possibles users break except Exception: raise usernames = usernames.union(set(seen_usernames)) self.logger.info("Grabbed {} {} names".format(len(usernames), follow)) return usernames
def follow_user( self, track: str, user_name: str, button: Union[WebElement, None] = None ) -> Tuple[bool, str]: # follow_state, msg """ Follow a user either from the profile page or post page or dialog box """ # list of available tracks to follow in: ["profile", "post" "dialog"] # check action availability if self.quota_supervisor.jump_follow(): return False, "jumped" if track in ["profile", "post"]: if track == "profile": # check URL of the webpage, if it already is user's profile # page, then do not navigate to it again user_link = "https://www.instagram.com/{}/".format(user_name) if not check_if_in_correct_page(self, user_link): nf_go_to_user_page(self, user_name) # find out CURRENT following status for _ in range(3): following_status, follow_button = get_following_status( self, track, user_name) if following_status in ["Follow", "Follow Back"]: nf_scroll_into_view(self, follow_button) nf_click_center_of_element(self, follow_button, skip_action_chain=True) sleep(3) following_status, follow_button = get_following_status( self, track, user_name) if following_status in ["Following", "Requested"]: break elif following_status == "Following": self.logger.info("Already following '{}'".format(user_name)) return False, "already followed" elif following_status == "Requested": self.logger.info( "Already requested '{}' to follow".format(user_name)) return False, "already requested" elif following_status == "Unblock": self.logger.info("User '{}' is blocked".format(user_name)) return False, "user is blocked" elif following_status == "UNAVAILABLE": self.logger.info("User '{}' is inaccessible".format(user_name)) return False, "user is inaccessible" elif following_status is None: sirens_wailing, emergency_state = emergency_exit(self) if sirens_wailing is True: return False, emergency_state else: self.logger.warning( "Couldn't follow '{}', unexpected failure".format( user_name)) return False, "unexpected failure" elif track == "dialog": nf_click_center_of_element(self, button) # general tasks after a successful follow self.logger.info("Followed {}".format(user_name)) add_follow_times(self, user_name) add_user_to_blacklist(self, user_name, self.quota_supervisor.FOLLOW) self.quota_supervisor.add_follow() return True, "success"