LoginSignup
4
5

GoogleDrive のファイル操作(アップロード/ダウンロード)を自動化する

Last updated at Posted at 2022-08-11

Pythonを使って「GoogleDriveへファイルアップロード」「GoogleDriveからのファイルダウンロード」を実現する手順を解説します。

概要

  • GoogleDriveへ自動アクセスするためGoogle Cloud projectを登録します。
  • GoogleDriveへログインし、認証コードを取得します。
  • 認証コードからアクセストークンを取得します。
  • アクセストークンを利用してGoogle Drive APIにより「GoogleDriveへのファイルアップロード」「GoogleDriveからのファイルダウンロード」を実現します。

GoogleDriveへ自動アクセスするためGoogle Cloud projectを登録

OAuthの設定

image
image
image

  • 承認済みのリダイレクト URIにhttp://localhost:4200/を設定します。
    image

  • クライアントIDクライアントシークレット を取得します。
    image

GoogleDriveへログインし、認証コードを取得

トークン取得用URLを作成し、ブラウザへ貼り付けます。

  • 下記のclient_id=xxxxxxxxxxxxxxxxxxxxxxxxには上記で取得したクライアントIDを指定します。
https://accounts.google.com/o/oauth2/v2/auth?scope=https%3A//www.googleapis.com/auth/drive&access_type=offline&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2F&client_id=xxxxxxxxxxxxxxxxxxxxxxxx
  • サインインが完了すると認証コードが発行されるので取得します。
    image
    image
    image

  • code=xxxxxxxxxxxxxと表示されます。このxxxxxxxxxxxxxが認証コードです。
    image
    注意
    URLに表示される認証コードはURLエンコードされています。
    認証コードはデコードしてから利用する必要があります。
    例 4%2F0Ad・・・ => 4/0Ad・・・
    参考サイト

認証コードからアクセストークンを取得

  • 下記手順を参考に認証コードからアクセストークンを取得します。
    更新トークンとアクセス トークンの認証コードを交換する

  • aaaaaaaaaaaaaaaaaには上記で取得した認証コードを指定します。

  • bbbbbbbbbbbbbbbbbには上記で取得したクライアントIDを指定します。

  • cccccccccccccccccには上記で取得したクライアントシークレットを指定します。

import urllib.parse
import urllib.request
import json

def get_googledrive_token(code: str):

    apl_client_id= "bbbbbbbbbbbbbbbbbbbbbbbbb"
    client_secret = "cccccccccccccccccccccccc"
    redirect_url = "http://localhost:4200/"

    url = "https://oauth2.googleapis.com/token"
    method = "POST"
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }

    params = {
        "client_id": apl_client_id
        ,"redirect_uri": redirect_url
        ,"client_secret": client_secret
        ,"code": code
        ,"grant_type": "authorization_code"
    }

    encoded_param = urllib.parse.urlencode(params).encode()

    request = urllib.request.Request(url, data=encoded_param, method=method, headers=headers)
    with urllib.request.urlopen(request) as res:
        body = res.read()
        dat = json.loads(body)
        print(dat)

if __name__ == '__main__':

    code = "aaaaaaaaaaaaaaaaaaaaaaaa"
    get_googledrive_token(code)
  • 下記のようなjsonが取得できます。
  • この中に以降の処理で必要なアクセストークン(access_token)及びリフレッシュトークン(refresh_token)が含まれます。
{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

アクセストークンの更新

  • 下記手順を参考にリフレッシュトークンからアクセストークンを取得します。
    アクセス トークンの更新(オフライン アクセス)

  • aaaaaaaaaaaaaaaaaには上記で取得したリフレッシュトークンを指定します。

  • bbbbbbbbbbbbbbbbbには上記で取得したクライアントIDを指定します。

  • cccccccccccccccccには上記で取得したクライアントシークレットを指定します。

import urllib.parse
import urllib.request
import json

def get_googledrive_reflesh_token(refresh_token: str):

    apl_client_id= "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
    client_secret = "cccccccccccccccccccccccccccccccccc"
    redirect_url = "http://localhost:4200/"

    url = "https://oauth2.googleapis.com/token"
    method = "POST"
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }

    params = {
        "client_id": apl_client_id
        ,"redirect_uri": redirect_url
        ,"client_secret": client_secret
        ,"refresh_token": refresh_token
        ,"grant_type": "refresh_token"
    }

    encoded_param = urllib.parse.urlencode(params).encode()

    request = urllib.request.Request(url, data=encoded_param, method=method, headers=headers)
    with urllib.request.urlopen(request) as res:
        body = res.read()
        dat = json.loads(body)
        print(dat)
        print("access_token:" + dat["access_token"])

if __name__ == '__main__':

    refresh_token = "aaaaaaaaaaaaaaaaaaaaaa"
    get_googledrive_reflesh_token(refresh_token)

  • 下記のようなjsonが取得できます。
  • この中に以降の処理で必要なアクセストークン(access_token)が含まれます。
{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "token_type": "Bearer"
}

アクセストークンの利用

GoogleDriveのフォルダ内容一覧取得

import urllib.parse
import urllib.request
import json

def get_googledrive_item(access_token: str, id: str):

    url = "https://www.googleapis.com/drive/v3/files/" + id
    method = "GET"
    headers = {
        'Authorization': 'Bearer ' + access_token
    }

    request = urllib.request.Request(url, method=method, headers=headers)
    with urllib.request.urlopen(request) as res:
        body = res.read()
        print(body)

