Python Google Drive API: enumere todo el árbol de archivos de la unidad

Estoy creando una aplicación Python que utiliza las API de Google Drive, por lo que el desarrollo es bueno, pero tengo un problema para recuperar todo el árbol de archivos de Google Drive, lo necesito para dos propósitos:

  1. Compruebe si existe una ruta, así que si quiero cargar test.txt en root / folder1 / folder2 quiero comprobar si el archivo ya existe y, en caso de que lo actualice,
  2. Cree un explorador de archivos visual, ahora sé que Google proporciona el suyo propio (no recuerdo el nombre ahora, pero sé que existe) pero quiero restringir el explorador de archivos a carpetas específicas.

Por ahora tengo una función que recupera la raíz de Gdrive y puedo construir las tres mediante una llamada recursiva a una función que me enumera el contenido de una sola carpeta, pero es extremadamente lenta y potencialmente puede hacer miles de solicitudes a Google y esto es inaceptable.

Aquí la función para obtener la raíz:

def drive_get_root(): """Retrieve a root list of File resources. Returns: List of dictionaries. """ #build the service, the driveHelper module will take care of authentication and credential storage drive_service = build('drive', 'v2', driveHelper.buildHttp()) # the result will be a list result = [] page_token = None while True: try: param = {} if page_token: param['pageToken'] = page_token files = drive_service.files().list(**param).execute() #add the files in the list result.extend(files['items']) page_token = files.get('nextPageToken') if not page_token: break except errors.HttpError, _error: print 'An error occurred: %s' % _error break return result 

Y aquí el de obtener el archivo de una carpeta.

 def drive_files_in_folder(folder_id): """Print files belonging to a folder. Args: folder_id: ID of the folder to get files from. """ #build the service, the driveHelper module will take care of authentication and credential storage drive_service = build('drive', 'v2', driveHelper.buildHttp()) # the result will be a list result = [] #code from google, is working so I didn't touch it page_token = None while True: try: param = {} if page_token: param['pageToken'] = page_token children = drive_service.children().list(folderId=folder_id, **param).execute() for child in children.get('items', []): result.append(drive_get_file(child['id'])) page_token = children.get('nextPageToken') if not page_token: break except errors.HttpError, _error: print 'An error occurred: %s' % _error break return result 

y por ejemplo ahora para verificar si existe un archivo, estoy usando esto:

 def drive_path_exist(file_path, list = False): """ This is a recursive function to che check if the given path exist """ #if the list param is empty set the list as the root of Gdrive if list == False: list = drive_get_root() #split the string to get the first item and check if is in the root file_path = string.split(file_path, "/") #if there is only one element in the filepath we are at the actual filename #so if is in this folder we can return it if len(file_path) == 1: exist = False for elem in list: if elem["title"] == file_path[0]: #set exist = to the elem because the elem is a dictionary with all the file info exist = elem return exist #if we are not at the last element we have to keep searching else: exist = False for elem in list: #check if the current item is in the folder if elem["title"] == file_path[0]: exist = True folder_id = elem["id"] #delete the first element and keep searching file_path.pop(0) if exist: #recursive call, we have to rejoin the filpath as string an passing as list the list #from the drive_file_exist function return drive_path_exist("/".join(file_path), drive_files_in_folder(folder_id)) 

¿Alguna idea de cómo resolver mi problema? Vi un poco de discusión aquí sobre el desbordamiento y, en algunas respuestas, la gente escribió que esto es posible, pero, por supuesto, ¡no dijeron cómo!

Gracias

Deja de pensar en Drive como una estructura de árbol. No lo es “Carpetas” son simplemente tags, por ejemplo. Un archivo puede tener varios padres.

Para construir una representación de un árbol en tu aplicación, debes hacer esto …

  1. Ejecutar una consulta de lista de unidades para recuperar todas las carpetas
  2. Iterar la matriz de resultados y examinar la propiedad de los padres para construir una jerarquía en memoria
  3. Ejecute una segunda consulta de la Lista de unidades para obtener todas las no carpetas (es decir, archivos)
  4. Para cada archivo devuelto, colóquelo en su árbol en memoria

