PyDriveでGoogle Driveの特定フォルダ配下のファイルをすべてダウンロードする

PyDriveでフォルダごとダウンロードしたかったが、一発でできるメソッドなどがないっぽい。
以下コード。authは済んでいるものとする( `gauth` )。

```Python
import os
from pydrive.drive import GoogleDrive

drive = GoogleDrive(gauth)

drive_folder_id = '{ダウンロード対象フォルダのID}'
save_folder = '{保存先フォルダのパス(ローカル)}'


def download_recursively(save_folder, drive_folder_id):
    # 保存先フォルダがなければ作成
    if not os.path.exists(save_folder):
        os.makedirs(save_folder)

    max_results = 100
    query = "'{}' in parents and trashed=false".format(drive_folder_id)

    for file_list in drive.ListFile({'q': query, 'maxResults': max_results}):
        for file in file_list:
            # mimeTypeでフォルダか判別
            if file['mimeType'] == 'application/vnd.google-apps.folder':
                download_recursively(os.path.join(save_folder, file['title']), file['id'])
            else:
                file.GetContentFile(os.path.join(save_folder, file['title']))

            
download_recursively(save_folder, drive_folder_id)
```


# 説明・補足

## GoogleDriveのフォルダの扱い

Googleドライブのフォルダを扱う際、ローカルのファイルのようなパス形式 (e.g. *hoge1/hoge2.txt*)では扱うことができないっぽい。
フォルダを扱いたいときは、フォルダのIDを指定しなければならないらしい。

IDはWeb版GoogleDriveのURL↓の*******の部分
https://drive.google.com/drive/u/0/folders/*******

`drive.ListFile()`で得られるファイルリストにはファイルもフォルダも含まれる。
フォルダに対して`file.GetContentFile()`をしてもエラーが出てフォルダをダウンロードすることはできない。
mimeTypeでファイルとフォルダの判別を行う必要がある。


## 'q'

`drive.ListFile({'q': {query}})`のようにqueryを指定することで、得られるファイルリストに含めるファイルの条件を指定できる。

`'{フォルダID}' in parents`で 指定のフォルダを親として持つファイルだけを抜き出せる。  
また、`trashed=false`を指定しないと、ゴミ箱に入っているファイルもリストに載ってしまうので注意。



その他の条件は以下参考
 [Search for Files and Team Drives | Drive REST API | Google Developers](https://developers.google.com/drive/api/v3/search-parameters)


## 'maxResults'

一度に取ってくるファイルの数(ファイルリストに含めるファイルの数)を指定する。
対象のファイルがあまりにも多い場合、一度に全部のファイルをとってくることができない。
(明確な上限値は公開されていない？ ↓Stack Overflow 参照)
PyDriveの場合は`maxResults`を指定すればページングもよしなにやってくれる。

`max_results`の`100`はマジックナンバー。特に意味はない。


**参考**

- [Clarification on maxResults and nextPageToken using Google Drive API v2 - Stack Overflow](https://stackoverflow.com/questions/11730454/clarification-on-maxresults-and-nextpagetoken-using-google-drive-api-v2)
- [Files: list | Drive REST API | Google Developers](https://developers.google.com/drive/api/v3/reference/files/list)
- [Paginate and iterate through files — PyDrive 1.2.1 documentation
](https://pythonhosted.org/PyDrive/filelist.html#paginate-and-iterate-through-files)





# 参考
1. [GitHub - gsuitedevs/PyDrive: Google Drive API Python wrapper library](https://github.com/gsuitedevs/PyDrive)
1. [Welcome to PyDrive's documentation! — PyDrive 1.2.1 documentation](https://pythonhosted.org/PyDrive/index.html#)
1. [Files: list | Drive REST API | Google Developers](https://developers.google.com/drive/api/v3/reference/files/list)
1. [Search for Files and Team Drives | Drive REST API | Google Developers](https://developers.google.com/drive/api/v3/search-parameters)
1. [Google Drive API v3 を使ってみた - Qiita](https://qiita.com/tearoom6/items/4d672f2e870e686b24c0) 
1. [Clarification on maxResults and nextPageToken using Google Drive API v2 - Stack Overflow](https://stackoverflow.com/questions/11730454/clarification-on-maxresults-and-nextpagetoken-using-google-drive-api-v2)