
Raspberry Pi カメラで撮った写真をGoogle Driveへアップロードし、PCやスマートフォンからも参照できると便利です。Raspberry Piにある画像ファイルをGoogle DriveへアップロードするPythonプログラミングの方法を解説します。
目次
開発環境
今回の開発環境を以下に示します。
- ハード:Raspberry Pi 3 Model B
- OS:Raspbian Jessie
- プログラミング言語:Python 3.6.1
OAuth 2.0 プログラミング
Google Drive APIでGoogle Driveへアクセスするには、OAuth 2.0の認証が必要です。OAuth 2.0 認証プロセスのPythonコードを以下に示します。OAuth 2.0 プログラミングについては、関連記事「Google Apps API使用に必要なOAuth 2.0認証について学ぶ」も参照してください。
from __future__ import print_function import os from oauth2client import client from oauth2client import tools from oauth2client.file import Storage try: import argparse flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args() except ImportError: flags = None CLIENT_SECRET_FILE = 'client_secret.json' CREDENTIAL_DIR = '.credentials' CREDENTIAL_FILE = 'google-drive-credential.json' def get_credentials(application_name, scopes): """Gets valid user credentials from storage. If nothing has been stored, or if the stored credentials are invalid, the OAuth2 flow is completed to obtain the new credentials. Returns: Credentials, the obtained credential. """ home_dir = os.path.expanduser('~') credential_dir = os.path.join(home_dir, CREDENTIAL_DIR) if not os.path.exists(credential_dir): os.makedirs(credential_dir) credential_path = os.path.join(credential_dir, CREDENTIAL_FILE) store = Storage(credential_path) credentials = store.get() if not credentials or credentials.invalid: flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, scopes) flow.user_agent = application_name if flags: credentials = tools.run_flow(flow, store, flags) else: # Needed only for compatibility with Python 2.6 credentials = tools.run(flow, store) print('Storing credentials to ' + credential_path) return credentials
Google Drive API プログラミング
以下のライブラリがインストールされていない場合は、事前にインストールしておいてください。
$ pip install –upgrade google-api-python-client |
$ pip install glob |
Raspberry Piで撮った写真をGoogle DriveへアップロードするPythonコードを以下に示します。
# -*- coding: utf-8 -*- from __future__ import print_function import httplib2 import os import sys from glob import glob from apiclient import discovery from apiclient.http import MediaFileUpload from oauth2gdrive import get_credentials # OAuth 2.0で設定するApplication ID APPLICATION_NAME = 'Upload files' # OAuth 2.0で設定するSCOPE:Google Driveにおいてファイル単位のアクセスを許可 SCOPES = 'https://www.googleapis.com/auth/drive.file' # アップロードするファイルが格納されているディレクトリ IMG_DIR = 'Pictures' # アプウロードするファイルの拡張子 FILE_EXTENSION = 'jpg' # ファイルを格納するGoogle Driveのフォルダ DRIVE_DIR = 'pi_Pictures' # Google DriveのフォルダのmimeType FOLDER_MIME_TYPE = 'application/vnd.google-apps.folder' # アップロードするファイルのmimeType FILE_MIME_TYPE = 'image/jpeg' def create_folder(drive_service): ''' Google Driveにアップロードするファイルを格納するホルダを作成する Google Driveに指定のフォルダが存在するかをチェックする ・指定のフォルダが存在しない場合は、新規にフォルダを作成する ・既に指定のフォルダが存在する場合は、フォルダの作成をスキップする Returns: folder-id, Google DriveのフォルダID ''' # 指定のフォルダが存在するかを問い合わせる query = "mimeType='" + FOLDER_MIME_TYPE + "'" + " and name='" + DRIVE_DIR + "'" response = drive_service.files().list(q=query, spaces='drive', fields='files(id, name)').execute() for folder in response.get('files', []): # 指定のフォルダが存在する場合は、そのフォルダIDを返却し復帰する print('Folder already exists:' + folder.get('name')) return folder.get('id') # 指定のフォルダを新規に作成し、そのフォルダIDを返却する folder_metadata = { 'mimeType': FOLDER_MIME_TYPE, 'name': DRIVE_DIR, } folder = drive_service.files().create(body=folder_metadata, fields='id, name').execute() print('Folder created:' + folder.get('name')) return folder.get('id') def upload_file(drive_service, drive_folder_id, upload_file_path): ''' Google Driveの指定したフォルダにファイルをアップロードする アップロードするファイル名が、Google Driveに存在するかをチェックする ・ファイル名が存在しない場合は、指定のファイルをアップロードする ・ファイル名が存在する場合は、指定のファイルのアップロードをスキップする Returns: void ''' # upload_file_pathがらファイル名を抽出する file_name = os.path.split(upload_file_path)[-1] # アップッローッドするファイル名が存在するかを問い合わせる query = "'" + drive_folder_id + "' in parents and mimeType='" + FILE_MIME_TYPE + "' and name='" + file_name + "'" response = drive_service.files().list(q=query, spaces='drive', fields='files(id, name)').execute() for upload_file in response.get('files', []): # ファイル名が存在する場合は、アップロードをスキップし復帰する print('File already exists:' + upload_file.get('name')) return # Google Driveの指定したフォルダへファイルをアップロードする media = MediaFileUpload(upload_file_path, mimetype=FILE_MIME_TYPE, resumable=True) file_metadata = { 'mimeType': FILE_MIME_TYPE, 'name': file_name, 'parents': [drive_folder_id], } created_file = drive_service.files().create(body=file_metadata, media_body=media, fields='id, name').execute() print('Upload sucssesful:' + created_file.get('name')) def uploadfiles(): ''' 指定したディレクトリ配下の全てのファイルをGoogle Driveへアップロードする 指定するディレクトリは、ホームディレクトリ配下のディレクトリとする 指定した拡張子を持つファイルのみをアップロードする Returns: void ''' # OAuth 2.0の認証プロセスを実行する credentials = get_credentials(APPLICATION_NAME, SCOPES) http = credentials.authorize(httplib2.Http()) drive_service = discovery.build('drive', 'v3', http=http) # アップロードする全てのファイルパスを取得する home_dir = os.path.expanduser('~') img_dir = os.path.join(home_dir, IMG_DIR) upload_files_path = glob(os.path.join(img_dir, '*.' + FILE_EXTENSION)) if not upload_files_path: # 該当するファイルが存在しない場合は終了する print('File does not exist. It does not upload.') sys.exit() # Google Driveにアップロードするファイルを格納するフォルダを作成する drive_folder_id = create_folder(drive_service) # アップロードするファイル数分繰り返す for upload_file_path in upload_files_path: # Google Driveにファイルをアップロードする print('Upload file:' + upload_file_path) upload_file(drive_service, drive_folder_id, upload_file_path) if __name__ == '__main__': uploadfiles()
[参考]
Pythonコードを実行する
Pythonコードの準備ができたら、Raspberry Piで撮った写真をGoogle Driveへアップロードできるか確認してみましょう。
アップロードするファイルを確認
アップロードするファイルを確認します。
- 上記のプログラムでは、ファイル拡張子が「jpg」のファイルをアップロードします。
OAuth 2.0 認証プロセス
OAuth 2.0 認証プロセスのログを以下に示します。
- 認証が成功し、クレデンシャルファイルが作成されたことが確認できます。
ファイルのアップロード
ファイルアップロード時のログを以下に示します。
- 一回目の実行では、Google Driveにフォルダを作成し、ファイルがアップロードされたことが確認できます。
- 二回目の実行では、フォルダの作成およびファイルのアップロードがスキップされていることが確認できます。
[注意] Google Drive でファイルを削除してもごみ箱に移動するだけで、完全に削除するまでは検索の対象となります。
Google Driveでアップロードしたファイルを確認
ブラウザでGoogleにログインし、Google Driveへアップロードしたファイルを確認します。
Raspberry PiからアップロードしたファイルがGoogle Driveで確認できました。