Si simplemente desea comprobar si el archivo-A existe en la carpeta B, el enfoque depende de si el nombre “carpeta-B” se garantiza que sea único.

Si es único, solo haga una consulta de FilesList para title = ‘file-A’, luego haga un Files Get para cada uno de sus padres y vea si alguno de ellos se llama ‘folder-B’.

Si ‘folder-B’ puede existir tanto en ‘folder-C’ como en ‘folder-D’, entonces es más complejo y deberá construir la jerarquía en la memoria de los pasos 1 y 2 anteriores.

No dices si estos archivos y carpetas están siendo creados por tu aplicación o por el usuario con la aplicación web de Google Drive. Si su aplicación es el creador de estos archivos / carpetas, hay un truco que puede usar para restringir sus búsquedas a una sola raíz. Di que tienes

 MyDrive/app_root/folder-C/folder-B/file-A 

puede hacer que todos los archivos de carpeta-C, carpeta-B y archivo-A de app_root

De esa manera usted puede restringir todas sus consultas para incluir

 and 'app_root_id' in parents 

Nunca funcionará así a excepción de los árboles muy pequeños. Debe reconsiderar todo su algoritmo para una aplicación en la nube (la ha escrito como una aplicación de escritorio en la que posee la máquina), ya que se agotará fácilmente. Debe reflejar el árbol de antemano (colas de tareas y almacén de datos) no solo para evitar los tiempos de espera, sino también para evitar los límites de velocidad de la unidad, y mantenerlo sincronizado de alguna manera (registrarse para push, etc.). No es fácil en absoluto. He hecho un visor de árbol de disco antes.

Una forma fácil de verificar si un archivo existe en una ruta específica es: drive_service.files (). List (q = “‘THE_ID_OF_SPECIFIC_PATH’ en padres y título = ‘un archivo'”). Ejecutar ()

Para recorrer todas las carpetas y archivos:

 import sys, os import socket import googleDriveAccess import logging logging.basicConfig() FOLDER_TYPE = 'application/vnd.google-apps.folder' def getlist(ds, q, **kwargs): result = None npt = '' while not npt is None: if npt != '': kwargs['pageToken'] = npt entries = ds.files().list(q=q, **kwargs).execute() if result is None: result = entries else: result['items'] += entries['items'] npt = entries.get('nextPageToken') return result def uenc(u): if isinstance(u, unicode): return u.encode('utf-8') else: return u def walk(ds, folderId, folderName, outf, depth): spc = ' ' * depth outf.write('%s+%s\n%s %s\n' % (spc, uenc(folderId), spc, uenc(folderName))) q = "'%s' in parents and mimeType='%s'" % (folderId, FOLDER_TYPE) entries = getlist(ds, q, **{'maxResults': 200}) for folder in entries['items']: walk(ds, folder['id'], folder['title'], outf, depth + 1) q = "'%s' in parents and mimeType!='%s'" % (folderId, FOLDER_TYPE) entries = getlist(ds, q, **{'maxResults': 200}) for f in entries['items']: outf.write('%s -%s\n%s %s\n' % (spc, uenc(f['id']), spc, uenc(f['title']))) def main(basedir): da = googleDriveAccess.DAClient(basedir) # clientId=None, script=False f = open(os.path.join(basedir, 'hierarchy.txt'), 'wb') walk(da.drive_service, 'root', u'root', f, 0) f.close() if __name__ == '__main__': logging.getLogger().setLevel(getattr(logging, 'INFO')) try: main(os.path.dirname(__file__)) except (socket.gaierror, ), e: sys.stderr.write('socket.gaierror') 

utilizando googleDriveAccess github.com/HatsuneMiku/googleDriveAccess