Python: загрузка файлов с Google Drive с помощью URL

Я пытаюсь загрузить файлы с Google Drive, и все, что у меня есть, это URL-адрес диска.

Я читал о API Google, который говорит о некоторых drive_service и MedioIO, который также требует некоторых учетных данных (в основном, json file / oauth). Но я не могу понять, как это работает.

Кроме того, попытался urllib2 urlretrieve, но мой случай, чтобы получить файлы с диска. Пробовал "wget" тоже, но бесполезно.

Попробовал pydrive библиотеку. Он имеет хорошие функции загрузки на диск, но нет вариантов загрузки.

Любая помощь будет оценена. Благодарю.

15 ответов

Решение

Если под "URL-адресом диска" вы подразумеваете общую ссылку на файл на Google Диске, то может помочь следующее:

import requests

def download_file_from_google_drive(id, destination):
    URL = "https://docs.google.com/uc?export=download"

    session = requests.Session()

    response = session.get(URL, params = { 'id' : id }, stream = True)
    token = get_confirm_token(response)

    if token:
        params = { 'id' : id, 'confirm' : token }
        response = session.get(URL, params = params, stream = True)

    save_response_content(response, destination)    

def get_confirm_token(response):
    for key, value in response.cookies.items():
        if key.startswith('download_warning'):
            return value

    return None

def save_response_content(response, destination):
    CHUNK_SIZE = 32768

    with open(destination, "wb") as f:
        for chunk in response.iter_content(CHUNK_SIZE):
            if chunk: # filter out keep-alive new chunks
                f.write(chunk)

if __name__ == "__main__":
    file_id = 'TAKE ID FROM SHAREABLE LINK'
    destination = 'DESTINATION FILE ON YOUR DISK'
    download_file_from_google_drive(file_id, destination)

Однако в snipped не используется ни pydrive, ни Google Drive SDK. Он использует модуль запросов (который, так или иначе, является альтернативой urllib2).

При загрузке больших файлов с Google Диска одного запроса GET недостаточно. Нужен второй - см. Большой файл wget/curl с Google Drive.

Я рекомендую пакет gdown:

import gdown

url = 'https://drive.google.com/uc?id=0B9P1L--7Wd2vU3VUVlFnbTgtS2c'
output = 'spam.txt'
gdown.download(url, output, quiet=False) 

Много раз сталкиваясь с подобными потребностями, я сделал очень простой урок GoogleDriveDownloader начиная с фрагмента @user115202 выше. Вы можете найти исходный код здесь.

Вы также можете установить его через pip:

pip install googledrivedownloader

Тогда использование так же просто, как:

from google_drive_downloader import GoogleDriveDownloader as gdd

gdd.download_file_from_google_drive(file_id='1iytA1n2z4go3uVCwE__vIKouTKyIDjEq',
                                    dest_path='./data/mnist.zip',
                                    unzip=True)

Этот фрагмент загрузит архив, размещенный на Google Диске. В этом случае 1iytA1n2z4go3uVCwE__vIKouTKyIDjEq является идентификатором ссылки общего доступа, полученной с Google Диска.

Вот простой способ сделать это без сторонних библиотек и учетной записи службы.

pip install google-api-core а также google-api-python-client

from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload
from google.oauth2 import service_account
import io

credz = {} #put json credentials her from service account or the like
# More info: https://cloud.google.com/docs/authentication

credentials = service_account.Credentials.from_service_account_info(credz)
drive_service = build('drive', 'v3', credentials=credentials)

file_id = '0BwwA4oUTeiV1UVNwOHItT0xfa2M'
request = drive_service.files().get_media(fileId=file_id)
#fh = io.BytesIO() # this can be used to keep in memory
fh = io.FileIO('file.tar.gz', 'wb') # this can be used to write to disk
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
    status, done = downloader.next_chunk()
    print("Download %d%%." % int(status.progress() * 100))


PyDrive позволяет скачать файл с функцией GetContentFile(), Вы можете найти документацию по функции здесь.

Смотрите пример ниже:

# Initialize GoogleDriveFile instance with file id.
file_obj = drive.CreateFile({'id': '<your file ID here>'})
file_obj.GetContentFile('cats.png') # Download file as 'cats.png'.

