【Python】Dropbox AIPを使ってファイルを操作する


投稿日 2022年6月18日 >> 更新日 2023年3月1日

概要

オンラインストレージサービスであるDropboxのPython SDK(Software Development Kit)を使って、Dropbox内の状態からファイル等の出し入れに至るまでの実装をします。Dropbox APIを使用するには公式サイトにて開発用アプリの作成が必要です。開発用アプリのアクセストークンを取得することによってDropboxにアクセスできます。

以下の記事で開発用アプリの作成手順とアクセストークンの取得方法を説明しているので宜しければご覧ください。

実行環境&使用ライブラリ

実行環境
Windows Subsystem for Linux
Python 3.6.9
pip 21.3.1
使用ライブラリ ライセンス
dropbox==11.32.0 MIT
$ pip install dropbox

Dropbox APIの実装

Dropbox APIを使うに当たってアクセストークンの取得が必要です。

以下の記事で開発用アプリの作成手順とアクセストークンの取得方法を説明しているので宜しければご覧ください。

Dropbox APIの完全なドキュメントは以下のWebサイトにあります。

モジュールをインポートしアクセストークンを読み込む

DropboxのPython用SDKをインストールしたらモジュールをインポートします。

import dropbox

次にDropboxオブジェクトにアクセストークンを渡してAPIとして使用できるようにします。

dbx = dropbox.Dropbox('アクセストークン')

print(type(dbx))
"""
<class 'dropbox.dropbox_client.Dropbox'>
"""

今回は私がオブジェクトに渡したアクセストークンの開発用アプリのタイプは「App foler」というタイプで、「permissions(権限)」のファイルコンテンツの書き込みと読み込みを有効にしています。

開発用アプリのタイプ

開発用アプリのpermissions(権限)

ちなみに、権限の変更を送信した上でアクセストークンを再度生成します。

【users_get_current_account()】でDropboxアカウントの情報を取得する

「Dropbox.users_get_current_account()」メソッドを呼び出してアカウント情報を全て取得します。

print(dbx.users_get_current_account())
"""
FullAccount(account_id= ...
"""

各種アカウント情報は以下の属性値に格納されています。

属性値 内容
account_id アカウントのID
account_type アカウントのタイプ
country アカウントの国
email アカウントのEメール
name アカウントの姓名
referral_link 開発用アプリのリンク
etc... その他もろもろ

print(dbx.users_get_current_account().email)
"""
examplt@gmail.com
"""

【files_list_folder()】でDropbox内のファイル・フォルダを一覧表示する

「Dropbox.files_list_folder('ルート')」メソッドを呼び出してDropbox内にあるコンテンツを表示します。実際のデータを取得するのではなく情報として取得します。

今回ここでは開発用アプリのタイプを「App folder」にしているため、操作できる範囲が限られています。「App folder」で開発用アプリを作成するとアクセストークンを生成すると同時にDropbox内に「/アプリ/開発用アプリ名」とフォルダが自動的に作成されます。したがって現時点ではフォルダ内に何もファイルは保存されていないので、よければDropboxアプリを開いて手動でファイル等を保存してからコードを実装してみて下さい。

print(dbx.files_list_folder(''))
"""
ListFolderResult(cursor='******', entries=[], has_more=False)
"""

現在は「/アプリ/開発用アプリ名/」の中身は空なので「entries」属性に格納されている情報はありません。

例えば「/アプリ/開発用アプリ名/testfile.txt」が保存されていた場合以下のように表示されます。

print(dbx.files_list_folder(''))
"""
ListFolderResult(cursor='*****', entries=[FileMetadata(client_modified=datetime.datetime(2022, 6, 18, 5, 29, 26), content_hash='*******', export_info=NOT_SET, file_lock_info=NOT_SET, has_explicit_shared_members=NOT_SET, id='id:*****', is_downloadable=True, media_info=NOT_SET, name='testfile.txt', parent_shared_folder_id=NOT_SET, path_display='/testfile.txt', path_lower='/testfile.txt', preview_url=NOT_SET, property_groups=NOT_SET, rev='******', server_modified=datetime.datetime(2022, 6, 18, 5, 29, 26), sharing_info=NOT_SET, size=4, symlink_info=NOT_SET)], has_more=False)
"""

