エミ眠太の自由帳
 エミ眠太の自由帳
    
 
 やってみた      2023-11-23      

PythonでGoogle Driveにファイルをアップロード・ダウンロードする。

Language:
 Python
Framework/Library:
 pandas Google Drive API
Technology:
 Web API データ分析・データ解析 IAM
Platform/Tool:
 GCP Google Drive

記事一覧へ

目次


はじめに

当方Google教原理主義者につき何から何までGoogleを利用していますが、もうデータベースまでGoogle様を利用することにしました。でも敬虔故に(?)無料で使用可能なGoogle Driveを今回は利用します。

アップロードダウンロードの準備・流れ

Google Driveへのファイルアップロード・ダウンロードには「Google Drive API」というライブラリが公式で用意されているためこちらを利用しましょう。またアップロード・ダウンロードするファイルには、前回Pythonで株価情報を取得・チャート化してみた。で使用したデータを使ってみたいと思います。全体の流れとしては以下の通りです。

  1. Google Drive APIの有効化
  2. Google Drive設定
  3. csvファイルのアップロード・csvファイルのダウンロード

1. Google Drive APIの有効化

APIの有効化

Google Drive APIを利用するにはGoogle Cloud Platform(以下GCP)からAPIの有効化が必要です。まずはこのリンク にアクセスして"有効にする"のボタンを押してください。

サービスアカウントの作成

続いてGCPで下画像の通りサービスアカウントを作成します。

サービスアカウントって?

「サービスアカウント」とはGoogle APIを利用するための認証情報の1種です。Googleは数多くのAPIを提供していますがAPIの利用には認証が必要になります。他の認証手段としては「APIキー」「OAuth 2.0 クライアントID」の2つがありますが、それぞれ取得情報と取得主体に応じて以下のような使い分けがされています。

  • APIキー・・・一般に公開されている情報を取得する際に、直接アクセスして利用します。
  • OAuth 2.0 クライアントID・・・一般への公開・非公開にかかわらず情報を取得する際に、Googleアカウントを持つユーザー認証経由でアクセスして利用します。
  • サービスアカウント・・・一般への公開・非公開にかかわらず情報を取得する際に、人間ではないサービスアカウント経由でアクセスして利用します。

例えば、Googleマップの情報やYouTubeの情報を取得する場合にはAPIキーが利用できますが、今回はGoogle DriveへのアクセスとなるためOAuth 2.0 クライアントIDもしくはサービスアカウントでアクセスする必要があります。しかし、OAuth 2.0 クライアントIDの場合、現在の当方の環境(外部ユーザへ開放されている、かつTesting版)ではRefresh Tokenが7日間で失効するという制約があったため、サービスアカウントを使用することにしました。

サービスアカウント作成

こちらのリンクからも飛べますが、GCPから"APIとサービス" > "認証情報"で下の画面に行けます。この画面から、"認証情報を作成" > "サービスアカウント"をクリックしてください。 下画像の通りサービスアカウント作成画面に遷移したら、詳細を設定していきます。まずは赤枠の通りサービスアカウント名を入力しましょう。するとサービスアカウントIDが自動で入力されるので、それで問題がない場合はそのまま使用してOKです。サービスアカウント名とサービスアカウントIDが入力できたら、一旦ここでは完了ボタンを押してください。上画像のサービスアカウント欄に今作成したサービスアカウントが確認できると思います。

秘密鍵作成

次に秘密鍵を作成しましょう。サービスアカウント欄に上で新規作成されたサービスアカウントが表示されていると思いますが、一番右にペンのアイコンがあると思います。それをクリックすると下画像のような"IAMと管理"というページに飛びます。画面左のナビゲーションで"サービスアカウント"が選択されていること、主画面上のタブで"キー"が選択されていることを確認した上で、"鍵を追加" > "新しい鍵を作成"というボタンを押してください。すると下画像の通りダイアログが出てきます。ここでキーのタイプを"JSON"の状態にしたまま"作成"ボタンを押すとJSONファイルがダウンロードされます。このJSONファイルがAPIを利用する際の秘密鍵となりますので、今回作成するPythonファイルと同じディレクトリに格納しておいてください。

2. Google Drive設定

サービアカウントのメールアドレス

