Я все еще новичок в Python и работаю над своим первым REST API. У меня есть файл JSON с несколькими уровнями. Когда я создаю фрейм данных с пандами, что бы я ни пытался, я не могу получить доступ к нужному мне уровню.
API построен с помощью Flask и имеет правильные параметры для книги, главы и стиха.
Ниже приведен небольшой пример данных JSON.
{
"book": "Python",
"chapters": [
{
"chapter": "1",
"verses": [
{
"verse": "1",
"text": "Testing"
},
{
"verse": "2",
"text": "Testing 2"
}
]
}
]
}
Вот мой код:
@app.route("/api/v1/<book>/<chapter>/<verse>/")
def api(book, chapter, verse):
book = book.replace(" ", "").title()
df = pd.read_json(f"Python/{book}.json")
filt = (df['chapters']['chapter'] == chapter) & (df['chapters']['verses']['verse'] == verse)
text = df.loc[filt].to_json()
result_dictionary = {'Book': book, 'Chapter': chapter, "Verse": verse, "Text": text}
return result_dictionary
Вот ошибка, которую я получаю:
KeyError
KeyError: 'chapter'
Я попытался нормализовать данные, используя df.loc для фильтрации и просто пытаясь получить доступ к данным напрямую.
Ожидается, что конечная точка API позволит пользователю указать книгу, главу и стих в качестве аргументов, а затем вернет текст для данной позиции на основе этих предоставленных параметров.
Вы пытаетесь получить доступ к списку в dict с помощью ключа dict?
Получит результат. Но df.loc[filt] требует список с (булевыми) фильтрами, а выше генерирует только одно значение false или true, поэтому вы не можете фильтровать его.
Вы можете фильтровать как:
df.from_dict(df['chapters'][0]['verses']).query("verse =='1'")
Вы можете сначала создать фрейм данных JSON, а затем запросить его.
import json
import pandas as pd
def api(book, chapter, verse):
# Read the JSON file
with open(f"Python/{book}.json", "r") as f:
data = json.load(f)
# Convert it into a DataFrame
df = pd.json_normalize(data, record_path=["chapters", "verses"], meta=["book", ["chapters", "chapter"]])
df.columns = ["Verse", "Text", "Book", "Chapter"] # rename columns
# Query the required content
query = f"Book == '{book}' and Chapter == '{chapter}' and Verse == '{verse}'"
result = df.query(query).to_dict(orient = "records")[0]
return result
Здесь df будет выглядеть так после json_normalize:
Verse Text Book Chapter
0 1 Testing Python 1
1 2 Testing 2 Python 1
2 1 Testing Python 2
3 2 Testing 2 Python 2
А result это:
{'Verse': '2', 'Text': 'Testing 2', 'Book': 'Python', 'Chapter': '1'}
Одна из проблем здесь в том, что "chapters" — это список
"chapters": [
Вот почему ["chapters"]["chapter"] не будет работать так, как вы хотите.
Если вы новичок в этом, может быть полезно «нормализовать» данные самостоятельно:
import json
with open("book.json") as f:
book = json.load(f)
for chapter in book["chapters"]:
for verse in chapter["verses"]:
row = book["book"], chapter["chapter"], verse["verse"], verse["text"]
print(repr(row))
('Python', '1', '1', 'Testing')
('Python', '1', '2', 'Testing 2')
Это можно передать pd.DataFrame()
df = pd.DataFrame(
([book["book"], chapter["chapter"], verse["verse"], verse["text"]]
for verse in chapter["verses"]
for chapter in book["chapters"]),
columns=["Book", "Chapter", "Verse", "Text"]
)
Book Chapter Verse Text
0 Python 1 1 Testing
1 Python 1 2 Testing 2
Хотя неясно, нужен ли вам вообще здесь датафрейм.
Это сработало отлично. Спасибо. Я еще не проверял другие ответы, но я тоже их проверю. Спасибо всем. Люблю сообщество Python.