def shuffle_actions(self, actions): if len(actions) <= 1: sleep(7 * 60) return actions old_order = actions[:] random.shuffle(actions) if actions[0] == old_order[-1]: actions = actions[1:] + actions[0:1] return actions
def like_comment(browser, original_comment_text, logger): """ Like the given comment """ comments_block_XPath = read_xpath( like_comment.__name__, "comments_block" ) # quite an efficient # location path try: comments_block = browser.find_elements_by_xpath(comments_block_XPath) for comment_line in comments_block: comment_elem = comment_line.find_elements_by_tag_name("span")[0] comment = extract_text_from_element(comment_elem) if comment and (comment == original_comment_text): # find "Like" span (a direct child of Like button) span_like_elements = comment_line.find_elements_by_xpath( read_xpath(like_comment.__name__, "span_like_elements") ) if not span_like_elements: # this is most likely a liked comment return True, "success" # like the given comment span_like = span_like_elements[0] comment_like_button = span_like.find_element_by_xpath( read_xpath(like_comment.__name__, "comment_like_button") ) click_element(browser, comment_like_button) # verify if like succeeded by waiting until the like button # element goes stale.. button_change = explicit_wait( browser, "SO", [comment_like_button], logger, 7, False ) if button_change: logger.info("--> Liked the comment!") sleep(random.uniform(1, 2)) return True, "success" else: logger.info("--> Unfortunately, comment was not liked.") sleep(random.uniform(0, 1)) return False, "failure" except (NoSuchElementException, StaleElementReferenceException) as exc: logger.error( "Error occured while liking a comment.\n\t{}\n\n".format( str(exc).encode("utf-8") ) ) return False, "error" return None, "unknown"
def act(self, count=0): if self.aborting: return actions = self.get_actions(self.settings or {}) while datetime.datetime.now() < self.end_time: try: self.shuffle_actions(actions) self.logger.warning("shuffled actions: %s" % list(map(lambda a: a["name"], actions))) for f in actions: if self.aborting: self.logger.warning("ABORTING") return self.logger.warning("RUN: %s" % f["name"]) f["fun"]() count = 0 sleep(1 * 60) sleep(2 * 60) except NoSuchElementException as exc: # if changes to IG layout, upload the file to help us locate the change file_path = os.path.join( gettempdir(), '{}.html'.format(time.strftime('%Y%m%d-%H%M%S'))) with open(file_path, 'wb') as fp: fp.write(self.browser.page_source.encode('utf8')) print( '{0}\nIf raising an issue, please also upload the file located at:\n{1}\n{0}' .format('*' * 70, file_path)) # full stacktrace when raising Github issue self.logger.exception(exc) except (ConnectionRefusedError, RemoteDisconnected, ProtocolError, MaxRetryError, AttributeError) as exc: return self.try_again(count, exc) except Exception as exc: if 'RemoteDisconnected' in str(exc): return self.try_again(count, exc) self.logger.error("Excepiton in act(): %s \n %s" % (exc, traceback.format_exc())) raise
def get_links(browser, page, logger, media, element): links = [] try: # Get image links in scope from hashtag, location and other pages link_elems = element.find_elements_by_xpath('//a[starts-with(@href, "/p/")]') sleep(2) if link_elems: for link_elem in link_elems: try: post_href = link_elem.get_attribute("href") post_elem = element.find_elements_by_xpath( "//a[@href='/p/" + post_href.split("/")[-2] + "/']/child::div" ) if len(post_elem) == 1 and MEDIA_PHOTO in media: # Single photo links.append(post_href) if len(post_elem) == 2: # Carousel or Video post_category = element.find_element_by_xpath( "//a[@href='/p/" + post_href.split("/")[-2] + "/']/child::div[@class='u7YqG']/child::div" ).get_attribute("aria-label") if post_category in media: links.append(post_href) except WebDriverException: logger.info( "Cannot detect post media type. Skip {}".format(post_href) ) else: logger.info("'{}' page does not contain a picture".format(page)) except BaseException as e: logger.error("link_elems error {}".format(str(e))) return links
def like_image(browser, username, blacklist, logger, logfolder, total_liked_img): """Likes the browser opened image""" # check action availability if quota_supervisor("likes") == "jump": return False, "jumped" like_xpath = read_xpath(like_image.__name__, "like") unlike_xpath = read_xpath(like_image.__name__, "unlike") # find first for like element like_elem = browser.find_elements_by_xpath(like_xpath) if len(like_elem) == 1: # sleep real quick right before clicking the element sleep(2) like_elem = browser.find_elements_by_xpath(like_xpath) click_element(browser, like_elem[0]) # check now we have unlike instead of like liked_elem = browser.find_elements_by_xpath(unlike_xpath) if len(liked_elem) == 1: logger.info("--> Image Liked!") Event().liked(username) update_activity( browser, action="likes", state=None, logfolder=logfolder, logger=logger ) if blacklist["enabled"] is True: action = "liked" add_user_to_blacklist( username, blacklist["campaign"], action, logger, logfolder ) # get the post-like delay time to sleep naply = get_action_delay("like") sleep(naply) # after every 10 liked image do checking on the block if total_liked_img % 10 == 0 and not verify_liked_image(browser, logger): return False, "block on likes" return True, "success" else: # if like not seceded wait for 2 min logger.info("--> Image was not able to get Liked! maybe blocked ?") sleep(120) else: liked_elem = browser.find_elements_by_xpath(unlike_xpath) if len(liked_elem) == 1: logger.info("--> Image already liked!") return False, "already liked" logger.info("--> Invalid Like Element!") return False, "invalid element"
def act(self): env = self.settings or {} actions = [ lambda: self.like_by_tags( tags=shuffle(env.get("like_by_tags", [])) if env.get("enable_like_by_tags", True) else [], amount=env.get("like_by_tags_amount", 1), skip_top_posts=env.get("like_by_tags_skip_top_posts", True), use_smart_hashtags=env.get("like_by_tags_use_smart_hashtags", False), interact=env.get("like_by_tags_interact", False)), lambda: self.like_by_locations( locations=shuffle(env.get("like_by_locations", [])) if env.get("enable_like_by_locations", True) else [], amount=env.get("like_by_locations_amount", 1), skip_top_posts=env.get("like_by_locations_skip_top_posts", True )), lambda: self.follow_user_followers( usernames=shuffle(env.get("follow_user_followers", [])) if env.get("enable_follow_user_followers", True) else [], amount=env.get("follow_user_followers_amount", 9), randomize=env.get("follow_user_followers_randomize", False), interact=env.get("follow_user_followers_interact", True), sleep_delay=env.get("follow_user_followers_sleep_delay", 600)), lambda: self.like_by_feed( amount=env.get("like_by_feed_amount", 10) if env.get("enable_like_by_feed", True) else 0, randomize=env.get("like_by_feed_randomize", True), unfollow=env.get("like_by_feed_unfollow", False), interact=env.get("like_by_feed_interact", False)), lambda: self.unfollow_users( amount=env.get("unfollow_users_amount", 50) if env.get("enable_unfollow", True) else 0, # customList=(False, [], "all"), InstapyFollowed=(env.get("unfollow_users_InstapyFollowed", True ), "nonfollowers" if env.get("unfollow_users_nonfollowers", False) else "all"), # 'all' or 'nonfollowers' # nonFollowers=False, # allFollowing=False, style=env.get("unfollow_users_style", 'FIFO' ), # or 'LIFO', 'RANDOM' unfollow_after=env.get("unfollow_users_unfollow_after", 2) * 24 * 60 * 60, sleep_delay=env.get("unfollow_users_sleep_delay", 600)) ] while datetime.datetime.now() < self.end_time: try: sleep(10) random.shuffle(actions) for f in actions: f() except Exception as exc: # if changes to IG layout, upload the file to help us locate the change if isinstance(exc, NoSuchElementException): file_path = os.path.join( gettempdir(), '{}.html'.format(time.strftime('%Y%m%d-%H%M%S'))) with open(file_path, 'wb') as fp: fp.write(self.browser.page_source.encode('utf8')) print( '{0}\nIf raising an issue, please also upload the file located at:\n{1}\n{0}' .format('*' * 70, file_path)) # full stacktrace when raising Github issue self.logger.exception(exc)
def get_links_for_username( browser, username, person, amount, logger, logfolder, randomize=False, media=None, taggedImages=False, imageToFind=None ): """ Fetches the number of links specified by amount and returns a list of links """ if media is None: # All known media types media = MEDIA_ALL_TYPES elif media == MEDIA_PHOTO: # Include posts with multiple images in it media = [MEDIA_PHOTO, MEDIA_CAROUSEL] else: # Make it an array to use it in the following part media = [media] logger.info("Getting {} image list...".format(person)) user_link = "https://www.instagram.com/{}/".format(person) if taggedImages: user_link = user_link + "tagged/" # Check URL of the webpage, if it already is user's profile page, # then do not navigate to it again web_address_navigator(browser, user_link) if not is_page_available(browser, logger): logger.error( "Instagram error: The link you followed may be broken, or the " "page may have been removed..." ) return False # if private user, we can get links only if we following following_status, _ = get_following_status( browser, "profile", username, person, None, logger, logfolder ) # if following_status is None: # browser.wait_for_valid_connection(browser, username, logger) # if following_status == 'Follow': # browser.wait_for_valid_authorization(browser, username, logger) is_private = is_private_profile(browser, logger, following_status == "Following") if ( is_private is None or (is_private is True and following_status not in ["Following", True]) or (following_status == "Blocked") ): logger.info("This user is private and we are not following") return False web_address_navigator(browser, user_link) # Get links links = [] main_elem = browser.find_element_by_tag_name("article") posts_count = get_number_of_posts(browser) attempt = 0 if posts_count is not None and amount > posts_count: logger.info( "You have requested to get {} posts from {}'s profile page BUT" " there only {} posts available :D".format(amount, person, posts_count) ) amount = posts_count while len(links) < amount: initial_links = links sleep(1.25) browser.execute_script("window.scrollTo(0, document.body.scrollHeight);") # update server calls after a scroll request update_activity(browser, state=None) # using `extend` or `+=` results reference stay alive which affects # previous assignment (can use `copy()` for it) main_elem = browser.find_element_by_tag_name("article") tempLinks = get_links(browser, person, logger, media, main_elem) links = links + tempLinks links = sorted(set(links), key=links.index) if len(tempLinks)>0 and (imageToFind is not None) and (imageToFind in tempLinks): break if len(links) == len(initial_links): logger.info("Pausing 45s during scroll for new links. Currently at: {} of {} (attempt:{})".format(len(links),amount,attempt)) sleep(45.0) if attempt >= 60: logger.info( "There are possibly less posts than {} in {}'s profile " "page!".format(amount, person) ) break else: attempt += 1 else: attempt = 0 if randomize is True: random.shuffle(links) return links[:amount]
def OnePass(username, password, username1, amountToQuickscan, amountToLookup, iCnt, iMax): # start the scan session = InstaPy(username=username, password=password) session.login() prepare_my_database(session.logger) randomize = False media = MEDIA_PHOTO taggedImages = True links = [] try: # build list of links to ignore from the data base: those recently queried (less than 20 hours old) and those posted more than 72 hours ago. ignore_links = getFreshTaggedLinks(username1) ignore_links = list(dict.fromkeys(ignore_links)) fresh_links = get_links_for_username(session.browser, session.username, username1, amountToQuickscan, session.logger, session.logfolder, randomize, media, taggedImages) links = list(set(fresh_links) - set(ignore_links)) session.logger.info("Links quickscanned: {}".format(len(fresh_links))) session.logger.info("Links to ignore: {}".format(len(ignore_links))) links = links[:amountToLookup] if len( links) > amountToLookup else links session.logger.info("Links to lookup: {}".format(len(links))) except NoSuchElementException: session.logger.error("Element not found, skipping this username") i = 0 # for each link in the list, follow it and grab lots of statistics. This consumes instagram resources. # then follow the posting username and get their statistics. This consumes instragram resources. sleep(1.2) for i, posted_link in enumerate(links): sleep(3.0) # session.logger.info("Processing link {}:{}".format(i+1,len(links))) session.logger.info( "Processing link:{} {}/{}:{}/{} totalLinks: {}/{}".format( posted_link, iCnt, iMax, username, username1, i + 1, len(links))) try: try: inappropriate, posted_by_username, posted_link_likes_count, posted_link_comments_count, posted_link_datetime_str, posted_link_location_name, posted_link_image_text, is_video, reason, scope = check_link2( session.browser, posted_link, session.dont_like, session.mandatory_words, session.mandatory_language, session.is_mandatory_character, session.mandatory_character, session.check_character_set, session.ignore_if_contains, session.logger, ) except: inappropriate = True if not inappropriate: sleep(1.5) try: posted_by_followers_count, posted_by_following_count = get_relationship_counts( session.browser, posted_by_username, session.logger) # posted_by_posts_count = get_number_of_posts(session.browser) posted_by_posts_count = None except: # if you can't get follower count, then you're probably out of daily page pulls # Might as well quit! session.logger.warning( "Might be out of daily page pulls. Closing session.") posted_by_posts_count = None posted_by_followers_count = None posted_by_following_count = None session.end() return False session.logger.info( "-Posted on: {} by: {} posts: {} followers: {} following: {}" .format(posted_link_datetime_str, posted_by_username, posted_by_posts_count, posted_by_followers_count, posted_by_following_count)) now = datetime.now(timezone.utc) last_checked_datetime_str = now.strftime( "%Y-%m-%dT%H:%M:%S.%fZ") posted_link_datetime = datetime.strptime( posted_link_datetime_str, "%Y-%m-%dT%H:%M:%S.%fZ") last_checked_datetime = datetime.strptime( last_checked_datetime_str, "%Y-%m-%dT%H:%M:%S.%fZ") deltatime = (last_checked_datetime - posted_link_datetime) last_checked_age_in_hrs = deltatime.seconds / 3600.00 storeRecord(username1, last_checked_datetime, posted_link, posted_link_datetime, posted_link_location_name, posted_link_likes_count, posted_link_comments_count, posted_by_username, posted_by_posts_count, posted_by_followers_count, posted_by_following_count) storeTaggedActivitytoDB( session.logger, username1, last_checked_datetime, posted_link, posted_link_datetime, posted_link_location_name, posted_link_likes_count, posted_link_comments_count, posted_by_username, posted_by_posts_count, posted_by_followers_count, posted_by_following_count) sleep(1.0) except NoSuchElementException as err: session.logger.error("Invalid Page: {}".format(err)) session.end() return True
def gatherAndStoreLinkData(session, username1, posted_link): "Given a posted_link, gather it's info and update the database" # session.logger.info("Processing link: {}".format(posted_link)) try: inappropriate = True sleep(1.0) try: inappropriate, posted_by_username, posted_link_likes_count, posted_link_comments_count, posted_link_datetime_str, posted_link_location_name, posted_link_image_text, is_video, reason, scope = check_link2( session.browser, posted_link, session.dont_like, session.mandatory_words, session.mandatory_language, session.is_mandatory_character, session.mandatory_character, session.check_character_set, session.ignore_if_contains, session.logger, ) session.logger.info("-Posted on: {} by: {} ".format( posted_link_datetime_str, posted_by_username)) except: inappropriate = True updateSessionActivityToDB(session) if not inappropriate: sleep(1.0) try: posted_by_followers_count, posted_by_following_count = get_relationship_counts( session.browser, posted_by_username, session.logger) # posted_by_posts_count = get_number_of_posts(session.browser) posted_by_posts_count = None except: session.logger.warning( "Might be out of daily page pulls. Closing session.") posted_by_posts_count = None posted_by_followers_count = None posted_by_following_count = None return False session.logger.info( "-Posts: {} followers: {} following: {}".format( posted_by_posts_count, posted_by_followers_count, posted_by_following_count)) now = datetime.now(timezone.utc) last_checked_datetime_str = now.strftime("%Y-%m-%dT%H:%M:%S.%fZ") posted_link_datetime = datetime.strptime(posted_link_datetime_str, "%Y-%m-%dT%H:%M:%S.%fZ") last_checked_datetime = datetime.strptime( last_checked_datetime_str, "%Y-%m-%dT%H:%M:%S.%fZ") deltatime = (last_checked_datetime - posted_link_datetime) # last_checked_age_in_hrs = deltatime.seconds / 3600.00 storeRecord(username1, last_checked_datetime, posted_link, posted_link_datetime, posted_link_location_name, posted_link_likes_count, posted_link_comments_count, posted_by_username, posted_by_posts_count, posted_by_followers_count, posted_by_following_count) storeTaggedActivitytoDB( session.logger, username1, last_checked_datetime, posted_link, posted_link_datetime, posted_link_location_name, posted_link_likes_count, posted_link_comments_count, posted_by_username, posted_by_posts_count, posted_by_followers_count, posted_by_following_count) if reason == "Unavailable Page": # delete link from data base deleteLinkFromDB(session, username1, posted_link) sleep(1.0) except NoSuchElementException as err: session.logger.error("Invalid Page: {}".format(err)) return True
def nf_interact_with_post( self, link: str, amount: int, state: dict, user_validated: bool = False, ): try: self.logger.info("about to check post") sleep(1) inappropriate, user_name, is_video, image_links, reason, scope = nf_check_post(self, link) self.logger.info("about to verify post") sleep(1) if not inappropriate and self.delimit_liking: self.liking_approved = verify_liking( self.browser, self.max_likes, self.min_likes, self.logger ) if not inappropriate and self.liking_approved: # validate user self.logger.info("about to validate user") sleep(1) if user_validated: valid = True details = "User already validated" else: valid, details = nf_validate_user_call(self, user_name, link) self.logger.info("Valid User: {}, details: {}".format(valid, details)) if not valid: state["not_valid_users"] += 1 return True, "not_valid_users", state # try to like self.logger.info("about to like post") sleep(1) like_state, msg = like_image( self.browser, "user_name", self.blacklist, self.logger, self.logfolder, state['liked_img'], ) if like_state is True: state['liked_img'] += 1 self.logger.info("Like# [{}/{}]".format(state['liked_img'], amount)) self.logger.info(link) # reset jump counter after a successful like self.jumps["consequent"]["likes"] = 0 checked_img = True temp_comments = [] commenting = random.randint(0, 100) <= self.comment_percentage following = random.randint(0, 100) <= self.follow_percentage interact = random.randint(0, 100) <= self.user_interact_percentage if self.use_image_analysis and (following or commenting): try: ( checked_img, temp_comments, image_analysis_tags, ) = self.ImgAn.image_analysis(image_links, logger=self.logger) # TODO: image_analysis except Exception as err: self.logger.error( "Image analysis error: {}".format(err) ) # comments if ( self.do_comment and user_name not in self.dont_include and checked_img and commenting ): comments = (self.comments + (self.video_comments if is_video else self.photo_comments)) success = process_comments(self, user_name, comments, temp_comments) if success: state['commented'] += 1 else: self.logger.info("--> Not commented") sleep(1) # following if ( self.do_follow and user_name not in self.dont_include and checked_img and following and not follow_restriction( "read", user_name, self.follow_times, self.logger ) ): self.logger.info("about to follow user") sleep(1) follow_state, msg = follow_user( self.browser, "post", self.username, user_name, 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) # interactions (only of user not previously validated to impede recursion) if interact and not user_validated: self.logger.info( "--> User gonna be interacted: '{}'".format( user_name ) ) # disable re-validating user in like_by_users like_by_users( self, [user_name], None, True, ) elif msg == "already liked": state['already_liked'] += 1 return True, msg, state elif msg == "block on likes": return False, msg, state elif msg == "jumped": # will break the loop after certain consecutive # jumps self.jumps["consequent"]["likes"] += 1 return True, "success", state else: self.logger.info( "--> Image not liked: {}".format(reason.encode("utf-8")) ) state["inap_img"] += 1 return True, "inap_img", state except NoSuchElementException as err: self.logger.error("Invalid Page: {}".format(err)) return False, "Invalid Page", state
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 like_by_users( self, usernames: List[str], amount: int = None, users_validated: bool = False ): """Likes some amounts of images for each usernames""" if self.aborting: return self amount = amount or self.user_interact_amount usernames = usernames or [] self.quotient_breach = False for index, username in enumerate(usernames): if self.quotient_breach: break state = { 'liked_img': 0, 'already_liked': 0, 'inap_img': 0, 'commented': 0, 'followed': 0, 'not_valid_users': 0, } self.logger.info( "Username [{}/{}]".format(index + 1, len(usernames)) ) self.logger.info("--> {}".format(username.encode("utf-8"))) if len(usernames) == 1 and users_validated: nf_go_from_post_to_profile(self, username) else: nf_go_to_user_page(self, username) if not users_validated: validation, details = nf_validate_user_call(self, username) if not validation: self.logger.info( "--> Not a valid user: {}".format(details) ) state["not_valid_users"] += 1 continue try_again = 0 sc_rolled = 0 scroll_nap = 1.5 already_interacted_links = [] try: while state['liked_img'] in range(0, amount): if self.jumps["consequent"]["likes"] >= self.jumps["limit"]["likes"]: self.logger.warning( "--> Like quotient reached its peak!\t~leaving " "Like-By-Users activity\n" ) self.quotient_breach = True # reset jump counter after a breach report self.jumps["consequent"]["likes"] = 0 break if sc_rolled > 100: try_again += 1 if try_again > 2: # you can try again as much as you want by changing this number self.logger.info( "'{}' user POSSIBLY has less valid images than " "desired:{} found:{}...".format( username, amount, len(already_interacted_links)) ) break self.logger.info( "Scrolled too much! ~ sleeping 10 minutes") sleep(600) sc_rolled = 0 main_elem = self.browser.find_element_by_tag_name("main") # feed = main_elem.find_elements_by_xpath('//div[@class=" _2z6nI"]') posts = nf_get_all_posts_on_element(main_elem) # Interact with links instead of just storing them for post in posts: link = post.get_attribute("href") if link not in already_interacted_links: self.logger.info("about to scroll to post") sleep(1) nf_scroll_into_view(self, post) self.logger.info("about to click to post") sleep(1) nf_click_center_of_element(self, post) success, msg, state = nf_interact_with_post( self, link, amount, state, users_validated, ) self.logger.info( "Returned from liking, should still be in post page") sleep(5) nf_find_and_press_back( self, "https://www.instagram.com/{}/".format(username) ) already_interacted_links.append(link) if success: break if msg == "block on likes": # TODO deal with block on likes break else: # For loop ended means all posts in screen has been interacted with # 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("Username [{}/{}]".format(index + 1, len(usernames))) self.logger.info("--> {} ended".format(username.encode("utf-8"))) 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 like_by_tags( self, tags: List[str] = None, amount: int = 50, skip_top_posts: bool = True, use_smart_hashtags: bool = False, use_smart_location_hashtags: bool = False, ): """Likes (default) 50 images per given tag""" if self.aborting: return self # if smart hashtag is enabled if use_smart_hashtags is True and self.smart_hashtags != []: self.logger.info("Using smart hashtags") tags = self.smart_hashtags elif use_smart_location_hashtags is True and self.smart_location_hashtags != []: self.logger.info("Using smart location hashtags") tags = self.smart_location_hashtags # deletes white spaces in tags tags = [tag.strip() for tag in tags] tags = tags or [] self.quotient_breach = False for index, tag in enumerate(tags): if self.quotient_breach: break state = { 'liked_img': 0, 'already_liked': 0, 'inap_img': 0, 'commented': 0, 'followed': 0, 'not_valid_users': 0, } self.logger.info("Tag [{}/{}]".format(index + 1, len(tags))) self.logger.info("--> {}".format(tag.encode("utf-8"))) tag = tag[1:] if tag[:1] == "#" else tag nf_go_to_tag_page(self, tag) # get amount of post with this hashtag try: possible_posts = self.browser.execute_script( "return window._sharedData.entry_data." "TagPage[0].graphql.hashtag.edge_hashtag_to_media.count" ) except WebDriverException: try: possible_posts = self.browser.find_element_by_xpath( read_xpath("get_links_for_tag", "possible_post") ).text if possible_posts: possible_posts = format_number(possible_posts) else: self.logger.info( "Failed to get the amount of possible posts in '{}' tag " "~empty string".format(tag) ) possible_posts = None except NoSuchElementException: self.logger.info( "Failed to get the amount of possible posts in {} tag".format(tag) ) possible_posts = None self.logger.info( "desired amount: {} | top posts [{}] | possible posts: " "{}".format( amount, "enabled" if not skip_top_posts else "disabled", possible_posts, ) ) if possible_posts is not None: amount = possible_posts if amount > possible_posts else amount # sometimes pages do not have the correct amount of posts as it is # written there, it may be cos of some posts is deleted but still keeps # counted for the tag sleep(1) try_again = 0 sc_rolled = 0 scroll_nap = 1.5 already_interacted_links = [] try: while state['liked_img'] in range(0, amount): if sc_rolled > 100: try_again += 1 if try_again > 2: self.logger.info( "'{}' tag POSSIBLY has less images than " "desired:{} found:{}...".format( tag, amount, len(already_interacted_links) ) ) break self.logger.info("Scrolled too much! ~ sleeping 10 minutes") sleep(600) sc_rolled = 0 main_elem = self.browser.find_element_by_tag_name("main") posts = nf_get_all_posts_on_element(main_elem) # Interact with links instead of just storing them for post in posts: link = post.get_attribute("href") if link not in already_interacted_links: self.logger.info("about to scroll to post") sleep(1) nf_scroll_into_view(self, post) self.logger.info("about to click to post") sleep(1) nf_click_center_of_element(self, post) success, msg, state = nf_interact_with_post( self, link, amount, state, ) self.logger.info("Returned from liking, should still be in post page") sleep(2) nf_find_and_press_back(self, "https://www.instagram.com/explore/tags/{}/".format(tag)) already_interacted_links.append(link) if success: break if msg == "block on likes": # TODO deal with block on likes break else: # For loop ended means all posts in screen has been interacted with # 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(2) self.logger.info("Tag [{}/{}]".format(index + 1, len(tags))) self.logger.info("--> {} ended".format(tag.encode("utf-8"))) 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 check_browser(browser, logfolder, logger, proxy_address): # set initial state to offline update_activity( browser, action=None, state="trying to connect", logfolder=logfolder, logger=logger, ) # check connection status try: logger.info("-- Connection Checklist [1/3] (Internet Connection Status)") browser.get("view-source:https://api.myip.com/") pre = browser.find_element_by_tag_name("pre").text current_ip_info = json.loads(pre) if ( proxy_address is not None and socket.gethostbyname(proxy_address) != current_ip_info["ip"] ): logger.warn("- Proxy is set, but it's not working properly") logger.warn( '- Expected Proxy IP is "{}", and the current IP is "{}"'.format( proxy_address, current_ip_info["ip"] ) ) # logger.warn("- Try again or disable the Proxy Address on your setup") # logger.warn("- Aborting connection...") # return False else: logger.info("- Internet Connection Status: ok") logger.info( '- Current IP is "{}" and it\'s from "{}/{}"'.format( current_ip_info["ip"], current_ip_info["country"], current_ip_info["cc"], ) ) update_activity( browser, action=None, state="Internet connection is ok", logfolder=logfolder, logger=logger, ) except Exception: logger.warn("- Internet Connection Status: error") update_activity( browser, action=None, state="There is an issue with the internet connection", logfolder=logfolder, logger=logger, ) return False # check Instagram.com status try: logger.info("-- Connection Checklist [2/3] (Instagram Server Status)") browser.get("https://isitdownorjust.me/instagram-com/") sleep(2) # collect isitdownorjust.me website information website_status = browser.find_element_by_xpath( read_xpath(login_user.__name__, "website_status") ) response_time = browser.find_element_by_xpath( read_xpath(login_user.__name__, "response_time") ) response_code = browser.find_element_by_xpath( read_xpath(login_user.__name__, "response_code") ) logger.info("- Instagram WebSite Status: {} ".format(website_status.text)) logger.info("- Instagram Response Time: {} ".format(response_time.text)) logger.info("- Instagram Reponse Code: {}".format(response_code.text)) logger.info("- Instagram Server Status: ok") update_activity( browser, action=None, state="Instagram servers are running correctly", logfolder=logfolder, logger=logger, ) except Exception: logger.warn("- Instagram Server Status: error") update_activity( browser, action=None, state="Instagram server is down", logfolder=logfolder, logger=logger, ) return False # check if hide-selenium extension is running logger.info("-- Connection Checklist [3/3] (Hide Selenium Extension)") webdriver = browser.execute_script("return window.navigator.webdriver") logger.info("- window.navigator.webdriver response: {}".format(webdriver)) if webdriver: logger.warn("- Hide Selenium Extension: error") else: logger.info("- Hide Selenium Extension: ok") # everything is ok, then continue(True) return True