ファイル名のみを取得したい場合は、「entries」属性内の「name」を繰り返し処理で呼び出します。

for entry in dbx.files_list_folder('').entries:
    print(entry.name)
"""
testfile.txt
"""

フォルダーを指定して中身を表示させたい場合は、引数に「/フォルダー」とルートである「/」を付けて実行します。

for entry in dbx.files_list_folder('/folder').entries:
    print(entry.name)
"""
sample.txt
"""

【files_create_folder()」でDropboxにフォルダーを作成する

「Dropbox.files_create_folder('/フォルダー名')」を使ってDropbox内にフォルダーを作成します。

dbx.files_create_folder('/folder2')
"""
FolderMetadata(id='id: ...
"""

Dropbox内を確認してみます。

for entry in dbx.files_list_folder('').entries:
    print(entry.name)
"""
folder2
testfile.txt
"""

【files_upload()】でDropboxにファイルをアップロードする

「Dropbox.files_upload('バイト型', '/ファイル名')」でDropbox内にファイルをアップロードします。

注意したいのが第一引数にバイト型のデータを渡すことです。そして第二引数はルートを示す「/」とそこに配置するファイル名です。
ファイルサイズに関しては公式にて150MBを超えるファイルではこのメソッドを使用しないでくださいとあります。

byte_text = b'upload data'

print(byte_text)
"""
b'upload data'
"""

print(type(byte_text))
"""
<class 'bytes'>
"""

dbx.files_upload(byte_text, '/upload_file.txt')
"""
FileMetadata(client_modified=datetime.datetime(2022, 6, 18, 22, 6, 41), ....
"""

上記の実行結果では、開発用アプリでのタイプ「App folder」なのでアクセストークンを生成すると同時に自動で「/アプリ/開発用アプリ名/」が作成されているので、第二引数の「'/upload_file.txt'」とするとDropbox内の「/アプリ/開発用アプリ名/upload_file.txt」という感じにアップロードされます。

既存のファイルをアップロードする場合は、Python組み込み関数の「open()」を使用します。

# バイナリデータとしてカレントディレクトリのファイルを読み込む
dbx.files_upload(open('sample.txt', 'rb').read(), '/upload_sample.txt')
"""
FileMetadata(client_modified=datetime.datetime(2022, 6, 18, 22, 6, 41), ....
"""

改めてDropbox内(「/アプリ/開発用アプリ名/」)のファイル一覧を表示してみます。

# ('')ではルートフォルダーを指している
for entry in dbx.files_list_folder('').entries:
    print(entry.name)
"""
folder2
testfile.txt
upload_file.txt
upload_sample.txt
"""

【files_download_to_file()】でDropbox内のファイルをローカルにダウンロードする

「Dropbox.files_download_to_file('ローカルファイル名', '/ダウンロードファイル名')」を使ってDropbox内にあるファイルを指定したディレクトリにダウンロードします。
第一引数に保存先となるファイル名で、第二引数にダウンロードするDropbox内のファイル名です。

dbx.files_download_to_file('download_file.txt', '/dropbox_file.txt')
"""
FileMetadata(client_modified=datetime.datetime(2022, 6, 18, 5, 37, 12), ...
"""

【files_download_zip_to_file()】でDropbox内のファイルまたはフォルダーをzip形式にしてダウンロードする

「Dropbox.files_download_zip_to_file('zipファイル', '/フォルダー')」を使用してDropbox内のフォルダーをZIP形式でダウンロードします。
第一引数に保存先となるzip名で、第二引数にダウンロードするDropbox内のフォルダー名です。

公式ではフォルダのサイズは20GB未満である必要との事なので注意が必要です。

dbx.files_download_zip_to_file('zip_file.zip', '/folder2')
"""
DownloadZipResult(metadata=FolderMetadata(id=...
"""

