0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PythonからGooglePhotoに画像や動画をアップロード

Posted at

PythonからGooglePhotoに画像や動画をアップロードする手順です。

事前準備

Photo Library APIの有効化

はじめにGoogle PhotoのAPIを利用するために「Photo Library API」を有効化する。まず下記のURLからGCPのコンソールにアクセスする。

検索窓で「Google Photo」と入力し、画像赤枠の「Photo Library API」を選択する。

手順1.png

Photo Library APIの設定画面に遷移するので、「有効にする」を押下する。

手順2.png

実行後、下記のような画面に変わればAPIの有効化は完了。GooglePhotoに対してAPI経由で処理を実行できるようになっている。

スクリーンショット 2023-01-15 13.42.24.png

認証情報の作成

次にAPIの実行するために必要な、認証情報を作成する。認証情報の作成手順は下記の記事の手順と同じなので、こちらを参照。

作成した認証情報はclient_secrets.jsonの名称で保存しておく。

開発

必要ライブラリのインストール

今回はPhotoAPIを利用するためのgoogle-api-python-clientと認証に利用するgoogle-auth-oauthlibをインストールする。

下記のコマンドを実行し、ライブラリのインストールを行う。

pip install google-api-python-client google-auth-oauthlib

実装

main.py
import pickle
from pathlib import Path

import requests
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build

# 各URLやスコープ
API_SERVICE_NAME = "photoslibrary"
API_VERSION = "v1"
SCOPES = ["https://www.googleapis.com/auth/photoslibrary.appendonly"]


class GooglePhotoFacade:
    # ログインしてセッションオブジェクトを返す
    def __init__(
        self,
        credential_path: str,
        token_path: str = "",
    ):
        with build(
            API_SERVICE_NAME,
            API_VERSION,
            credentials=self._login(credential_path, token_path),
            static_discovery=False,
        ) as service:
            self.service = service
            print("Google OAuth is Complete.")

        self.credential_path = credential_path
        self.token_path = token_path

    def _login(self, credential_path: str, token_path: str) -> any:
        """Googleの認証を行う

        Args:
            credential_path (str): GCPから取得したclient_secret.jsonのパス
            token_path (str): Oauth2認証によって得られたトークンを保存するパス。

        Returns:
            googleapiclient.discovery.Resource: _description_
        """

        if Path(token_path).exists():
            # TOKENファイルを読み込み
            with open(token_path, "rb") as token:
                credential = pickle.load(token)
            if credential.valid:
                print("トークンが有効です.")
                return credential
            if credential and credential.expired and credential.refresh_token:
                print("トークンの期限切れのため、リフレッシュします.")
                # TOKENをリフレッシュ
                credential.refresh(Request())
        else:
            print("トークンが存在しないため、作成します.")
            credential = InstalledAppFlow.from_client_secrets_file(
                credential_path, SCOPES
            ).run_local_server()

        # CredentialをTOKENファイルとして保存
        with open(token_path, "wb") as token:
            pickle.dump(credential, token)

        return credential

    def upload(
        self, local_file_path: str,
    ):

        self._login(self.credential_path, self.token_path)  # トークンの期限を確認
        
        save_file_name:str = Path(local_file_path).name
        with open(str(local_file_path), "rb") as image_data:
            url = "https://photoslibrary.googleapis.com/v1/uploads"
            headers = {
                "Authorization": "Bearer " + self.service._http.credentials.token,
                "Content-Type": "application/octet-stream",
                "X-Goog-Upload-File-Name": save_file_name.encode(),
                "X-Goog-Upload-Protocol": "raw",
            }
            response = requests.post(url, data=image_data.raw, headers=headers)

        upload_token = response.content.decode("utf-8")
        print("Google Photoへのアップロードが完了しました。")
        body = {"newMediaItems": [{"simpleMediaItem": {"uploadToken": upload_token}}]}

        upload_response = self.service.mediaItems().batchCreate(body=body).execute()
        print("Google Photoへのアップロードした動画の登録に成功しました。")

        # uploadしたURLを返す
        return upload_response["newMediaItemResults"][0]["mediaItem"]


if __name__ == "__main__":
    g = GooglePhotoFacade(
        credential_path="client_secret.json", token_path="token.pkl"
    )
    g.upload(
        local_file_path="qiitan.png", # ここに保存する画像を指定する。
    )

動作確認

動作確認として、下記のQiitanの画像をアップロードしてみる。

qiitan.png

$ python main.py
トークンが存在しないため、作成します.
Please visit this URL to authorize this application: ${省略}
Google OAuth is Complete.
Google Photoへのアップロードが完了しました。
Google Photoへのアップロードした動画の登録に成功しました。

初回実行時はOAuth2の認証画面が表示される。はじめに、アップロードしたいGooglePhotoのアカウントを選択する。

スクリーンショット 2023-01-15 13.56.14.png

下記の画面に遷移されるので「続行」を押下する。

スクリーンショット 2023-01-15 13.56.30.png

その後下記の画面へ遷移するので、再度「続行」を押下する。

スクリーンショット 2023-01-15 13.56.38.png

その後、トークンがtoken.pklの名称でローカル保存される。2回目以降はローカルに保存したトークンを利用するので認証画面なしで実行ができる。

実行後、Google Photoにアクセスし、Qiitanの画像がアップロードされていることを確認する。

スクリーンショット 2023-01-15 14.18.10.png

同じソースコードで動画もアップロードが可能である。local_file_pathにmp4形式の動画を指定する。

main.py
~~~省略~~~

if __name__ == "__main__":
    g = GooglePhotoFacade(
        credential_path="client_secret.json", token_path="token.pkl"
    )
    g.upload(
        local_file_path="sample.mp4", # 動画を指定する
    )

再度下記のコマンドでアップロード処理を実行する。

python main.py

動画がアップロードされたことが確認できる。

スクリーンショット 2023-01-15 14.26.24.png

参考資料

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?