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 update_activity(Settings, action="server_calls"): """ Record every Instagram server call (page load, content load, likes, comments, connects, unconnect). """ # check action availability quota_supervisor(Settings, "server_calls") # get a DB and start a connection db, id = get_database(Settings) conn = sqlite3.connect(db) with conn: conn.row_factory = sqlite3.Row cur = conn.cursor() # collect today data cur.execute( "SELECT * FROM recordActivity WHERE profile_id=:var AND " "STRFTIME('%Y-%m-%d %H', created) == STRFTIME('%Y-%m-%d " "%H', 'now', 'localtime')", {"var": id}) data = cur.fetchone() if data is None: # create a new record for the new day cur.execute( "INSERT INTO recordActivity VALUES " "(?, 0, 0, 0, 0, 1, STRFTIME('%Y-%m-%d %H:%M:%S', " "'now', 'localtime'))", (id, )) else: # sqlite3.Row' object does not support item assignment -> so, # convert it into a new dict data = dict(data) # update data[action] += 1 quota_supervisor(Settings, action, update=True) if action != "server_calls": # always update server calls data["server_calls"] += 1 quota_supervisor(Settings, "server_calls", update=True) sql = ( "UPDATE recordActivity set " "likes = ?, comments = ?, follows = ?, unfollows = ?, server_calls = ?, " "created = STRFTIME('%Y-%m-%d %H:%M:%S', 'now', " "'localtime') " "WHERE profile_id=? AND STRFTIME('%Y-%m-%d %H', created) " "== " "STRFTIME('%Y-%m-%d %H', 'now', 'localtime')") cur.execute(sql, (data['likes'], data['comments'], data['follows'], data['unfollows'], data['server_calls'], id)) # commit the latest changes conn.commit()
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 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 search_and_endorse(self, query, city_code, school_code, random_start=True, max_pages=3, max_endorsements=25, sleep_delay=6): """ search linkedin and endose few first connections """ if quota_supervisor(Settings, "connects") == "jump": return #False, "jumped" print("Searching for: ", query, city_code, school_code) search_url = "https://www.linkedin.com/search/results/people/?" if city_code: search_url = search_url + "&facetGeoRegion=" + city_code if school_code: search_url = search_url + "&facetSchool=" + school_code search_url = search_url + "&facetNetwork=%5B%22F%22%5D" search_url = search_url + "&keywords=" + query search_url = search_url + "&origin=" + "FACETED_SEARCH" if random_start: trial = 0 while True and trial < 3: st = random.randint(1, 3) temp_search_url = search_url + "&page=" + str(st) web_address_navigator(Settings, self.browser, temp_search_url) self.logger.info("Testing page:".format(st)) result_items = self.browser.find_elements_by_css_selector( "div.search-result__wrapper") if len(result_items) > 0: break trial = trial + 1 else: st = 1 connects = 0 for page_no in list(range(st, st + 1)): collected_profile_links = [] try: temp_search_url = search_url + "&page=" + str(page_no) if page_no > st and st > 1: web_address_navigator(Settings, self.browser, temp_search_url) self.logger.info("Starting page: {}".format(page_no)) for jc in range(2, 11): sleep(1) self.browser.execute_script( "window.scrollTo(0, document.body.scrollHeight/" + str(jc) + "-100);") result_items = self.browser.find_elements_by_css_selector( "div.search-result__wrapper") # print(result_items) for result_item in result_items: try: link = result_item.find_element_by_css_selector( "div > a") self.logger.info("Profile : {}".format( link.get_attribute("href"))) collected_profile_links.append( link.get_attribute("href")) name = result_item.find_element_by_css_selector( "h3 > span > span > span") self.logger.info("Name : {}".format(name.text)) except Exception as e: self.logger.error(e) except Exception as e: self.logger.error(e) for collected_profile_link in collected_profile_links: self.endorse(collected_profile_link, sleep_delay=sleep_delay) connects = connects + 1 if connects >= max_endorsements: self.logger.info( "max_endorsements({}) for this iteration reached , Returning..." .format(max_endorsements)) return self.logger.info("============Next Page==============")
def search_and_connect(self, query, connection_relationship_code, city_code, school_code=None, past_company=None, random_start=True, max_pages=10, max_connects=25, sleep_delay=6): """ search linkedin and connect from a given profile """ if quota_supervisor(Settings, "connects") == "jump": return 0 self.logger.info( "Searching for: query={}, connection_relationship_code={}, city_code={}, school_code={}" .format(query, connection_relationship_code, city_code, school_code)) connects = 0 prev_connects = -1 search_url = "https://www.linkedin.com/search/results/people/?" if connection_relationship_code: search_url = search_url + "&facetNetwork=" + connection_relationship_code if city_code: search_url = search_url + "&facetGeoRegion=" + city_code if school_code: search_url = search_url + "&facetSchool=" + school_code if past_company: search_url = search_url + "&facetPastCompany=" + past_company search_url = search_url + "&keywords=" + query search_url = search_url + "&origin=" + "FACETED_SEARCH" temp_search_url = search_url + "&page=1" print(temp_search_url) time.sleep(10) if self.test_page( search_url=temp_search_url, page_no=1, css_selector_identifier="div.search-result__wrapper") == False: self.logger.info( "============Definitely no Result, Next Query==============") return 0 if random_start: trial = 0 st = 5 while True and trial < 5 and st > 1: st = random.randint(1, st - 1) temp_search_url = search_url + "&page=" + str(st) if self.test_page(temp_search_url, st, "div.search-result__wrapper"): break trial = trial + 1 else: st = 1 for page_no in list(range(st, st + max_pages)): if prev_connects == connects: self.logger.info( "============Limits might have exceeded or all Invites pending from this page(let's exit either case)==============" ) break else: prev_connects = connects try: temp_search_url = search_url + "&page=" + str(page_no) if page_no > st and st > 1: web_address_navigator(Settings, self.browser, temp_search_url) self.logger.info("Starting page: {}".format(page_no)) for jc in range(2, 11): sleep(1) self.browser.execute_script( "window.scrollTo(0, document.body.scrollHeight/" + str(jc) + "-100);") if len( self.browser.find_elements_by_css_selector( "div.search-result__wrapper")) == 0: self.logger.info( "============Last Page Reached or asking for Premium membership==============" ) break for i in range( 0, len( self.browser.find_elements_by_css_selector( "div.search-result__wrapper"))): try: res_item = self.browser.find_elements_by_css_selector( "li.search-result div.search-entity div.search-result__wrapper" )[i] # div.search-result__actions div button") # pp.pprint(res_item.get_attribute('innerHTML')) link = res_item.find_element_by_css_selector("div > a") profile_link = link.get_attribute("href") self.logger.info("Profile : {}".format(profile_link)) user_name = profile_link.split('/')[4] # self.logger.info("user_name : {}".format(user_name)) name = res_item.find_element_by_css_selector( "h3 > span > span > span") #//span/span/span[1]") self.logger.info("Name : {}".format(name.text)) if connect_restriction("read", user_name, self.connect_times, self.logger): self.logger.info("already connected") continue try: connect_button = res_item.find_element_by_xpath( "//div[3]/div/button[text()='Connect']") self.logger.info( "Connect button found, connecting...") self.browser.execute_script( "var evt = document.createEvent('MouseEvents');" + "evt.initMouseEvent('click',true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0,null);" + "arguments[0].dispatchEvent(evt);", res_item.find_element_by_xpath( '//div[3]/div/button[text()="Connect"]')) self.logger.info("Clicked {}".format( connect_button.text)) sleep(2) except Exception: invite_sent_button = res_item.find_element_by_xpath( "//div[3]/div/button[text()='Invite Sent']") self.logger.info("Already {}".format( invite_sent_button.text)) continue try: modal = self.browser.find_element_by_css_selector( "div.modal-wormhole-content > div") if modal: try: sendnow_or_done_button = modal.find_element_by_xpath( "//div[1]/div/section/div/div[2]/button[2]" ) #text()='Send now']") self.logger.info( sendnow_or_done_button.text) if not (sendnow_or_done_button.text == 'Done' or sendnow_or_done_button.text == 'Send now'): raise Exception( "Send Now or Done button not found" ) if sendnow_or_done_button.is_enabled(): (ActionChains( self.browser).move_to_element( sendnow_or_done_button).click( ).perform()) self.logger.info("Clicked {}".format( sendnow_or_done_button.text)) connects = connects + 1 connect_restriction( "write", user_name, None, self.logger) try: # update server calls update_activity( Settings, 'connects') except Exception as e: self.logger.error(e) sleep(2) else: try: #TODO: input("find correct close XPATH") close_button = modal.find_element_by_xpath( "//div[1]/div/section/div/header/button" ) (ActionChains( self.browser).move_to_element( close_button).click(). perform()) print(sendnow_or_done_button.text, "disabled, clicked close") sleep(2) except Exception as e: print( "close_button not found, Failed with:", e) except Exception as e: print( "sendnow_or_done_button not found, Failed with:", e) else: self.logger.info("Popup not found") except Exception as e: print("Popup not found, Failed with:", e) try: new_popup_buttons = self.browser.find_elements_by_css_selector( "#artdeco-modal-outlet div.artdeco-modal-overlay div.artdeco-modal div.artdeco-modal__actionbar button.artdeco-button" ) gotit_button = new_popup_buttons[1] (ActionChains(self.browser).move_to_element( gotit_button).click().perform()) print(gotit_button.text, " clicked") sleep(2) except Exception as e: print("New Popup also not found, Failed with:", e) self.logger.info( "Connects sent in this iteration: {}".format( connects)) delay_random = random.randint(ceil(sleep_delay * 0.85), ceil(sleep_delay * 1.14)) sleep(delay_random) if connects >= max_connects: self.logger.info( "max_connects({}) for this iteration reached , Returning..." .format(max_connects)) return except Exception as e: self.logger.error(e) except Exception as e: self.logger.error(e) self.logger.info("============Next Page==============") return connects