Linuxの場合は、コマンドラインにて「unzip」コマンドを実行することでzipファイルを解凍できます。

$ ls
...   zip_file.zip

$ unzip zip_file.zip

$ ls
...  foloder2  zip_files.zip

【files_get_temporary_link()】で指定されたDropbox内のファイルリンクを一時的に発行する

「Dropbox.files_get_temporary_link('ファイルパス')」を使用してDropbox内にある特定のファイルリンクを発行します。

公式では発行してから4時間ほどで期限切れになることや、ブラウザ上では直接使用しないようにと記されています。

例えばDropbox内の「testfile.txt」というファイルリンクを発行する場合は以下のように実行します。

dbx.files_get_temporary_link('/testfile.txt')
"""
GetTemporaryLinkResult(link='https://ucb0cc572...
"""

上記を実行すると「link」以外にも様々な情報が表示されます。リンクのみを取得したい場合は属性「link」を付けて実行します。

dbx.files_get_temporary_link('/testfile.txt').link
"""
'https://ucef7b4d7f.....oggC_U/file'
"""

【files_save_url()】でDropbox内にURLからデータ(画像等)を保存

「files_save_url('ファイル名', 'URL')」を使ってDropbox内にURLからのデータを保存します。
第一引数はURLから取得されたデータのファイル名、第二引数はURLとなります。

公式ではURLからの転送は5分以内に完了する必要があることに注意してくださいとのことです。

このWebサイト(ZerofromLight)のURLを使って画像をDropbox内に保存してみます。

dbx.files_save_url('/image/nginx.png', 'https://zerofromlight.com/media/markdownx/981ce864-4071-41e9-927c-476730575a05.png')
"""
SaveUrlResult('async_job_id', ...
"""

上記実装での保存先は、「image」フォルダー内に「nginx.png」というファイル名で指定しています。

「image」フォルダー内を確認していみると画像ファイルが保存されていることがわかります。

for entry in dbx.files_list_folder('/image').entries:
    print(entry.name)
"""
nginx.png
"""

【files_copy()】でDropbox内のファイル・フォルダーをコピーする

「Dropbox.files_copy('/オリジナルファイル', '/コピーファイル')」を使用してDropbox内のファイルもしくはフォルダーをコピーします。
フォルダーをコピーされた場合はファイルだー内にあるファイルもコピーされるとのことです。

「Dropbox.files_list_folder()」メソッドを使ってDropbox内のファイルを確認します。

for entry in dbx.files_list_folder('').entries:
    print(entry.name)
"""
folder2
image
testfile.txt
upload_file.txt
upload_sample.txt
"""

「testfile.txt」を「copy_file.txt」としてコピーします。

dbx.files_copy('/testfile.txt', '/copy_file.txt')
"""
FileMetadata(client_modified=datetime.datetime(2022, 6, 18, 5, 29, 26), ...
"""

もう一度Dropbox内のファイルを確認してみます。

for entry in dbx.files_list_folder('').entries:
    print(entry.name)
"""
folder2
image
testfile.txt
upload_file.txt
upload_sample.txt
copy_file.txt
"""

コピーされているのが分かります。

【files_move()】でDropbox内のファイルまたはフォルダーを移動する

「Dropbox.files_move('/ファイル', '/フォルダ2/移動先ファイル')」を使ってDropbox内のファイルまたはフォルダーを移動します。

dbx.files_move('/testfile.txt', '/folder2/move_testfile.txt')
"""
FileMetadata(client_modified=datetime.datetime(2022, 6, 18, 5, 29, 26), ...
"""

Dropbox内を確認してみると「testfile.txt」がルートのフォルダーに無いことが確認できます。

for entry in dbx.files_list_folder('').entries:
    print(entry.name)
"""
folder2
image
upload_file.txt
upload_sample.txt
copy_file.txt
"""

【files_delete()】でDropbox内のファイル・フォルダーを削除する

「Dropbox.files_delete('ファイル名')」を使用してDropbox内のファイルまたはフォルダーを削除します。
フォルダーを指定した場合はその中身のファイルを全て一緒に削除されます。