GCP側の設定が終わったら次はGoogle Drive側の設定ですが、その前に1つGCP側から重要な情報を控えてくる必要があります。メールアドレスです。2つ上の画像内で、サービスアカウントIDというものが出てきましたが、ここに"abcde-460@quicstart-~~~~~.iam.gserviceaccount.com"という情報があると思います。このメーアドレスがGoogle Drive側の設定で必要になりますのでコピーしておきます。コピーできたら早速Google Driveを開きましょう(※URL)。

Google Driveに移動・設定

ここで適当にフォルダを作ってください。参考までにsample_folderとしました。sample_folder内に遷移しパンくずリストのsample_folderをクリックし、下画像のように"共有" > "共有"を押してください。 すると下のようなダイアログが出てきます。ここで先ほど控えておいたメールアドレスを入力して(任意ですが)"通知"を外すと"共有"ボタンが出てきます。これをクリックしたらGoogle Drive側の設定は完了です。これでPythonコードからアクセスできるようになりました。

3. csvファイルのアップロード・csvファイルのダウンロード

ようやく準備が整ったので、最後にcsvファイルをアップロード・ダウンロードするための記述をしていきましょう。今回はupdown_sample.pyというファイルを作ってそこに記述していきます。また、先ほど作成したJSONファイルの秘密鍵を同じディレクトリ内に格納しましょう。格納する際にはこのJSONファイル名をclient_secrets.jsonに変更しておいてください。

