Google Photos APIのOauth2トークンを更新

Created 2019年1月31日0:54
Updated 2019年1月31日1:06
Categories Python Google Photos API

これまでの記事の調査で、何とかGoogle Photos APIから画像をダウンロードすることができました。

しかし、しばらくスクリプトを動かしていると401 Unauthorizedエラーが出てしまいダウンロードが停止してしまいました。

原因

エラーの直接的な原因はログイントークンのタイムアウトでした。

トークンオブジェクトを実際に見てみると分かるのですが、expires_inが3600になっており、3600秒でタイムアウトしてしまうようです。

また、ログインに使っているRequests-OAuthlibは自動的にトークンの更新を行う機能があるはずなのですが、残念ながらこれがうまく動いていませんでした。

本当なら上手く動くように設定を見直した方が良いのかもしれませんが、今回は簡単のため手動でトークンを更新する方法を試したいと思います。

コード

トークン更新用の関数の作成

まず、トークンを更新するための関数を作成しました。

引数のgoogleオブジェクトは以前の記事で作成したセッションオブジェクトです。

def refresh_token(google):
    token = google.refresh_token(google.auto_refresh_url, **google.auto_refresh_kwargs)
    google.token = token

初期化時に渡したauto_refresh_kwargsauto_refresh_urlを用いて手動でリフレッシュを行っています。

ちなみに、Googleの場合はauto_refresh_urlはOauthでログインする際のURLと同じです。

ダウンロードスクリプトの作成

これを使い、画像のダウンロードスクリプトにセッションがタイムアウトしそうになったらトークンの更新を行う機能を追加します。

なお、画像をダウンロードするスクリプトの詳細な説明は割愛します(こちらに記事を書いています)。

また、login()関数はこちらの記事をペーストして作成してください。

import time
from datetime import datetime, timedelta


def download_photos(media_items):
    # セッションオブジェクト取得
    google = login()
    # ログイン時間を記録
    last_login_time = datetime.now()
    for media_item in media_items:
        # ログインから50分以上経過したらトークンをリフレッシュ
        if datetime.now() - last_login_time > timedelta(minutes=50):
            refresh_token(google)
            # ログイン時間を更新
            last_login_time = datetime.now()
        # 画像のダウンロード
        ...
        # 迷惑にならないようsleep
        time.sleep(10)

タイムアウトは60分ですが、余裕をもって50分で更新するようにしています。

長時間かけてたくさんの画像をダウンロードする場合は、このような対策が必要になるかもしれません。

ただ、本来はRequests-OAuthlibの自動トークンリフレッシュが使えれば何も問題はないのですが・・・

あとがき

3日ほどGoogle Photos APIでいろいろやって、ようやく本来の目的であった3000枚程度の画像をダウンロードできました。

ハマった箇所が多かったのでしんどいように見えますが、もろもろの問題は原因が分かれば解決は簡単でした。APIも堅牢で安定しており、Oauth2もいい感じだと思います。さすがGoogle製ですね・・・

Google Photos APIはまた使いそうなので、来週くらいまでにライブラリを作ってまとめようと思います。

参考

コメントを投稿

コメント