Dropbox内にあるルートフォルダーの「folder2」を削除します。まずはその中身を確認します。

for entry in dbx.files_list_folder('/folder2').entries:
    print(entry.name)
"""
testfile.txt
move_testfile.txt
"""

「folder2」を削除します。

dbx.files_delete('/folder2')
"""
FolderMetadata(id='id: ...
"""

ルートのフォルダーを確認すると「folder2」は削除されていることがわかります。

for entry in dbx.files_list_folder('').entries:
    print(entry.name)
"""
image
upload_file.txt
upload_sample.txt
copy_file.txt
"""

Dropbox APIのサンプルプログラムを実行してみよう

DropboxさんはAPIのチュートリアルとサンプルプログラムを用意してくれています。

このサンプルプログラムは、ローカルにあるファイルを一つずつ確認したながらDropboxにアップロードしていくというプログラムになっています。

Pythonコマンドでサンプルプログラムを実行するので、まずはPythonファイルをダウンロードします。

サンプルコードのページにアクセスされたら下図の画面右上の「Raw」をクリックします。

するとサンプルコードの生データに切り替わるので、そのURLをコピーしておきます。

そして作業ディレクトリでファイルをダウンロードしたいので、「wget」コマンドを使用してダウンロードします。

$ wget 生データのURL

$ ls
updown.py

作業ディレクトリに「updown.py」としてダウンロードされました。

どのように実行するのかコードを確認します。

...

import dropbox

# OAuth2 access token.  TODO: login etc.
TOKEN = ''

parser = argparse.ArgumentParser(description='Sync ~/Downloads to Dropbox')
parser.add_argument('folder', nargs='?', default='Downloads',
                    help='Folder name in your Dropbox')
parser.add_argument('rootdir', nargs='?', default='~/Downloads',
                    help='Local directory to upload')
parser.add_argument('--token', default=TOKEN,
                    help='Access token '
                    '(see https://www.dropbox.com/developers/apps)')
...

argparse.ArgumentParserはPython標準ライブラリでPythonプログラムの実行時にコマンドラインで引数を設定したい場合に使用されます。

上記の内容だと、第一引数が「folder」、第二引数が「rootdir」、第三引数が「--token」となっています。

各引数に設定されている値は以下です。

引数 デフォルト 内容
folder Downloads Dropbox内のDownloadsフォルダーを指している
rootdir ~/Downloads ローカルの「/home/.../Downloads」ディレクトリを指している
--token Dropbox開発用アプリのアクセストークン。デフォルトは空

コマンドラインでの例は以下です。

$ python3 updown.py foder rootdir token

コマンドラインからそれぞれ引数に渡す変数を準備します。

※システムが再起動されると変数は消えます

$ folder="Dropbox内のルートフォルダー(/)"

$ rootdir="updown.pyがある作業ディレクトリ"

$ token="アクセストークン"

Dropbox内のフォルダーは「/」から始まるのでルートやフォルダーを指定する際は頭に「/」を付けるのが無難でしょう。

rootdirはサンプルプログラムが実行されるディレクトリを設定しています。作業ディレクトリの確認は「pwd」コマンドです。

アクセストークンは開発用アプリの「settings」にて生成できます。

各変数を使用する場合は、頭に「$」を付けることによって内容を取得します。

$ python3 updown.py $folder $rootdir --token $token
Dropbox folder name: /
Local directory: /home/.../dir
Total elapsed time for list_folder: 0.709
Descending into  ...
Upload updown.py? [Y/n] y
Total elapsed time for upload 8707 bytes: 1.185
uploaded as b'updown.py'

作業ディレクトリにあるファイルを一つずつ確認して、「Yes/No」でアップロード「する/しない」を決めます。

アップロードが無事終わるとDropboxのアカウントフォルダー内に「updown.py」ファイルがアップロードされています。

これだけでもかなり有難いサンプルプログラムで自身も非常に勉強になります。

それでは以上となります。

最後までご覧いただきありがとうございました。