Spotify API повторил ошибку http 429 при использовании Spotipy

Я работаю над проектом, использующим Spotipy, который делает много запросов. Примерно 18 часов назад я предполагаю, что достиг предела скорости, потому что отправлял много запросов, и код начал просто останавливаться и зависать навсегда, как только он дошел до строки, содержащей ссылку на API. После этого я сдался и пошел спать. ~ 12 часов назад я решил переписать весь проект, так как он был беспорядочным, и поэтому я мог реализовать интервал между запросами API. Я также узнал, что могу установить retries = 0, чтобы он выдавал ошибку, а не зависал на неопределенный срок. Я переписывал проект, мне удалось сделать только 1 запрос к API, прежде чем я начал каждый раз получать http 429 ошибки. Я оставил его в покое еще на пару часов, пока не попытался устранить неполадки еще раз, и произошло то же самое: мне удалось добиться одного успеха, а затем возникли ошибки.

restart.py:

import spotipy # type: ignore
from spotipy.oauth2 import SpotifyOAuth # type: ignore
import time

def create_client() -> spotipy.Spotify:
    sp: spotipy.Spotify = spotipy.Spotify(
        retries=0,
        auth_manager=SpotifyOAuth(
            client_id='my_id',
            client_secret='_my_secret',
            scope='playlist-read-private playlist-modify-public playlist-modify-private',
            redirect_uri='http://localhost:8888/callback'
        )
    )
    return sp

class APIRequests:
    def __init__(self, user_id: str) -> None:
        self.recent_request: float = time.time()
        self.sp: spotipy.Spotify = create_client()
        self.user_id: str = user_id

    def get_playlist_tracks(self, playlist: str, offset: int, retries: int=0):
        delta_time = time.time() - self.recent_request
        if delta_time > 1:
            try:
                return self.sp.user_playlist_tracks(self.user_id, playlist, offset=offset, limit=100)
            except spotipy.exceptions.SpotifyException as e:
                if e.http_status == 429:
                    print(e)
                    print(e.headers.get('retry-after'))
                    print(f'retrying: waiting {(2 ** retries) * 4} seconds...')
                    time.sleep((2 ** retries) * 4)
                    retries += 1
                    return self.get_playlist_tracks(playlist, offset, retries)
                else:
                    raise e
        else:
            time.sleep(1 - delta_time)
            self.get_playlist_tracks(playlist, offset)

api_client: APIRequests = APIRequests('my_user_id')

def get_playlist_tracks(playlist: str) -> list:
    offset: int = 0
    tracks: list = []
    while True:
        print('sending request ...')
        request_batch = api_client.get_playlist_tracks(playlist, offset)
        print('request recieved')
        for track in request_batch['items']:
            tracks.append(track['track'])
        
        if not request_batch["next"]:
                break
    
    return tracks

if __name__ == '__main__':
    tracks = get_playlist_tracks('my_playlist')

    print(len(tracks))

В моем переписанном коде все запросы разделены как минимум 1 секундой (хотя это даже не имеет значения, потому что я все равно не могу пройти мимо 1 запроса). Кроме того, после получения ошибки http 429 он будет ждать экспоненциально увеличивающееся время, прежде чем повторить попытку. Это не имеет никакого эффекта. Я запускал его до тех пор, пока между попытками не прошло 2 минуты, но ошибка все равно выдавалась.

Что для меня не имеет смысла, так это то, что ограничение скорости применяется только к количеству запросов, сделанных в любом 30-секундном окне. Если я подожду до 2 минут, проблем не должно возникнуть. Если бы я получал только ошибку, я бы предположил, что у меня какой-то 24-часовой запрет API или что-то в этом роде, но возможность сделать 1 успешный запрос не имеет смысла.

Я попробовал использовать идентификатор/секрет клиента для обоих двух приложений, которые есть в моей учетной записи разработчика Spotify, и у меня возникла та же проблема.

Правильно ли я подхожу к этому? Есть ли у меня проблема в моем коде? Любая помощь приветствуется.

Кроме того:

Из Документации Spotify API:

Если ваше приложение ограничено по скорости, оно получит ответ об ошибке 429 от Spotify. Ваше приложение может использовать эту информацию как сигнал для замедления количества запросов API, которые оно отправляет к веб-API. Заголовок ответа 429 обычно включает заголовок Retry-After со значением в секундах. Рассмотрите возможность ожидания количества секунд, указанного в Retry-After, прежде чем ваше приложение снова вызовет веб-API.

Я не вижу ничего подобного в сообщении об ошибке. Как я могу получить доступ к повторной попытке и решит ли это мою проблему?

в коде вы используете retry-after, но, возможно, так и должно быть Retry-After. ИЛИ, возможно, отобразите все заголовки, чтобы увидеть, что вы действительно получаете.

furas 01.05.2024 03:57

Я не знаю ограничений в Spotify, но в других API часто есть ограничение на 1-минутное окно и дневной лимит, а иногда и месячный лимит.

furas 01.05.2024 04:01

@furas Как мне получить доступ к retry-after? Или как мне получить доступ к заголовкам? [developer.spotify.com/documentation/web-api/concepts/… документация по пределу скорости) не упоминает ничего, кроме 30-секундного окна.

flakpm 01.05.2024 04:11

Прошло уже почти 24 часа, как все перестало работать, и теперь все снова работает. Должен ли я ответить на свой вопрос и сказать, что все выяснилось само собой? Стоит ли мне удалить свой вопрос? (Извините, я новичок на сайте)

flakpm 01.05.2024 07:19

Вы могли бы ответить на свой вопрос. Эта информация может быть полезна — особенно потому, что вы не нашли эту информацию в официальной документации.

furas 01.05.2024 11:38
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
5
267
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Прочитав сообщение об ошибке более внимательно, я обнаружил, что у меня истекло время ожидания из-за слишком большого количества раз превышения предела скорости. В тот раз мой тайм-аут длился чуть меньше 24 часов. Единственное решение – ждать.

Я предполагаю, что чем меньше вы пытаетесь отправить запросы во время тайм-аута, тем он короче, поскольку еще два раза, когда у меня был тайм-аут с тех пор, как я задал вопрос, были намного короче, чем первый, и я не проверял, чтобы увидеть если бы у меня не было тайм-аута так же, как в первый раз.

Что касается того, чтобы избежать тайм-аута, я не уверен. Даже если я ограничил количество запросов до 1 в секунду, тайм-аут у меня все равно был еще дважды, но я также отправлял запросы без перерыва более часа, когда у меня вышел тайм-аут.

Чтобы устранить тайм-аут: просто подождите и время от времени проверяйте, можете ли вы снова отправлять запросы. У меня второй раз это длилось около 12 часов.

Чтобы избежать тайм-аута: не отправляйте слишком много запросов одновременно.

Другие вопросы по теме