Skip to content

Instantly share code, notes, and snippets.

@ochen1

ochen1/example.py

Last active Apr 26, 2021
Embed
What would you like to do?
Google Login
from signal import pause
from rich.console import Console
from google_login import *
console = Console()
console.log("Initializing ChromeOptions...")
options = webdriver.ChromeOptions()
options.headless = False
options.add_argument("--no-sandbox")
options.add_argument("--disable-gpu")
options.add_argument("--disable-dev-shm-usage")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
def get_user_details(driver, google_login):
console.log("Navigating to user account details webpage...")
with google_login.wait_for_load():
driver.get("https://myaccount.google.com/")
assert urlparse(driver.current_url).hostname == "myaccount.google.com"
console.log("Collecting data...")
user_detail_data = {
"IJ_values": {
62: "full_name",
63: "email",
64: "gender",
65: "first_name",
73: "profile_picture"
}
}
data = {}
for index, name in user_detail_data["IJ_values"].items():
content = driver.execute_script("return window.IJ_values[{}]".format(index))
data[name] = content
return data
console.log("Starting Chrome...")
with webdriver.Chrome(options=options) as chrome:
chrome.get("about:blank")
google_login = GoogleLogin(chrome, console=console)
#console.log("Checking login status...")
#if google_login.user_is_logged_in():
# pass
#else:
# console.log(":warning: Not yet logged in. Logging in...", style="yellow")
# google_login.perform_google_login()
google_login.perform_google_login()
console.log("Getting user details...")
console.print(get_user_details(chrome, google_login))
console.log("Google login complete.", style="bold")
pause()
"""
Google Login by Oliver Chen, 2021
https://gist.github.com/ochen1/0d00e8e18daf03fba2f2d6bc7f6b7d3b
"""
from base64 import b64decode
from contextlib import contextmanager
from json import load
from random import uniform
from time import sleep
from urllib.parse import urlparse, parse_qs
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.expected_conditions import staleness_of
from selenium.webdriver.support.ui import WebDriverWait
from selenium_stealth import stealth
class GoogleLogin:
def __init__(self, driver: webdriver.chrome.webdriver.WebDriver, config=None, config_filename=None, console=None):
self.console = console
if config is not None:
self.config = config
else:
self.config = self.parse_config(config_filename=config_filename)
self.driver = driver
self.apply_stealth()
def parse_config(self, config_filename=None):
if config_filename is None:
config_filename = "config.json"
self.console and self.console.log("Parsing config...")
with open(config_filename) as config:
config = load(config)
config['google_account']['username'] = b64decode(config['google_account']['username']).decode()
config['google_account']['password'] = b64decode(config['google_account']['password']).decode()
return config
@staticmethod
def _randomly_wait(*args):
return sleep(round(uniform(*map(float, args)), 2))
@contextmanager
def wait_for_load(self, timeout=10):
old_page = self.driver.find_element_by_tag_name("html")
yield
WebDriverWait(self.driver, timeout).until(staleness_of(old_page))
sleep(1)
def apply_stealth(self):
self.console and self.console.log("Applying stealth...")
stealth(self.driver,
languages=["en-US", "en"],
vendor="Google Inc.",
platform="Win32",
webgl_vendor="Intel Inc.",
renderer="Intel Iris OpenGL Engine",
fix_hairline=True,
)
def perform_google_login(self):
self.console and self.console.log("Navigating to login page...")
with self.wait_for_load():
self.driver.get("https://accounts.google.com/ServiceLogin")
self._randomly_wait(0.5, 2.2)
self.console and self.console.log("Inputting username...")
self._randomly_wait(1.5, 2.2)
self.driver.find_element_by_css_selector("input#identifierId[name='identifier']"). \
send_keys(self.config['google_account'].get('username'), Keys.ENTER)
sleep(2)
self.console and self.console.log("Inputting password...")
self._randomly_wait(1.5, 2.5)
self.driver.find_element_by_css_selector("input[type='password'][name='password']"). \
send_keys(self.config['google_account'].get('password'), Keys.ENTER)
self.console and self.console.log("Waiting for Javascript login...")
sleep(5)
self.console and self.console.log("Checking login status...")
with self.wait_for_load():
self.driver.get("https://myaccount.google.com/?utm_source=sign_in_no_continue")
self._randomly_wait(1, 2)
self.driver.get("about:blank")
self.console and self.console.log("Logged in.", style="bold")
@KuroSol

This comment has been minimized.

Copy link

@KuroSol KuroSol commented Jan 27, 2021

can you please upload config.json file sample as well
I just made it by my self and i got
File "/Users/apple/PycharmProjects/google-login/google_login.py", line 35, in parse_config
config["google_account"]["username"] = b64decode(config["google_account"]["username"]).decode()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/base64.py", line 87, in b64decode
return binascii.a2b_base64(s)
binascii.Error: Incorrect padding
this error

@ochen1

This comment has been minimized.

Copy link
Owner Author

@ochen1 ochen1 commented Jan 28, 2021

@KuroSol I'm so sorry, I forgot to describe the config! 😅

I originally uploaded this in a rush for the conversation here: https://gist.github.com/ikegami-yukino/51b247080976cb41fe93

Here is an example config.json file.

{
    "headless": false,
    "google_account": {
        "username": "base64-encoded username",
        "password": "base64-encoded password"
    }
}

You can base64-encode your strings with:

from base64 import b64encode
print(b64encode(b"username@gmail.com"))
print(b64encode(b"password12345!Password!!"))

Please note that base64 encodings can be easily reversed, and is NOT a substitution for encryption. You should always store passwords used in production encrypted (if not hashed, as would not be possible in this case).

@ochen1

This comment has been minimized.

Copy link
Owner Author

@ochen1 ochen1 commented Jan 28, 2021

I found the reason it wasn't working for you guys. I implemented the apply_stealth method but forgot to call it 🤦‍♂️

I've also added a sample config.json as a comment.

It should work now if you correctly generate your config.json and run the bot with no exception thrown from base64 decoding.

Make sure you have installed the requirements.

pip install rich selenium-stealth

If you're on *nix, you might need to use pip3.

Some mentions:
@KuroSol @jmzg1229

Can you guys check if it works for you now?

@ochen1

This comment has been minimized.

Copy link
Owner Author

@ochen1 ochen1 commented Jan 28, 2021

I think we're doing debugging right now:

  1. Bugs are reported
  2. That's weird, it worked on my machine. 😕
  3. I found bug: I forgot to call the stealth method
  4. How did that ever work on my machine??

The loop repeats. The bug still persists as reported, for some unknown reason 🤔

I'm going to test using another account.

@adv-zl

This comment has been minimized.

Copy link

@adv-zl adv-zl commented Jan 29, 2021

OSX catalina, ChromeDriver 88.0.4324.96, not working

@ochen1

This comment has been minimized.

Copy link
Owner Author

@ochen1 ochen1 commented Jan 29, 2021

@adv-zl
Hi! This is indeed not working as of now.

If it works for anyone, it most likely either means they are using a G-Suite account or are very lucky.

I've developed another proof of concept that works as of now, but I need to find a good way of packaging it and then distributing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment