Accessing JSON elements
Question:
I am getting the weather information from a URL.
weather = urllib2.urlopen('url')
wjson = weather.read()
and what I am getting is:
{
"data": {
"current_condition": [{
"cloudcover": "0",
"humidity": "54",
"observation_time": "08:49 AM",
"precipMM": "0.0",
"pressure": "1025",
"temp_C": "10",
"temp_F": "50",
"visibility": "10",
"weatherCode": "113",
"weatherDesc": [{
"value": "Sunny"
}],
"weatherIconUrl": [{
"value": "http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0001_sunny.png"
}],
"winddir16Point": "E",
"winddirDegree": "100",
"windspeedKmph": "22",
"windspeedMiles": "14"
}]
}
}
How can I access any element I want?
if I do: print wjson['data']['current_condition']['temp_C']
I am getting error saying:
string indices must be integers, not str.
Answers:
import json
weather = urllib2.urlopen('url')
wjson = weather.read()
wjdata = json.loads(wjson)
print wjdata['data']['current_condition'][0]['temp_C']
What you get from the url is a json string. And your can’t parse it with index directly.
You should convert it to a dict by json.loads
and then you can parse it with index.
Instead of using .read()
to intermediately save it to memory and then read it to json
, allow json
to load it directly from the file:
wjdata = json.load(urllib2.urlopen('url'))
Here’s an alternative solution using requests:
import requests
wjdata = requests.get('url').json()
print wjdata['data']['current_condition'][0]['temp_C']
‘temp_C’ is a key inside dictionary that is inside a list that is inside a dictionary
This way works:
wjson['data']['current_condition'][0]['temp_C']
>> '10'
Another alternative way using get method with requests:
import requests
wjdata = requests.get('url').json()
print wjdata.get('data').get('current_condition')[0].get('temp_C')
You can do it this way too:
MYJSON = {
'username': 'gula_gut',
'pics': '/0/myfavourite.jpeg',
'id': '1'
}
#changing username
MYJSON['username'] = 'calixto'
print(MYJSON['username'])
import json
# some JSON:
json_str = '{ "name":"Sarah", "age":25, "city":"Chicago"}'
# parse json_str:
json = json.loads(json_str)
# get tags from json
tags = []
for tag in json:
tags.append(tag)
# print each tag name e your content
for i in range(len(tags)):
print(tags[i] + ': ' + str(json[tags[i]]))
I did this method for in-depth navigation of a Json
def filter_dict(data: dict, extract):
try:
if isinstance(extract, list):
while extract:
if result := filter_dict(data, extract.pop(0)):
return result
shadow_data = data.copy()
for key in extract.split('.'):
if str(key).isnumeric():
key = int(key)
shadow_data = shadow_data[key]
return shadow_data
except (IndexError, KeyError, AttributeError, TypeError):
return None
filter_dict(wjdata, 'data.current_condition.0.temp_C')
# 10
Using the multiple fields:
filter_dict(wjdata, ['data.current_condition.0.temp_C', 'data.current_condition.1.temp_C']) This working as a OR when take the first element found
# 10
Like other answers have pointed out, the accepted answer to this question seems to ignore the data structure misunderstanding of the original poster.
The main issue seems to be that the original solution treats the JSON purely as a dictionary, when in fact it is a…
dictionary within a list, within a dictionary, within a dictionary
Thus,
['data']
is required to access the top-level key:value pair of the dictionary,
['current_conditions']
accesses the next level of dictionary,
then [0]
must be used to access the first element of the list (which has only 1 element).
Only then can ['temp_C']
be used to access the actual value for that key and retrieve the data.
x={
"data": {
"current_condition":
[{
"cloudcover": "0",
"humidity": "54",
"observation_time": "08:49 AM",
"precipMM": "0.0",
"pressure": "1025",
"temp_C": "10",
"temp_F": "50",
"visibility": "10",
"weatherCode": "113",
"weatherDesc":
[{
"value": "Sunny"
}],
"weatherIconUrl":
[{
"value": "http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0001_sunny.png"
}],
"winddir16Point": "E",
"winddirDegree": "100",
"windspeedKmph": "22",
"windspeedMiles": "14"
},
{
"cloudcover": "0",
"humidity": "54",
"observation_time": "08:49 AM",
"precipMM": "0.0",
"pressure": "1025",
"temp_C": "5",
"temp_F": "50",
"visibility": "10",
"weatherCode": "113",
"weatherDesc":
[{
"value": "Sunny"
}],
"weatherIconUrl":
[{
"value": "http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0001_sunny.png"
}],
"winddir16Point": "E",
"winddirDegree": "100",
"windspeedKmph": "22",
"windspeedMiles": "14"
} ]
}
}
print(x['data']['current_condition'][0]['weatherDesc'][0]['value'])
# results in 'Sunny'
In answer to another question in comments,
"Is there a way to do this without knowing the index, assuming there
were more current condition entries?"
Assuming numerous current_condition
entries it is unlikely that you would just want one value, or if you do then you’ll likely have another piece of information to locate that specific value (i.e. location or something).
Assuming you data set is named x
, i.e. x = {"data": ...}
.
If you want all of the current_condition
entries you can loop through the list (of current_conditions
) using:
y = []
for index in range(0,len(x['data']['current_condition']))
y.append(x['data']['current_condition'][index]['temp_C'])
I am getting the weather information from a URL.
weather = urllib2.urlopen('url')
wjson = weather.read()
and what I am getting is:
{
"data": {
"current_condition": [{
"cloudcover": "0",
"humidity": "54",
"observation_time": "08:49 AM",
"precipMM": "0.0",
"pressure": "1025",
"temp_C": "10",
"temp_F": "50",
"visibility": "10",
"weatherCode": "113",
"weatherDesc": [{
"value": "Sunny"
}],
"weatherIconUrl": [{
"value": "http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0001_sunny.png"
}],
"winddir16Point": "E",
"winddirDegree": "100",
"windspeedKmph": "22",
"windspeedMiles": "14"
}]
}
}
How can I access any element I want?
if I do: print wjson['data']['current_condition']['temp_C']
I am getting error saying:
string indices must be integers, not str.
import json
weather = urllib2.urlopen('url')
wjson = weather.read()
wjdata = json.loads(wjson)
print wjdata['data']['current_condition'][0]['temp_C']
What you get from the url is a json string. And your can’t parse it with index directly.
You should convert it to a dict by json.loads
and then you can parse it with index.
Instead of using .read()
to intermediately save it to memory and then read it to json
, allow json
to load it directly from the file:
wjdata = json.load(urllib2.urlopen('url'))
Here’s an alternative solution using requests:
import requests
wjdata = requests.get('url').json()
print wjdata['data']['current_condition'][0]['temp_C']
‘temp_C’ is a key inside dictionary that is inside a list that is inside a dictionary
This way works:
wjson['data']['current_condition'][0]['temp_C']
>> '10'
Another alternative way using get method with requests:
import requests
wjdata = requests.get('url').json()
print wjdata.get('data').get('current_condition')[0].get('temp_C')
You can do it this way too:
MYJSON = {
'username': 'gula_gut',
'pics': '/0/myfavourite.jpeg',
'id': '1'
}
#changing username
MYJSON['username'] = 'calixto'
print(MYJSON['username'])
import json
# some JSON:
json_str = '{ "name":"Sarah", "age":25, "city":"Chicago"}'
# parse json_str:
json = json.loads(json_str)
# get tags from json
tags = []
for tag in json:
tags.append(tag)
# print each tag name e your content
for i in range(len(tags)):
print(tags[i] + ': ' + str(json[tags[i]]))
I did this method for in-depth navigation of a Json
def filter_dict(data: dict, extract):
try:
if isinstance(extract, list):
while extract:
if result := filter_dict(data, extract.pop(0)):
return result
shadow_data = data.copy()
for key in extract.split('.'):
if str(key).isnumeric():
key = int(key)
shadow_data = shadow_data[key]
return shadow_data
except (IndexError, KeyError, AttributeError, TypeError):
return None
filter_dict(wjdata, 'data.current_condition.0.temp_C')
# 10
Using the multiple fields:
filter_dict(wjdata, ['data.current_condition.0.temp_C', 'data.current_condition.1.temp_C']) This working as a OR when take the first element found
# 10
Like other answers have pointed out, the accepted answer to this question seems to ignore the data structure misunderstanding of the original poster.
The main issue seems to be that the original solution treats the JSON purely as a dictionary, when in fact it is a…
dictionary within a list, within a dictionary, within a dictionary
Thus,
['data']
is required to access the top-level key:value pair of the dictionary,
['current_conditions']
accesses the next level of dictionary,
then [0]
must be used to access the first element of the list (which has only 1 element).
Only then can ['temp_C']
be used to access the actual value for that key and retrieve the data.
x={
"data": {
"current_condition":
[{
"cloudcover": "0",
"humidity": "54",
"observation_time": "08:49 AM",
"precipMM": "0.0",
"pressure": "1025",
"temp_C": "10",
"temp_F": "50",
"visibility": "10",
"weatherCode": "113",
"weatherDesc":
[{
"value": "Sunny"
}],
"weatherIconUrl":
[{
"value": "http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0001_sunny.png"
}],
"winddir16Point": "E",
"winddirDegree": "100",
"windspeedKmph": "22",
"windspeedMiles": "14"
},
{
"cloudcover": "0",
"humidity": "54",
"observation_time": "08:49 AM",
"precipMM": "0.0",
"pressure": "1025",
"temp_C": "5",
"temp_F": "50",
"visibility": "10",
"weatherCode": "113",
"weatherDesc":
[{
"value": "Sunny"
}],
"weatherIconUrl":
[{
"value": "http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0001_sunny.png"
}],
"winddir16Point": "E",
"winddirDegree": "100",
"windspeedKmph": "22",
"windspeedMiles": "14"
} ]
}
}
print(x['data']['current_condition'][0]['weatherDesc'][0]['value'])
# results in 'Sunny'
In answer to another question in comments,
"Is there a way to do this without knowing the index, assuming there
were more current condition entries?"
Assuming numerous current_condition
entries it is unlikely that you would just want one value, or if you do then you’ll likely have another piece of information to locate that specific value (i.e. location or something).
Assuming you data set is named x
, i.e. x = {"data": ...}
.
If you want all of the current_condition
entries you can loop through the list (of current_conditions
) using:
y = []
for index in range(0,len(x['data']['current_condition']))
y.append(x['data']['current_condition'][index]['temp_C'])