Sassyブログ

好きなことで暮らしを豊かにするブログ

PythonでGoogleDriveを操作するのにPyDrive2が便利

始めに

最近DBのバックアップを取るためにバックアップ先のストレージとしてGoogleドライブを利用することとしました。

バックアップは定期的に行いたく、プログラム上でバックアップファイルを収集して、それらをアップロードしようと考えています。

言語はPythonを使用しているため、PythonからGoogleDriveへの操作を簡単に行うのにPyDrive2というライブラリを使用することにしました。

PyDrive2とは

github.com

PyDrive2はgoogle-api-python-client のラッパーライブラリです。

Google APIのページのサンプルコードを見ていただくとわかるのですが、そこそこ手間のかかりそうな実装となっています。

Python quickstart  |  Google Docs API  |  Google Developers

PyDrive2を使うことでここら辺の複雑なコードを簡略化してくれます。

Google Drive APIを利用できるようにする

まずは管理コンソールにログインします。

Google Cloud Platform

左側のメニューから 有効なAPIとサービス を選択して、赤線の +APIとサービスの有効化 をクリックします。

表示されたGoogleサービスの一覧から Google Drive をクリックします。

すると以下の画面が表示されるのでAPIを有効化しましょう。

※私はすでに有効化済みなのでキャプチャは有効化されているものとなっています。

その後、管理画面に戻り左側のメニューから 認証情報 を選択し、+認証情報を作成クリックします。

表示されたリストから OAuthクライアントIDを選択します。

ウェブアプリケーションを選択してください。

承認済みの JavaScript 生成元には、http://localhost:8080のURLを追加し、 承認済みのリダイレクト URIには、http://localhost:8080/のURLを追加してください。

承認済みのリダイレクト URIの方は末尾に/が付いていますがこちらは必ずつけてください。

認証する際にパラメータ不正で失敗します。

入力後、作成ボタンをクリックするとclient_secrets.jsonが払い出されるので保存をします。

このclient_secrets.jsonは後ほど使います。

最初の1回だけローカルで認証を行う

PyDrive2はすでにインストールしているものとします。

client_secrets.jsonをプロジェクトのルートに配置してください。

PyDrive2を使えば以下のコードを実行し認証を行うだけで、後はGoogleDriveをインスタンス化してメソッドを呼び出してGoogleDriveの操作ができるようになります!

 gauth = GoogleAuth()
 gauth.LocalWebserverAuth()

上記のコードを貼り付けて実行を行うと

credentials.json, という秘匿情報ファイルが払い出されます。

この情報は私は.gitignoreに含めてgitで管理せずサーバーに配置しています。

gauth.LocalWebserverAuth()はローカルで認証を行い、秘匿情報ファイルを作成するために必要であるため、1度呼び出したらそれ以降は不要なのでコメントアウトするか削除してしまいましょう。

私はコメントアウトしてコメントアウトした理由をコメントに残しています。

また、上記の作業だけでは毎回認証を求められてしまうため、自動化スクリプトを作成するためにもsettings.yamlを作成して用意した秘匿情報を保存し次回以降その情報を使用するようにします。

ファイル名は必ずsettings.yamlとしてください。

このファイル名は決まっているのでそれ以外のファイル名にするとPyDrive2は読み込んでくれません。

client_config_file: client_secrets.json
save_credentials: True
save_credentials_backend: file
save_credentials_file: credentials.json
get_refresh_token: True

settings.yamlはプロジェクトフォルダのルートに配置します。

配置後再度実行して認証を行えばOKです。

DBバックアップを取得する

今回はDBバックアップの取得は本題では無いので簡単に載せておきます。

Python上でシェルコマンドを叩いて、バックアップ対象ファイルを所定のディレクトリ配下に集めてきています。

簡単に載せておきます

import subprocess

subprocess.run("sudo rm -rf {}".format(backaup_path), shell=True, check=True)
subprocess.run("mkdir {}".format(backaup_path), shell=True, check=True)
subprocess.run("sudo cp -p /var/lib/pgsql/14/data/postgresql.conf {}/postgresql.conf".format(backaup_path), shell=True, check=True)

・・・省略

subprocessを使うことでシェルコマンドをPython上で実行できるようになります。 shellオプションはshellを使うのでTrueで、checkオプションをTrueにしておくと実行したコマンドでエラーが発生するとPythonが例外を飛ばしてくれます。

上記のコードではエラーハンドリングしてませんが、実際は適宜エラーハンドリングするようにしましょう。

アップロード先のバックアップ用格納ディレクトリを作成する

ここからはPythonでGoogleDriveを操作します。

以下のコードでディレクトリを作成します。

bk_dir = drive.CreateFile({
        'title': 'postgres_bk_{}'.format(now_date_time),
        'mimeType': 'application/vnd.google-apps.folder',
        'parents': [{
            'id': folder_id,
            'kind': 'drive#fileLink',
        }],
    })
    bk_dir.Upload(param={'supportsTeamDrives': True})

実行した日付ごとにディレクトリを作成したいので、ディレクトリ名に日付を含めるようにしています。

titleで指定した文字列はディレクトリ名で使われます。

mimeTypeは種別で、ファイルを作成する場合は指定しなくて良いですが、ディレクトリを作成する場合は'application/vnd.google-apps.folder'としておきます。

'parents'は親ディレクトリの情報を指定します。

ファイルをアップロードする

次にファイルのアップロードです。

target_upload_file = drive.CreateFile({
            'title': target_file_name,
            'parents': [{
                'id': parent_folder_id,
                'kind': 'drive#fileLink',
            }]
        })
    target_upload_file.SetContentFile('{}/{}'.format(backaup_path, target_file_name))
    target_upload_file.Upload(param={'supportsTeamDrives': True})

呼び出すメソッドは、ディレクトリ作成時と同様にCreateFileメソッドです。

mimeTypeは省略できるので省略し、'parents'を指定します。

'parents'に指定するforlder_idは先ほど作成したディレクトリのIDになります。

その後、CreateFileの戻り値のオブジェクトからSetContentFileを呼び出して、アップロードする対象のファイルを指定します。

最後にUploadメソッドを呼び出して完了です。

もし共有ドライブにアップロードしたい場合はparam={'supportsTeamDrives': True}を引数に渡してください。

最後に

いかがでしたでしょうか?

PyDrive2を利用することで認証周りの複雑な実装から脱却できます。

google-api-python-clientGoogleが提供しているライブラリなので選定としては候補に挙がるのですが、個人で簡単に使用したり少人数のプロジェクトで作業を自動化したい場合には是非PyDrive2を使ってみるのはアリだと思います。

是非参考にしていただければ幸いです。