问题
I'm working on a DIY project to retrieve Google location history for multiple members of my household. With direction from StackOverflow member @t.m.adam, I came to realize that the signon process is quite involved (understatement). I am not using OAuth or 2FA at this point. Perhaps I'll graduate, but baby steps first.
I have the signin and cookie retrieval part, and the KML retrieval part working great. I was able to adapt the code in this project (google-login - github.com/tubaman/google-login) which uses selenium to sign in. I adapted the code in this project (Maps-Location-History - https://github.com/alexattia/Maps-Location-History) to retrieve and parse the KML data.
I want to sign in user1, retrieve KML, sign out user1, sign in user2, retrieve user2 KML, sign out user2. Just requesting "https://www.google.com/maps/timeline?authuser=0&logout&hl=en" doesn't do it. It appears that signing out may be as involved as signing in!
Upon closer inspection of the response to the logout request... "Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'report-sample' 'nonce-' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval'". Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list. It also shows messages referencing P3P policy p3p:CP="This is not a P3P policy! See g.co/p3phelp (https://support.google.com/accounts/answer/151657) for more info."
So, I guess I need to recreate the click stream of an interactive logout using Selenium. I just don't know where to start.
Here's the code of the sign-in and KML retrieval. Now I need some guidance on performing a successful sign-out.
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from http.cookiejar import (_warn_unhandled_exception, FileCookieJar, LoadError,
Cookie, MISSING_FILENAME_TEXT, MozillaCookieJar)
import sys
import re
import netrc
import logging
import argparse
import os
import time
from datetime import datetime
import calendar
import numpy as np
import pandas as pd
from bs4 import BeautifulSoup
import process_location
def setup_webdriver():
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--window-size=1024,768")
chrome_options.binary_location = '/usr/bin/chromium-browser'
driver = webdriver.Chrome(executable_path="/usr/bin/chromedriver", chrome_options=chrome_options)
return driver
def copy_cookies_to_session(driver, session):
"""Copy cookies from selenium webdriver to requests.Session"""
cookies = driver.get_cookies()
for cookie in cookies:
session.cookies.set(
cookie['name'],
cookie['value'],
domain=cookie['domain'],
path=cookie['path']
)
class Session(requests.Session):
"""A Google session"""
def __init__(self, *args, **kwargs):
super(Session, self).__init__(*args, **kwargs)
self.url = "https://console.developers.google.com"
def find_sign_in(self, driver):
conditions = [
EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, "Sign in")),
EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, "SIGN IN")),
]
for condition in conditions:
try:
sign_in = WebDriverWait(driver, 5).until(condition)
except:
pass
else:
break
return sign_in
def login(self, username, password, url=None):
if url is not None:
self.url = url
driver = setup_webdriver()
try:
driver.get(self.url)
driver.find_element_by_id("Email").clear()
driver.find_element_by_id("Email").send_keys(username)
try:
driver.find_element_by_id("Passwd").clear()
driver.find_element_by_id("Passwd").send_keys(password)
except:
driver.find_element_by_id("next").click()
condition = EC.visibility_of_element_located((By.ID, "Passwd"))
passwd = WebDriverWait(driver, 5).until(condition)
passwd.clear()
passwd.send_keys(password)
driver.find_element_by_id("signIn").click()
copy_cookies_to_session(driver, self)
assert self.is_logged_in()
except:
driver.save_screenshot('/tmp/googlelogin_problem.png')
raise
finally:
driver.quit()
def is_logged_in(self):
response = self.get(self.url, allow_redirects=False)
if response.status_code == 302:
login_url = "https://accounts.google.com/ServiceLogin"
return not response.headers['location'].startswith(login_url)
else:
return response.status_code == 200
def save(self, filename):
cj = MozillaCookieJar(filename)
for cookie in self.cookies:
cj.set_cookie(cookie)
cj.save(ignore_discard=True, ignore_expires=True)
def load(self, filename):
cj = MozillaCookieJar(filename)
cj.load(ignore_discard=True, ignore_expires=True)
for cookie in cj:
self.cookies.set_cookie(cookie)
def get_session(user, cookies_path, url, session):
username, _, password = netrc.netrc().authenticators(user)
username = '%s@gmail.com' % username
logger.debug("trying to load saved session")
try:
session.load(cookies_path)
except IOError:
logger.debug("error loading saved session")
logger.debug("logging in")
session.login(username, password, url=url)
session.save(cookies_path)
else:
logger.debug("loaded saved session")
logger.debug("are we still logged in?")
if not session.is_logged_in():
logger.debug("no, so logging in")
session.login(username, password, url=url)
logger.debug("saving session")
session.save(cookies_path)
else:
logger.debug("yup, we're still logged in")
return session
def get_kml(user, folder):
logger.debug('{} get_kml'.format(user))
#cookies_path = '%s%s_cookies.txt' % folder, user
cookies_path = '{}{}_cookies.txt'.format(folder, user)
url = 'https://www.google.com/maps/timeline'
cls = Session()
cls = get_session(user, cookies_path, url, cls)
#cookies = dict(cookie=cookie_content)
url = 'https://www.google.com/maps/timeline/kml?authuser=0&pb=!1m8!1m3!1i2018!2i3!3i2!2m3!1i2018!2i3!3i2'
r = cls.get(url)
if r.status_code == 200:
logger.debug('{} current location:'.format(user))
logger.debug(r.text)
else:
logger.debug('{} get_kml error - status_code= {}'.format(user, r.status_code))
url = 'https://www.google.com/maps/timeline?authuser=0&logout&hl=en'
r = cls.get(url)
logger.debug('{} get_kml logout - status_code= {}'.format(user, r.status_code))
cookies_folder = '/home/pi/Projects/GeoFence/GoogleMaps/LocationHistory/LocationHistoryData/'
log_file = os.path.splitext(os.path.realpath(__file__))[0] + '.log'
logger = logging.getLogger(__name__)
logging.basicConfig(filename=log_file, level=logging.DEBUG)
#logging.basicConfig(filename=log_file, level=logging.WARN)
get_kml('user1', cookies_folder)
get_kml('user2', cookies_folder)
sys.exit()
来源:https://stackoverflow.com/questions/49635179/programmatic-google-signin-signout-user1-then-signin-user2-python