class Login: def __init__(self, driver): self.driver = driver self.twitter_common = TwitterCommon(driver) self.utils = Utils(driver) def __find_elements(self): try: username_or_email_field = WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.NAME, "session[username_or_email]"))) password_field = self.driver.find_element_by_name("session[password]") except: self.utils.handle_error("Login: username or password xpath outdated") return (username_or_email_field, password_field) @property def logged_in(self): return not not self.twitter_common.get_cookie("auth_token") def __submit_login_credentials(self, username_or_email, password): username_or_email_field, password_field = self.__find_elements() Utils.clear_fields(username_or_email_field, password_field) username_or_email_field.send_keys(username_or_email) password_field.send_keys(password) password_field.send_keys(Keys.ENTER) def __handle_login_errors(self): error = self.utils.url_starts_with("https://twitter.com/login/error") if not error: return try: error = self.driver.find_element_by_css_selector('div[class="css-901oao r-daml9f r-1qd0xha r-a023e6 r-16dba41 r-ad9z0x r-bcqeeo r-qvutc0"] > span[class="css-901oao css-16my406 r-1qd0xha r-ad9z0x r-bcqeeo r-qvutc0"]').text except Exception as err: error = err self.utils.handle_error(error) def login(self, username_or_email, password): if (self.logged_in): return self.utils.navigate(TwitterUrls.twitter_loginurl) self.__submit_login_credentials(username_or_email, password) self.__handle_login_errors()
class Logout: def __init__(self, driver): self.driver = driver self.utils = Utils(driver) def logout(self): logged_in = Login(self.driver).logged_in if not logged_in: self.utils.quit() self.driver.get('https://twitter.com/logout') try: confirm_logout_btn = WebDriverWait(self.driver, 3).until( EC.presence_of_element_located( (By.XPATH, '//div[@data-testid="confirmationSheetConfirm"]'))) except NoSuchElementException: self.utils.handle_error( "Logout: confirm logout button xpath outdated") else: self.utils.click_js(confirm_logout_btn) self.utils.quit()
from driver import Driver from login import Login from followers import Followers from home import Home from logout import Logout from util import Utils driver = Driver().driver util = Utils(driver) def main(): username = "" password = "" Login(driver).login(username, password) # Followers(driver).follow('jannatmirza07') # Home(driver, username).like_and_comment() # Logout(driver).logout() try: main() except Exception as error: util.handle_error(error)
class Followers: def __init__(self, driver): self.driver = driver self.utils = Utils(driver) def __find_followable_people_element(self): tries = 0 while True: tries += 1 try: follow_element = WebDriverWait(self.driver, 2).until(EC.presence_of_element_located((By.XPATH, '//div[contains(@style,"position: absolute;") and .//div[contains(@data-testid, "-follow")]]'))) except Exception as error: if tries > 2: self.utils.handle_error(error) self.utils.scroll_to_end() continue else: return follow_element def __find_username_and_follow_btn(self, follow_element): try: username = follow_element.find_element_by_xpath('.//div[contains(@class, "r-1re7ezh r-18u37iz")]/span').text follow_btn = follow_element.find_element_by_xpath('.//div[contains(@data-testid, "-follow")]') except: self.utils.handle_error("Followers: username or follow_btn xpath outdated") return (username, follow_btn) def __handle_if_error_occured(self, username, last_followed_user): if username == last_followed_user: try: error = WebDriverWait(self.driver, 2).until(EC.presence_of_element_located((By.XPATH, '//div[@data-testid="toast"]//div[contains(@class, "r-16dba41")]//span'))).text except NoSuchElementException: error = "Followers: Xpath for error text of followers is outdated" except: error = "Followers: Unexpected error" self.utils.handle_error(error) def __wait_before_next_follow(self): delay = round(random.uniform(2, 4), 3) print(f"Waiting {delay} seconds before next follow") time.sleep(delay) def follow(self, username_or_query, is_username=True, limit=400): if is_username: self.utils.navigate(TwitterUrls.get_link_of_user_followers(username_or_query)) else: self.utils.navigate(TwitterUrls.get_twitter_users_link(username_or_query)) current_iteration = 1 last_followed_user = None while current_iteration <= limit: current_iteration += 1 follow_element = self.__find_followable_people_element() username, follow_btn = self.__find_username_and_follow_btn(follow_element) self.__handle_if_error_occured(username, last_followed_user) self.utils.click_js(follow_btn) print(f"Just followed {username}") last_followed_user = username self.__wait_before_next_follow()
class Home: def __init__(self, driver, username): self.driver = driver self.utils = Utils(driver) self.username = username def __find_post(self): tries = 0 while True: tries += 1 try: post = WebDriverWait(self.driver, 5).until( EC.presence_of_element_located(( By.XPATH, f'//div[ .//div[@data-testid="like"] and contains(@style, "position: absolute") and .//div[ contains( @class, "css-bfa6kz r-1re7ezh")]//span[text() != "{self.username}" ] ]' ))) except Exception as error: if (tries > 2): playsound('./alert_sound.mp3') print(error) if input("Do you want to quitr? y/n").lower() == 'n': tries = 0 continue self.utils.quit() self.utils.scroll_to_end() continue else: return post def __find_required_elements(self, post): try: username = post.find_element_by_xpath( './/div[ contains( @class, "css-bfa6kz r-1re7ezh")]//span' ).text like_btn = post.find_element_by_xpath( './/div[@data-testid="like"]') reply_btn = post.find_element_by_xpath( './/div[@data-testid="reply"]') except: self.utils.handle_error( "Home: username, likebtn or reply btn xpath outdated") return (username, like_btn, reply_btn) def __reply(self, reply_btn, comment): self.utils.click_js(reply_btn) try: reply_input = self.driver.find_element_by_xpath( '(//div[@data-testid="tweetTextarea_0"])[1]') except: self.utils.handle_error("Home: Reply input field xpath outdated") else: reply_input.send_keys(comment, Keys.CONTROL + Keys.ENTER) def __get_comment(self): comments = [ f"Nice post", f"Awesome work", f"Impressive work", f"Coool" ] return comments[random.randint(0, len(comments) - 1)] def __handle_like_error(self, like_btn): print(like_btn.get_attribute('data-testid')) if like_btn.get_attribute('data-testid') != 'unlike': try: error = WebDriverWait(self.driver, 3).until( EC.presence_of_element_located( (By.XPATH, '//div[@data-testid="toast" and @role="alert"]//span' ))).text except NoSuchElementException: error = """Home: Like error occured...\nPossible Reasons:\n1: Slow internet\n2: Xpath for error text of like is outdated OR error text is not displayed by twitter""" except: error = 'Home: Unexpected error' self.utils.handle_error(error) def like_and_comment(self, like_only=True, limit=1000): self.utils.navigate(TwitterUrls.twitter_home_url) current_iteration = 1 while current_iteration <= limit: post = self.__find_post() username, like_btn, reply_btn = self.__find_required_elements(post) print(":" * 20 + f"POST OF user {username} found" + ":" * 20) self.utils.click_js(like_btn) print("-->post liked") time.sleep(random.uniform(.5, .8)) self.__handle_like_error(like_btn) if not like_only: self.__reply(reply_btn, self.__get_comment()) print("-->replied to the post") delay = random.uniform(2, 4) print(f"Waiting {delay} seconds.") time.sleep(delay)