pyDriveを使ってフォルダ丸ごとアップロードするプログラム
今回作成したのはローカルのディレクトリにあるファイルを一括転送するプログラムで、2階層のディレクトリ構造で下記のように2階層目にデータファイルがある構造を想定しています。
この構成でtestディレクトリを丸々アップロードするプログラムです。
生成したファイルオブジェクトに属性を設定して、最後にアップロードします。
['parents']:格納するディレクトリのIDを指定します。
Google Driveはパス名やファイル名でデータを管理しておらず、IDを使ってデータ構造を管理します。
自分のIDはアップロード後に、gf['id']で参照することができます。
フォルダを作成し、その下にファイルをアップロードする場合は、作成したフォルダの['id']を取得し、アップロードするファイルの['parents']にフォルダの['id']を設定します。
フォルダの生成もファイルの生成とほぼ同様です。1つだけポイントは
ListFile()を使用してGoogle Drive上のファイルの一覧を取得することができます。
'q'を使ってQueryで条件を指定することができます。
ここでは、
os.walkを使用してローカルのディレクトリ・ファイル一覧を取得します。上記ではディレクトリの一覧のみを取得していますが、ファイルに関しても同じように処理できます。
はじめに
pyDriveを使うための事前準備はこちらに書いてあるのでご参考にしてください。今回作成したのはローカルのディレクトリにあるファイルを一括転送するプログラムで、2階層のディレクトリ構造で下記のように2階層目にデータファイルがある構造を想定しています。
この構成でtestディレクトリを丸々アップロードするプログラムです。
/home/static/Data/test
|
|
+- dir1
| |
| +- Data1
| +- Data2
|
+- dir2
|
+- Data3
+- Data4
とりあえずプログラム
実際に使う場合は下記を自分の環境に合わせて設定してください。その他はコピペすれば動くはずです。 parentid: Google Drive上のアップロード先フォルダのIDを指定、この下にデータがアップロードされます
path: ローカルのデータ格納フォルダ
import os import sys import datetime from pydrive.auth import GoogleAuth from pydrive.drive import GoogleDrive def auth_gd(): gauth = GoogleAuth() gauth.CommandLineAuth() drive = GoogleDrive(gauth) return drive def upload2googledrive(): drive = auth_gd() parentid = 'xxxxxxxx' #project-root directory path = "/home/static/Data/test" #path to local data # "test"フォルダをGoogle Drive上に作成 t_folder = create_dir(parentid, os.path.basename(path), drive) # ローカルのディレクトリ一覧取得 flag = "" dir_list=get_dirlist(path) for d in dir_list: d_folder = create_dir(t_folder['id'], os.path.basename(d), drive)
#ローカルのファイル一覧取得 file_list=get_filelist(d) for f in file_list: upload_file(d_folder['id'], f, drive)
# ディレクトリがGoogle Drive上に存在するかどうかをチェックし、
# 存在しなければ作成、すでに存在すれば既存のフォルダを返す def create_dir(pid, fname, drive=None): if drive == None: drive = auth_gd() ret = check_files(pid, fname, drive) if ret == False: folder = drive.CreateFile({'title': fname, 'mimeType': 'application/vnd.google-apps.folder'}) folder['parents']= [{'id': pid}] folder.Upload() else: folder = ret print(folder['title']+" exists") return folder
#同じ名前のファイルがGoogle Drive上に存在するかチェックし、
#存在しなければアップロード、存在すれば既存のファイルを返す def upload_file(pid, fname, drive=None): if drive == None: drive = auth_gd() ret = check_files(pid, fname, drive) if ret == False: gf = drive.CreateFile() gf['parents']= [{'id': pid}] gf.SetContentFile(fname) gf['title'] = os.path.basename(fname) gf.Upload() else: gf = ret print(gf['title']+" exists") return gf
#Google Drive上にその名前のファイル/フォルダがあるかチェック、なければFalseを、あれば既存のファイル/フォルダを返す def check_files(pid, fname, drive=None): if drive == None: drive = auth_gd() query = '"{}" in parents'.format(pid) query += ' and title = "' + os.path.basename(fname) + '"' list = drive.ListFile({'q': query}).GetList() if len(list)> 0: return list[0] return False def get_dirlist(basedir): ret = [] for path, dirnames, filenames in os.walk(basedir): for dir in sorted(dirnames): d = os.path.join(path, dir) ret.append(d) return ret def get_filelist(basedir): ret = [] for path, dirnames, filenames in os.walk(basedir): for filename in sorted(filenames): fullpath = os.path.join(path, filename) ret.append(fullpath) return ret if __name__ == '__main__': upload2googledrive()
プログラム解説
Google Driveのファイル管理について
初めに、pyDriveでGoogle Driveを取り扱ううえで厄介なのがファイルがファイル名でなくIDで管理されていることです。IDで管理されているということは、同じ名前のファイルを同じフォルダにアップロードできてしまい、別ファイルとして存在できてしまいます。そのためこのプログラムではファイル名(title)でlistを確認し、同じファイル名のファイルが存在すればそれを返すようにすることで二重生成を防いでいます。毎回フォルダ作成やファイルアップロードのたびにこのチェックが入るので、けっこうなやり取りが発生します。ファイルのアップロード
gf = drive.CreateFile() gf['parents']= [{'id': pid}] gf.SetContentFile(fname) gf['title'] = os.path.basename(fname) gf.Upload()CreateFileを使用し、google driveのGoogleDriveFileオブジェクトを生成します。
生成したファイルオブジェクトに属性を設定して、最後にアップロードします。
['parents']:格納するディレクトリのIDを指定します。
Google Driveはパス名やファイル名でデータを管理しておらず、IDを使ってデータ構造を管理します。
自分のIDはアップロード後に、gf['id']で参照することができます。
フォルダを作成し、その下にファイルをアップロードする場合は、作成したフォルダの['id']を取得し、アップロードするファイルの['parents']にフォルダの['id']を設定します。
フォルダの生成
folder = drive.CreateFile({'title': fname, 'mimeType': 'application/vnd.google-apps.folder'}) folder['parents']= [{'id': pid}] folder.Upload()
フォルダの生成もファイルの生成とほぼ同様です。1つだけポイントは
'mimeType': 'application/vnd.google-apps.folder'とすることです。
Google Drive上の情報取得
query = '"{}" in parents'.format(pid) query += ' and title = "' + os.path.basename(fname) + '"' list = drive.ListFile({'q': query}).GetList()
ListFile()を使用してGoogle Drive上のファイルの一覧を取得することができます。
'q'を使ってQueryで条件を指定することができます。
ここでは、
- in parentsで親となるフォルダを指定している
- title=を使ってファイル・フォルダ名を指定している
ローカルファイルの一覧取得
ret = [] for path, dirnames, filenames in os.walk(basedir): for dir in sorted(dirnames): d = os.path.join(path, dir) ret.append(d)
os.walkを使用してローカルのディレクトリ・ファイル一覧を取得します。上記ではディレクトリの一覧のみを取得していますが、ファイルに関しても同じように処理できます。