Google Photos APIにPythonでアクセス

Created 2019年1月26日0:06
Updated 2019年1月30日0:34
Categories Python Google Photos API

Google Photosにある画像をスクリプトで取得したいと思い、やり方を調べてみました。

昔はPicasa APIみたいなのを使わないといけませんでしたが、Google Photos APIというのができたみたいです。

ただし、Google Photos APIを使うにはOauth2で認証しなければなりません。

GoogleのメジャーなAPIならPythonの公式ライブラリがあるのですが、Photos APIは確認した限り無かったので、自分で認証や取得を行う必要があります。

今回は、Requests-OAuthlibを用いて認証を行ってみました。

事前準備

  • このページを参考に、Google Photos APIを有効にしてください
  • Google Developer Consoleの認証情報ページから認証情報の入ったJSONをダウンロードしてください

JSONの内容はこんな感じです。

{
    "installed":{
        "client_id":"#####",
        "project_id":"#####",
        "auth_uri":"#####",
        "token_uri":"#####",
        ...
    }
}

コード

ダウンロードしたcredentials.jsonをスクリプトと同じディレクトリに配置してください。

from pathlib import Path
from requests_oauthlib import OAuth2Session
import json

# APIのURLやスコープ
api_url = "https://photoslibrary.googleapis.com/v1/mediaItems"
scope = ["https://www.googleapis.com/auth/photoslibrary.readonly"]


# ログイン後に取得したトークンをtoken.jsonに保存
def save_token(token):
    token = {
        "access_token": token.get("access_token"),
        "refresh_token": token.get("refresh_token"),
        "token_type": token.get("token_type"),
        "expires_in": token.get("expires_in")
    }
    Path("token.json").write_text(json.dumps(token))


# token.jsonが存在したら読み込み
def load_token():
    # 存在しない場合は期限切れのダミーを返す
    token = {
        "access_token": "",
        "refresh_token": "",
        "token_type": "",
        "expires_in": "-30",
    }
    path = Path("token.json")
    if path.exists():
        token = json.loads(path.read_text())
    return token


# ログインしてセッションオブジェクトを返す
def login():
    # 認証情報を読み込み
    auth_info = json.loads(Path("credentials.json").read_text()).get("installed", None)
    assert auth_info is not None
    # トークンがあったら読み込む
    token = load_token()
    # トークン更新用の認証情報
    extras = {
        "client_id": auth_info.get("client_id"),
        "client_secret": auth_info.get("client_secret"),
    }
    # セッションオブジェクトを作成
    google = OAuth2Session(
        auth_info.get("client_id"),
        scope=scope,
        token=token,
        auto_refresh_kwargs=extras,
        token_updater=save_token,
        auto_refresh_url=auth_info.get("token_uri"),
        redirect_uri=auth_info.get("redirect_uris")[0]
    )
    # ログインしていない場合ログインを行う
    if not google.authorized:
        authorization_url, state = google.authorization_url(
            auth_info.get("auth_uri"),
            access_type="offline",
            prompt="select_account"
        )
        # 認証URLにアクセスしてコードをペースト
        print("Access {} and paste code.".format(authorization_url))
        access_code = input(">>> ")
        google.fetch_token(
            auth_info.get("token_uri"),
            client_secret=auth_info.get("client_secret"),
            code=access_code
        )
        assert google.authorized
        # トークンを保存(本来自動保存なのだが、なぜか動かないので追加)
        save_token(google.token)
    return google


def test():
    google = login()
    # Photosのコンテンツを取得
    response = google.get(api_url)
    print(response.text)


if __name__ == "__main__":
    test()

実行するとURLが表示されますので、ブラウザでアクセスして表示されたコードを入力してください。

その後、Google Photosのメディア一覧が表示されると思います。

なお、実行後はトークンが平文でtoken.jsonとして保存されます。扱いには注意してください。

参考

コメントを投稿

コメント

名無し

参考になりました。ありがとうございます。