Запрос API пагинации в Python

Я пытаюсь получить все страницы из этой конкретной конечной точки в API, а затем преобразовать ответы .json в фрейм данных Pandas. Мой механик просматривает значение ключа в файле .json, который вложен в «мета»-ключ в разделе hasMore`. Если есть еще одна страница результатов, она вернет True, если страниц больше нет, она вернет False в качестве значений.

Я могу распечатать результат has_More, и он вернется True, поэтому я знаю, что он нашел правильное значение. Однако, когда я запускаю эту функцию, я получаю пустой список с .json или кадрами данных. Некоторое время пробовал новый код, но всегда получал пустые списки.

import requests
import json
import pandas as pd

url = "https://xxxxxxxx.xxxxxxxxx.com/projects/api/v3/tasklists"

def get_all_tasklists(url, pageSize=100, page=1):

    response = requests.get(f'{url}?page = {page}&pageSize = {pageSize}',
                            headers = {"authorization": xxxxxxxxxxxx}
                            )
    
    meta_data = json.loads(response.text)['meta']
    has_More = meta_data['page']['hasMore']

    timelogs = []
  
    if has_More == True:
        x = pd.json_normalize(json.loads(response.text))
        timelogs.extend(x)
        page += 1
    else:
        print(timelogs)
    


get_all_tasklists(url, pageSize=100, page=1)
x перезаписывается в каждом цикле. Добавьте фреймы данных в список и используйте concat.
e-motta 06.06.2024 20:09

Я предполагаю, что вы правы, потому что вы, вероятно, знаете больше о кодировании, чем я (нет даже двухмесячного опыта), но мне просто интересно, почему я не хочу, чтобы x был переписан? Я думаю, что хочу каждый раз перезаписывать его новым ответом .json, который «очищается» с помощью json_normalize?

Michael Mesa 06.06.2024 21:18

Если вы перезапишете переменную, данные, на которые она ссылается, «потеряются». Таким образом, каждый цикл будет эффективно отбрасывать данные, полученные в предыдущем цикле. Если только вы не сохраните ссылку на него где-нибудь еще, например, в списке.

e-motta 06.06.2024 22:57
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Пара проблем:

Во-первых, ваш код будет получать только одну страницу за один вызов. Учитывая, что вы назвали это get_all_xxx, это, вероятно, непреднамеренное поведение. Во-вторых, вы используете list.extend вместо list.append, что, вероятно, вам и нужно. В-третьих, эта функция не имеет возврата.

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

import requests
import json
import pandas as pd

url = "https://xxxxxxxx.xxxxxxxxx.com/projects/api/v3/tasklists"

def get_all_tasklists(url, pageSize=100, page=1):
    dataframes = []

    while True:
        response = requests.get(
            f'{url}?page = {page}&pageSize = {pageSize}',
            headers = {"authorization": xxxxxxxxxxxx}
        )

        meta_data = json.loads(response.text)['meta']
        has_more = meta_data['page']['hasMore']

        x = pd.json_normalize(json.loads(response.text))
        dataframes.append(x)
  
        if has_more:
            page += 1
        else:
            return pd.concat(timelogs)
    
get_all_tasklists(url, pageSize=100, page=1)

Черт, ты хорош. Именно то, что я хотел. Это дерьмо оказалось намного сложнее, чем ожидалось (особенно для нуба). Итак, «Пока True: проверяет, что «if has_More:» истинно? Если это так, продолжайте инициировать ответ -> посмотрите мои мета_данные/has_More на предмет значения bool -> загрузите json, чтобы нормализовать и добавить в мой список DF -> If bool значение теперь False, взять все журналы времени в списке и объединить их в один?

Michael Mesa 06.06.2024 21:39

Более или менее. Фактически этот цикл выглядит следующим образом: Fetch -> добавить в список -> если больше, ПЕРЕЙДИТЕ к 1, если больше нет, разбить и склеить список. В этом коде есть пара острых углов, которые вы, возможно, захотите решить в качестве упражнения: что произойдет, если первая страница пуста (т. е. нулевые результаты API)? Что произойдет, если вы введете несколько страниц и внезапно получите недопустимый результат JSON — будете ли вы пытаться сохранить то, что осталось, или потерпите неудачу при выполнении всей функции?

walkrflocka 06.06.2024 22:49

@MichaelMesa, а True: по сути, это просто бесконечный цикл. Вы выходите из него с «возвращением».

Pac0 06.06.2024 23:46

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