请看一下我的Git Hub response美元.我还将我的Python代码附加到了这篇文章中.

from __future__ import print_function

import time

from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

from google.oauth2 import service_account

# Set your credentials file path
credentials_path = '/Users/baker/Desktop/a3/credentials.json'

# Set your template document ID
template_document_id = '12g6okE4Hvr5VCMiGo6Z7szNSp_cZIRafdLHafGdEtRs'

# Set your Google Sheets document ID
spreadsheet_id = '1uzt7TxPSzJkcts6RIJv36KCD8IstYa2UAve8DKe2UZs'

# Set the sheet name in the Google Sheets document
sheet_name = 'Sheet1'

# Load credentials from the JSON file
credentials = service_account.Credentials.from_service_account_file(
    credentials_path,
    scopes=['https://www.googleapis.com/auth/documents', 'https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']
)

# Fill-in IDs of your Docs template & any Sheets data source
DOCS_FILE_ID = "12g6okE4Hvr5VCMiGo6Z7szNSp_cZIRafdLHafGdEtRs"
SHEETS_FILE_ID = "1uzt7TxPSzJkcts6RIJv36KCD8IstYa2UAve8DKe2UZs"

# Set the folder ID in Google Drive to save the merged documents
folder_id = '1Wknll1g5MiJSaVKtS2e-AHlL8EzeT6UG'

# application constants
SOURCES = ('text', 'sheets')
SOURCE = 'sheets'  # Choose one of the data SOURCES
COLUMNS = ['to_name', 'to_title', 'to_company', 'to_address']
TEXT_SOURCE_DATA = (
    ('Ms. Lara Brown', 'Googler', 'Google NYC', '111 8th Ave\n'
                                                'New York, NY  10011-5201'),
    ('Mr. Jeff Erson', 'Googler', 'Google NYC', '76 9th Ave\n'
                                                'New York, NY  10011-4962'),
)


# Build the Google Docs and Google Sheets services
DRIVE = build('drive', 'v2', credentials=credentials)
DOCS = build('docs', 'v1', credentials=credentials)
SHEETS = build('sheets', 'v4', credentials=credentials)

def get_data(source):
    """Gets mail merge data from chosen data source.
    """
    try:
        if source not in {'sheets', 'text'}:
            raise ValueError(f"ERROR: unsupported source {source}; "
                             f"choose from {SOURCES}")
        return SAFE_DISPATCH[source]()
    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

def _get_text_data():
    """(private) Returns plain text data; can alter to read from CSV file.
    """
    return TEXT_SOURCE_DATA

def _get_sheets_data(service=SHEETS):
    """(private) Returns data from Google Sheets source. It gets all rows of
        'Sheet1' (the default Sheet in a new spreadsheet), but drops the first
        (header) row. Use any desired data range (in standard A1 notation).
    """
    return service.spreadsheets().values().get(spreadsheetId=SHEETS_FILE_ID,
                                               range='Sheet1').execute().get(
        'values')[1:]
    # skip header row

# data source dispatch table [better alternative vs. eval()]
SAFE_DISPATCH = {k: globals().get('_get_%s_data' % k) for k in SOURCES}

def _copy_template(tmpl_id, source, service):
    """(private) Copies letter template document using Drive API then
        returns file ID of (new) copy.
    """
    try:
        body = {'name': 'Merged form letter (%s)' % source}
        return service.files().copy(body=body, fileId=tmpl_id,
                                    fields='id').execute().get('id')
    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

def merge_template(tmpl_id, source, service):
    """Copies template document and merges data into newly-minted copy then
        returns its file ID.
    """
    try:
        # copy template and set context data struct for merging template values
        copy_id = _copy_template(tmpl_id, source, service)
        context = merge.iteritems() if hasattr({},
                                               'iteritems') else merge.items()

        # "search & replace" API requests for mail merge substitutions
        reqs = [{'replaceAllText': {
            'containsText': {
                'text': '{{%s}}' % key.upper(),  # {{VARS}} are uppercase
                'matchCase': True,
            },
            'replaceText': value,
        }} for key, value in context]

        # send requests to Docs API to do actual merge
        DOCS.documents().batchUpdate(body={'requests': reqs},
                                     documentId=copy_id, fields='').execute()
        return copy_id
    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

