使用 Python 访问 Google Sheet 的更好方法

Better way to get access to Google Sheet with Python

如何使获取 Google 电子表格的过程自动化?

现在我们使用 gspreadoauth2client.service_account 来访问 Google 电子表格。它工作正常,但使用 OAuth2 凭据让我们手动将每个电子表格从凭据 json-file.

共享到 "client_email"
import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope = [
            'https://www.googleapis.com/auth/spreadsheets',
        'https://www.googleapis.com/auth/drive'
    ]
credentials = 
ServiceAccountCredentials.from_json_keyfile_name('path.json', scope)
    gs = gspread.authorize(credentials)

可以,但如何修改?

所以期望的结果是:有人与我共享电子表格,我可以在 Python 中立即开始使用它。可能吗?也许我们可以使用传入电子邮件中的一些触发器来提供有关共享或类似信息的信息?

你可以试试这个脚本。它有几个部分我们可以区分:

  1. 请求访问云端硬盘和 Gmail。如您所见,我们使用完整的 drive 范围而不是 drive.file这是因为有一个 导致 drive.file 崩溃的现有错误 (1),所以与此同时我们有 使用这个。
     from __future__ import print_function
        import pickle
        import sys
        import os.path
        from googleapiclient.discovery import build
        from google_auth_oauthlib.flow import InstalledAppFlow
        from google.auth.transport.requests import Request

        # If modifying these scopes, delete the file token.pickle.
        SCOPES = ['https://www.googleapis.com/auth/drive', 
              'https://www.googleapis.com/auth/gmail.modify']

        creds = None
        # The file token.pickle stores the user's access and refresh tokens, and is
        # created automatically when the authorization flow completes for the first
        # time.
        if os.path.exists('token.pickle'):
            with open('token.pickle', 'rb') as token:
                creds = pickle.load(token)
        # 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()
            # Save the credentials for the next run
            with open('token.pickle', 'wb') as token:
                pickle.dump(creds, token)
        mail_service = build('gmail', 'v1', credentials=creds)
        drive_service = build('drive','v3', credentials=creds)
  1. 正在声明一些变量。这里没有问题,只需声明 我们将在其中保存邮件 ID、文件名和 根据我们的需要格式化的文件名。
     mail_ids = []
     file_name = []
     name_string = []
  1. 获取电子邮件。我们只会接收未读邮件 drive-shares-noreply。在此之后,我们将把它们标记为“已读”,这样我们 下次我们执行脚本时不会拿走它们。
    def get_emails(mail_ids):
        user_id = 'me' #Or your email
        query = 'from:drive-shares-noreply@google.com, is:UNREAD' #Will search mails from drive shares and unread
        response = mail_service.users().messages().list(userId=user_id, q=query).execute()
        items = response.get('messages', [])
        if not items:
            print('No unread mails found')
            sys.exit()
        else:
            for items in items:
                mail_ids.append(items['id'])
            for mail_ids in mail_ids:
                mail_service.users().messages().modify(userId=user_id, id=mail_ids, body={"removeLabelIds":["UNREAD"]}).execute() #Marks the mails as read
  1. 获取电子邮件的文件名。 sharing sheets email 的 Subject 的语法是“文件名 - Invitation to edit”,所以我们取每封邮件的主题,稍后我们会格式化字符串。
def get_filename(mail_ids, file_name):
    user_id = 'me'
    headers = []
    for mail_ids in mail_ids:
        response = mail_service.users().messages().get(userId=user_id, id=mail_ids, format="metadata", metadataHeaders="Subject").execute()
        items = response.get('payload', [])
        headers.append(items['headers'])
    length = len(headers)
    for i in range(length):
        file_name.append(headers[i][0]['value'])

def process_name(file_name, name_string):
    for file_name in file_name:
        name_string.append(str(file_name).replace(" - Invitation to edit", ""))

  1. 授予 client_email
  2. 权限
def give_permissions(name_string):
    for name_string in name_string:
        body = "'{}'".format(name_string)
        results = drive_service.files().list(q="name = "+body).execute()
        items = results.get('files', [])
        if not items:
            print('No files found.')
            sys.exit()
        else:
            print('Files:')
            for item in items:
                print(u'{0} ({1})'.format(item['name'], item['id']))
                file_id = item['id']

    user_permission = {
        'type': 'user',
        'role': 'writer',
        'emailAddress': 'your_client_email'
    }
    drive_service.permissions().create(body=user_permission, fileId=file_id).execute()
  1. 然后我们只需要调用函数
get_emails(mail_ids)
get_filename(mail_ids, file_name)
process_name(file_name, name_string)
give_permissions(name_string)

无法为收到的每封新电子邮件触发此脚本,但您可以使用计时器或类似的东西触发它,它会搜索新电子邮件。

(1) 根据 documentation

的最新更新,drive.file 范围仅适用于某些文件