The Problem

For a program I'm making, I need to be able to sign into the user's Google Account via Selenium and do stuff on it. However, I have to use Replit to do this, and due to the nature of Replit, this limits me to have to ask the user for credentials and log in opposed to doing something like using a pre-existing Chrome/Edge/Firefox/Chronium profile to get in. However, I can't seem to get past Google's anti-bot firewalls no matter what I try.

The (failed) attempts

Note that all of these attempts utilize stack overflow's login with google button to work because "it works every time". So far, I've tried:

  • Using Selenium_Stealth to hide myself as an older browser and then reverting after logging in (as suggested by this SO post)
  • Swapping out the regular Chromedriver with its "ungoogled" counterpart
  • Swapping out the regular Chromedriver with its "undetectable" counterpart

All of these attempts have failed. Here are the only things that I can think of that I never tried:

  • Swapping out Chrome and chromedriver with Firefox and geckodriver, because they (to my knowledge) require profiles to set up properly and I have no way (to my Googleable knowledge) to find Firefox profiles because of how they are stored in Replit (in an invisible nix folder that can ony be accessed through the terminal)
  • Using Pre-logged in Profiles to get into the user's Google Account, for the reason outlined in "The Problem" section

When I try other solutions someone suggests/I found, I'll update this section

The code

Before you run the code, I recommend you to make the following file structure on your PC and update debug_screenshots_path appropriately:

 Debug Screenshots
├  Login
└  Errors

Alternatively, you can manually comment/change the following lines of code:

  • 67
  • 69 (nice)
  • 72
  • 82
  • 86
  • 92
  • 96
  • 101
  • 104
  • 113
  • 117

Also, I recommend that you change the gmail_overide variable to your own email, so you don't have to type it in every time. To activate the override, just submit a blank field when prompted for your gmail.

With that out of the way, here's the code in all of its glory. It purposely stops shortly after submitting the email, as you usually get caught by Google by then:


from selenium import webdriver
import undetected_chromedriver as uc

from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import *

from selenium_stealth import stealth as hide

import time

import os

gmail_overide = "[email protected]" # By leaving the email field blank when prompted, the program automatically uses the email provided here. You're welcome :)

debug_screenshots_path = "Debug Screenshots" #<-- Change to YOUR OWN FOLDER DIR!!!


print("Starting webdriver...")
options = Options()
# UNCOMMENT THE FOLLOWING IF TESTING UNGOOGLED CHROME OR UNDETECTED CHROMEDRIVER
options.add_argument("start-maximized")
options.add_argument("--no-sandbox")
# UNCOMENT THE FOLLOWING IF TESING UNGOOGLED CHROME
# options.add_argument("--disable-dev-shm-usage")
# options.add_experimental_option("excludeSwitches", ["enable-automation"])
# options.add_experimental_option('useAutomationExtension', False)
# options.add_experimental_option('excludeSwitches', ['enable-logging'])


driver = uc.Chrome(headless=True, use_subprocess=False, driver_executable_path = "/nix/store/n4qcnqy0isnvxcpcgv6i2z9ql9wsxksw-chromedriver-114.0.5735.90/bin/chromedriver", options=options)
print("Hiding a wolf in sheepish clothing...")

# UNCOMMENT THE FOLLOWING IF TESTING BROWSER DEGRADE STRAT
hide(driver,
  user_agent='DN',
  languages=["en-US", "en"],
  vendor="Google Inc.",
  platform="Win32",
  webgl_vendor="Intel Inc.",
  renderer="Intel Iris OpenGL Engine",
  fix_hairline=True  
)


def delete_old_debug_info():
  print("Deleting old news...")
  for folders in os.listdir(debug_screenshots_path):
    for files in os.listdir(f"{debug_screenshots_path}/{folders}"):
      os.remove(f"{debug_screenshots_path}/{folders}/{files}")

