Sheets API:使用 Python 从电子表格中读取数据

Sheets API: reading data from spreadsheet with Python

我正在尝试从共享 我的个人电子邮件地址 的 Google 电子表格中检索数据。我在 json 文件中设置了一个服务帐户,如下所示:

{
  "type": "service_account",
  "project_id": "my-project-name",
  "private_key_id": "012345678901234567890123456789",
  "private_key": "-----BEGIN PRIVATE KEY-----\xxxxx\n-----END PRIVATE KEY-----\n",
  "client_email": "my-name@my-project-name.iam.gserviceaccount.com",
  "client_id": "9876543210",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/my-name%40my-project-name.iam.gserviceaccount.com"
}

我的代码(见下文)的基本原理是这样的:给定一个共享给我的 url 电子表格 (--> spreadsheet_idsheet_id),它找到选项卡名称 (name),并使用它来检索最终转换为 pd.DataFrame.

的数据 (data_values)

现在我的问题是,当我 运行 在公开可用的在线电子表格上使用此功能时,它工作正常,但每当我尝试 运行 在我有权访问的电子表格上使用它时,但它不是公开可用的,它失败并出现以下错误:

Error code: 403, PERMISSION_DENIED: The request is missing a valid API key

好像服务帐户(链接到我的 Google 帐户,因此链接到我的个人电子邮件)无法访问共享到我的个人帐户的内容。这是设计使然吗?我怎样才能克服这个?我非常喜欢自动解决方案,而不是必须分别手动设置每个电子表格的访问权限,以便与我的服务帐户地址共享,而不是我的个人地址。

编辑: 从那时起,我手动将我的服务帐户的电子邮件地址添加到其中一个文件中,并且成功了。看来,服务帐户无法访问我的个人电子邮件文件,只能访问那些特别 与服务帐户共享的文件?我是否也应该始终与我的服务帐户电子邮件地址共享每个文件?

代码:

def get_spreadsheet_data(name, spreadsheet_id, sheet_id, service_account_json_path, scope):

    creds = ServiceAccountCredentials.from_json_keyfile_name(service_account_json_path, scope)
    service = build('sheets', 'v4', credentials=creds)
    sheets = service.spreadsheets()

    # If name is not provided, generate it from spreadsheet_id
    if not name:
        a = sheets.get(
            spreadsheetId=spreadsheet_id,
            fields='sheets(properties(index,sheetId,title))'
        ).execute()
        name = [sheet['properties']['title'] for sheet in a['sheets'] \
                if int(sheet['properties']['sheetId']) == int(sheet_id)][0]
    
    data_table = sheets.values().get(spreadsheetId=spreadsheet_id, range=name).execute()
    data_values = data_table.get('values', [])
        
    df = pd.DataFrame(data_values)
    return df

出于文档目的发布此内容。

作为,服务帐户和您的普通帐户是完全不同的帐户。

服务帐户本身只能访问与其共享(或由其创建)的文件,而不能访问与您的常规帐户共享的文件。

如官方文档中所述:

Typically, an application uses a service account when the application uses Google APIs to work with its own data rather than a user's data.

如果您有 Workspace 帐户,则可以使用该服务帐户代表您域中的其他用户(例如您的常规帐户):请参阅 Delegating domain-wide authority to the service account 了解相关信息。否则,无法使用您的服务帐户访问用户文件。

参考: