Home > other >  Trouble Looping through JSON elements pulled using API
Trouble Looping through JSON elements pulled using API

Time:10-04

I am trying to pull search results data from an API on a website and put it into a pandas dataframe. I've been able to successfully pull the info from the API into a JSON format.

The next step I'm stuck on is how to loop through the search results on a particular page and then again for each page of results.

Here is what I've tried so far:

#Step 1: Connect to an API
import requests
import json
response_API = requests.get('https://www.federalregister.gov/api/v1/documents.json?conditions[publication_date][gte]=09/01/2021&conditions[term]=economy&order=relevant&page=1')
#200

#Step 2: Get the data from API
data = response_API.text

#Step 3: Parse the data into JSON format
parse_json = json.loads(data)

#Step 4: Extract data
title = parse_json['results'][0]['title']
pub_date = parse_json['results'][0]['publication_date']
agency = parse_json['results'][0]['agencies'][0]['name']

Here is where I've tried to put this all into a loop:

import numpy as np
import pandas as pd
df=[]
for page in np.arange(0,7):
    url = 'https://www.federalregister.gov/api/v1/documents.json?conditions[publication_date][gte]=09/01/2021&conditions[term]=economy&order=relevant&page={page}'.format(page=page)
    response_API = requests.get(url)
    print(response_API.status_code)
    data = response_API.text
    parse_json = json.loads(data)

    for i in parse_json:
        title = parse_json['results'][i]['title']
        pub_date = parse_json['results'][i]['publication_date']
        agency = parse_json['results'][i]['agencies'][0]['name']    
        df.append([title,pub_date,agency])


cols = ["Title", "Date","Agency"]

df = pd.DataFrame(df,columns=cols)

I feel like I'm close to the correct answer, but I'm not sure how to move forward from here. I need to iterate through the results where I placed the i's when parsing through the json data, but I get an error that reads, "Type Error: list indices must be integers or slices, not str". I understand I can't put the i's in those spots, but how else am I supposed to iterate through the results?

Any help would be appreciated! Thank you!

CodePudding user response:

Slightly different approach: rather than iterating through the response, read into a dataframe then save what you need. The saves the first agency name in the list.

df_list=[]
for page in np.arange(0,7):
    url = 'https://www.federalregister.gov/api/v1/documents.json?conditions[publication_date][gte]=09/01/2021&conditions[term]=economy&order=relevant&page={page}'.format(page=page)
    response_API = requests.get(url)
    # print(response_API.status_code)
    data = response_API.text
    parse_json = json.loads(data)
    df = pd.json_normalize(parse_json['results'])
    df['Agency'] = df['agencies'][0][0]['raw_name']
    df_list.append(df[['title', 'publication_date', 'Agency']])
    
df_final = pd.concat(df_list)
df_final

                                                title publication_date                           Agency
0   Determination of the Promotion of Economy and ...       2021-09-28  OFFICE OF MANAGEMENT AND BUDGET
1   Corporate Average Fuel Economy Standards for M...       2021-09-03  OFFICE OF MANAGEMENT AND BUDGET
2   Public Hearing for Corporate Average Fuel Econ...       2021-09-14  OFFICE OF MANAGEMENT AND BUDGET
3   Investigation of Urea Ammonium Nitrate Solutio...       2021-09-08  OFFICE OF MANAGEMENT AND BUDGET
4   Call for Nominations To Serve on the National ...       2021-09-08  OFFICE OF MANAGEMENT AND BUDGET
..                                                ...              ...                              ...
15  Energy Conservation Program: Test Procedure fo...       2021-09-14           DEPARTMENT OF COMMERCE
16  Self-Regulatory Organizations; The Nasdaq Stoc...       2021-09-09           DEPARTMENT OF COMMERCE
17  Regulations To Improve Administration and Enfo...       2021-09-20           DEPARTMENT OF COMMERCE
18                Towing Vessel Firefighting Training       2021-09-01           DEPARTMENT OF COMMERCE
19  Patient Protection and Affordable Care Act; Up...       2021-09-27           DEPARTMENT OF COMMERCE

[140 rows x 3 columns]

CodePudding user response:

I think you are very close!

import numpy as np
import pandas as pd
import requests

BASE_URL = "'https://www.federalregister.gov/api/v1/documents.json?conditions[publication_date][gte]=09/01/2021&conditions[term]=economy&order=relevant&page={page}"

results = []
for page in range(0, 7):
    response = requests.get(BASE_URL.format(page=page))
    if response.ok:
        resp_json = response.json()
        for res in resp_json["results"]:
            results.append(
                [
                    res["title"],
                    res["publication_date"],
                    [agency["name"] for agency in res["agencies"]]
                ]
            )

df = pd.DataFrame(results, columns=["Title", "Date", "Agencies"])

In this block of code, I used the requests library's built-in .json() method, which can automatically convert a response's text to a JSON dict (if it's in the proper format).

The if response.ok is a little less-verbose way provided by requests to check if the status code is < 400, and can prevent errors that might occur when attempting to parse the response if there was a problem with the HTTP call.

Finally, I'm not sure what data you need exactly for your DataFrame, but each object in the "results" list from the pages pulled from that website has "agencies" as a list of agencies... wasn't sure if you wanted to drop all that data, so I kept the names as a list.

*Edit:

In case the response objects don't contain the proper keys, we can use the .get() method of Python dictionaries.

# ...snip
        for res in resp_json["results"]:
            results.append(
                [
                    res.get("title"),  # This will return `None` as a default, instead of causing a KeyError
                    res.get("publication_date"),
                    [
                        # Here, get the 'raw_name' or None, in case 'name' key doesn't exist
                        agency.get("name", agency.get("raw_name"))
                        for agency in res.get("agencies", [])
                    ]
                ]
            )

CodePudding user response:

Try this:

for i in  parse_json['results']:
        title =[i]['title']
        pub_date = [i]['publication_date']
        agency = [i]['agencies'][0]['name']    
        df.append([title,pub_date,agency])
  • Related