-
-
Save ochen1/0d00e8e18daf03fba2f2d6bc7f6b7d3b to your computer and use it in GitHub Desktop.
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") |
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?
I think we're doing debugging right now:
- Bugs are reported
- That's weird, it worked on my machine. 😕
- I found bug: I forgot to call the stealth method
- 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.
OSX catalina, ChromeDriver 88.0.4324.96, not working
@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.
@ochen1 what is your discord?
My Discord is idontknow#8950 , but this example is completely outdated and will not work.
I plan on deleting this thread soon.
@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.You can base64-encode your strings with:
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).