问题
I want to copy an existing template ppt present in my google drive. Then I want to change the placeholder text to some other text.
here is what I am trying.
from google.oauth2 import service_account
import googleapiclient.discovery
SCOPES = (
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/presentations',
)
SERVICE_ACCOUNT_FILE = 'cred.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
SLIDES = discovery.build('slides', 'v1', credentials=credentials)
DRIVE = discovery.build('drive', 'v3', credentials=credentials)
TMPLFILE = 'title slide template'
rsp = DRIVE.files().list(q="name='%s'" % TMPLFILE).execute().get('files')[0]
print(rsp)
DATA = {'name': 'Google Slides API template DEMO'}
print('** Copying template %r as %r' % (rsp['name'], DATA['name']))
DECK_ID = DRIVE.files().copy(body=DATA, fileId=rsp['id']).execute().get('id')
print(DECK_ID)
print('** Replacing placeholder text')
reqs = [
{'replaceAllText': {
'containsText': {'text': '{{text}}'},
'replaceText': final_til[0]
}},
]
SLIDES.presentations().batchUpdate(body={'requests': reqs},
presentationId=DECK_ID).execute()
print('DONE')
But it is not working. I don't get any error. everything works fine but I don't see the new ppt.
Output:
{'kind': 'drive#file', 'id': '15mVjkrT7PkckKetK_q9aYRVxaDcwDdHpAh7xjrAWB6Q', 'name': 'title slide template', 'mimeType': 'application/vnd.google-apps.presentation'} <--- rsp
** Copying template 'title slide template' as 'Google Slides API template DEMO'
11O97tySSNaboW6YRVD62Q7HLs8aVuS2pWyLYXImdSec <-- DECK_ID
** Replacing placeholder text
DONE
If I change
SLIDES.presentations().batchUpdate(body={'requests': reqs},
presentationId=DECK_ID).execute()
to
SLIDES.presentations().batchUpdate(body={'requests': reqs},
presentationId=rsp.get('id')).execute()
then it does replace the text but in my template file which I don't want.
Why is this happening?
回答1:
I believe your current situation and goal as follows.
- From your script,
- You are using googleapis for python.
- You have already been able to use Drive API and Slides API using the service account.
an existing template ppt present
is a Google Slides which is not the PowerPoint file.
Modification points:
From your script and
But it is not working. I don't get any error. everything works fine but I don't see the new ppt.
, I understood that you might want to see the Google Slides copied by the service account at your Google Drive.- When the Google Slides is copied by the service account, the copied Google Slides is put to the Drive of the service account. The Drive of service account is different from your Google Drive. By this, you cannot see the copied Google Slides on your Drive. I thought that this might be the reason of your issue.
In order to see the Google Slides copied by the service account at your Google Drive, for example, the following workarounds can be used.
- Share the copied Google Slides with your email of Google account.
- In this case, you can see the shared file at the shared folder.
- At first, it creates new folder in your Google Drive and share the folder with the email of the service account. And when the Google Slides is copied, it sets the shared folder as the destination folder.
- Share the copied Google Slides with your email of Google account.
Workaround 1:
In this workaround, it shares the copied Google Slides with your email of Google account. When this is reflected to your script, it becomes as follows.
Modified script:
In this case, new permission is created to the copied file using "Permissions: create".
From:print(DECK_ID)
print('** Replacing placeholder text')
To:
print(DECK_ID)
permission = {
'type': 'user',
'role': 'writer',
'emailAddress': '###@gmail.com' # <--- Please set the email of your Google account.
}
DRIVE.permissions().create(fileId=DECK_ID, body=permission).execute()
print('** Replacing placeholder text')
Workaround 2:
In this workaround, the Google Slides is copied to the shared folder in your Google Drive. Before you use this script, please create new folder and share the folder with the email of service account. When this is reflected to your script, it becomes as follows.
Modified script:
In this case, the metadata is added to the request body of DRIVE.files().copy()
.
DATA = {'name': 'Google Slides API template DEMO'}
To:
DATA = {'name': 'Google Slides API template DEMO', 'parents': ['###']}
- Please set the folder ID of shared folder to
###
.
References:
- Permissions: create
- Files: copy
回答2:
@Tanaike's answer is great, but there is one other option too:
Account Impersonation
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
delegated_credentials = credentials.with_subject(<email>)
DRIVE = build('drive','v3', credentials = delegated_credentials)
Here is a good overview: Using OAuth 2.0 for Server to Server Applications, specifically this section goes through the code.
Remember to set Domain Wide Delegation in both the GCP console and the Admin console.
The project initialized in the GCP Cloud console has also been granted scopes from within the Admin console > Security > API Controls > Domain wide delegation > Add new
The first thing the script does is build the credentials using from_service_account_file
:
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
Then it builds the delegated credentials, that is, the user to be impersonated:
delegated_credentials = credentials.with_subject('<EMAIL>')
From there it can build the service as normal. You can save to the user's drive as if it were the user doing it themselves.
References
- Service Accounts
- Using OAuth 2.0 for Server to Server Applications
来源:https://stackoverflow.com/questions/64626446/unable-to-copy-a-google-slide-file-using-google-drive-api