Как извлечь все результаты из запроса GET, который охватывает несколько страниц?

#python #json #dataframe #python-requests #append

Вопрос:

Я успешно написал код, который вызывает API, а затем преобразует результаты в фрейм данных.

 wax_wallet = "zqsfm.wam"

# Get Assets from AtomicHub API
response1 = requests.get(
    "https://wax.api.atomicassets.io/atomicassets/v1/assets?"
    f"owner={wax_wallet}"
    "amp;collection_whitelist=nftdraft2121"
    "amp;page=1"
    "amp;limit=1000"
    "amp;order=asc"
    "amp;sort=name")

# Save Response as JSON
json_assets = response1.json()

# Convert JSON to DataFrame
df = pd.json_normalize(json_assets['data'])
 

Этот API возвращает не более 1000 элементов на страницу, поэтому мне нужно, чтобы он просматривал столько страниц, сколько необходимо, и в конечном итоге получал результаты, сохраненные во фрейме данных.

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

 asset_count = 2500
pages = int(math.ceil(asset_count / 1000))

# Get Assets from AtomicHub API
all_assets = []
for page in range(1, pages):
    url = f'https://wax.api.atomicassets.io/atomicassets/v1/assets?owner={wax_wallet}' 
          f'amp;collection_whitelist=nftdraft2121amp;page={page}amp;limit=1000amp;order=ascamp;sort=name'
    response = rq.get(url)
    all_assets.append(json.loads(response.text))["response"]
 

Заранее спасибо за любую помощь!

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

1. Лучше использовать params аргумент, а не формировать строку запроса вручную: requests.get("https://wax.api.atomicassets.io/atomicassets/v1/assets", params={"owner": wax_wallet, "collection_whitelist": "nftdraft2121", "page": "1", "limit": "1000", "order": "asc", "sort": "name") . Также вы можете использовать response.json() .

Ответ №1:

Вы можете превратить их в кадры данных, а затем объединить отдельные кадры в конечный результат:

 def get_page(page_num):
    wax_wallet = "zqsfm.wam"

    response = requests.get(
        "https://wax.api.atomicassets.io/atomicassets/v1/assets",
        params={
            "owner": wax_wallet,
            "collection_whitelist": "nftdraft2121",
            "page": page_num,
            "limit": "1000",
            "order": "asc",
            "sort": "name"
        }
    )

    json_assets = response.json()
    return pd.json_normalize(json_assets['data'])

# The number of pages you want
number_of_pages_requested = 10

# Get all pages as dataframes
pages = [get_page(n   1) for n in range(number_of_pages_requested)]

# Combine pages to single dataframe
df = pd.concat(pages)
 

Изменить: обновлено с использованием параметров на основе комментария Олвина Рота

Правка 2: исправлена ошибка индексирования

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

1. Не уверен, что вы имеете в виду под своим вопросом. Но хорошее предложение с использованием параметров

2. Вы уже отредактировали свой ответ, включая мое предложение из комментариев, поэтому мой вопрос сейчас не имеет смысла. Я просто хотел указать вам, что вам нужно кодировать каждое значение в кодировку url, если вы формируете URL вручную, и лучше использовать params то, что сделает это внутренне.

3. @tituszban Спасибо за ответ! Это работает почти идеально; однако это не совсем то, на что я надеюсь. Мне нужно вернуть 3 страницы, но этот код возвращает первую страницу дважды, а затем вторую страницу один раз. Например, у меня есть 2500 элементов, разбросанных по 3 страницам. Этот вывод возвращает 1-1000, 1-1000, затем 1,001-2,000. Есть какие-нибудь идеи?

4. @python_noob_5, используйте range(1, number_of_pages_requested 1)

5. @OlvinRoght прав. Я предпочитаю делать n 1 . Обновил свой ответ

Ответ №2:

Я думаю, это должно помочь:-

 import requests

all_assets = []
URL = 'https://wax.api.atomicassets.io/atomicassets/v1/assets'
params = {
    'owner': 'zqsfm.wam',
    'collection_whitelist': 'nftdraft2121',
    'page': 1,
    'order': 'asc',
    'sort': 'name',
    'limit': 1000
}
with requests.Session() as session:
    while True:
        print(f"Getting page {params['page']}")
        response = session.get(URL, params=params)
        response.raise_for_status()
        _j = response.json()
        data = _j['data']
        if len(data) > 0:
            all_assets.append(data)
            params['page']  = 1
        else:
            break
print('Done')
 

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

1. Лучше избегать имен переменных, которые могут привести к теневому импорту. Кроме того, бесконечные петли-это в основном плохой шаблон, лучше добавить какое-то строгое условие.

2. Я предполагаю, что вы имеете в виду переменную с именем «json». На том основании, что я не импортирую json, я не вижу проблемы. Кроме того, в данном конкретном случае невозможно узнать, сколько страниц может быть возвращено. Это может быть выведено только путем запроса страницы, которая находится за пределами доступного диапазона, и когда это происходит, возникает четко определенное условие