「一行解説」を見る
  1. (l.3-20) 参考情報として前回Pythonで株価情報を取得・チャート化してみた。で使用したデータをインポートして出力しています。
  2. (l.22) 入出力に関わるモジュールをインポートします。今回はBytesIO()メソッドをダウンロード時に利用します。
  3. (l.23) サービスアカウントを用いて認証を行うために必要なモジュールをインポートします。
  4. (l.24) Google API サービスのクライアントオブジェクトを作成するためのモジュールをインポートします。
  5. (l.25) ファイルのアップロード・ダウンロードに使用するモジュールをインポートします。
  6. (l.27) 上でディレクトリに格納済みのサービスアカウントの秘密鍵のパスです。
  7. (l.28) Google Driveにおいてアップロード先・ダウンロード元のフォルダのIDを指定します。先ほど、sample_folderというフォルダをGoogle Drive上に作成しましたがそのフォルダのIDとなります。IDについてはフォルダを開いた際のURLから取得できます。(URLの最後のディレクトリそのものです。)
  8. (l.29) 今回利用するデータをアップロードするために格納するファイルの名前です。
  9. (l.31-34) サービスアカウントの秘密鍵を利用して認証を設定します。引数にはサービスアカウントの秘密鍵のパスと、Google Drive API に対する読み取り/書き込みの権限を指定するscopesを設定しています。今回利用するスコープではドライブにあるすべてのファイルを表示・管理できます。なお、scopesの種類についてはこちらservice_accountに関わるGitHubレポジトリはこちらをご利用ください。
  10. (l.36) Google Drive APIの「クライアントライブラリ」build()メソッドを用いて作成します。クライアントライブラリとはGoogleのAPIと通信を行い様々な操作(取得・作成・削除等)するためのオブジェクトのようなものです。引数にはGoogle Drive APIを指す"drive"、対象のAPIのバージョンを指す"v3"、 (l.31-34) で設定した認証情報を指定しています。
  11. (l.38-41) アップロードするファイルの名前と配置先のフォルダを指定するためにメタデータを指定します。
  12. (l.43) Google Drive APIのMediaFileUploadというクラスを利用してアップロードのためのインスタンスを作成しています。第一引数にはアップロードしたいファイルのファイルパスを指定します。第二引数にはresumable=Trueとすることで、アップロードが中断された場合に再開できるように、リジューマブル(再開可能)なアップロードを有効にしています。これにより大きなファイルのアップロード時に途中で接続が切れた場合に再開が可能となります。
  13. (l.44) 実際にGoogle Driveにファイルをアップロードする部分です。build()メソッドで作成したクライアントライブラリに対して.files()メソッドを呼び出すことでファイル操作関連のリソースを呼び出します。さらに.create()メソッドでファイルを作成し、引数としてbodymedia_body内にそれぞれ上で作成したfile_metadatamediaを指定します。fieldsにはレスポンスとして返される情報として今回はidのみ指定しています。最後に.execute()メソッドを呼び出すことで、処理を実行をします。これでファイルアップロードは完了です。
  14. (l.48) これ以降はファイルダウンロードに関わる部分です。ファイルの有無を検索するためのクエリを作成します。
  15. (l.49-50) ここではfile_pathが空でない(具体的なファイル名が指定されている)場合、かつfolder_idが指定されている場合に、parentsフィールドが指定されたフォルダ内で検索する条件を追加しています。これにより、特定のフォルダ内で指定されたファイル名に一致するファイルを検索する条件が構築されます。
  16. (l.52) 実際にGoogle Drive内からファイルを検索する部分です。ファイル作成時でも利用した、build()メソッドで作成したクライアントライブラリに対して.files()メソッドを呼び出しています。ここでは検索を実行したいので、引数として (l.48) で作成したクエリを指定することで指定条件に一致するファイルを.list()メソッドで検索しています。
  17. (l.53) 実行結果は辞書形式でその中の"files"キーに検索結果のファイルリストが格納されています。.get()メソッドを使ってこのキーにアクセスし、検索結果を取得しています。もし"files"キーが存在しない場合には空のリストが返されます。
  18. (l.58-59) ここでは検索結果の有無で場合分けをしていますが、存在する場合には最初に見つかったファイルの情報にアクセスし、そのファイルIDを変数downloaded_file_idに格納しています。見つかったファイルは後でターミナルから確認できるように、 (l.59) の通り出力しておきます。
  19. (l.61) (l.44)ではアップロードするためにbuild()メソッドで作成したクライアントライブラリに対して.files()メソッドを呼び出してファイル操作関連のリソースを呼び出した上で.create()メソッドでファイルを作成しました。今度はパラメータに先ほどの変数downloaded_file_idを指定して.get_media()メソッドでファイルダウンロードの準備をします。
  20. (l.62-63) ここでは (l.62) と (l.63) でダウンロードするファイルに対してのその形式を指示していますが、 (l.62) についてはお試しでローカルに書き込んでいるだけなので飛ばしてもらって構いませんが、もしこのコード例のようにローカルにダウンロードしたい場合は、引数にダウンロードする際のファイル名とバイナリでの書き込みを意味する"wb"を指定してio.FIle()メソッドでファイルを開きます。続いて、 (l.63) についてはio.BytesIO()メソッドを利用することでメモリ上に一時的にダウンロードするようにします。
  21. (l.64-65) その後Google Drive APIのMediaIoBaseDownloadクラスを利用して (l.61-63) で設定した情報をもとにそれぞれローカル・メモリにダウンロードするためのインスタンスを作成します。
  22. (l.67-71) この部分については、 (l.73-77) でカバーしているため省略します。
  23. (l.73-77) ここからインスタンスをもとに実際にデータをダウンロードしていきます。
    • (l.73) いきなりdone1 = Falseとしていますが、変数done1False初期化することによってダウンロードが完了したかどうかを示すフラグを用意して、次のwhileに備えています。
    • (l.74-75) MediaIoBaseDownloadクラス内のnext_chunk()メソッドを呼び出して、複数のかたまりに分割してGoogle Driveからファイルをダウンロードする部分です。status1にはダウンロードの進捗情報が含まれ、ダウンロードが完了したかどうかを示すフラグが更新されます。
    • (l.76) MediaIoBaseDownloadクラス内の.progress()メソッドを利用してファイルダウンロードの進捗率を表示します。
    • (l.77) 続いて (l.63) で作成したio.BytesIO()のオブジェクトであるfh1に対して、.seek(0)とすることでファイルポインタの位置を"0"=先頭に戻しています。通常ファイルを読み取り後に再度同じファイルを読み取る際、ファイルポインタがファイルの最後に進んだままだと何も読み取れないません。そのためファイルポインタをファイルの先頭に戻しておくことで期待通り全データを取得できるようにしています。
  24. (l.79-80) 最後に取得したデータをDataFrame形式で出力しましょう。
  25. (l.82-95) (l.7-20) と同じ結果が出力されていれば成功です。

これでupdown_sample.pyによるファイルのアップロード・ダウンロード設定が完了しました。

まとめ

今回Google Drive APIの基本操作として「アップロード」、「検索」、「ダウンロード」の3種類を実行しました。CRUDなアプリケーションを作るのには物足りないですが、個人的にはデータベース代わりに少量のデータを保管・読み取りするだけなら使えそうだなという印象です(がいかがでしょうか?)。


記事をシェアする


関連する記事

よろしければこちらの記事も参考にしてみてください。

Loading...




記事一覧へ