def login_via_password():
  delete_old_debug_info()
  print("Alright, let's get you logged in.")
  username = input("Enter your gmail here: ")
  if username.strip() == '':
    print("Using preset...")
    username = gmail_overide

  driver.get("https://stackoverflow.com/users/login") # Getting to the login page

  # Get rid of the cookies button in the way of the Google Button
  try:
    driver.save_screenshot(f"{debug_screenshots_path}/Login/SO Login Page.png")
    WebDriverWait(driver, 10).until(expected_conditions.element_to_be_clickable((By.XPATH, '//button[@id="onetrust-reject-all-handler"]'))).click()
    driver.save_screenshot(f"{debug_screenshots_path}/Login/Cookieless SO Login Page.png")
  except NoSuchElementException:
    print("[WARNING] Couldn't Find Stuff in the Way!")
    driver.save_screenshot(f"{debug_screenshots_path}/Errors/NoSuchElementException - Cookies.png")

  # Go to and click the Google login button
  try:
    google_login_button = driver.find_element(By.XPATH,'//*[@id="openid-buttons"]/button[1]')
    actions = ActionChains(driver)
    actions.move_to_element(google_login_button).perform()
    google_login_button.click()
  except ElementClickInterceptedException:
      print("[ERROR] Element is not clickable because something is in the way!")
      driver.save_screenshot(f"{debug_screenshots_path}/Errors/ElementClickInterceptedException.png")
      driver.quit()
      return False
  else:
    driver.save_screenshot(f"{debug_screenshots_path}/Login/Google Email Login Page.png")
  try:
      WebDriverWait(driver, 60).until(expected_conditions.element_to_be_clickable(
          (By.XPATH, "//Input[@id= 'identifierId']"))).send_keys(username)      # Enters username
  except TimeoutException:
      print("[ERROR] Could not find the username field!")
      driver.save_screenshot(f"{debug_screenshots_path}/Errors/TimeoutException.png")
      driver.quit()
      return False
  else:
      driver.save_screenshot(f"{debug_screenshots_path}/Login/Google Username Field.png")
  try:
    WebDriverWait(driver, 60).until(expected_conditions.element_to_be_clickable(
      (By.ID, "identifierNext"))).click() # Goes to the password prompt
    time.sleep(5)
    driver.save_screenshot(f"{debug_screenshots_path}/Login/Google Password Field (Submitted Username).png")
  except TimeoutException:
    print("[ERROR] Could not find the email submit button!")
    driver.save_screenshot(f"{debug_screenshots_path}/Errors/TimeoutException.png")
    driver.quit()
    return False

  try:
    WebDriverWait(driver, 60).until(expected_conditions.presence_of_element_located(
        (By.ID, "password"))).send_keys("test") # Enters something random to test if the password field is there at all
  except TimeoutException:
    print("[ERROR] Could not find the password field! We probably got busted...")
    driver.save_screenshot(f"{debug_screenshots_path}/Errors/TimeoutException - Busted.png")
    driver.quit()
    return False
  print("Wow, I think we made it across the firewall! Maybe there's hope afterall...")
  driver.save_screenshot(f"{debug_screenshots_path}/Login/Got Past the Google Guards.png")
  driver.quit()
  return True


print("Logged in? " + str(login_via_password()))

Testing on Replit (the platform where my problem originates from)

If you want to see the Replit this is stored on, thanks! That's way more than I thought anyone would do to help out a stranger. As for the Replit itself, here it is. Do note that the code on the Replit is functionally the same but coded slightly differently from the code here, as this one's a bit more cleaned up and better commented. If you run into permission errors when attempting to run it, you need to go into the Replit's shell/terminal and run chmod 777 /nix/store/n4qcnqy0isnvxcpcgv6i2z9ql9wsxksw-chromedriver-114.0.5735.90/bin/chromedriver. It should work fine after that (at least up untl Google gets in your way).

If you plan on forking the Replit, you'll need to follow an answer I made here in order to get undetected-chrome working properly. After that, you need to show hidden files and search for a file called replit.nix exists. If not, make it and ensure this is its contents (if it's not there already):

{ pkgs }: {
  deps = [
    pkgs.geckodriver
    pkgs.ungoogled-chromium
    pkgs.chromedriver
  ];
}

Then, everything should be fine. Double-Check that undetected-chromedriver, selenium_stealth, and ungoogled_chromedriver are imported by quickly trying to pip install them. You'll need to chmod 777 the dir where chromedriver is saved anytime you get permission errors thanks to the finicky undetected-chromedriver.


Thanks for reading this long post! This took me hours to write and it's gotten considerably more late since I've started writing this, so there mght be edits I need to make here and there. I hope you have a nice day :)

0

There are 0 best solutions below