如何使用Python和Google Sheets API在现有的Google Sheets文件中创建新的工作表?

qzlgjiam  于 2023-03-28  发布在  Python
关注(0)|答案(1)|浏览(149)

我尝试使用一年前使用的旧python代码(在不同的帐户中),但现在它不再工作了,我无法修复它。

def create_new_sheet(sheet_name, sheet_id):

    SCOPES = ['https://www.googleapis.com/auth/spreadsheets']

    SERVICE_ACCOUNT_FILE = 'token.json'
    creds = None
    creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes = SCOPES)

    SPREADSHEET_ID = sheet_id

    service = build('sheets', 'v4', credentials=creds)
            
    body = {
        "requests":{
            "addSheet":{
                "properties":{
                    "title":f"{sheet_name}"
                }
            }
        }
    }

    service.spreadsheets().batchUpdate(spreadsheetId = SPREADSHEET_ID, body = body).execute()

我已经有了令牌,使用它我可以读取数据而没有任何问题,但是当我尝试创建一个新工作表时,会发生以下错误:
MalformedError: Service account info was not in the expected format, missing fields client_email.
我基本上在做我过去做过的事情,但现在我有这个错误。有人能帮助我理解这里发生了什么吗?

bihw5rsg

bihw5rsg1#

您收到的错误消息表明您正在尝试使用服务帐户执行此操作,并且您正在使用的名为token.json的服务帐户密钥文件没有正确的结构。
代码的运行方式取决于您是想对普通用户还是服务帐户使用OAuth。
这是我用来测试service account方法的完整代码:

from googleapiclient.discovery import build
from google.oauth2 import service_account

def create_new_sheet(sheet_name, sheet_id):

    SCOPES = ['https://www.googleapis.com/auth/spreadsheets']

    SERVICE_ACCOUNT_FILE = 'token.json'
    creds = None
    creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes = SCOPES)

    SPREADSHEET_ID = sheet_id

    service = build('sheets', 'v4', credentials=creds)
            
    body = {
        "requests":{
            "addSheet":{
                "properties":{
                    "title":f"{sheet_name}"
                }
            }
        }
    }

    service.spreadsheets().batchUpdate(spreadsheetId = SPREADSHEET_ID, body = body).execute()

if __name__ == '__main__':
    create_new_sheet('Test name', 'Spreadtsheet ID')

这是名为token.json的服务帐户密钥文件应具有的结构:

{
  "type": "service_account",
  "project_id": "",
  "private_key_id": "",
  "private_key": "-----BEGIN PRIVATE KEY-----\n
PRIVATE KEY HERE
\n-----END PRIVATE KEY-----\n",
  "client_email": "",
  "client_id": "",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": ""
}

根据错误消息,您似乎缺少token.json文件中的client_email字段。请确保创建一个新字段,并从GCP控制台正确下载,然后重试。
如果你想使用OAuth来验证一个普通用户,这个用户是文件的编辑者,你应该使用下面的代码:

from __future__ import print_function

import os.path

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

def sheets_batch_update(spreadsheet_id, title):
     
    SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
    creds = None
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())
    # pylint: disable=maybe-no-member

    try:
        service = build('sheets', 'v4', credentials=creds)

        requests = []
        # Change the spreadsheet's title.
        requests.append({
            'addSheet': {
                'properties': {
                    'title': title
                },
            }
        })

        body = {
            'requests': requests
        }
        response = service.spreadsheets().batchUpdate(
            spreadsheetId=spreadsheet_id,
            body=body).execute()

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

if __name__ == '__main__':
    sheets_batch_update('Spreadsheet ID', 'Test name')

如果使用此方法,请确保删除当前的token.json文件,因为这种情况下的结构会有所不同。

参考文献:

相关问题