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 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 open_comment_section(browser, logger): missing_comment_elem_warning = ( "--> Comment Button Not Found!" "\t~may cause issues with browser windows of smaller widths") comment_elem = browser.find_elements_by_xpath( "//button/span[@aria-label='Comment']") if len(comment_elem) > 0: try: click_element(browser, Settings, comment_elem[0]) except WebDriverException: logger.warning(missing_comment_elem_warning) else: logger.warning(missing_comment_elem_warning)
def confirm_unfollow(browser): """ Deal with the confirmation dialog boxes during an unfollow """ attempt = 0 while attempt < 3: try: attempt += 1 button_xp = "//button[text()='Unfollow']" # "//button[contains( # text(), 'Unfollow')]" unfollow_button = browser.find_element_by_xpath(button_xp) if unfollow_button.is_displayed(): click_element(browser, Settings, unfollow_button) sleep(2) break except (ElementNotVisibleException, NoSuchElementException) as exc: # prob confirm dialog didn't pop up if isinstance(exc, ElementNotVisibleException): break elif isinstance(exc, NoSuchElementException): sleep(1)
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 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 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 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