Search code examples
pythonselenium-webdriverweb-scrapingfirefoxbrowser-automation

Optimizing Selenium script for faster execution


I've developed a Python script using Selenium for automating tasks on Twitter, including logging in, posting tweets with images, liking own tweets, retweeting, and logging out. While the script works fine, I've noticed that the processes are relatively slow. I'm looking for ways to optimize these of problem for the script for faster execution.

I've already implemented time.sleep() to introduce delays, but I'm open to better approaches. I'm using Firefox WebDriver with headless mode enabled. The script is being executed on RTX 3050. Any insights or suggestions on how to enhance the overall efficiency of the script would be highly appreciated



User
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC 
from selenium.webdriver.common.keys import Keys
import time


class TwitterBot:
    def __init__(self, username, password):
        self.username = username
        self.password = password
        options = Options()
        options.add_argument('--disk-cache-dir=/path/to/cache')
        options.add_argument('--headless')
        self.bot = webdriver.Firefox(options=options)


    def login(self):
        bot = self.bot
        bot.get('https://twitter.com/login')
        time.sleep(3)
        email = bot.find_element(By.XPATH, "//input[@name='text']")
        email.send_keys(self.username)
        email.send_keys(Keys.RETURN)
        time.sleep(3)
        password = bot.find_element(By.XPATH, "//input[@name='password']")
        password.send_keys(self.password)
        password.send_keys(Keys.RETURN)
        time.sleep(4)

    def post_tweet_with_image(self, tweet_text, image_path):
        bot = self.bot
        bot.get('https://twitter.com/compose/tweet')
        time.sleep(3)

        tweet_input = bot.find_element(By.XPATH, "//div[@data-testid='tweetTextarea_0']")
        tweet_input.send_keys(tweet_text)
        time.sleep(2)

        if image_path:
            image_input = bot.find_element(By.XPATH, "//input[@data-testid='fileInput']")
            image_input.send_keys(image_path)
            time.sleep(2)

        tweet_button = bot.find_element(By.XPATH, "//text()[.='Post']/ancestor::div[1]")
        tweet_button.click()
        time.sleep(10)
    def like_own_tweet(self):
        bot = self.bot
    # Go to profile
        profile_button = bot.find_element(By.XPATH, "//span[normalize-space()='Profile']")
        profile_button.click()
        time.sleep(3)
        bot.execute_script('window.scrollTo(0,document.body.scrollHeight)')
        time.sleep(3)
    # Locate the latest tweet on your profile
        tweet = bot.find_element(By.XPATH, "/html[1]/body[1]/div[1]/div[1]/div[1]/div[2]/main[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[3]/div[1]/div[1]/section[1]/div[1]/div[1]/div[1]/div[1]/div[1]/article[1]/div[1]/div[1]/div[2]/div[2]/div[2]/div[1]")   
        tweet.click()
        time.sleep(3)
    # Like the tweet
        like_button = bot.find_element(By.XPATH, "/html[1]/body[1]/div[1]/div[1]/div[1]/div[2]/main[1]/div[1]/div[1]/div[1]/div[1]/div[1]/section[1]/div[1]/div[1]/div[1]/div[1]/div[1]/article[1]/div[1]/div[1]/div[3]/div[6]/div[1]/div[1]/div[3]/div[1]/div[1]/div[1]/*[name()='svg'][1]")
        like_button.click()
        time.sleep(3)
    def retweet_from_user(self, user_handle):
        bot = self.bot
        search_bar = bot.find_element(By.XPATH, "//input[@data-testid='SearchBox_Search_Input']")

        search_bar.clear()
        search_bar.send_keys(f"from:{user_handle}")
        search_bar.send_keys(Keys.RETURN)
        time.sleep(5)
        bot.find_element(By.LINK_TEXT,"Latest").click()
        time.sleep(3)
        # Click on the latest tweet from the user
        tweet = bot.find_element(By.XPATH, "/html[1]/body[1]/div[1]/div[1]/div[1]/div[2]/main[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[3]/section[1]/div[1]/div[1]/div[1]/div[1]/div[1]/article[1]/div[1]/div[1]/div[2]/div[2]/div[2]/div[1]")
        tweet.click()
        time.sleep(3)
        # Retweet the tweet
        retweet_button = bot.find_element(By.XPATH, "/html[1]/body[1]/div[1]/div[1]/div[1]/div[2]/main[1]/div[1]/div[1]/div[1]/div[1]/div[1]/section[1]/div[1]/div[1]/div[1]/div[1]/div[1]/article[1]/div[1]/div[1]/div[3]/div[6]/div[1]/div[1]/div[2]/div[1]/div[1]/div[1]/*[name()='svg'][1]")
        retweet_button.click()
        repost_button = bot.find_element(By.XPATH,"/html[1]/body[1]/div[1]/div[1]/div[1]/div[1]/div[2]/div[1]/div[1]/div[1]/div[2]/div[1]/div[3]/div[1]/div[1]/div[1]/div[1]/div[2]/div[1]/span[1]")
        repost_button.click()
        time.sleep(3)


    def logout(self):
        bot = self.bot
        profile_button = bot.find_element(By.XPATH, "//div[@data-testid='SideNav_AccountSwitcher_Button']")
        profile_button.click()
        time.sleep(2)
        logout_button = bot.find_element(By.XPATH, "//div[@data-testid='AccountSwitcher_Logout_Button']")
        logout_button.click()
        time.sleep(2)

    def close_browser(self):
        self.bot.quit()

if __name__ == "__main__":
    users = [ "write user names and the password here"]

    for user_info in users[:15]:
        username = user_info["username"]
        password = user_info["password"]

        # Create an instance of the TwitterBot
        twitter_bot = TwitterBot(username, password)
        twitter_bot.login()

        # Loop to post multiple tweets
        while True:
            tweet_text = "anything"
            image_path = r"C:\Users\hp\Downloads\anything.jpeg"


            # Post the tweet
            twitter_bot.post_tweet_with_image(tweet_text, image_path)

            # Like and retweet functionality
            break

        # Close the browser session
        twitter_bot.close_browser()

Solution

  • Get rid of all the time.sleep()s... they are a bad practice and slow down your script. Replace them with WebDriverWait.

    If you are going to click an element, wait for it to be clickable.

    wait = WebDriverWait(driver, 10)
    wait.until(EC.element_to_be_clickable(...)).click()
    

    If you are going to otherwise interact with an element, e.g. .text or .send_keys(), wait for it to be visible.

    wait.until(EC.visibility_of_element_located(...)).send_keys()
    

    For example,

    wait = WebDriverWait(driver, 10)
    wait.until(EC.visibility_of_element_located((By.XPATH, "//input[@name='text']"))).send_keys(self.username)
    

    For more info and examples, see the docs.

    If you want even more speed and you are doing multiple tasks in one run, you can add parallelism and run each action as a separate thread. I'll leave that as an exercise for the reader because it's more involved and there are some risks if you don't know what you're doing. See the docs for more info.