首页 > 解决方案 > Google Photos 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)

谷歌脚本:

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, api_name, api_version, 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, API_VERSION, 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

标签: pythongoogle-apigoogle-api-python-clientgoogle-photos-api

解决方案


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

['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

编辑:

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

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

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

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

要从相册中删除媒体项目,请使用媒体项目和相册的标识符调用 albums.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 拥有该媒体的人的那些规则。


推荐阅读