如何使用服务帐户和typescript从google drive下载电子表格/node. js [duplicate]

qxsslcnc  于 2023-02-08  发布在  Node.js
关注(0)|答案(2)|浏览(109)
    • 此问题在此处已有答案**:

How to download dynamic files from google drive(1个答案)
17小时前关门了。
我正在尝试使用服务帐户下载文件夹中包含的所有电子表格。我找不到解决方案,希望有人能帮助我。
我通过身份验证并成功获得drive.files.list,但无法下载文件。
这是我的密码

import { google } from "googleapis";
import { privatekey } from "./privatekey";
import { createWriteStream, writeFileSync } from "fs";

let jwtClient = new google.auth.JWT(privatekey.client_email, undefined, privatekey.private_key, [
    "https://www.googleapis.com/auth/drive",
]);
//authenticate request
jwtClient.authorize(function (err, tokens) {
    if (err) {
        console.log(err);
        return;
    } else {
        console.log("Successfully connected");
    }
});

const folder_id = FOLDER_ID
let drive = google.drive("v3");
drive.files.list(
    {
        auth: jwtClient,
        q: `'${folder_id}' in parents and trashed=false`,
    },
    function (err, response) {
        if (err) {
            console.log("The API returned an error: " + err);
            return;
        }
        var files = response?.data.files;
        if (files?.length == 0) return;
        files?.forEach(async (file) => {
            let fileId = file.id;
            fileId == null ? (fileId = undefined) : (fileId = fileId);
            //writeFileSync(`./cartella/${file.id}.xlsx`, "");
            prova(jwtClient, fileId, file.mimeType);
            //await getFileFromStream(jwtClient, fileId, file.mimeType);
        });
    }
);

function getFileFromStream(auth: any, fileId: any, mimeType: any) {
    const destPath = `./cartella/${fileId}.xls`;
    const dest = createWriteStream(destPath);
    return new Promise(async (resolve, reject) => {
        const drive = google.drive({ version: "v3", auth });
        drive.files.get({
            fileId: fileId,
            alt: "media",
        }),
            (err: any, res: any): void => {
                res.data
                    .on("end", () => {
                        console.log("Done");
                    })
                    .on("error", (error: any) => {
                        console.log("Error during download", error);
                    })
                    .pipe(dest);
            };
    });
}
function prova(auth: any, fileId: any, mimeType: any) {
    const destPath = `./cartella/${fileId}.xls`;
    const dest = createWriteStream(destPath);

    const drive = google.drive({ version: "v3", auth });
    drive.files.export({ fileId: fileId, mimeType: mimeType },{responseType: "stream"}, (err: any, res: any) => {
  if (err) {
    //   handle error
          console.log("error: ",err)
  } else {
          if (res == null) return
    res.data
      .on("end", function () {
        console.log("Done");
      })
      .on("error", function (err: any) {
        console.log("Error during download", err);
      })
      .pipe(dest);
  }})
}

首先,我将服务帐户添加到Google Drive文件夹的编辑器中
函数getFileFromStream返回一个大错误,但我认为最有趣的是这个错误

domain: 'global',
reason: 'fileNotDownloadable',       
message: 'Only files with binary content can be downloaded. Use Export with Docs Editors files.',            locationType: 'parameter',    
   location: 'alt'     }   ]

所以我尝试使用drive.files.export,但得到的响应是

status: 400,  
   statusText: 'Bad Request',   
   request: {       
       responseURL: 'https://www.googleapis.com/drive/v3/files/file_id/export?mimeType=application%2Fvnd.google-apps.spreadsheet'   
  }

我还尝试了一种不同的身份验证方法,如这里提出的方法:
Setting up Google Drive API on NodeJS using a service account
但还是不行
我哪里做错了?

omhiaaxx

omhiaaxx1#

以下方法将下载非Google云端硬盘mime types的文件。只有当它是Google云端硬盘mime types时,您才需要使用导出功能,并且在下载时需要转换它,例如将Google工作表转换为Excel文件,或将Google docs文件转换为Microsoft word文件。

def download_file(service, file_id):

    try:

        # Call the Drive v3 API
        # Get file name, so we can save it as the same with the same name.
        file = service.files().get(fileId=file_id).execute()
        file_name = file.get("name")
        print(f'File name is: {file_name}')

        # Call the Drive v3 API
        # get the file media data
        request = service.files().get_media(fileId=file_id)

        fh = io.BytesIO()
        downloader = MediaIoBaseDownload(fh, request)
        done = False
        while done is False:
            status, done = downloader.next_chunk()
            print("Download %d%%" % int(status.progress() * 100))

        # The file has been downloaded into RAM, now save it in a file
        fh.seek(0)
        with open(file_name, 'wb') as f:
            shutil.copyfileobj(fh, f, length=131072)

    except HttpError as error:
        # TODO(developer) - Handle errors from drive API.
        print(f'An error occurred: {error}')

相关问题