if __name__ == '__main__':
    # fill-in your data to merge into document template variables
    merge = {
        # sender data
        'my_name': 'Ayme A. Coder',
        'my_address': '1600 Amphitheatre Pkwy\n'
                      'Mountain View, CA  94043-1351',
        'my_email': 'http://google.com',
        'my_phone': '+1-650-253-0000',
        # - - - - - - - - - - - - - - - - - - - - - - - - - -
        # recipient data (supplied by 'text' or 'sheets' data source)
        'to_name': None,
        'to_title': None,
        'to_company': None,
        'to_address': None,
        # - - - - - - - - - - - - - - - - - - - - - - - - - -
        'date': time.strftime('%Y %B %d'),
        # - - - - - - - - - - - - - - - - - - - - - - - - - -
        'body': 'Google, headquartered in Mountain View, unveiled the new '
                'Android phone at the Consumer Electronics Show. CEO Sundar '
                'Pichai said in his keynote that users love their new phones.'
    }

    # get row data, then loop through & process each form letter
    data = get_data(SOURCE)  # get data from data source
    for i, row in enumerate(data):
        merge.update(dict(zip(COLUMNS, row)))
        print('Merged letter %d: docs.google.com/document/d/%s/edit' % (
            i + 1, merge_template(DOCS_FILE_ID, SOURCE, DRIVE)))

预期行为

访问生成的链接(即,链接不要求访问并直接指向我要访问的生成的文档),以及将生成的邮件合并文件存放在我的文件夹中.

实际行为

Receive the following message:

Merged letter 1: docs.google.com/document/d/11ePx7cP-M49rBVtF4gvaMBA02ZH92W5xOK5DXOzdH9Q/edit
Merged letter 2: docs.google.com/document/d/1to3zGwJYsBflIeiOm9pydNOdmQ9IJDXxbtNADEsylkA/edit

从这个Angular 看,我的代码运行得很好,但随后.我访问这些链接,它要求我请求访问,尽管我使用相同的Gmail帐户执行了前面的所有步骤(即使用相同的Gmail帐户构建所有凭据,等等).

推荐答案

从你下面的情况来看,

从这个Angular 看,我的代码运行得很好,但随后.我访问这些链接,它要求我请求访问,尽管我使用相同的Gmail帐户执行了前面的所有步骤(即使用相同的Gmail帐户构建所有凭据,等等).

我知道这个脚本运行正常,没有错误.而且,大约it asks for me to request access,当我看到你的展示脚本时,似乎你正在使用服务帐户.并且,使用服务帐户复制模板文件.约the same Gmail account,如果这是您的Google帐户,则服务帐户与您的Google帐户不同.我想这可能是你现在这个问题的原因.

在这种情况下,需要添加从您的Google帐户访问的权限.当这反映在您的脚本中时,下面的修改如何?

从…:

def _copy_template(tmpl_id, source, service):
    """(private) Copies letter template document using Drive API then
        returns file ID of (new) copy.
    """
    try:
        body = {'name': 'Merged form letter (%s)' % source}
        return service.files().copy(body=body, fileId=tmpl_id,
                                    fields='id').execute().get('id')
    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

至:

def _copy_template(tmpl_id, source, service):
    """(private) Copies letter template document using Drive API then
        returns file ID of (new) copy.
    """
    try:
        body = {'name': 'Merged form letter (%s)' % source}
        copiedFileId = service.files().copy(body=body, fileId=tmpl_id, fields='id').execute().get('id')
        permission = {
            "type": "user",
            "role": "writer",
            "emailAddress": "###" # <--- Please set your gmail of your account.
        }
        res = service.permissions().create(fileId=copiedFileId, body=permission).execute()
        return copiedFileId

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error
  • 通过此修改,在复制模板文件后,您的帐户将作为写入者添加到复制文件的权限中.

注:

  • 作为另一种方法,当复制的文件被创建到您帐户的Google Drive中的特定文件夹时,当复制模板文件时,您自动拥有复制文件的权限.在这种情况下,请与服务帐户共享您的文件夹.并且,请将您的_copy_template修改如下.

    • 从…

        body = {'name': 'Merged form letter (%s)' % source}
      
    •   body = {'name': 'Merged form letter (%s)' % source, 'parents': ['###folderId###']}
      

参考资料:

Python相关问答推荐

返回nxon矩阵的diag元素,而不使用for循环

Python会扔掉未使用的表情吗?

图像 pyramid .难以创建所需的合成图像

无法定位元素错误404

如何在给定的条件下使numpy数组的计算速度最快?

NumPy中条件嵌套for循环的向量化

在单次扫描中创建列表

交替字符串位置的正则表达式

python sklearn ValueError:使用序列设置数组元素

pysnmp—lextudio使用next()和getCmd()生成器导致TypeError:tuple对象不是迭代器''

统计numpy. ndarray中的项目列表出现次数的最快方法

获取PANDA GROUP BY转换中的组的名称

Pandas在rame中在组内洗牌行,保持相对组的顺序不变,

Seaborn散点图使用多个不同的标记而不是点

当我定义一个继承的类时,我可以避免使用`metaclass=`吗?

极柱内丢失类型信息""

有没有一种方法可以在朗肯代理中集成向量嵌入

Polars定制函数返回多列

极点用特定值替换前n行

FileNotFoundError:[WinError 2]系统找不到指定的文件:在os.listdir中查找扩展名