Google Photos API BatchRemoveMediaItems работает в Postman, но не на Python

#python #google-api #google-api-python-client #google-photos-api

#python #google-api #google-api-python-client #google-photos-api

Вопрос:

У меня есть скрипт, который периодически загружает некоторые отредактированные на Python изображения в альбом Google Photos. Поскольку нет общедоступного API, который позволяет перезаписывать существующие изображения, я должен

  1. получить идентификаторы носителей изображений в альбоме,
  2. удалите их из альбома и
  3. загружайте новые.

Части скрипта upload и 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, 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
 

Комментарии:

1. Какое полное сообщение об ошибке?

2. RemoveMediaItems просто выдает пустое сообщение JSON, даже в случае успеха. Результатом приведенного выше сценария является <связанный метод Response.json из <Response [401]>>

Ответ №1:

Похоже, что в ваших областях вы включили только

 ['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% есть действительный медиафайл.

Это мой метод аутентификации:

 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)

 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]>
 

Заключительные мысли: я получил 400 ошибок из-за неправильных идентификаторов альбомов и носителей, прежде чем я все исправил. Это наводит меня на мысль, что ваш 401 вытекает из тех правил в документах, на которые я ссылался, относительно ТОГО, КАК был загружен носитель, который вы пытаетесь удалить, и кому принадлежит этот носитель в соответствии с API.

Комментарии:

1. Спасибо Vizzyy. Я добавил область photoslibrary, но все еще получаю ошибку 401

2. Пожалуйста, удалите свой файл рассола токена и выполните повторную аутентификацию. Вы должны делать это каждый раз, когда меняете области видимости @Bradfrell

3. Кроме того, если вы добавляете эти разрешения верхнего уровня для полного доступа к photoslibrary, я думаю, вы можете удалить другую область edit.apponly. Кроме того, из вашего кода не похоже, что вы делитесь альбомами с другими пользователями, поэтому область общего доступа, возможно, не нужна

4. Выполнено. Все еще есть ошибка 401. Заранее спасибо @Vizzyy.

5. @Bradfrell я добавил еще несколько заметок в свой первоначальный пост