開発情報・ナレッジ

投稿者: ShiningStar株式会社 2024年7月5日 (金)

GoogleColab上でGoogleドライブのファイルをSPIRALのDBにアップロードしてみた

GoogleColab を使ってGoogleDriveに保存されているデータをSPIRALのDBへアップロードするプログラムを作成してみました。
GoogleColabとはGoogleの環境上でPythonコードを実行出来るサービスなのですが、
GoogleColab上では他のGoogleサービスとの連携が簡単に出来ます。
今回はGoogleDriveのデータをSPIRALにアップロードするプログラムを作成してみました。


全体像

GoogleDriveをマウントし操作可能にした上で、
サポートサイト のマルチパート形式でのレコード登録サンプルを参考にしてPythonでファイルアップロードするサンプルプログラムになります。

DB設定

任意のDBを作成し、SPIRALのAPIの仕様上アップロードするファイル型フィールドの他にもフィールドが必要なので、
登録日時フィールドにて差し替えキーワードをresistDateにして登録日時を格納するフィールドを追加してください。
次にファイル型フィールドを差し替えキーワードfileで追加してください。

サンプルプログラム

import os
import time
import base64
import hmac
import hashlib
import requests
import json
from google.colab import drive

# Google Driveをマウント
drive.mount('/content/drive')

# 設定値
LOCATOR_URL = "https://www.pi-pe.co.jp/api/locator"
API_TOKEN = ""
API_SECRET = ""
DB_TITLE = "colabo"  # アップロードするDBタイトル
RESIST_DATE_FIELD_NAME = "resistDate"  # 登録日時フィールドの差し替えキーワード
RESIST_DATE = "now"  # 登録日時フィールドのvalue値
FILE_FIELD = "file"  # ファイル型フィールドの差し替えキーワード
DATA_PATH = "/content/drive/My Drive/Images"  # アップロードしたいファイルが格納されているGoogleDriveのパス
FILE_TYPES = ['png']  # 対象のファイルタイプ
REQUESTS_PER_MINUTE_LIMIT = 600  # リクエスト上限数

# 変更不要
MULTIPART_BOUNDARY = "SPIRAL_API_MULTIPART_BOUNDARY"

# APIサーバーのURLを取得する関数
def get_api_server_url(locator_url, token):
    headers = {
        "X-SPIRAL-API": "locator/apiserver/request",
        "Content-Type": "application/json; charset=UTF-8",
    }
    data = {
        "spiral_api_token": token
    }
    response = requests.post(locator_url, headers=headers, json=data)
    response_json = response.json()
    return response_json['location']

# 署名を作成する関数
def create_signature(token, passkey, secret):
    key = f"{token}&{passkey}"
    signature = hmac.new(secret.encode(), key.encode(), hashlib.sha1).hexdigest()
    return signature

# マルチパートデータを作成する関数
def create_multipart_data(file_path, parameters):
    with open(file_path, "rb") as file:
        file_data = file.read()

    postdata = []
    postdata.append(f"--{MULTIPART_BOUNDARY}")
    postdata.append('Content-Type: application/json; charset="UTF-8"')  # charsetを追加
    postdata.append('Content-Disposition: form-data; name="json"')
    postdata.append("")
    postdata.append(json.dumps(parameters))
    postdata.append(f"--{MULTIPART_BOUNDARY}")
    postdata.append(f'Content-Type: application/octet-stream')  # Content-Typeを修正
    postdata.append(f'Content-Disposition: form-data; name="{FILE_FIELD}"; filename="{os.path.basename(file_path)}"')
    postdata.append("")
    postdata.append(file_data)  # ファイルデータはバイナリ形式のまま送信
    postdata.append(f"--{MULTIPART_BOUNDARY}--")
    postdata.append("")  # 空行を追加

    postdata_bytes = []
    for item in postdata:
        if isinstance(item, str):  # 文字列の場合
            postdata_bytes.append(item.encode('utf-8'))  # UTF-8でエンコード
        else:
            postdata_bytes.append(item)  # すでにバイト列の場合はそのまま

    return b'\r\n'.join(postdata_bytes)

