Google 相册 API BatchRemoveMediaItems 适用于 Postman 但不适用于 Python

问题描述

我有一个脚本,可以定期将一些 Python 编辑的图像上传到 Google 相册。由于没有允许覆盖现有图像的公共 API,我必须

  1. 获取相册中图片的 MediaID,
  2. 将它们从相册中删除
  3. 上传新的。

脚本的上传和 GetMediaID 部分工作正常,但删除照片的脚本在 Postman 中测试时效果很好,但在 Python 中运行时,我收到 401 响应。

代码

from GetMediaID import TACupdatemediaID,SeattleupdatemediaID,northupdatemediaID
import os
import pickle
from googlescript import Create_Service
import json
import requests
dir_path = os.path.join(os.getcwd())
API_NAME = 'photoslibrary'
API_VERSION = 'v1'
CLIENT_SECRET_FILE = dir_path + "\\" + "credentials.json"
print(CLIENT_SECRET_FILE)
ScopES = ['https://www.googleapis.com/auth/photoslibrary.edit.appcreateddata','https://www.googleapis.com/auth/photoslibrary.sharing',''
          ]

service = Create_Service(CLIENT_SECRET_FILE,API_NAME,API_VERSION,ScopES)

#print(service.albums().list().execute())


upload_url = 'https://photoslibrary.googleapis.com/v1/albums/AIJeZ-HdakZiXwq2i2jVhw8LR4NowHXBgPsBqYXZBt6qE61ELSGUprUkO1BVg4RJdMnzuxMotFJT:batchRemoveMediaItems'
token = pickle.load(open('token_photoslibrary_v1.pickle','rb'))


headers = {
    'Authorization': 'Bearer ' + token.token,'Content-type': 'application/json',}


request_body = {
   "mediaItemIds": [
        SeattleupdatemediaID,TACupdatemediaID,northupdatemediaID,]
  }
r = requests.post(upload_url,json=request_body)
print(r.json)

GoogleScript:

import pickle
import os
import datetime
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import Flow,InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload


def Create_Service(client_secret_file,api_name,api_version,*scopes):
    print(client_secret_file,scopes,sep='-')
    CLIENT_SECRET_FILE = client_secret_file
    API_SERVICE_NAME = api_name
    API_VERSION = api_version
    ScopES = [scope for scope in scopes[0]]

    cred = None

    pickle_file = f'token_{API_SERVICE_NAME}_{API_VERSION}.pickle'

    if os.path.exists(pickle_file):
        with open(pickle_file,'rb') as token:
            cred = pickle.load(token)

    if not cred or not cred.valid:
        if cred and cred.expired and cred.refresh_token:
            cred.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE,ScopES)
            cred = flow.run_local_server()

        with open(pickle_file,'wb') as token:
            pickle.dump(cred,token)

    try:
        service = build(API_SERVICE_NAME,credentials=cred)
        print(API_SERVICE_NAME,'service created successfully')
        return service
    except Exception as e:
        print(e)
    return None


def convert_to_RFC_datetime(year=1900,month=1,day=1,hour=0,minute=0):
    dt = datetime.datetime(year,month,day,hour,minute,0).isoformat() + 'Z'
    return dt

解决方法

看起来好像在你的范围中你只包含了

['https://www.googleapis.com/auth/photoslibrary.edit.appcreateddata','https://www.googleapis.com/auth/photoslibrary.sharing',''
          ]

我认为您得到的 401(未经授权的 http 代码)是因为您没有删除的范围,只有 appcreateddata

也许可以尝试添加 https://www.googleapis.com/auth/photoslibrary 范围

来源:https://developers.google.com/identity/protocols/oauth2/scopes#photoslibrary

编辑:

根据 the docs,您可能会遇到以下有关无效媒体项目的问题,或者有关媒体如何将其放入相册的情况(通过应用程序或作为上传的一部分——您是否手动在您开发时推送这些媒体项目之一?)。也许尝试删除媒体项目,直到找到一个有效的媒体项目。

您可以通过以下方式从相册中删除已添加的媒体项目 调用相册.batchRemoveMediaItems。

如果指定了无效的媒体项目,则整个请求将失败。 不支持部分成功。

请注意,您只能删除应用程序拥有的媒体项目 添加到相册或已作为相册的一部分在相册中创建的 上传。对于共享的相册,您只能删除由 其他合作者(如果您代表该所有者的行为) 专辑。

要从相册中删除媒体项目,请调用相册.batchRemoveMediaItems 带有媒体项和专辑的标识符。

我冒昧地亲自尝试了一下,我能够让它发挥作用。也许以下步骤可以帮助您解决删除问题,您可以从那里开始。

我首先使用 Try This API 来处理一些媒体项目。我抓住了第一个以确保我 100% 有一个有效的 mediaId。

这是我的身份验证方法:

def get_authorized_session():
scopes = ['https://www.googleapis.com/auth/photoslibrary','https://www.googleapis.com/auth/photoslibrary.sharing']

cred = None

if os.path.exists('config/token.pickle'):
    with open('config/token.pickle','rb') as token:
        cred = pickle.load(token)
# If there are no (valid) credentials available,let the user log in.
if not cred or not cred.valid:
    if cred and cred.expired and cred.refresh_token:
        cred.refresh(Request())
    else:
        flow = InstalledAppFlow.from_client_secrets_file(
            'config/client_id.json',scopes)
        cred = flow.run_local_server(port=0)
    # Save the credentials for the next run
    with open('config/token.pickle','wb') as token:
        pickle.dump(cred,token)

session = AuthorizedSession(cred)

return session

我通过(注意 appcreatedOnly 的参数)获得了专辑 ID

def get_albums(session,appCreatedOnly=False):
    params = {
        'excludeNonAppCreatedData': appCreatedOnly
    }

    while True:

        albums = session.get('https://photoslibrary.googleapis.com/v1/albums',params=params).json()

        # print(f"Server response: {albums}")

        if 'albums' in albums:

            for a in albums["albums"]:
                yield a

            if 'nextPageToken' in albums:
                params["pageToken"] = albums["nextPageToken"]
            else:
                return

        else:
            return

并提出以下要求:

session = get_authorized_session()
album_ids = get_albums()
album_title = 'albumtitlename'
album_id = album_ids[album_title]

request_body = {
    "mediaItemIds": [
        "ABg_5juBs_P76D6xYEgl3H0hZJB5n3qq1wFbGmRsl16B5dTvbNAa7G8-kxRrQZjBzGIf4SGMtpfdMRBSxEDhoy"
    ]
}

response = session.post(f'https://photoslibrary.googleapis.com/v1/albums/{album_id}:batchRemoveMediaItems',request_body)

print(response)

回复:

<Response [200]>

结束语:在我得到正确的专辑和媒体 ID 之前,我收到了 400 个错误。这让我相信您的 401 源于我链接的文档中关于您尝试删除的媒体是如何上传的以及根据 API 拥有该媒体的人的那些规则。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...