Этот код предполагает, что у вас есть аутентифицированный drive объект, документы по этому можно найти здесь и здесь.

В общем случае это делается так:

from pydrive.auth import GoogleAuth

gauth = GoogleAuth()
# Create local webserver which automatically handles authentication.
gauth.LocalWebserverAuth()

# Create GoogleDrive instance with authenticated GoogleAuth instance.
drive = GoogleDrive(gauth)

Информация о тихой аутентификации на сервере может быть найдена здесь и включает в себя написание settings.yaml (пример: здесь), в котором вы сохраняете детали аутентификации.

Вообще говоря, URL-адрес общего файла с Google Диска выглядит так

https://drive.google.com/file/d/1HV6vf8pB-EYnjcJcH65eGZVMa2v2tcMh/view?usp=sharing

где 1HV6vf8pB-EYnjcJcH65eGZVMa2v2tcMh соответствует fileID.

Следовательно, вы можете просто создать функцию для получения идентификатора файла из URL-адреса, например, где url = https://drive.google.com/file/d/1HV6vf8pB-EYnjcJcH65eGZVMa2v2tcMh/view?usp=sharing,

def url_to_id(url):
    x = url.split("/")
    return x[5]

Печать x даст

['https:', '', 'drive.google.com', 'file', 'd', '1HV6vf8pB-EYnjcJcH65eGZVMa2v2tcMh', 'view?usp=sharing']

Итак, поскольку мы хотим вернуть шестое значение массива, мы используем x[5].

      import requests

def download_file_from_google_drive(id, destination):
    URL = "https://docs.google.com/uc?export=download"

    session = requests.Session()

    response = session.get(URL, params = { 'id' : id , 'confirm': 1 }, stream = True)
    token = get_confirm_token(response)

    if token:
        params = { 'id' : id, 'confirm' : token }
        response = session.get(URL, params = params, stream = True)

    save_response_content(response, destination)    

def get_confirm_token(response):
    for key, value in response.cookies.items():
        if key.startswith('download_warning'):
            return value

    return None

def save_response_content(response, destination):
    CHUNK_SIZE = 32768

    with open(destination, "wb") as f:
        for chunk in response.iter_content(CHUNK_SIZE):
            if chunk: # filter out keep-alive new chunks
                f.write(chunk)

if __name__ == "__main__":
    file_id = 'TAKE ID FROM SHAREABLE LINK'
    destination = 'DESTINATION FILE ON YOUR DISK'
    download_file_from_google_drive(file_id, destination)

Просто повторяю принятый ответ, но добавляюconfirm=1параметр, поэтому он всегда загружается, даже если файл слишком большой

Это также было описано выше,

   from pydrive.auth import GoogleAuth
   gauth = GoogleAuth()
   gauth.LocalWebserverAuth()
   drive = GoogleDrive(gauth)

Это создает свой собственный сервер тоже делать грязную работу аутентификации

   file_obj = drive.CreateFile({'id': '<Put the file ID here>'})
   file_obj.GetContentFile('Demo.txt') 

Это загружает файл

# Importing [PyDrive][1] OAuth
from pydrive.auth import GoogleAuth

def download_tracking_file_by_id(file_id, download_dir):
    gauth = GoogleAuth(settings_file='../settings.yaml')
    # Try to load saved client credentials
    gauth.LoadCredentialsFile("../credentials.json")
    if gauth.credentials is None:
        # Authenticate if they're not there
        gauth.LocalWebserverAuth()
    elif gauth.access_token_expired:
        # Refresh them if expired
        gauth.Refresh()
    else:
        # Initialize the saved creds
        gauth.Authorize()
    # Save the current credentials to a file
    gauth.SaveCredentialsFile("../credentials.json")

    drive = GoogleDrive(gauth)

    logger.debug("Trying to download file_id " + str(file_id))
    file6 = drive.CreateFile({'id': file_id})
    file6.GetContentFile(download_dir+'mapmob.zip')
    zipfile.ZipFile(download_dir + 'test.zip').extractall(UNZIP_DIR)
    tracking_data_location = download_dir + 'test.json'
    return tracking_data_location