# APIリクエストを送信する関数
def api_request(api_url, data, headers):
    response = requests.post(api_url, headers=headers, data=data)
    return response.json()

# APIサーバーのURLを取得
API_URL = get_api_server_url(LOCATOR_URL, API_TOKEN)

processed_files = 0
start_time = time.time()

for root, dirs, files in os.walk(DATA_PATH):
    for file_name in files:
        if file_name.lower().endswith('png'):
            file_path = os.path.join(root, file_name)

            passkey = str(int(time.time()))
            signature = create_signature(API_TOKEN, passkey, API_SECRET)

            parameters = {
                "spiral_api_token": API_TOKEN,
                "db_title": DB_TITLE,
                "passkey": passkey,
                "signature": signature,
                "data": [
                    {"name": RESIST_DATE_FIELD_NAME, "value": RESIST_DATE}
                ],
            }

            multipart_data = create_multipart_data(file_path, parameters)

            headers = {
                "X-SPIRAL-API": "database/insert/request",
                "Content-Type": f'multipart/form-data; boundary={MULTIPART_BOUNDARY}',
            }

            api_response = api_request(API_URL, multipart_data, headers)

            # APIレスポンスの確認
            if api_response.get('code') == '0':
                print(f"File {file_name} uploaded successfully.")
            else:
                print(f"Error uploading file {file_name}: {api_response.get('message')}")
            processed_files += 1

            # リクエスト上限を超えないようにディレイ
            if processed_files % REQUESTS_PER_MINUTE_LIMIT == 0:
                time.sleep(60 - (time.time() - start_time))
                start_time = time.time()

print(f"Processed files: {processed_files}") 
            

GoogleDriveのパスの確認方法

データをアップロードする時にアップロードしたいファイルのパスを確認する必要があります。

from google.colab import drive
# Google Driveをマウント
drive.mount('/content/drive') 
            

こちらのGoogleDriveをマウントする記述のみをコードブロックに貼り付けて実行する事で、
サイドバーのファイル欄からディレクトリを確認することができます。

設定方法

GoogleColabへアクセスして新規ノートブックを作成してください。
作成したら上記サンプルプログラムをそのまま貼り付けてください。
GoogleDriveのパスがご不明な方は上記のGoogleDriveのパスの確認方法に従ってパスを確認してください。
後に、

# 設定値
LOCATOR_URL = "https://www.pi-pe.co.jp/api/locator"
API_TOKEN = ""
API_SECRET = ""
DB_TITLE = "colabo"  # アップロードするDBタイトル
RESIST_DATE_FIELD_NAME = "resistDate"  # 登録日時フィールドの差し替えキーワード
RESIST_DATE = "now"  # 登録日時フィールドのvalue値
FILE_FIELD = "file"  # ファイル型フィールドの差し替えキーワード
DATA_PATH = "/content/drive/My Drive/Images"  # アップロードしたいファイルが格納されているGoogleDriveのパス
FILE_TYPES = ['png']  # 対象のファイルタイプ
REQUESTS_PER_MINUTE_LIMIT = 600  # リクエスト上限数

こちらをお使いの環境に合わせて修正してください。
その他は変更せずに稼働いたします。

修正が終わったら、
左上にあります再生ボタンの様なボタンを押すとプログラムが実行され、
GoogleDrive上の指定したパスかつ指定したファイルタイプ(拡張子)のファイルがアップロードされます。

その他

GoogleColab上では他のGoogleサービスとの連携がかなり容易でAPI認証等必要ないので、
例えば他には容易にGmailのデータをSPIRALに格納することが出来ます。
GoogleサービスとSPIRALの連携には非常に良い環境なので、
GoogleサービスとSPIRALのデータ連携をする場合は是非GoogleColabの利用をご検討頂けると幸いです。
また、外部環境との連携ですのでデータの取扱には十分にご注意ください。

解決しない場合はこちら コンテンツに関しての
要望はこちら