본문 바로가기
개발일기/파이썬

[Python3.9/Google API] Google Drive API 연동 A 부터 Z까지

by 프로그래머콩 2023. 9. 27.

Google Console Project 생성

 

 

Google Drive Api 사용 

 

"drive api" 검색

 

구글 드라이브 api "사용"

 

"사용자 인증 정보 만들기" 눌러서 이동

 

 

먼저 Oauth 동의 화면 부터 만들라는 메시지가 보통 나타날것임

 

 

OAuth 동의 화면

 

범위

- 파일 읽기 및 다운로드만 처리할 할거라면 아래의 권한만 줘도 충분

 

  

 

 

테스트 사용자

- 실제 테스트할 구글 유저의 email 작성해주면 됨

 

기타 나머지 - 딱히 수정 하지 않음

 

 

 

 

사용자 인증 정보

 

 

 

json으로 저장하였으며 이 정보는 언제든 다시 다운로드 받을 수 있음

json 파일 내용 생김새

나는 이 json 파일을 다운로드 받아 "config.json"이라는 이름으로 바꾸고 사용했음.

 

 

Redirect Uri

참고 : URI넘어가서 가져온 토큰으로 만든 데이터파일 이름이  " token.pikcle"가 될 예정

 

 

 

프로그래밍

 

 

파일구조

( 참고로, token.pickle파일은 처음엔 없음. 1회 실행해야 생성됨)

 

 

코드

from __future__ import print_function
import io
import os.path
import pickle

from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from googleapiclient.http import MediaIoBaseDownload

class GoogleDriveAPI():
    # If modifying these scopes, delete the file token.json.
    SCOPES = [
        # 'https://www.googleapis.com/auth/drive.metadata.readonly' # 가져오거나 읽기만 할때 쓰는 권한
        'https://www.googleapis.com/auth/drive'
    ]

    json_key_path = ""
    
    docs_result = {
        'status':False,
        'result':{}
    }
    
    service = None
    creds = None
    items = None
    
    folderId = ''
    
    # key 설정파일
    def set_json_key_path(self, path="client_secret.json"):
        self.json_key_path = path

    def __init__(self):
        pass
        # self.set_drive_url(url=url)


    def google_api_connect(self):
    	# 유효한 token 파일 없으면 접속해서 인증 후 token파일 생성하는 코드
        # print(self.json_key_path)
        """
            Shows basic usage of the Drive v3 API.
            Prints the names and ids of the first 10 files the user has access to.
        """
        creds = None
        # The file token.pickle stores the user's access and refresh tokens, and is
        # created automatically when the authorization flow completes for the first
        # time.
        if os.path.exists('token.pickle'):
            with open('token.pickle', 'rb') as token:
                creds = pickle.load(token)
        # If there are no (valid) credentials available, let the user log in.
        if not creds or not creds.valid:
            if creds and creds.expired and creds.refresh_token:
                creds.refresh(Request())
            else:
                flow = InstalledAppFlow.from_client_secrets_file(
                    self.json_key_path, self.SCOPES)
                creds = flow.run_local_server(port=8080)


            # Save the credentials for the next run
            with open('token.pickle', 'wb') as token:
                pickle.dump(creds, token)
        self.creds = creds
        self.service = build('drive', 'v3', credentials=creds)

        # Call the Drive v3 API
        results = self.service.files().list(
            pageSize=10, fields="nextPageToken, files(id, name)").execute()
        items = results.get('files', [])
        self.items = items
        if not items:
            print('No files found.')
        else:
            print('Files:')
            for item in items:
                print(u'{0} ({1})'.format(item['name'], item['id']))

    def get_files(self, folderId=''):
        self.folderId = folderId
        # 구글드라이브에 있는 파일&파일 id 출력
        # results = self.service.files().list(pageSize=100, fields="nextPageToken, files(id, name)").execute()
        results = self.service.files().list(pageSize=100, fields=folderId).execute()
        # items = results.get('files', [])
        files = results.get('files', [])
        if not files:
            print('No files found.')
        else:
            print('Files:')
            for file in files:
                print(f'{file["name"]} ({file["id"]})')
        return files

    def downlosd_file2(self, file_name='', folder_id=''):
        if file_name !='':
            # 파일 다운로드
            request = self.service.files().get_media(fileId=folder_id)
            file = io.FileIO(file_name, 'wb')
            downloader = MediaIoBaseDownload(file, request)
            print(downloader)

    def downlosd_file(self, real_file_id='', file_name=''):
        """Downloads a file
          Args:
              real_file_id: ID of the file to download
          Returns : IO object with location.

          Load pre-authorized user credentials from the environment.
          TODO(developer) - See https://developers.google.com/identity
          for guides on implementing OAuth2 for the application.
          """

        try:
            # create drive api client
            # service = build('drive', 'v3', credentials=self.creds)

            # pylint: disable=maybe-no-member
            request = self.service.files().get_media(fileId=real_file_id)
            with open(file_name, 'wb') as file:
                downloader = MediaIoBaseDownload(file, request)
                done = False

                while done is False:
                    status, done = downloader.next_chunk()
                    print(F'Download {int(status.progress() * 100)}.')
            return True
        except HttpError as error:
            print(F'An error occurred: {error}')

        return file


if __name__ == "__main__":
    configDir = "config.json"

    file_name = 'test222.txt'
    file_name = 'test.zip'
    folder_id = '1h------------------6XU7'
    file_id = '1------------Z03YO4a-I'
    gdrive = GoogleDriveAPI()
    gdrive.set_json_key_path(configDir)
    gdrive.google_api_connect()
    # gdrive.downlosd_file2(file_name=file_name, folder_id=foleder_id)
    gdrive.downlosd_file(file_id,file_name)

 

 

 

 

참고1: 

- 파일 접근시 403과 같은 에러가 발생할 경우 :

-- 코드에서 SCOPE를 잘못 작성해주었거나

-- Oauth에서 권한을 잘못 주었을 가능성이 높음

 

참고2:

- 인증시 400, 403 redirect실패 등의 메시지가 나타나며 uri가 없다는(mistach) 출력의 경우

--진짜 uri잘못 입력한 것. 사용자 인증 정보 uri 입력하는곳에 가서 입력 정보 입력 다시 해주기