Вышеуказанная функция загружает файл с заданным идентификатором file_id в указанную папку загрузок. Теперь остается вопрос, как получить file_id? Просто разделите URL по id =, чтобы получить file_id.

file_id = url.split("id=")[1]

Я пытался использовать Google Colaboratory: https://colab.research.google.com/

Предположим, ваша ссылка для общего доступа https://docs.google.com/spreadsheets/d/12hiI0NK7M0KEfscMfyBaLT9gxcZMleeu/edit?usp=sharing&amp;amp;ouid=102608702203033509854&amp;amp;rtpof=true&amp;amp;sd=true

все, что вам нужно, это идентификатор 12hiI0NK7M0KEfscMfyBaLT9gxcZMleeu.

команда в ячейке

      !gdown 12hiI0NK7M0KEfscMfyBaLT9gxcZMleeu

запустите ячейку, и вы увидите, что файл загружен в /content/Amazon_Reviews.xlsx

Примечание: нужно знать, как использовать Google colab

Для тех, кого интересует ссылка для загрузки через HTTP, Google API и большинство клиентов предоставляютwebContentLinkполе, содержащее его (обратите внимание на права доступа к файлу для его использования)

Исправлена ​​версия на 2023 год + генератор отслеживания прогресса

      import requests


def download_file_from_google_drive(file_id, destination, chunk_size=32768):
    url = "https://docs.google.com/uc?export=download"

    session = requests.Session()
    params = {'id': file_id, 'confirm': 1}
    response = session.get(url, params=params, stream=True)

    for i, chunk_size_ in save_response_content(response, destination, chunk_size):
        yield i, chunk_size_


def get_confirm_token(response):
    for key, value in response.cookies.items():
        if key.startswith('download_warning'):
            return value

    return None


def save_response_content(response, destination, chunk_size):
    with open(destination, "wb") as f:
        for i, chunk in enumerate(response.iter_content(chunk_size)):
            if chunk:  # filter out keep-alive new chunks
                f.write(chunk)
                yield i, chunk_size


if __name__ == '__main__':
    file_id = '...'
    destination = '...'
    for i, chunk_size in download_file_from_google_drive(file_id, destination):
        print(i, chunk_size)

Я использовал принятое решение в течение длительного периода, но теперь Google изменил ответ с предупреждением о загрузке, поэтому оно больше не работает.

Сейчас я использую API, поскольку это более безопасный способ гарантировать, что он не остановится внезапно, но я также мог бы заставить его работать, анализируя HTML-код ответа в поисках URL-адреса загрузки, как показано ниже:

      import requests
from html.parser import HTMLParser

class MyHTMLParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.action = None

    def handle_starttag(self, tag, attrs):
        if tag == "form":
            for name, value in attrs:
                if name == "id" and value == "download-form":
                    for name, value in attrs:
                        if name == "action":
                            self.action = value

DOWNLOAD_URL = 'https://docs.google.com/uc?export=download'
session = requests.Session()
response = session.get(file_url, params={'id': id}, stream=True)

content_type = response.headers['content-type']
if content_type == 'text/html; charset=utf-8':
    parser = MyHTMLParser()
    parser.feed(response.text)
    download_url = parser.action
    response = session.post(download_url, stream=True)
    
file = response.content

Этот пример основан на аналоге RayB, но хранит файл в памяти и немного проще, и вы можете вставить его в colab, и он работает.

      import googleapiclient.discovery
import oauth2client.client
from google.colab import auth
auth.authenticate_user()

def download_gdrive(id):
  creds = oauth2client.client.GoogleCredentials.get_application_default()
  service = googleapiclient.discovery.build('drive', 'v3', credentials=creds)
  return service.files().get_media(fileId=id).execute()

a = download_gdrive("1F-yaQB8fdsfsdafm2l8WFjhEiYSHZrCcr")

Вы можете установить https://pypi.org/project/googleDriveFileDownloader/

pip install googleDriveFileDownloader

И загрузите файл, вот пример кода для загрузки

from googleDriveFileDownloader import googleDriveFileDownloader
a = googleDriveFileDownloader()
a.downloadFile("https://drive.google.com/uc?id=1O4x8rwGJAh8gRo8sjm0kuKFf6vCEm93G&export=download")
Другие вопросы по тегам