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()
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.