Skip to content

Commit b0da74f

Browse files
committed
added google drive api tutorial
1 parent 2760d68 commit b0da74f

File tree

9 files changed

+367
-0
lines changed

9 files changed

+367
-0
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,6 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
9696
- [How to Download Torrent Files in Python](https://www.thepythoncode.com/article/download-torrent-files-in-python). ([code](general/torrent-downloader))
9797
- [How to Use Google Custom Search Engine API in Python](https://www.thepythoncode.com/article/use-google-custom-search-engine-api-in-python). ([code](general/using-custom-search-engine-api))
9898
- [How to Use Github API in Python](https://www.thepythoncode.com/article/using-github-api-in-python). ([code](general/github-api))
99+
- [How to Use Google Drive API in Python](https://www.thepythoncode.com/article/using-google-drive--api-in-python). ([code](general/using-google-drive-api))
99100

100101
For any feedback, please consider pulling requests.

Diff for: general/using-google-drive-api/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# [How to Use Google Drive API in Python](https://www.thepythoncode.com/article/using-google-drive--api-in-python)
2+
To use the scripts, you should:
3+
- `pip3 install -r requirements.txt`
4+
- Enable Google Drive API to get `credentials.json` file, check [the tutorial](https://www.thepythoncode.com/article/using-google-drive--api-in-python) for more information.

Diff for: general/using-google-drive-api/download_files.py

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import pickle
2+
import os
3+
import re
4+
import io
5+
from googleapiclient.discovery import build
6+
from google_auth_oauthlib.flow import InstalledAppFlow
7+
from google.auth.transport.requests import Request
8+
from googleapiclient.http import MediaIoBaseDownload
9+
import requests
10+
from tqdm import tqdm
11+
12+
# If modifying these scopes, delete the file token.pickle.
13+
SCOPES = ['https://www.googleapis.com/auth/drive.metadata',
14+
'https://www.googleapis.com/auth/drive',
15+
'https://www.googleapis.com/auth/drive.file'
16+
]
17+
18+
19+
def get_gdrive_service():
20+
creds = None
21+
# The file token.pickle stores the user's access and refresh tokens, and is
22+
# created automatically when the authorization flow completes for the first
23+
# time.
24+
if os.path.exists('token.pickle'):
25+
with open('token.pickle', 'rb') as token:
26+
creds = pickle.load(token)
27+
# If there are no (valid) credentials available, let the user log in.
28+
if not creds or not creds.valid:
29+
if creds and creds.expired and creds.refresh_token:
30+
creds.refresh(Request())
31+
else:
32+
flow = InstalledAppFlow.from_client_secrets_file(
33+
'credentials.json', SCOPES)
34+
creds = flow.run_local_server(port=0)
35+
# Save the credentials for the next run
36+
with open('token.pickle', 'wb') as token:
37+
pickle.dump(creds, token)
38+
# initiate Google Drive service API
39+
return build('drive', 'v3', credentials=creds)
40+
41+
42+
def download_file_from_google_drive(id, destination):
43+
def get_confirm_token(response):
44+
for key, value in response.cookies.items():
45+
if key.startswith('download_warning'):
46+
return value
47+
return None
48+
49+
def save_response_content(response, destination):
50+
CHUNK_SIZE = 32768
51+
# get the file size from Content-length response header
52+
file_size = int(response.headers.get("Content-Length", 0))
53+
# extract Content disposition from response headers
54+
content_disposition = response.headers.get("content-disposition")
55+
# parse filename
56+
filename = re.findall("filename=\"(.+)\"", content_disposition)[0]
57+
print("[+] File size:", file_size)
58+
print("[+] File name:", filename)
59+
progress = tqdm(response.iter_content(CHUNK_SIZE), f"Downloading {filename}", total=file_size, unit="Byte", unit_scale=True, unit_divisor=1024)
60+
with open(destination, "wb") as f:
61+
for chunk in progress:
62+
if chunk: # filter out keep-alive new chunks
63+
f.write(chunk)
64+
# update the progress bar
65+
progress.update(len(chunk))
66+
progress.close()
67+
68+
# base URL for download
69+
URL = "https://docs.google.com/uc?export=download"
70+
# init a HTTP session
71+
session = requests.Session()
72+
# make a request
73+
response = session.get(URL, params = {'id': id}, stream=True)
74+
print("[+] Downloading", response.url)
75+
# get confirmation token
76+
token = get_confirm_token(response)
77+
if token:
78+
params = {'id': id, 'confirm':token}
79+
response = session.get(URL, params=params, stream=True)
80+
# download to disk
81+
save_response_content(response, destination)
82+
83+
84+
def search(service, query):
85+
# search for the file
86+
result = []
87+
page_token = None
88+
while True:
89+
response = service.files().list(q=query,
90+
spaces="drive",
91+
fields="nextPageToken, files(id, name, mimeType)",
92+
pageToken=page_token).execute()
93+
# iterate over filtered files
94+
for file in response.get("files", []):
95+
print(f"Found file: {file['name']} with the id {file['id']} and type {file['mimeType']}")
96+
result.append((file["id"], file["name"], file["mimeType"]))
97+
page_token = response.get('nextPageToken', None)
98+
if not page_token:
99+
# no more files
100+
break
101+
return result
102+
103+
104+
def download():
105+
service = get_gdrive_service()
106+
# the name of the file you want to download from Google Drive
107+
filename = "bbc.zip"
108+
# search for the file by name
109+
search_result = search(service, query=f"name='{filename}'")
110+
# get the GDrive ID of the file
111+
file_id = search_result[0][0]
112+
# make it shareable
113+
service.permissions().create(body={"role": "reader", "type": "anyone"}, fileId=file_id).execute()
114+
# download file
115+
download_file_from_google_drive(file_id, filename)
116+
117+
118+
if __name__ == '__main__':
119+
download()

Diff for: general/using-google-drive-api/list_files.py

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import pickle
2+
import os
3+
from googleapiclient.discovery import build
4+
from google_auth_oauthlib.flow import InstalledAppFlow
5+
from google.auth.transport.requests import Request
6+
from tabulate import tabulate
7+
8+
# If modifying these scopes, delete the file token.pickle.
9+
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
10+
11+
12+
def get_gdrive_service():
13+
creds = None
14+
# The file token.pickle stores the user's access and refresh tokens, and is
15+
# created automatically when the authorization flow completes for the first
16+
# time.
17+
if os.path.exists('token.pickle'):
18+
with open('token.pickle', 'rb') as token:
19+
creds = pickle.load(token)
20+
# If there are no (valid) credentials available, let the user log in.
21+
if not creds or not creds.valid:
22+
if creds and creds.expired and creds.refresh_token:
23+
creds.refresh(Request())
24+
else:
25+
flow = InstalledAppFlow.from_client_secrets_file(
26+
'credentials.json', SCOPES)
27+
creds = flow.run_local_server(port=0)
28+
# Save the credentials for the next run
29+
with open('token.pickle', 'wb') as token:
30+
pickle.dump(creds, token)
31+
# return Google Drive API service
32+
return build('drive', 'v3', credentials=creds)
33+
34+
35+
36+
def main():
37+
"""Shows basic usage of the Drive v3 API.
38+
Prints the names and ids of the first 5 files the user has access to.
39+
"""
40+
service = get_gdrive_service()
41+
# Call the Drive v3 API
42+
results = service.files().list(
43+
pageSize=5, fields="nextPageToken, files(id, name, mimeType, size, parents, modifiedTime)").execute()
44+
# get the results
45+
items = results.get('files', [])
46+
# list all 20 files & folders
47+
list_files(items)
48+
49+
50+
51+
def list_files(items):
52+
"""given items returned by Google Drive API, prints them in a tabular way"""
53+
if not items:
54+
# empty drive
55+
print('No files found.')
56+
else:
57+
rows = []
58+
for item in items:
59+
# get the File ID
60+
id = item["id"]
61+
# get the name of file
62+
name = item["name"]
63+
try:
64+
# parent directory ID
65+
parents = item["parents"]
66+
except:
67+
# has no parrents
68+
parents = "N/A"
69+
try:
70+
# get the size in nice bytes format (KB, MB, etc.)
71+
size = get_size_format(int(item["size"]))
72+
except:
73+
# not a file, may be a folder
74+
size = "N/A"
75+
# get the Google Drive type of file
76+
mime_type = item["mimeType"]
77+
# get last modified date time
78+
modified_time = item["modifiedTime"]
79+
# append everything to the list
80+
rows.append((id, name, parents, size, mime_type, modified_time))
81+
print("Files:")
82+
# convert to a human readable table
83+
table = tabulate(rows, headers=["ID", "Name", "Parents", "Size", "Type", "Modified Time"])
84+
# print the table
85+
print(table)
86+
87+
88+
def get_size_format(b, factor=1024, suffix="B"):
89+
"""
90+
Scale bytes to its proper byte format
91+
e.g:
92+
1253656 => '1.20MB'
93+
1253656678 => '1.17GB'
94+
"""
95+
for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]:
96+
if b < factor:
97+
return f"{b:.2f}{unit}{suffix}"
98+
b /= factor
99+
return f"{b:.2f}Y{suffix}"
100+
101+
102+
if __name__ == '__main__':
103+
main()

Diff for: general/using-google-drive-api/requirements.txt

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
google-api-python-client
2+
google-auth-httplib2
3+
google-auth-oauthlib
4+
tabulate
5+
requests
6+
tqdm

Diff for: general/using-google-drive-api/search_files.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import pickle
2+
import os
3+
from googleapiclient.discovery import build
4+
from google_auth_oauthlib.flow import InstalledAppFlow
5+
from google.auth.transport.requests import Request
6+
from tabulate import tabulate
7+
8+
# If modifying these scopes, delete the file token.pickle.
9+
SCOPES = ['https://www.googleapis.com/auth/drive.metadata']
10+
11+
def get_gdrive_service():
12+
creds = None
13+
# The file token.pickle stores the user's access and refresh tokens, and is
14+
# created automatically when the authorization flow completes for the first
15+
# time.
16+
if os.path.exists('token.pickle'):
17+
with open('token.pickle', 'rb') as token:
18+
creds = pickle.load(token)
19+
# If there are no (valid) credentials available, let the user log in.
20+
if not creds or not creds.valid:
21+
if creds and creds.expired and creds.refresh_token:
22+
creds.refresh(Request())
23+
else:
24+
flow = InstalledAppFlow.from_client_secrets_file(
25+
'credentials.json', SCOPES)
26+
creds = flow.run_local_server(port=0)
27+
# Save the credentials for the next run
28+
with open('token.pickle', 'wb') as token:
29+
pickle.dump(creds, token)
30+
31+
return build('drive', 'v3', credentials=creds)
32+
33+
34+
def search(service, query):
35+
# search for the file
36+
result = []
37+
page_token = None
38+
while True:
39+
response = service.files().list(q=query,
40+
spaces="drive",
41+
fields="nextPageToken, files(id, name, mimeType)",
42+
pageToken=page_token).execute()
43+
# iterate over filtered files
44+
for file in response.get("files", []):
45+
result.append((file["id"], file["name"], file["mimeType"]))
46+
page_token = response.get('nextPageToken', None)
47+
if not page_token:
48+
# no more files
49+
break
50+
return result
51+
52+
53+
def main():
54+
# filter to text files
55+
filetype = "text/plain"
56+
# authenticate Google Drive API
57+
service = get_gdrive_service()
58+
# search for files that has type of text/plain
59+
search_result = search(service, query=f"mimeType='{filetype}'")
60+
# convert to table to print well
61+
table = tabulate(search_result, headers=["ID", "Name", "Type"])
62+
print(table)
63+
64+
65+
66+
if __name__ == '__main__':
67+
main()

Diff for: general/using-google-drive-api/some_text.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a text file in the google drive

Diff for: general/using-google-drive-api/test.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
A test file to upload

Diff for: general/using-google-drive-api/upload-files.py

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import pickle
2+
import os
3+
from googleapiclient.discovery import build
4+
from google_auth_oauthlib.flow import InstalledAppFlow
5+
from google.auth.transport.requests import Request
6+
from googleapiclient.http import MediaFileUpload
7+
8+
# If modifying these scopes, delete the file token.pickle.
9+
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly',
10+
'https://www.googleapis.com/auth/drive.file']
11+
12+
13+
def get_gdrive_service():
14+
creds = None
15+
# The file token.pickle stores the user's access and refresh tokens, and is
16+
# created automatically when the authorization flow completes for the first
17+
# time.
18+
if os.path.exists('token.pickle'):
19+
with open('token.pickle', 'rb') as token:
20+
creds = pickle.load(token)
21+
# If there are no (valid) credentials available, let the user log in.
22+
if not creds or not creds.valid:
23+
if creds and creds.expired and creds.refresh_token:
24+
creds.refresh(Request())
25+
else:
26+
flow = InstalledAppFlow.from_client_secrets_file(
27+
'credentials.json', SCOPES)
28+
creds = flow.run_local_server(port=0)
29+
# Save the credentials for the next run
30+
with open('token.pickle', 'wb') as token:
31+
pickle.dump(creds, token)
32+
33+
return build('drive', 'v3', credentials=creds)
34+
35+
36+
def upload_files():
37+
"""
38+
Creates a folder and upload a file to it
39+
"""
40+
# authenticate account
41+
service = get_gdrive_service()
42+
# folder details we want to make
43+
folder_metadata = {
44+
"name": "TestFolder",
45+
"mimeType": "application/vnd.google-apps.folder"
46+
}
47+
# create the folder
48+
file = service.files().create(body=folder_metadata, fields="id").execute()
49+
# get the folder id
50+
folder_id = file.get("id")
51+
print("Folder ID:", folder_id)
52+
# upload a file text file
53+
# first, define file metadata, such as the name and the parent folder ID
54+
file_metadata = {
55+
"name": "test.txt",
56+
"parents": [folder_id]
57+
}
58+
# upload
59+
media = MediaFileUpload("test.txt", resumable=True)
60+
file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
61+
print("File created, id:", file.get("id"))
62+
63+
64+
if __name__ == '__main__':
65+
upload_files()

0 commit comments

Comments
 (0)