def get_googledrive_list(access_token: str):

    url = "https://www.googleapis.com/drive/v2/files/root/children"
    method = "GET"
    headers = {
        'Authorization': 'Bearer ' + access_token
    }

    request = urllib.request.Request(url, method=method, headers=headers)
    with urllib.request.urlopen(request) as res:
        body = res.read()
        #print(body)
        dat = json.loads(body)
        print(dat)
        if dat["items"]:
            list = dat["items"]
            for item in list:
                print(item["id"])
                get_googledrive_item(access_token,item["id"])
                print("  ")

if __name__ == '__main__':

    access_token = "aaaaaaaaaaaaaaaaaaa"
    get_googledrive_list(access_token)
  • 下記のようなjsonが取得できます。
{'kind': 'drive#file', 'id': 'xxxxxxxxxxxxx', 'name': 'pictures', 'mimeType': 'application/vnd.google-apps.folder'}

GoogleDriveへのファイル登録

  • 下記手順を参考にGoogleDriveへファイルを登録します。
    Perform a resumable upload

  • aaaaaaaaaaaaaaaaaには上記で取得したアクセストークンを指定します。

  • bbbbbbbbbbbbbbbbbには上記で取得した格納対象フォルダのidを指定します。

import pathlib
import urllib.parse
import urllib.request
import json
import os

def upload_file_session(access_token: str, upload_url:str, target_file:pathlib.Path):

    contentLength = os.path.getsize(target_file)
    print("contentLength:" + str(contentLength))

    with open(target_file, 'rb') as f:

        file_split_size = 1024 * 1024 * 10

        current_pos = 0

        while current_pos < contentLength:

            remain = contentLength - current_pos
            next_size = file_split_size
            if remain <= file_split_size:
                next_size = remain

            file_body = f.read(next_size)

            reange_string = "bytes " + str(current_pos) + "-" + str(current_pos + next_size -1) + "/" + str(contentLength)
            print(reange_string)

            method = "PUT"
            headers = {
                'Content-Type': 'application/octet-stream'
                ,'Authorization': "Bearer " + access_token
                ,'Content-Length': next_size
                ,'Content-Range': reange_string
            }

            request = urllib.request.Request(upload_url, data=file_body, method=method, headers=headers)
            with urllib.request.urlopen(request) as res:
                body = res.read()
                print(body)
            except urllib.error.HTTPError as err:
                print(err)

            current_pos = current_pos + next_size



def upload_file(access_token: str, parent_id: str, target_file:pathlib.Path):

    url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable"
    method = "POST"
    headers = {
        'Content-Type': 'application/json'
        ,'Authorization': 'Bearer ' + access_token
    }

    params = {
        "name": target_file.name,
        "parents": [parent_id]
      }

    encoded_param = json.dumps(params).encode("utf-8")
    print(encoded_param)
    request = urllib.request.Request(url, data=encoded_param, method=method, headers=headers)

    with urllib.request.urlopen(request) as res:
        headers = res.info()
        print(headers)
        upload_url = headers["Location"]
        print("upload_url:" + upload_url)
        upload_file_session(access_token,upload_url,target_file)

if __name__ == '__main__':

    access_token = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    parent_id = "bbbbbbbbbbbbbbbbbbbbbbbbb"
    target_file = pathlib.Path("c:/tmp/テスト.docx")

    upload_file(access_token,parent_id,target_file)

GoogleDriveからのファイルダウンロード

  • 下記手順を参考にGoogleDriveからファイルをダウンロードします。
    https://developers.google.com/drive/api/v3/reference/files/get

  • aaaaaaaaaaaaaaaaaには上記で取得したアクセストークンを指定します。

  • bbbbbbbbbbbbbbbbbには上記で取得したダウンロード対象ファイルのidを指定します。

import urllib.parse
import urllib.request
import urllib
import json

def download_file_content(access_token: str, item_id:str, file_name:str):

    url = "https://www.googleapis.com/drive/v3/files/" + urllib.parse.quote(item_id)

    method = "GET"
    headers = {
        'Authorization': 'Bearer ' + access_token
    }

    params = {
        "alt":"media"
      }

    param_str = urllib.parse.urlencode(params)
    print(param_str)
    url = url + "?" + param_str

    request = urllib.request.Request(url, method=method, headers=headers)
    with urllib.request.urlopen(request) as res:
        body = res.read()
        save_name = "c:/tmp/" + file_name
        with open(save_name, mode="wb") as f:
          f.write(body)


def download_file(access_token: str, item_id:str):

    url = "https://www.googleapis.com/drive/v3/files/" + urllib.parse.quote(item_id)

    method = "GET"
    headers = {
        'Authorization': 'Bearer ' + access_token
    }

    params = {
        "fields": "id,name,webContentLink",
      }

    param_str = urllib.parse.urlencode(params)
    print(param_str)
    url = url + "?" + param_str

    request = urllib.request.Request(url, method=method, headers=headers)
    with urllib.request.urlopen(request) as res:
        body = res.read()

        dat = json.loads(body)
        print(dat)

        file_name = dat["name"]

        print("file_name:"+ file_name)

        download_file_content(access_token,item_id,file_name)

if __name__ == '__main__':

    access_token = "aaaaaaaaaaaaaaaaaaaaaaa"
    item_id = "bbbbbbbbbbbbbbbbbbbbbbbbbbbb"

    download_file(access_token,item_id)

👇関連記事

👇参考URL

[keywords]
GoogleDrive TypeScript Python

GoogleDrive のファイル操作(アップロード/ダウンロード)を自動化する

更新日:2024年02月07日

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5