[Python]GoogleDriveAPIの基本的な使い方
導入方法
導入方法はこれまでの記事で紹介しています。参考にしてみてください。
準備
以降の記述は、ここまで書いていることを前提にしています。あとは鍵などの事前準備ができていることですね。
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
SCOPES = ['https://www.googleapis.com/auth/drive']
store = file.Storage('token.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('./client_secret.json', SCOPES)
creds = tools.run_flow(flow, store)
drive_service = build('drive', 'v3', http=creds.authorize(Http()))
【create】フォルダ作成
まずはフォルダの作成から。
drive_service = build('drive', 'v3', http=http_auth)
'''ここから'''
file_metadata = {
'name': 'フォルダ名',
'mimeType': 'application/vnd.google-apps.folder'
'parents': ['格納するフォルダのID']
}
drive_service = drive.files().create(body=file_metadata,
fields='id').execute()
#fieldに指定したidをfileから取得できる
print ('Folder ID: %s' % file.get('id'))
ファイル作成時の戻り値が、フォルダのIDを含んでいるため取得して表示できます。ちなみにこれをうまく利用すると、**作成したフォルダのIDを取得しておいて、そのフォルダにファイルをアップロードをする。**というプログラムとかも書けちゃいますね。
参考[フォルダ作成]
【MediaFileUpload, create】ファイルをアップロードする
次にファイルをアップロードする方法です。
from apiclient.http import MediaFileUpload
#~省略~
drive_service = build('drive', 'v3', http=http_auth)
'''ここから'''
folder_id = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
file_metadata = {
'name': 'sample.txt',
'parents': [folder_id]
}
media = MediaFileUpload(
'local_path/to/sample.txt',
mimetype='text/plain',
resumable=True
)
file = drive_service.files().create(
body=file_metadata, media_body=media, fields='id'
).execute()
#fieldに指定したidをfileから取得できる
print ('File ID: %s' % file.get('id'))
別途、importしたMediaFileUploadというクラスを用いて操作します。おおよそbodyにGoogleDrive側の情報、media_bodyにアップロードしたいファイルの情報を入れる。って感じですね。
参考
【delete】ファイル,フォルダの削除
drive_service = build('drive', 'v3', http=http_auth)
'''ここから'''
file = drive_service.files().delete(
fileId='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
).execute()
#fieldに指定したidをfileから取得できる
print('File ID: %s' % file.get('id'))
deleteメソッドのキーワード引数に削除したいファイルまたはフォルダのIDを代入して実行してください。
例に漏れず、ファイル削除時の戻り値がフォルダのIDを含んでいるため、取得して表示できますね。
【list】ファイルやフォルダの一覧を取得する
色々わかりづらい感じのlistについてまとめます。
drive_service = build('drive', 'v3', http=http_auth)
results = drive_service.files().list(
q="name = 'テスト' or name contains '試験'"
pageSize=10,
fields="files(id, name)"
).execute()
items = results.get('files', [])
if not items:
print('No files found.')
else:
print('Files:')
for item in items:
print(u'{0} ({1})'.format(item['name'], item['id']))
listに指定できるキーワード引数
引数名 | 型 | 内容 |
---|---|---|
corpora | String | どこを対象に検索するのか指定するということでしょうかね 「user」、「domain」、「drive」、および「allDrives(効率的に非推奨?)」のいずれかを指定します。 デフォで「user」らしい 参考[corporaについての言及] https://www.milk-island.net/translate/ggd/drive/api/v3/enable-shareddrives.html |
spaces | String | コーパス内でクエリするスペースのカンマ区切りリストでサポートされている値は「drive」、「appDataFolder」、および「photos」 つまりどういうことだ。これの指定よってドライブ以外にもappDataFolderとかも検索対象に含められるということだろうか。 |
q | String | 検索条件を指定できる https://developers.google.com/drive/api/v3/search-files https://developers.google.com/drive/api/v3/reference/query-ref 複数条件があっても一つの文字列で表現する。条件のつなぎ方は「 and 」や「 or 」 【例】q = “name contains ‘hello’ and name contains ‘goodbye'” |
driveId | String | 検索する共有ドライブのID。corporaに「drive」か「AllDrives」を指定しているときにつけるみたい。 指定しなくても共有ドライブ探してるっぽいけどそういうことではないのかな? |
fields | String | レスポンスにどのような値を含めるか指定できる。代表格はidやname パフォーマンスを考慮して必要なフィールドだけ選ばせているみたい。 【例】fields=”nextPageToken, files(id, name)” この例であれば、nextPageTokenキーの値、filesキー内のidキーの値、nameキーの値を取得 ほかにどんな値が取得できるから以下から探して下さいhttps://developers.google.com/resources/api-libraries/documentation/drive/v3/python/latest/drive_v3.files.html#list |
orderBy | String | 【例】orderBy=”folder,modifiedTime desc” フォルダでソートし、修正時間の降順でさらにソートしている 項目はカンマ区切りで、降順ならスペースdescでできる 使い方がよくわからない指定項目もあるけど、以下の指定ができる ‘createdTime’ ‘folder’ ‘modifiedByMeTime’ ‘modifiedTime’ ‘name’ ‘name_natural’ ‘quotaBytesUsed’ ‘recency’ ‘sharedWithMeTime’ ‘starred’ ‘viewedByMeTime’ |
pageSize | integer | 1ページ当たりの処理(表示)件数。 |
pageToken | String | 次のページを呼び出すのに必要なトークン |
参考[listに指定できるキーワード引数]https://developers.google.com/drive/api/v3/reference/files/list
ページという概念
GoogleDriveAPiでファイルを検索する時に、1回のリクエストに対して返せるレスポンスに含める情報には限界があります。そのため、レスポンスは「10個あったからその情報を返すよ。でもまだあるかも!」という感じになっています。その、「まだ返せる情報があるかどうか」を持っているのがnextPageTokenです。Noneが入っているならば、検索結果は出し尽くしたということですね。
以下のプログラムではnextPageTokenがある間はリクエストし続けています。そうすることで条件に合うす全てのフォルダを検索できるということですね。
pageSizeの限界値はわかりませんが、そういうことです。
page_token = None
while True:
response = drive.files().list(
spaces='drive',
fields='nextPageToken, files(id, name)',
pageToken=page_token
).execute()
for file in response.get('files', []):
print('Found file: %s (%s)(%s)' %
(file.get('name'), file.get('id'), file.get('parent')))
page_token = response.get('nextPageToken', None)
if page_token is None:
break
参考[nextPageTokenに関して言及があったところ]
【余談】q(query)のおすすめの書き方
listメソッドのキーワード引数qに渡すのは、1つの文字列です。そのため、変数で動的に変化させたい条件があった時、複数の条件で検索したい時に、文字連結の連続でわかりにくくなってしまいます。
そのため、以下のように配列で複数の条件を書きますそうしたら最後にそれを「and」で連結してしまいます。「or」を混在させたい場合はちょっと厄介ですが、1つの例として参考にしてみてください。
condition_list = [
"'xxxxxxxxxxxxxxxxxxx' in parents",
"name = '%s'" % name
]
conditions = " and ".join(condition_list)
results = drive.files().list(
q=conditions
pageSize=10, fields="nextPageToken, files(id, name)"
).execute()
items = results.get('files', [])
Discussion