tl;dr If you want to get started with your Latitude data right away, check out my gist at the bottom.
I've started a new project! I'm investigating ways to share my life with others electronically, with little to no conscious effort on my part.
One of the things I'd like to share is my location history. I'm not sure how much or how little information I want to give to a total stranger, but I believe that if I want to share a significant amount of my life with everyone on the Internet, context is key -- and location makes a huge deal when it comes to taking events in my life into context. Right now I live in San Francisco, but two months ago I lived in Minneapolis, and somewhere in between I spent time with my family in Wausau. Knowing this is key to understanding what I want to share with the world.
I'm being intentionally vague about the actual project I'm working on, but that's okay -- this post is about one of the key elements, and I'll post more later when I start assembling other parts.
Read on to find out how to get your super-interesting real-time location data out of everyone's favorite location-tracking Google app.
How to Geolog 101
What's the best, most convenient, cheapest way to tell people where I've been in the past? There are plenty of ways to log my location, and most of them involve the use of GPS to lock onto my location, and some kind of data logging device to put the data into a format I can use.
I could build a device from scratch involving a GPS module, a microcontroller and a data logger, or I could just use my Android phone!
Android, as we all know, is developed by Google, and Google puts out tons of other cool web products. One of those products is Google Latitude.
From Google's website:
{% blockquote %}
Google Latitude is a location-aware mobile app developed by Google as a successor to its earlier SMS-based service Dodgeball. Latitude allows a mobile phone user to allow certain people to view their current location. Via their own Google Account, the user's cell phone location is mapped on Google Maps.
{% endblockquote %}
Perfect! Plus -- if I use my cell phone, it uses Skyhook to approximate my location even better with the use of wifi hotspots and cell phone towers.
So, Google Latitude will log my location over time in Location History. All I need to do is carry my cell phone on me and keep it turned on. Easy.
My next goal, then, is to get my data out of Location History and into a form I can use.
Prerequisites (Whatchu Need)
To be able to follow along and extract your own Location History data, you'll need the following:
- Location History data in your Google account
- A Python 2.7+ installation
- The Google API Python Client -- I used
pip install google-api-python-client
to install this. - A Google account.
- A Google API project with access to the Latitude API. See Creating a project for information on creating a new API project.
After you create a project, you'll want to go to the API Access
tab and create an OAuth 2.0 Client ID. Make sure you set the application type to Installed application
and the installed application type to Other
.
Accessing Your Data Using A Poorly-Documented (But Well-Written) API Library
Authentication
The Google Location History API runs on OAuth 2. It's finnicky because of that. OAuth 2 is finnicky. Avoid writing an OAuth 2 client from scratch if you can -- you'll regret it. Use the tools you're given by the developers who know what they're doing.
It took me about four hours to figure out the basics of the API because the documentation is a bit lacking. You should still check out the docs though -- here's Google's only Latitude API sample, and here's some samples for other applications that might help you out.
Hopefully I can save you some time by explaining how the script I wrote to authenticate with the Google OAuth endpoint via the Python API works and why it works that way.
Here's the code you'll need to authenticate with Google:
import httplib2
from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import AccessTokenRefreshError
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run
CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
REQUESTED_SCOPE = 'https://www.googleapis.com/auth/latitude.all.best'
flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, REQUESTED_SCOPE)
storage = Storage('credentials.dat')
credentials = storage.get()
if credentials == None or credentials.invalid:
credentials = run(flow, storage)
http = httplib2.Http()
http = credentials.authorize(http)
In the above example, you need to replace CLIENT_ID
and CLIENT_SECRET
with real values. Fill those in with the values found in the application you created above in the Google API Console.
When you run this code, Python will open your web browser to an authorization page. If you're not logged into a Google account, you'll be asked to log in. You'll then be asked to allow access to your location history.
After you grant access to your application to access your location history, you can close your browser window. The Python script will continue by saving your login credentials in credentials.dat
as shown in the script above -- if you want to change that, just provide a different path to Storage()
. Once you have credentials.dat
saved, you won't have to log in again until your OAuth token expires.
Great! Now you have authorization to access your Location History data. How do you actually access it?
Accessing Your Data
This uses some of the code Google provides in their API acess examples. This code follows immediately after the authentication above and assumes you have a valid http
instance available from credentials.authorize()
.
latitude = build('latitude', 'v1', http=http)
try:
# access Location History data via the "latitude" object; put your code here!
except AccessTokenRefreshError:
print 'Access token refresh error. Please restart the application to reauthorize.'
The latitude
object indicates you want to access the Latitude API, version 1, using the credentials.authorize()
http
object to make the requests.
Inside that try
section you'll need to use the latitude
object to access your data. Here's the syntax you need:
response = latitude.location().list(granularity='best').execute()
By default, Google assumes that you want the latest results. Specifying the keyword argument granularity='best'
indicates you want the best available location granularity as well. You're allowed to do this because earlier, when you asked the user for permission, you told Google you wanted permission to use the best-available location data (REQUESTED_SCOPE = 'https://www.googleapis.com/auth/latitude.all.best').
When you request this data, you'll get the 100 latest data points. You can access them by looping through the object response['items']
. If the response
object has no key items
, then the Google API returned no results.
Since Latitude likes to take one point a minute, you almost certainly won't get all your data with one query. So, how do you cycle through this data?
Iterating Through Your Data
You can specify other arguments to the latitude
object inside the location().list()
function as well. One option you can specify is max_time
, which indicates that you want no objects with the milliseconds timestamp later than the one you provide in the max_time
argument.
Since the latitude.location().list().execute()
function returns the 100 latest location items that match your query, you can cycle through the list by doing the following:
- Run a
latitude.location().list(granularity='best').execute()
and save that data. - Take the least-recent data point in that set of data, look for the key
timestampMs
, and subtract 1 millisecond. - Take that new lower timestamp and use it in the query as follows:
latitude.location().list(granularity='best', max_time=LOWER_TIMESTAMP_HERE).execute()
.
Since you asked the API to return no results with a timestamp greater than the one you provided, you'll get a new page of the next-100-most-recent Latitude results. Yay!
If you keep doing that, someday you'll get a response
back that doesn't have an items
key. This means you don't have any results left. You could either check for an items
key with if items in response
, or you could just try
to read response[items]
and catch the Exception with except KeyError:
. The second one is "more Pythonic" if you want to get super pedantic and PEP-8ic.
Working Sample
Here's a working sample. I'm using this with my application's OAuth2 ID and secret and it saves all my data as a big pile of JSON files. Hopefully this gets you up and running!
{% gist 5993157 google_latitude_api_access.py %}
Alternatives to Latitude for Geologging
If you don't want to use Google Latitude to log your GPS location constantly (which is probably a good idea, because the API is shutting down in less than a month), then you can log the data on your phone with an app instead. Ultra GPS Logger is the best one I've found in the Play Store, and at $5ish it's much cheaper than buying a dedicated hardware device.
Summary
In this post, I detailed how to use the Google API library for Python with the Google Latitude API to get your personal location history data out of Google Latitude and onto your computer in a versatile data format.
In my next post, I'll be writing about the purpose for which I'm using this location history data, and why it's so important to have accurate location data!