GooglePhotosAPIを使った画像アップロード方法

とっと
とっと

 PythonのプログラムとGoogle Photos APIを使って、Googleフォトに画像を1枚アップロードする方法をまとめます。

プログラムを使って、画像ファイルをGoogleフォトへアップロードできるようになります。

前提として、Googleアカウントを持っている必要があります。

概要

 大きく4つのステップとなります。

 STEP1,2,3が準備編で、STEP4で実際に画像をアップロードします。

  • STEP1
    テストユーザを追加
  • STEP2
    Google Photos APIを有効化
  • STEP3
    必要なファイルを準備
  • STEP4
    画像ファイルのアップロード

手順

STEP1. テストユーザを追加

 まず、Googleフォトへのログイン権限を許可するため、テストユーザを追加します。

Google Cloud Platformログインします。

APIとサービスから、Oauth同意画面を選択します。

テストユーザのところにある+ADD USERSを選択します。

④アクセスしたいGoogleフォトアカウントのgmailアドレスを入力し、保存します。

このステップを実施しておかないと、あとのステップでGoogleログインする時に許可がない、と怒られてしまい、先に進めなくなります。

STEP2. Google Photos APIを有効化

 次に、Google Photos APIを有効化します。

Google Cloud Platformログインします。

APIとサービスを選択します。

ライブラリを選択します。

④検索バーに”photos”と入力し、Photos Library APIを選択します。

有効化を選択します。

STEP3. 必要なファイルを準備

 Google Photos APIを使って画像をアルバムにアップロードするために必要な物は、3つです。

  • アップロードしたい画像ファイル
  • 認証ファイル
  • APIを使ったアップロードプログラム

アップロードしたい画像ファイル

 アップロードしたい画像ファイルを用意し、任意のフォルダに入れておきます。

 ここでは、ファイル名をtest.jpgとして用意することにします。

認証ファイル

 APIをつかってGoogleフォトにアクセスするために必要となる、認証ファイルを用意します。

Google Cloud Platformログインします。

APIとサービスから、OAuth同意画面を選択します。

外部を選択し、次へを選択します。

アプリケーション名を”Google Photos with Python”にして次へを選択します。

APIとサービスから、認証情報を選択します。

⑥上部にある+認証情報を作成を選択し、OAuthクライアント IDを選択します。

アプリケーションの種類からデスクトップアプリを選択し、名前を”Google Photos with Python”にします。

JSONをダウンロードからclient_secret_xxxxxxxxx.jsonというファイルをダウンロードします。

⑨ダウンロードした.jsonファイルを”credentials.json”にリネームします。

⑩credentials.jsonファイルをtest.jpgファイルと同じフォルダに入れておきます。

アプリケーション名は好きな名前でOKです。

APIを使ったアップロードプログラム

 APIを使って、Googleフォトにtest.jpgファイルをアップロードするプログラムコードを作成します。ここでは、Pythonで作成したサンプルコード(upload.py)を載せておきます。

 このファイルも、test.jpgファイルと同じフォルダに入れておきます。

upload.pyは、以下3つのステップでtest.jpgをアップロードします。

  1. Googleフォトにログイン;login関数
  2. testという名前でアルバムを作成;create_albums関数
  3. test.jpgをtestアルバムにアップロード;upload関数

コードの冒頭でimportしているライブラリは、事前にインストールしておきましょう。

from pathlib import Path
from requests_oauthlib import OAuth2Session
import json
import os,sys

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

albums_url = "https://photoslibrary.googleapis.com/v1/albums"
upload_url = "https://photoslibrary.googleapis.com/v1/uploads"
media_url = "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"

def main():
 #Googleフォトにログインする
 google = login()

 #testという名前の新しいアルバムを作成
 album_id = create_albums(google, "test")

 #写真のアップロード
 upload(google, album_id)

# ログインしてセッションオブジェクトを返す
def login():
 # 認証情報を読み込み
 auth_info = json.loads(Path(resource_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

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

 path = Path(resource_path("./token.json"))

 if path.exists():
   token = json.loads(path.read_text())
 return token

# ログイン後に取得したトークンを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))

def create_albums(google, name):
 data = {
   "album":{
     "title": name
   }
 }
 data = json.dumps(data)

 r = google.post(albums_url, data=data)
 print(r.content)

 r = r.json()
 albumid = r["id"]

 print(albumid)

 return albumid
 
def upload(google, album_id):
 headers = {
   'Authorization': "Bearer " + str(google.token),
   'Content-Type': 'application/octet-stream',
   'X-Goog-Upload-File-Name': "test.jpg",
   'X-Goog-Upload-Protocol': "raw",
 }

 image_path = resource_path("./test.jpg")

 with open(image_path, 'rb') as image_data:
   # 写真のアップロード
   response1 = google.post(upload_url, headers=headers, data=image_data)
   print("\nresponse1=" + str(response1.content))

   r = response1.content

   data = {
     'albumId': album_id,
     "newMediaItems":[{
         "simpleMediaItem":
           {"uploadToken":r.decode("utf-8")}
         }
       ]
     }
   data = json.dumps(data)

   print("\ndata=" + data)

   #写真の登録
   response2 = google.post(media_url, data=data)
   print("\nresponse2=" + str(response2.content))

def resource_path(relative_path):
 try:
   base_path = sys._MEIPASS
 except Exception:
   base_path = os.path.dirname(__file__)
 return os.path.join(base_path, relative_path)

if __name__ == "__main__":
 main()

STEP4. 画像ファイルのアップロード

 ここまでで、以下3つのファイルを準備できました。

  • test.jpg (アップロードしたい画像ファイル)
  • credentials.json (認証ファイル)
  • upload.py (APIを使ったアップロードプログラム)

 それでは早速、PythonプログラムからAPIを使って、Googleフォトにtest.jpgファイルをアップロードしてみます。

①pythonコード(test.py)を実行します。

②初回実行時はtokenファイルが無いため、標準出力画面にURLが表示され、一旦処理がストップします。

③標準出力に表示されたURLをCtrl + クリックし、ブラウザで表示します。

ブラウザのURL欄にコピペでもOKです。

④ログインを促されるので、アクセスしたいGoogleアカウントでログインします。

画像を拡大表示

⑤ログインすると、ランダムに生成されたコードが表示されますので、コピーして標準出力画面の”>>>”となっているところにペーストします。

ここまでがログイン動作(login関数)となります。

⑥コードをペーストすると、あとはプログラムが自動でtestという名前でアルバム新規作成し、test.jpgファイルをそのアルバムにアップロードするところまでを行ってくれますので、動作が完了するのを待ちます。

⑦プログラムの動作がおわったら、Googleフォトにログインし、testという名前のアルバムにtest.jpgがアップロードされていることを確認し、終わりとなります。

参考サイト

 upload.pyのコードは、以下2つの記事をまるっと参考にさせていただきました。

https://blog.sakaki333.com/ui/post/detail/62

404 Not Found

upload関数で使用しているupload_urlmedia_urlの値については、かなり試行錯誤しましたので、本記事のupload.pyのコードではその点も明記しておきました。

また参考記事では、upload関数の第3引数と第4引数に、アップロードする画像ファイルの情報を辞書型で渡していますが、本記事のコードでは簡易化しています。

とっと
とっと

以上になります!