Retrieving Google+ Auto-Backup Images via Python
Categories:
Retrieving Google+ Auto-Backup Images via Python

Learn how to programmatically access and download your Google+ Auto-Backup images using Python and the Google Photos Library API.
Before Google+ was deprecated, many users utilized its auto-backup feature to store photos and videos. While Google Photos has largely superseded this functionality, you might still have legacy content or wish to manage your media programmatically. This article guides you through the process of using Python to access and retrieve these images, leveraging the Google Photos Library API. We'll cover authentication, searching for media, and downloading files.
Understanding the Google Photos Library API
The Google Photos Library API is the primary interface for interacting with user content in Google Photos. It allows applications to list media items, search for specific photos or videos, and retrieve their metadata and download URLs. It's important to note that this API provides read-only access to user data; it does not support uploading, deleting, or modifying media items. For our purpose of retrieving auto-backup images, this API is perfectly suited.
sequenceDiagram participant User participant PythonApp as Python Application participant GoogleAPI as Google Photos Library API participant GoogleAuth as Google OAuth2 User->>PythonApp: Initiates script PythonApp->>GoogleAuth: Request authorization URL GoogleAuth-->>PythonApp: Authorization URL PythonApp->>User: Open browser for authentication User->>GoogleAuth: Grants permission GoogleAuth-->>PythonApp: Authorization Code PythonApp->>GoogleAuth: Exchange code for tokens GoogleAuth-->>PythonApp: Access & Refresh Tokens PythonApp->>GoogleAPI: Search media items (with Access Token) GoogleAPI-->>PythonApp: List of media items (metadata + download URLs) PythonApp->>GoogleAPI: Download each media item GoogleAPI-->>PythonApp: Media file data PythonApp->>User: Saves images locally
Authentication and Media Retrieval Flow
Setting Up Your Google Cloud Project
Before you can write any Python code, you need to set up a project in the Google Cloud Console and enable the Google Photos Library API. This involves creating OAuth 2.0 client credentials, which your Python application will use to authenticate with Google's services. Make sure to download the client_secret.json
file, as it contains the necessary credentials for your application.
1. Create a Google Cloud Project
Navigate to the Google Cloud Console (console.cloud.google.com), create a new project, or select an existing one.
2. Enable the Google Photos Library API
In the Cloud Console, go to 'APIs & Services' > 'Library'. Search for 'Google Photos Library API' and enable it.
3. Configure OAuth Consent Screen
Go to 'APIs & Services' > 'OAuth consent screen'. Configure it with an application name and scope https://www.googleapis.com/auth/photoslibrary.readonly
.
4. Create OAuth 2.0 Client ID
Under 'APIs & Services' > 'Credentials', click 'Create Credentials' > 'OAuth client ID'. Choose 'Desktop app' as the application type. Download the client_secret.json
file and save it in your project directory.
Python Implementation for Image Retrieval
With your Google Cloud project configured, we can now proceed with the Python implementation. We'll use the google-auth-oauthlib
and google-api-python-client
libraries to handle authentication and API interactions. The script will first authenticate, then list media items, and finally download them.
import os
import pickle
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload
import io
# Scopes required for read-only access to Google Photos
SCOPES = ['https://www.googleapis.com/auth/photoslibrary.readonly']
def authenticate_google_photos():
creds = None
# The file token.pickle stores the user's access and refresh tokens
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'client_secret.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
return creds
def get_photos_service():
creds = authenticate_google_photos()
service = build('photoslibrary', 'v1', credentials=creds, static_discovery=False)
return service
def download_media_items(service, download_path='google_photos_backup'):
if not os.path.exists(download_path):
os.makedirs(download_path)
page_token = None
while True:
results = service.mediaItems().list(pageSize=100, pageToken=page_token).execute()
items = results.get('mediaItems', [])
if not items:
print('No media items found.')
break
for item in items:
filename = item['filename']
base_url = item['baseUrl']
# Append '=d' to the baseUrl to get the direct download link
download_url = f"{base_url}=d"
file_path = os.path.join(download_path, filename)
if os.path.exists(file_path):
print(f"Skipping existing file: {filename}")
continue
print(f"Downloading {filename}...")
try:
request = service.mediaItems().get(mediaItemId=item['id'])
# The actual download requires a separate HTTP request, not directly via service.mediaItems().get
# For direct download, we use the 'baseUrl=d' approach with a simple HTTP GET
# For simplicity, this example assumes direct download via requests library or similar
# A more robust solution would use googleapiclient.http.MediaIoBaseDownload for resumable downloads
# For this example, we'll simulate a direct download using the base_url=d
# In a real scenario, you'd use requests.get(download_url, stream=True) and save content
# Placeholder for actual download logic:
# response = requests.get(download_url, stream=True)
# with open(file_path, 'wb') as f:
# for chunk in response.iter_content(chunk_size=8192):
# f.write(chunk)
# For demonstration, we'll just print the download URL
print(f"Simulating download of {filename} from {download_url}")
# To make this functional, you'd integrate a library like 'requests'
# import requests
# r = requests.get(download_url, stream=True)
# with open(file_path, 'wb') as f:
# for chunk in r.iter_content(chunk_size=8192):
# f.write(chunk)
except Exception as e:
print(f"Error downloading {filename}: {e}")
page_token = results.get('nextPageToken')
if not page_token:
break
if __name__ == '__main__':
service = get_photos_service()
download_media_items(service)
print("Download process completed.")
Python script for authenticating and listing Google Photos media items. Note: Actual download logic using requests
library is commented out for brevity but is essential for a functional script.
token.pickle
file stores your authentication tokens. Keep it secure and avoid committing it to version control. If you need to re-authenticate or change scopes, delete this file.Refining Your Search and Download
The provided script lists all media items. You might want to filter these items, for example, by date, album, or specific keywords. The Google Photos Library API offers robust search capabilities through the mediaItems.search
method. You can specify dateFilter
, contentFilter
, or mediaTypeFilter
to narrow down your results. For instance, to find only photos, you would use mediaTypeFilter={'mediaTypes': ['PHOTO']}
.
def search_and_download_photos(service, download_path='filtered_photos_backup'):
if not os.path.exists(download_path):
os.makedirs(download_path)
# Example: Search for photos only
body = {
'filters': {
'mediaTypeFilter': {
'mediaTypes': ['PHOTO']
}
},
'pageSize': 100
}
page_token = None
while True:
if page_token:
body['pageToken'] = page_token
results = service.mediaItems().search(body=body).execute()
items = results.get('mediaItems', [])
if not items:
print('No filtered media items found.')
break
for item in items:
filename = item['filename']
base_url = item['baseUrl']
download_url = f"{base_url}=d"
file_path = os.path.join(download_path, filename)
if os.path.exists(file_path):
print(f"Skipping existing file: {filename}")
continue
print(f"Downloading filtered {filename}...")
# Actual download logic using 'requests' library would go here
# import requests
# r = requests.get(download_url, stream=True)
# with open(file_path, 'wb') as f:
# for chunk in r.iter_content(chunk_size=8192):
# f.write(chunk)
print(f"Simulating download of {filename} from {download_url}")
page_token = results.get('nextPageToken')
if not page_token:
break
# To run this:
# if __name__ == '__main__':
# service = get_photos_service()
# search_and_download_photos(service)
# print("Filtered download process completed.")
Example of searching for specific media types (photos only) before downloading.
429 Too Many Requests
errors.