Raspberry Pi カメラで撮った写真をGoogle Driveへアップロードする

  • このエントリーをはてなブックマークに追加
クラウドコンピュターのイメージ

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へアップロードできるか確認してみましょう。

アップロードするファイルを確認

アップロードするファイルを確認します。

Google Drive へファイルをアップロード

  • 上記のプログラムでは、ファイル拡張子が「jpg」のファイルをアップロードします。

OAuth 2.0 認証プロセス

OAuth 2.0 認証プロセスのログを以下に示します。

Google Drive へファイルをアップロード

  • 認証が成功し、クレデンシャルファイルが作成されたことが確認できます。

ファイルのアップロード

ファイルアップロード時のログを以下に示します。

Google Drive へファイルをアップロード

  • 一回目の実行では、Google Driveにフォルダを作成し、ファイルがアップロードされたことが確認できます。
  • 二回目の実行では、フォルダの作成およびファイルのアップロードがスキップされていることが確認できます。

[注意] Google Drive でファイルを削除してもごみ箱に移動するだけで、完全に削除するまでは検索の対象となります。

Google Driveでアップロードしたファイルを確認

ブラウザでGoogleにログインし、Google Driveへアップロードしたファイルを確認します。

Google Drive へファイルをアップロード

Raspberry PiからアップロードしたファイルがGoogle Driveで確認できました。

SNSでもご購読できます。

コメントを残す

*