Created
August 28, 2025 20:02
-
-
Save ericswpark/d405fa6fe50885e7b2bb3b2360542316 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import datetime | |
| import time | |
| from selenium import webdriver | |
| from selenium.webdriver.common.by import By | |
| from selenium.webdriver.edge.service import Service as EdgeService | |
| from selenium.webdriver.support.ui import WebDriverWait | |
| from selenium.webdriver.support import expected_conditions as EC | |
| from dotenv import load_dotenv | |
| RETRY_MAX_COUNT = 30 | |
| RETRY_WAIT_SEC = 2 | |
| def retry_action(func, func_name): | |
| for _ in range(RETRY_MAX_COUNT): | |
| result = func() | |
| if result: | |
| return result | |
| print(f"Error: function {func_name} did not succeed. Trying again...") | |
| time.sleep(RETRY_WAIT_SEC) | |
| def get_shadow_input(driver, outer_element_id): | |
| def get_shadow_input_inner(): | |
| outer = driver.find_element(By.ID, outer_element_id) | |
| return driver.execute_script("return arguments[0].shadowRoot.querySelector('input')", outer) | |
| retry_action(get_shadow_input_inner, f"get_shadow_input | {outer_element_id}") | |
| def get_shadow_button(driver, button_id): | |
| def get_shadow_button_inner(): | |
| outer = driver.find_element(By.ID, button_id) | |
| return driver.execute_script("return arguments[0].shadowRoot.querySelector('button'), arguments[0]", outer)[0] or outer | |
| retry_action(get_shadow_button_inner, f"get_shadow_button | {button_id}") | |
| def login(driver, wait, username, password): | |
| # Username | |
| wait.until(EC.presence_of_element_located((By.ID, "login-form_username"))) | |
| user_input = get_shadow_input(driver, "login-form_username") | |
| user_input.send_keys(username) | |
| # Next | |
| wait.until(EC.presence_of_element_located((By.ID, "verifUseridBtn"))) | |
| next_button = driver.find_element(By.ID, "verifUseridBtn") | |
| driver.execute_script("arguments[0].click();", next_button) | |
| # Password | |
| wait.until(EC.presence_of_element_located((By.ID, "login-form_password"))) | |
| pass_input = get_shadow_input(driver, "login-form_password") | |
| pass_input.send_keys(password) | |
| # Sign in | |
| wait.until(EC.presence_of_element_located((By.ID, "signBtn"))) | |
| sign_in_btn = driver.find_element(By.ID, "signBtn") | |
| driver.execute_script("arguments[0].click();", sign_in_btn) | |
| def find_sdf_button(driver, wait, title): | |
| wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, f"sdf-button[title='{title}']"))) | |
| return driver.find_element(By.CSS_SELECTOR, f"sdf-button[title='{title}']") | |
| def clock_in(driver, wait): | |
| clock_in_button = find_sdf_button(driver, wait, "Clock In") | |
| driver.execute_script("arguments[0].click();", clock_in_button) | |
| print("✅ Successfully Clocked In!") | |
| def clock_out(driver, wait): | |
| clock_out_button = find_sdf_button(driver, wait, "Clock Out") | |
| driver.execute_script("arguments[0].click();", clock_out_button) | |
| print("✅ Successfully Clocked Out!") | |
| def auto_clock(driver, wait): | |
| now = datetime.datetime.now() | |
| hour = now.hour | |
| minute = now.minute | |
| time_str = now.strftime("%I:%M %p") | |
| print(f"🕒 Current time: {time_str}") | |
| # Between 7:00 AM and 11:00 AM → Clock in | |
| if 7 <= hour < 11: | |
| clock_in(driver=driver, wait=wait) | |
| # Between 5:30 PM and 6:00 PM → Ask user if they want to clock out early | |
| elif hour == 17 and minute >= 30: | |
| minutes_left = 60 - minute | |
| choice = input(f"⏳ There's still {minutes_left} minutes left until 6 PM. Clock out anyway? (y/n): ").strip().lower() | |
| if choice == 'y': | |
| clock_out(driver=driver, wait=wait) | |
| else: | |
| print("⚠️ Keeping you clocked in.") | |
| # Between 6:00 PM and 12:59 AM → Clock out | |
| elif (hour >= 18 and hour <= 23) or (hour >= 0 and hour < 1): | |
| clock_out(driver=driver, wait=wait) | |
| # Other times → Ask the user what to do | |
| else: | |
| choice = input("❓Time is ambiguous. Would you like to clock in (i) or clock out (o)? ").strip().lower() | |
| if choice == 'i': | |
| clock_in(driver=driver, wait=wait) | |
| elif choice == 'o': | |
| clock_out(driver=driver, wait=wait) | |
| else: | |
| print("⚠️ No action taken.") | |
| def main(): | |
| # Load .env for credentials | |
| load_dotenv() | |
| USERNAME = os.getenv("ADP_USER") | |
| PASSWORD = os.getenv("ADP_PASS") | |
| if not USERNAME or not PASSWORD: | |
| raise ValueError("Set ADP_USER and ADP_PASS in your .env file") | |
| # Edge WebDriver path | |
| #EDGEDRIVER_PATH = "C:/path/to/msedgedriver.exe" # Update this | |
| # Set up Edge driver | |
| #service = EdgeService(executable_path=EDGEDRIVER_PATH) | |
| service = EdgeService() | |
| options = webdriver.EdgeOptions() | |
| driver = webdriver.Edge(service=service, options=options) | |
| wait = WebDriverWait(driver, 120) | |
| try: | |
| # Navigate to initial page | |
| driver.get("https://workforcenow.adp.com/theme/index.html#/home") | |
| # Sign in | |
| login(driver=driver, wait=wait, username=USERNAME, password=PASSWORD) | |
| # Auto clock-in/out based on schedule | |
| auto_clock(driver=driver, wait=wait) | |
| time.sleep(10) | |
| finally: | |
| driver.quit() | |
| if __name__ == "__main__": | |
| main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| selenium | |
| python-dotenv |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment