def likers_from_post(browser, logger, Selectors, amount=20): """ Get the list of users from the 'Likes' dialog of a photo """ liked_counter_button = '//form/div/div/div/div/div/span/span/a[@role="button"]' try: liked_this = browser.find_elements_by_xpath(liked_counter_button) element_to_click = liked_this[0] sleep(1) click_element(browser, Settings, element_to_click) logger.info("opening likes") # update server calls # update_activity(Settings) sleep(1) # get a reference to the 'Likes' dialog box dialog = browser.find_element_by_xpath( Selectors.likes_dialog_body_xpath) # scroll down the page previous_len = -1 browser.execute_script( "arguments[0].scrollTop = arguments[0].scrollHeight", dialog) update_activity(Settings) sleep(1) start_time = time.time() user_list = [] while (not user_list or (len(user_list) != previous_len) and (len(user_list) < amount)): previous_len = len(user_list) scroll_bottom(browser, dialog, 2) user_list = get_users_from_dialog(user_list, dialog, logger) # write & update records at Progress Tracker progress_tracker(len(user_list), amount, start_time, None) if previous_len + 10 >= amount: logger.info("Scrolling finished") sleep(1) break random.shuffle(user_list) sleep(1) close_dialog_box(browser) logger.info("Got {} likers shuffled randomly whom you can follow:\n{}" "\n".format(len(user_list), user_list)) return user_list except Exception as exc: logger.Error("Some problem occured!\n\t{}".format( str(exc).encode("utf-8"))) return []
def is_commenting_enabled(browser, logger): """ Find out if commenting on the post is enabled """ try: comments_disabled = browser.execute_script( "return window._sharedData.entry_data." "PostPage[0].graphql.shortcode_media.comments_disabled") except WebDriverException: try: browser.execute_script("location.reload()") update_activity(Settings) comments_disabled = browser.execute_script( "return window._sharedData.entry_data." "PostPage[0].graphql.shortcode_media.comments_disabled") except Exception as e: msg = ("Failed to check comments' status for verification!\n\t{}" .format(str(e).encode("utf-8"))) return False, "Failure" if comments_disabled is True: msg = "Comments are disabled for this post." return False, msg return True, "Success"
def get_following_status(browser, track, username, person, person_id, logger, logfolder): """ Verify if you are following the user in the loaded page """ if track == "profile": ig_homepage = "https://www.medium.com/" web_address_navigator(browser, ig_homepage + person, Settings) follow_button_XP = ( '//*[@id="page-container"]/div/div/ul/li/div/div/span/button[@type="button"]/span[text()="Follow"]' ) failure_msg = "--> Unable to detect the following status of '{}'!" # user_inaccessible_msg = ( # "Couldn't access the profile page of '{}'!\t~might have changed the" # " username".format(person)) # check if the page is available # valid_page = is_page_available(browser, logger, Settings) # if not valid_page: # logger.warning(user_inaccessible_msg) # person_new = verify_username_by_id(browser, # username, # person, # None, # logger, # logfolder) # if person_new: # web_address_navigator( browser, ig_homepage + person_new, Settings) # valid_page = is_page_available(browser, logger, Settings) # if not valid_page: # logger.error(failure_msg.format(person_new.encode("utf-8"))) # return "UNAVAILABLE", None # else: # logger.error(failure_msg.format(person.encode("utf-8"))) # return "UNAVAILABLE", None # wait until the follow button is located and visible, then get it follow_button = explicit_wait(browser, "VOEL", [follow_button_XP, "XPath"], logger, 7, False) logger.info("follow_button = {}".format(follow_button)) if not follow_button: browser.execute_script("location.reload()") update_activity(Settings) follow_button = explicit_wait(browser, "VOEL", [follow_button_XP, "XPath"], logger, 14, False) logger.info("follow_button retried = {}".format(follow_button)) if not follow_button: # cannot find the any of the expected buttons logger.error(failure_msg.format(person.encode("utf-8"))) return None, None # get follow status following_status = follow_button.text logger.info("following_status returned = {}".format(following_status)) return following_status, follow_button
def comment_image(browser, username, comments, blacklist, logger, logfolder, Settings): """Checks if it should comment on the image""" # check action availability if quota_supervisor(Settings, "comments") == "jump": return False, "jumped" rand_comment = random.choice(comments).format(username) rand_comment = emoji.demojize(rand_comment) rand_comment = emoji.emojize(rand_comment, use_aliases=True) open_comment_section(browser, logger) comment_input = get_comment_input(browser) try: if len(comment_input) > 0: comment_input[0].clear() comment_input = get_comment_input(browser) # below, an extra space is added to force # the input box to update the reactJS core comment_to_be_sent = rand_comment + " " browser.execute_script( "arguments[0].value = arguments[1];", comment_input[0], comment_to_be_sent, ) # below, it also will remove that extra space added above # COS '\b' is a backspace char in ASCII comment_input[0].send_keys("\b") comment_input = get_comment_input(browser) comment_input[0].submit() update_activity(Settings, "comments") if blacklist["enabled"] is True: action = "commented" add_user_to_blacklist( username, blacklist["campaign"], action, logger, logfolder ) else: logger.warning( "--> Comment Action Likely Failed!" "\t~comment Element was not found" ) return False, "commenting disabled" except InvalidElementStateException: logger.warning( "--> Comment Action Likely Failed!" "\t~encountered `InvalidElementStateException` :/" ) return False, "invalid element state" logger.info("--> Commented: {}".format(rand_comment.encode("utf-8"))) # get the post-comment delay time to sleep naply = get_action_delay("comment", Settings) sleep(naply) return True, "success"
def friend_user(browser, track, login, userid_to_friend, times, blacklist, logger, logfolder): """ Friend a user either from the profile page or post page or dialog box """ # list of available tracks to friend in: ["profile", "post" "dialog"] # check action availability if quota_supervisor(Settings, "friends") == "jump": return False, "jumped" # check URL of the webpage, if it already is user's profile # page, then do not navigate to it again if friend_restriction("read", userid_to_friend, 1, logger): logger.info("Already connected {} or more times".format(times)) return False, "already friended" user_link = "https://www.facebook.com/{}/".format(userid_to_friend) web_address_navigator(browser, user_link, logger, Settings) # find out CURRENT friending status friending_status, friend_button = get_friending_status( browser, track, login, userid_to_friend, None, logger, logfolder) logger.info(friending_status) if friending_status in ["Add Friend"]: click_visibly(browser, Settings, friend_button) # click to friend friend_state, msg = verify_action(browser, "friend", track, login, userid_to_friend, None, logger, logfolder) if friend_state is not True: return False, msg elif friending_status is None: # TODO:BUG:2nd login has to be fixed with userid of loggedin user sirens_wailing, emergency_state = emergency_exit( browser, Settings, "https://facebook.com", login, login, logger, logfolder) if sirens_wailing is True: return False, emergency_state else: logger.warning( "--> Add Friend button not present '{}'!\t~unexpected failure". format(userid_to_friend)) return False, "unexpected failure" # general tasks after a successful friend logger.info("--> Friended '{}'!".format(userid_to_friend.encode("utf-8"))) update_activity(Settings, 'friendeds') logtime = datetime.now().strftime('%Y-%m-%d %H:%M') log_friended_pool(login, userid_to_friend, logger, logfolder, logtime, userid_to_friend) friend_restriction("write", userid_to_friend, None, logger) return True, "success"
def get_friending_status(browser, track, username, person, person_id, logger, logfolder): """ Verify if you are friending the user in the loaded page """ if track == "profile": ig_homepage = "https://www.facebook.com/" web_address_navigator( browser, ig_homepage + person, Settings) friend_button_XP = ("//div[@id='fbTimelineHeadline']/div/div/div/div/button[@type='button'][text()='Add Friend']") failure_msg = "--> Unable to detect the friending status of '{}'!" user_inaccessible_msg = ( "Couldn't access the profile page of '{}'!\t~might have changed the" " username".format(person)) # check if the page is available valid_page = is_page_available(browser, logger, Settings) if not valid_page: logger.warning(user_inaccessible_msg) person_new = verify_username_by_id(browser, username, person, None, logger, logfolder) if person_new: web_address_navigator( browser, ig_homepage + person_new, Settings) valid_page = is_page_available(browser, logger, Settings) if not valid_page: logger.error(failure_msg.format(person_new.encode("utf-8"))) return "UNAVAILABLE", None else: logger.error(failure_msg.format(person.encode("utf-8"))) return "UNAVAILABLE", None # wait until the friend button is located and visible, then get it friend_button = explicit_wait(browser, "VOEL", [friend_button_XP, "XPath"], logger, 7, False) if not friend_button: browser.execute_script("location.reload()") update_activity(Settings) friend_button = explicit_wait(browser, "VOEL", [friend_button_XP, "XPath"], logger, 14, False) if not friend_button: # cannot find the any of the expected buttons logger.error(failure_msg.format(person.encode("utf-8"))) return None, None # get friend status friending_status = friend_button.text return friending_status, friend_button
def verify_liking(browser, max, min, logger): """ Get the amount of existing existing likes and compare it against max & min values defined by user """ try: likes_count = browser.execute_script( "return window._sharedData.entry_data." "PostPage[0].graphql.shortcode_media.edge_media_preview_like" ".count") except WebDriverException: try: browser.execute_script("location.reload()") update_activity(Settings) likes_count = browser.execute_script( "return window._sharedData.entry_data." "PostPage[0].graphql.shortcode_media.edge_media_preview_like" ".count") except WebDriverException: try: likes_count = (browser.find_element_by_css_selector( "section._1w76c._nlmjy > div > a > span").text) if likes_count: likes_count = format_number(likes_count) else: logger.info( "Failed to check likes' count ~empty string\n") return True except NoSuchElementException: logger.info("Failed to check likes' count\n") return True if max is not None and likes_count > max: logger.info( "Not liked this post! ~more likes exist off maximum limit at " "{}".format(likes_count)) return False elif min is not None and likes_count < min: logger.info( "Not liked this post! ~less likes exist off minumum limit " "at {}".format(likes_count) ) return False return True
def like_image(browser, username, blacklist, logger, logfolder, Settings): """Likes the browser opened image""" # check action availability if quota_supervisor(Settings, "likes") == "jump": return False, "jumped" like_xpath = "//section/span/button/span[@aria-label='Like']" unlike_xpath = "//section/span/button/span[@aria-label='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) click_element(browser, Settings, 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!') update_activity(Settings, 'likes') 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", Settings) sleep(naply) 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 login_user( browser, username, userid, password, logger, logfolder, switch_language=True, bypass_suspicious_attempt=False, bypass_with_mobile=False, ): """Logins the user with the given username and password""" assert username, "Username not provided" assert password, "Password not provided" ig_homepage = "https://www.facebook.com" web_address_navigator(browser, ig_homepage, logger, Settings) cookie_loaded = False # try to load cookie from username try: for cookie in pickle.load( open("{0}{1}_cookie.pkl".format(logfolder, username), "rb")): browser.add_cookie(cookie) cookie_loaded = True except (WebDriverException, OSError, IOError): logger.info("Cookie file not found, creating cookie...") # include time.sleep(1) to prevent getting stuck on google.com time.sleep(1) # changes facebook website language to english to use english xpaths if switch_language: links = browser.find_elements_by_xpath('//*[@id="pageFooter"]/ul/li') for link in links: if link.get_attribute("title") == "English (UK)": click_element(browser, Settings, link) web_address_navigator(browser, ig_homepage, logger, Settings) reload_webpage(browser, Settings) # cookie has been LOADED, so the user SHOULD be logged in # check if the user IS logged in login_state = check_authorization( browser, Settings, "https://www.facebook.com/", username, userid, "activity counts", logger, logfolder, True, ) logger.info("check_authorization: {}".format(login_state)) if login_state is True: # dismiss_notification_offer(browser, logger) return True # if user is still not logged in, then there is an issue with the cookie # so go create a new cookie.. if cookie_loaded: logger.info( "Issue with cookie for user {}. Creating new cookie...".format( username)) # wait until the 'username' input element is located and visible input_username_XP = '//*[@id="email"]' # explicit_wait(browser, "VOEL", [input_username_XP, "XPath"], logger) input_username = browser.find_element_by_xpath(input_username_XP) logger.info("moving to input_username") logger.info("entering input_username") (ActionChains(browser).move_to_element(input_username).click().send_keys( username).perform()) # update server calls for both 'click' and 'send_keys' actions for i in range(2): update_activity(Settings) sleep(1) # password input_password = browser.find_elements_by_xpath('//*[@id="pass"]') if not isinstance(password, str): password = str(password) logger.info("entering input_password") (ActionChains(browser).move_to_element( input_password[0]).click().send_keys(password).perform()) # update server calls for both 'click' and 'send_keys' actions for i in range(2): update_activity(Settings) sleep(1) logger.info("submitting login_button") login_button = browser.find_element_by_xpath('//*[@type="submit"]') (ActionChains(browser).move_to_element(login_button).click().perform()) # update server calls update_activity(Settings) sleep(1) if bypass_suspicious_attempt is True: bypass_suspicious_login(browser, bypass_with_mobile, logger) # Check if user is logged-in (If there's two 'nav' elements) nav = browser.find_elements_by_xpath('//div[@role="navigation"]') if len(nav) == 2: # create cookie for username logger.info("logged in") pickle.dump( browser.get_cookies(), open("{0}{1}_cookie.pkl".format(logfolder, username), "wb"), ) return True else: return False
def check_link(browser, post_link, dont_like, mandatory_words, mandatory_language, mandatory_character, is_mandatory_character, check_character_set, ignore_if_contains, logger): """ Check the given link if it is appropriate :param browser: The selenium webdriver instance :param post_link: :param dont_like: hashtags of inappropriate phrases :param mandatory_words: words of appropriate phrases :param ignore_if_contains: :param logger: the logger instance :return: tuple of boolean: True if inappropriate, string: the username, boolean: True if it is video media, string: the message if inappropriate else 'None', string: set the scope of the return value """ # Check URL of the webpage, if it already is post's page, then do not # navigate to it again web_address_navigator(browser, post_link, logger, Settings) """Check if the Post is Valid/Exists""" try: post_page = browser.execute_script( "return window._sharedData.entry_data.PostPage") except WebDriverException: # handle the possible `entry_data` error try: browser.execute_script("location.reload()") update_activity(Settings) post_page = browser.execute_script( "return window._sharedData.entry_data.PostPage") except WebDriverException: post_page = None if post_page is None: logger.warning('Unavailable Page: {}'.format( post_link.encode('utf-8'))) return True, None, None, 'Unavailable Page', "Failure" """Gets the description of the post's link and checks for the dont_like tags""" graphql = 'graphql' in post_page[0] if graphql: media = post_page[0]['graphql']['shortcode_media'] is_video = media['is_video'] user_name = media['owner']['username'] image_text = media['edge_media_to_caption']['edges'] image_text = image_text[0]['node']['text'] if image_text else None location = media['location'] location_name = location['name'] if location else None media_edge_string = get_media_edge_comment_string(media) # double {{ allows us to call .format here: owner_comments = browser.execute_script( ''' latest_comments = window._sharedData.entry_data.PostPage[ 0].graphql.shortcode_media.{}.edges; if (latest_comments === undefined) {{ latest_comments = Array(); owner_comments = latest_comments .filter(item => item.node.owner.username == arguments[0]) .map(item => item.node.text) .reduce((item, total) => item + '\\n' + total, ''); return owner_comments;}} else {{ return null;}} '''.format(media_edge_string), user_name) else: media = post_page[0]['media'] is_video = media['is_video'] user_name = media['owner']['username'] image_text = media['caption'] owner_comments = browser.execute_script( ''' latest_comments = window._sharedData.entry_data.PostPage[ 0].media.comments.nodes; if (latest_comments === undefined) { latest_comments = Array(); owner_comments = latest_comments .filter(item => item.user.username == arguments[0]) .map(item => item.text) .reduce((item, total) => item + '\\n' + total, ''); return owner_comments;} else { return null;} ''', user_name) if owner_comments == '': owner_comments = None """Append owner comments to description as it might contain further tags""" if image_text is None: image_text = owner_comments elif owner_comments: image_text = image_text + '\n' + owner_comments """If the image still has no description gets the first comment""" if image_text is None: if graphql: media_edge_string = get_media_edge_comment_string(media) image_text = media[media_edge_string]['edges'] image_text = image_text[0]['node']['text'] if image_text else None else: image_text = media['comments']['nodes'] image_text = image_text[0]['text'] if image_text else None if image_text is None: image_text = "No description" logger.info('Image from: {}'.format(user_name.encode('utf-8'))) logger.info('Link: {}'.format(post_link.encode('utf-8'))) logger.info('Description: {}'.format(image_text.encode('utf-8'))) """Check if mandatory character set, before adding the location to the text""" if mandatory_language: if not check_character_set(image_text): return True, user_name, is_video, 'Mandatory language not ' \ 'fulfilled', "Not mandatory " \ "language" """Append location to image_text so we can search through both in one go.""" if location_name: logger.info('Location: {}'.format(location_name.encode('utf-8'))) image_text = image_text + '\n' + location_name if mandatory_words: if not any((word in image_text for word in mandatory_words)): return True, user_name, is_video, 'Mandatory words not ' \ 'fulfilled', "Not mandatory " \ "likes" image_text_lower = [x.lower() for x in image_text] ignore_if_contains_lower = [x.lower() for x in ignore_if_contains] if any((word in image_text_lower for word in ignore_if_contains_lower)): return False, user_name, is_video, 'None', "Pass" dont_like_regex = [] for dont_likes in dont_like: if dont_likes.startswith("#"): dont_like_regex.append(dont_likes + "([^\d\w]|$)") elif dont_likes.startswith("["): dont_like_regex.append("#" + dont_likes[1:] + "[\d\w]+([^\d\w]|$)") elif dont_likes.startswith("]"): dont_like_regex.append("#[\d\w]+" + dont_likes[1:] + "([^\d\w]|$)") else: dont_like_regex.append("#[\d\w]*" + dont_likes + "[\d\w]*([^\d\w]|$)") for dont_likes_regex in dont_like_regex: quash = re.search(dont_likes_regex, image_text, re.IGNORECASE) if quash: quashed = \ (((quash.group(0)).split('#')[1]).split(' ')[0]).split('\n')[ 0].encode( 'utf-8') # dismiss possible space and newlines iffy = ( (re.split(r'\W+', dont_likes_regex))[3] if dont_likes_regex.endswith('*([^\\d\\w]|$)') else # 'word' without format (re.split(r'\W+', dont_likes_regex))[1] if dont_likes_regex.endswith('+([^\\d\\w]|$)') else # '[word' (re.split(r'\W+', dont_likes_regex))[3] if dont_likes_regex.startswith('#[\\d\\w]+') else # ']word' (re.split(r'\W+', dont_likes_regex))[1]) # '#word' inapp_unit = 'Inappropriate! ~ contains "{}"'.format( quashed if iffy == quashed else '" in "'.join([str(iffy), str(quashed)])) return True, user_name, is_video, inapp_unit, "Undesired word" return False, user_name, is_video, 'None', "Success"
def get_links_for_username(browser, username, person, amount, logger, logfolder, randomize=False, media=None, taggedImages=False): """Fetches the number of links specified by amount and returns a list of links""" if media is None: # All known media types media = ['', 'Post', 'Video'] elif media == 'Photo': # Include posts with multiple images in it media = ['', 'Post'] 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.facebook.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, logger, Settings) if "Page Not Found" in browser.title: logger.error( 'Facebook 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, follow_button = get_following_status(browser, 'profile', username, person, None, logger, logfolder) if following == 'Following': following = True is_private = is_private_profile(Settings, browser, logger, following) if (is_private is None) or (is_private is True and not following) or (following == 'Blocked'): return False # 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 browser.execute_script( "window.scrollTo(0, document.body.scrollHeight);") # update server calls after a scroll request update_activity(Settings) sleep(0.66) # using `extend` or `+=` results reference stay alive which affects # previous assignment (can use `copy()` for it) links = links + get_links(browser, person, logger, media, main_elem) links = sorted(set(links), key=links.index) if len(links) == len(initial_links): if attempt >= 7: 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 unfollow_user(browser, track, username, userid, person, person_id, button, relationship_data, logger, logfolder, Settings): """ 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 quota_supervisor(Settings, "unfollows") == "jump": 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.facebook.com/{}/".format(person) web_address_navigator(browser, user_link, Settings) # find out CURRENT follow status following_status, follow_button = get_following_status( browser, track, username, person, person_id, logger, logfolder) if following_status in ["Following", "Requested"]: click_element(browser, Settings, follow_button) # click to unfollow sleep(4) # TODO: use explicit wait here confirm_unfollow(browser) unfollow_state, msg = verify_action(browser, "unfollow", track, username, person, person_id, logger, logfolder) if unfollow_state is not True: return False, msg elif following_status in ["Follow", "Follow Back"]: logger.info("--> Already unfollowed '{}'! or a private user that " "rejected your req".format(person)) post_unfollow_cleanup(["successful", "uncertain"], username, person, relationship_data, person_id, logger, logfolder) return False, "already unfollowed" elif following_status in ["Unblock", "UNAVAILABLE"]: if following_status == "Unblock": failure_msg = "user is in block" elif following_status == "UNAVAILABLE": failure_msg = "user is inaccessible" logger.warning("--> Couldn't unfollow '{}'!\t~{}".format( person, failure_msg)) post_unfollow_cleanup("uncertain", username, person, relationship_data, person_id, logger, logfolder) return False, following_status elif following_status is None: sirens_wailing, emergency_state = emergency_exit( browser, Settings, username, userid, logger, logfolder) if sirens_wailing is True: return False, emergency_state else: logger.warning( "--> Couldn't unfollow '{}'!\t~unexpected failure".format( person)) return False, "unexpected failure" elif track == "dialog": """ Method of unfollowing from a dialog box """ click_element(browser, Settings, button) sleep(4) # TODO: use explicit wait here confirm_unfollow(browser) # general tasks after a successful unfollow logger.info("--> Unfollowed '{}'!".format(person)) update_activity(Settings, 'unfollows') post_unfollow_cleanup("successful", username, person, relationship_data, person_id, logger, logfolder) # get the post-unfollow delay time to sleep naply = get_action_delay("unfollow", Settings) sleep(naply) return True, "success"
def follow_user(browser, track, login, userid_to_follow, button, blacklist, logger, logfolder, Settings): """ 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 quota_supervisor(Settings, "follows") == "jump": 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.facebook.com/{}/".format(userid_to_follow) web_address_navigator(browser, user_link, Settings) # find out CURRENT following status following_status, follow_button = \ get_following_status(browser, track, login, userid_to_follow, None, logger, logfolder) if following_status in ["Follow", "Follow Back"]: click_visibly(browser, Settings, follow_button) # click to follow follow_state, msg = verify_action(browser, "follow", track, login, userid_to_follow, None, logger, logfolder) if follow_state is not True: return False, msg elif following_status in ["Following", "Requested"]: if following_status == "Following": logger.info( "--> Already following '{}'!\n".format(userid_to_follow)) elif following_status == "Requested": logger.info("--> Already requested '{}' to follow!\n".format( userid_to_follow)) sleep(1) return False, "already followed" elif following_status in ["Unblock", "UNAVAILABLE"]: if following_status == "Unblock": failure_msg = "user is in block" elif following_status == "UNAVAILABLE": failure_msg = "user is inaccessible" logger.warning("--> Couldn't follow '{}'!\t~{}".format( userid_to_follow, failure_msg)) return False, following_status elif following_status is None: # TODO:BUG:2nd login has to be fixed with userid of loggedin user sirens_wailing, emergency_state = emergency_exit( browser, Settings, "https://www.facebook.com", login, login, logger, logfolder) if sirens_wailing is True: return False, emergency_state else: logger.warning( "--> Couldn't unfollow '{}'!\t~unexpected failure".format( userid_to_follow)) return False, "unexpected failure" elif track == "dialog": click_element(browser, Settings, button) sleep(3) # general tasks after a successful follow logger.info("--> Followed '{}'!".format(userid_to_follow.encode("utf-8"))) update_activity(Settings, 'follows') # get user ID to record alongside username user_id = get_user_id(browser, track, userid_to_follow, logger) logtime = datetime.now().strftime('%Y-%m-%d %H:%M') log_followed_pool(login, userid_to_follow, logger, logfolder, logtime, user_id) follow_restriction("write", userid_to_follow, None, logger) if blacklist['enabled'] is True: action = 'followed' add_user_to_blacklist(userid_to_follow, blacklist['campaign'], action, logger, logfolder) # get the post-follow delay time to sleep naply = get_action_delay("follow", Settings) sleep(naply) return True, "success"
def login_user(browser, username, userid, password, logger, logfolder, switch_language=True, bypass_suspicious_attempt=False, bypass_with_mobile=False): """Logins the user with the given username and password""" assert username, 'Username not provided' assert password, 'Password not provided' print(username, password) ig_homepage = "https://accounts.google.com/ServiceLogin?continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Fhl%3Den%26feature%3Dcomment%26app%3Ddesktop%26next%3D%252Fall_comments%253Fv%253DLAr6oAKieHk%26action_handle_signin%3Dtrue&uilel=3&service=youtube&passive=true&hl=en" web_address_navigator(browser, ig_homepage, Settings) cookie_loaded = False # try to load cookie from username try: for cookie in pickle.load( open('{0}{1}_cookie.pkl'.format(logfolder, username), 'rb')): browser.add_cookie(cookie) cookie_loaded = True except (WebDriverException, OSError, IOError): print("Cookie file not found, creating cookie...") # include time.sleep(1) to prevent getting stuck on google.com time.sleep(1) web_address_navigator(browser, ig_homepage, Settings) reload_webpage(browser, Settings) # try: # profile_pic = browser.find_element_by_xpath('//header/div[8]/details/summary/img') # if profile_pic: # login_state = True # else: # login_state = False # except Exception as e: # print(e) # login_state = False # print('login_state:', login_state) # if login_state is True: # # dismiss_notification_offer(browser, logger) # return True # if user is still not logged in, then there is an issue with the cookie # so go create a new cookie.. if cookie_loaded: print("Issue with cookie for user {}. Creating " "new cookie...".format(username)) # wait until the 'username' input element is located and visible input_username_XP = '//*[@id="identifierId"]' # explicit_wait(browser, "VOEL", [input_username_XP, "XPath"], logger) input_username = browser.find_element_by_xpath(input_username_XP) print('moving to input_username') print('entering input_username') (ActionChains(browser).move_to_element(input_username).click().send_keys( username).perform()) sleep(1) (ActionChains(browser).send_keys(Keys.ENTER).perform()) # update server calls for both 'click' and 'send_keys' actions for i in range(2): update_activity(Settings) sleep(1) # password input_password = browser.find_elements_by_xpath( "//*[@id='password']/div[1]/div/div[1]/input") if not isinstance(password, str): password = str(password) print('entering input_password') (ActionChains(browser).move_to_element( input_password[0]).click().send_keys(password).perform()) sleep(1) (ActionChains(browser).send_keys(Keys.ENTER).perform()) # update server calls for both 'click' and 'send_keys' actions for i in range(2): update_activity(Settings) sleep(1) print('submitting (ie just pres enter)') (ActionChains(browser).send_keys(Keys.ENTER).perform()) # update server calls update_activity(Settings) sleep(1) # wait until page fully load explicit_wait(browser, "PFL", [], logger, 5) try: profile_pic = browser.find_element_by_xpath('//*[@id="img"]') if profile_pic: login_state = True print('logged in') pickle.dump( browser.get_cookies(), open('{0}{1}_cookie.pkl'.format(logfolder, username), 'wb')) else: login_state = False except Exception as e: print(e) login_state = False return login_state
def login_user(browser, username, password, userid, logger, logfolder): """Logins the user with the given username and password""" assert username, 'Username not provided' assert password, 'Password not provided' print(username, password) homepage = "https://www.medium.com/" web_address_navigator(browser, homepage, Settings) cookie_loaded = False # try to load cookie from username try: for cookie in pickle.load( open('{0}{1}_cookie.pkl'.format(logfolder, username), 'rb')): browser.add_cookie(cookie) cookie_loaded = True except (WebDriverException, OSError, IOError): print("Cookie file not found, creating cookie...") # include time.sleep(1) to prevent getting stuck on google.com time.sleep(1) web_address_navigator(browser, homepage, Settings) reload_webpage(browser, Settings) # if user is still not logged in, then there is an issue with the cookie # so go create a new cookie.. # cookie has been LOADED, so the user SHOULD be logged in # check if the user IS logged in if cookie_loaded: login_state = check_authorization(browser, Settings, "https://www.medium.com", username, userid, "activity counts", logger, logfolder, True) print('check_authorization:', login_state) if login_state is True: # dismiss_notification_offer(browser, logger) return True else: print("Issue with cookie for user {}. Creating " "new cookie...".format(username)) input_username_XP = '//div[2]/div[1]/input[@name="email"]' input_usernames = browser.find_elements_by_xpath( input_username_XP) #TODO : Two tags found just take the last one print('moving to input_username') print('entering input_username: {}'.format(username)) #email login doesn't reprompt (ActionChains(browser).move_to_element( input_usernames[-1]).click().send_keys(username).perform()) # update server calls for both 'click' and 'send_keys' actions for i in range(2): update_activity(Settings) sleep(1) # password input_passeord_XP = '//div[2]/div[2]/input[@name="password"]' input_passwords = browser.find_elements_by_xpath(input_passeord_XP) print('entering input_password') (ActionChains(browser).move_to_element( input_passwords[-1]).click().send_keys(password).perform()) # update server calls for both 'click' and 'send_keys' actions for i in range(2): update_activity(Settings) sleep(1) print('submitting login_button') login_button_XP = '//div[2]/div[3]/input' login_button = browser.find_element_by_xpath(login_button_XP) (ActionChains(browser).move_to_element(login_button).click().perform()) # update server calls update_activity(Settings) sleep(2) # wait until page fully load explicit_wait(browser, "PFL", [], logger, 5) # Check if user is logged-in (If there's two 'nav' elements) login_state = check_authorization(browser, Settings, "https://www.medium.com/login", username, userid, "activity counts", logger, logfolder, True) print('check_authorization again:', login_state) return login_state
def login_user(browser, username, userid, password, logger, logfolder, switch_language=True, bypass_suspicious_attempt=False, bypass_with_mobile=False): """Logins the user with the given username and password""" assert username, 'Username not provided' assert password, 'Password not provided' print(username, password) ig_homepage = "https://www.facebook.com" web_address_navigator(browser, ig_homepage, Settings) cookie_loaded = False # try to load cookie from username try: for cookie in pickle.load( open('{0}{1}_cookie.pkl'.format(logfolder, username), 'rb')): browser.add_cookie(cookie) cookie_loaded = True except (WebDriverException, OSError, IOError): print("Cookie file not found, creating cookie...") # include time.sleep(1) to prevent getting stuck on google.com time.sleep(1) # changes facebook website language to english to use english xpaths if switch_language: links = browser.find_elements_by_xpath('//*[@id="pageFooter"]/ul/li') for link in links: if link.get_attribute('title') == "English (UK)": click_element(browser, Settings, link) web_address_navigator(browser, ig_homepage, Settings) reload_webpage(browser, Settings) # cookie has been LOADED, so the user SHOULD be logged in # check if the user IS logged in login_state = check_authorization(browser, Settings, "https://www.facebook.com/", username, userid, "activity counts", logger, logfolder, True) print('check_authorization:', login_state) if login_state is True: # dismiss_notification_offer(browser, logger) return True # if user is still not logged in, then there is an issue with the cookie # so go create a new cookie.. if cookie_loaded: print("Issue with cookie for user {}. Creating " "new cookie...".format(username)) # # Check if the first div is 'Create an Account' or 'Log In' # login_elem = browser.find_element_by_xpath( # '//*[@id="email"]' # ) # if login_elem is not None: # try: # (ActionChains(browser) # .move_to_element(login_elem) # .click() # .perform()) # except MoveTargetOutOfBoundsException: # login_elem.click() # # update server calls # update_activity(Settings) # Enter username and password and logs the user in # Sometimes the element name isn't 'Username' and 'Password' # (valid for placeholder too) # wait until it navigates to the login page # login_page_title = "Login" # explicit_wait(browser, "TC", login_page_title, logger) # wait until the 'username' input element is located and visible input_username_XP = '//*[@id="email"]' # explicit_wait(browser, "VOEL", [input_username_XP, "XPath"], logger) input_username = browser.find_element_by_xpath(input_username_XP) print('moving to input_username') print('entering input_username') (ActionChains(browser).move_to_element(input_username).click().send_keys( username).perform()) # update server calls for both 'click' and 'send_keys' actions for i in range(2): update_activity(Settings) sleep(1) # password input_password = browser.find_elements_by_xpath('//*[@id="pass"]') if not isinstance(password, str): password = str(password) print('entering input_password') (ActionChains(browser).move_to_element( input_password[0]).click().send_keys(password).perform()) # update server calls for both 'click' and 'send_keys' actions for i in range(2): update_activity(Settings) sleep(1) print('submitting login_button') login_button = browser.find_element_by_xpath('//*[@type="submit"]') (ActionChains(browser).move_to_element(login_button).click().perform()) # update server calls update_activity(Settings) sleep(1) # dismiss_get_app_offer(browser, logger) # dismiss_notification_offer(browser, logger) if bypass_suspicious_attempt is True: bypass_suspicious_login(browser, bypass_with_mobile) # wait until page fully load # explicit_wait(browser, "PFL", [], logger, 5) # Check if user is logged-in (If there's two 'nav' elements) nav = browser.find_elements_by_xpath('//div[@role="navigation"]') if len(nav) == 2: # create cookie for username print('logged in') pickle.dump( browser.get_cookies(), open('{0}{1}_cookie.pkl'.format(logfolder, username), 'wb')) return True else: return False
def likers_from_post(browser, logger, Selectors, amount=20): """ Get the list of users from the 'Likes' dialog of a photo """ liked_counter_button = \ '//form/div/div/div/div/div/span/span/a[@role="button"]' try: liked_this = browser.find_elements_by_xpath(liked_counter_button) element_to_click = liked_this[0] # print('element_to_click:', element_to_click) # likers = [] # for liker in liked_this: # if " like this" not in liker.text: # likers.append(liker.text) # if check_exists_by_xpath(browser, liked_counter_button): # if " others" in liked_this[-1].text: # element_to_click = liked_this[-1] # elif " likes" in liked_this[0].text: # element_to_click = liked_this[0] # else: # print("Few likes, not guaranteed you don't follow these" # " likers already.\nGot photo likers: {}\n" # .format(likers)) # return likers # else: # print("Couldn't find liked counter button. May be a video.") # print("Moving on..") # return [] sleep(1) click_element(browser, Settings, element_to_click) print("opening likes") # update server calls # update_activity(Settings) sleep(1) # get a reference to the 'Likes' dialog box dialog = browser.find_element_by_xpath( Selectors.likes_dialog_body_xpath) # scroll down the page previous_len = -1 browser.execute_script( "arguments[0].scrollTop = arguments[0].scrollHeight", dialog) update_activity(Settings) sleep(1) start_time = time.time() user_list = [] while (not user_list or (len(user_list) != previous_len) and (len(user_list) < amount)): previous_len = len(user_list) scroll_bottom(browser, dialog, 2) user_list = get_users_from_dialog(user_list, dialog, logger) # print('user_list (loop):') # print(user_list) # write & update records at Progress Tracker progress_tracker(len(user_list), amount, start_time, None) if previous_len + 10 >= amount: print("\nScrolling finished") sleep(1) break print('\n') # print('user_list:') # print(user_list) random.shuffle(user_list) sleep(1) close_dialog_box(browser) print("Got {} likers shuffled randomly whom you can follow:\n{}" "\n".format(len(user_list), user_list)) return user_list except Exception as exc: print("Some problem occured!\n\t{}".format(str(exc).encode("utf-8"))) return []
def bypass_suspicious_login(browser, bypass_with_mobile): """Bypass suspicious loggin attempt verification. This should be only enabled when there isn't available cookie for the username, otherwise it will and shows "Unable to locate email or phone button" message, folollowed by CRITICAL - Wrong login data!""" # close sign up Facebook modal if available try: close_button = browser.find_element_by_xpath("[text()='Close']") (ActionChains(browser).move_to_element(close_button).click().perform()) # update server calls update_activity(Settings) except NoSuchElementException: pass try: # click on "This was me" button if challenge page was called this_was_me_button = browser.find_element_by_xpath( "//button[@name='choice'][text()='This Was Me']") (ActionChains(browser).move_to_element( this_was_me_button).click().perform()) # update server calls update_activity(Settings) except NoSuchElementException: # no verification needed pass try: choice = browser.find_element_by_xpath("//label[@for='choice_1']").text except NoSuchElementException: try: choice = browser.find_element_by_xpath( "//label[@class='_q0nt5']").text except Exception: try: choice = browser.find_element_by_xpath( "//label[@class='_q0nt5 _a7z3k']").text except Exception: print("Unable to locate email or phone button, maybe " "bypass_suspicious_login=True isn't needed anymore.") return False if bypass_with_mobile: choice = browser.find_element_by_xpath("//label[@for='choice_0']").text mobile_button = browser.find_element_by_xpath( "//label[@for='choice_0']") (ActionChains(browser).move_to_element( mobile_button).click().perform()) sleep(5) send_security_code_button = browser.find_element_by_xpath( "//button[text()='Send Security Code']") (ActionChains(browser).move_to_element( send_security_code_button).click().perform()) # update server calls update_activity(Settings) print('Facebook detected an unusual login attempt') print('A security code was sent to your {}'.format(choice)) security_code = input('Type the security code here: ') security_code_field = browser.find_element_by_xpath( ("//input[@id='security_code']")) (ActionChains(browser).move_to_element( security_code_field).click().send_keys(security_code).perform()) # update server calls for both 'click' and 'send_keys' actions for i in range(2): update_activity(Settings) submit_security_code_button = browser.find_element_by_xpath( "//button[text()='Submit']") (ActionChains(browser).move_to_element( submit_security_code_button).click().perform()) # update server calls update_activity(Settings) try: sleep(5) # locate wrong security code message wrong_login = browser.find_element_by_xpath( ("//p[text()='Please check the code we sent you and try " "again.']")) if wrong_login is not None: print(('Wrong security code! Please check the code Facebook' 'sent you and try again.')) except NoSuchElementException: # correct security code pass