from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time from get_message import generate_custom_message import logging import random from logging.handlers import RotatingFileHandler import os from dotenv import load_dotenv load_dotenv() # Constants for login USERNAME = os.getenv("USERNAME") PASSWORD = os.getenv("PASSWORD") # Set up logging # Set up rotating log handler handler = RotatingFileHandler('./wyzant_logs.log', maxBytes=5000000, backupCount=5) # 5 MB per log file, keeps 5 backups logging.basicConfig( handlers=[handler], level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) logging.info("Starting script...") REFRESH_WAIT_TIME = 120 REFRESH_VARIANCE = 15 # Selenium Config chrome_driver_path = "/usr/local/bin/chromedriver/chromedriver" service = Service(executable_path=chrome_driver_path) driver = webdriver.Chrome(service=service) # Go to login site logging.info("Navigating to login page...") driver.get("https://www.wyzant.com/login") # Login time.sleep(3) username_input = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//form[@class='sso-login-form']//input[@id='Username']")) ) username_input.send_keys(USERNAME) password_input = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//form[@class='sso-login-form']//input[@id='Password']")) ) password_input.send_keys(PASSWORD) logging.info("Entered username and password...") login_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, "//form[@class='sso-login-form']//button[@type='submit']")) ) login_button.click() logging.info("Clicked login button.") # Wait and click jobs link time.sleep(3) WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//div[@class='profile-image round-photo']")) ) job_count_element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, "//div[@data-templateid='jobCountTemplate']")) ) job_count_element.click() logging.info("Clicked jobs list link button.") # Loop over the jobs list until no more jobs are found while True: try: # Wait for the jobs list to load and locate the first job link time.sleep(2) first_job_description = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "#jobs-list .job-description")) ) first_job_link = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "#jobs-list .row.spc-small-ew .job-details-link")) ) first_student = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "#jobs-list .text-semibold.spc-zero-n.spc-tiny-s")) ) # Extract job info for GPT job_description_text = first_job_description.text job_subject_text = first_job_link.text job_student_text = first_student.text # Generate and send message message = generate_custom_message(job_description_text, job_student_text, job_subject_text) logging.info(f"Generated custom message for {job_student_text}, subject: {job_subject_text}.") first_job_link.click() # Wait for the message text area and send the message time.sleep(3) text_area = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "personal_message")) ) text_area.clear() # Clears the text area if there's any existing text text_area.send_keys(message) # Insert your message # Check if the hourly rate checkbox exists and click it if present try: checkbox = WebDriverWait(driver, 2).until( EC.presence_of_element_located((By.ID, "agree_partner_hourly_rate")) ) checkbox.click() logging.info("Clicked rate agreement checkbox.") except: logging.info("No rate agreement checkbox found.") # Submit the application submit_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "input.btn.old-button-color")) ) submit_button.click() logging.info("Application submitted successfully.") # Wait for the page to redirect to the jobs list again time.sleep(3) except Exception as e: logging.error(f"Failed find a job to apply. Waiting 1 mins") delay = random.uniform(REFRESH_WAIT_TIME - REFRESH_VARIANCE, REFRESH_WAIT_TIME + REFRESH_VARIANCE) time.sleep(60) driver.refresh() time.sleep(10)