How to parse through JSON object in Python

5.1k views Asked by At

I know there are tons of this exact question on here but I can't find an answer.

I'm trying to use the Google Maps API for Geocoding to go through a list of sloppy addresses, and get formatted addresses.

I have this exact code from the Google documentation:

import urllib2

address="1600+Amphitheatre+Parkway,+Mountain+View,+CA"
url="https://maps.googleapis.com/maps/api/geocode/json?address=%s" % address

response = urllib2.urlopen(url)
jsongeocode = response.read()

It then says that jsongeocode is a JSON object. However, from what I've gathered from looking online is that this IS NOT a JSON object yet. If i'm wrong here and it is a JSON object, how do I parse it?

If I call print(jsongeocode) it prints what appears to be a JSON object with the proper attributes in my terminal.

So I try to convert the jsongeocode object to a JSON object:

jdata = json.load(jsongeocode)

This gives me this error:

AttributeError: 'bytes' object has no attribute 'read'

EDIT

I've switched the json function call to jdata = json.loads(jsongeocode), but now the error I get is this:

TypeError: The JSON Object must be str, not 'bytes'
3

There are 3 answers

0
mhawke On BEST ANSWER

Your code works fine in Python 2. You just need to parse the JSON string returned by the API using json.loads(jsongeocode).

The error message TypeError: The JSON Object must be str, not 'bytes' suggests to me that you are using Python 3. However, you are importing the urllib2 module which is only present in Python 2. I'm not sure how you achieved that. Anyway, assuming Python 3:

import json
from urllib.request import urlopen

address="1600+Amphitheatre+Parkway,+Mountain+View,+CA"
url="https://maps.googleapis.com/maps/api/geocode/json?address=%s" % address
response = urlopen(url)
json_byte_string = response.read()

>>> type(json_byte_string)
<class 'bytes'>
>>> jdata = json.loads(json_byte_string)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.4/json/__init__.py", line 312, in loads
    s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'

So there is the exception that you have seen. The response contained in json_byte_string is a byte string - it is of class bytes, however, in Python 3 json.loads() expects a str which is a Unicode string. So you need to convert json_byte_string from a byte string to Unicode. To do that requires that you know the encoding of the byte string. Here I use UTF8 because that is what was specified in the Content-Type response header:

>>> response.headers['Content-Type']
'application/json; charset=UTF-8'

>>> json_string = str(json_byte_string, 'utf8')
>>> type(json_string)
<class 'str'>

Now it can be passed to json.loads():

>>> jdata = json.loads(json_string)
>>> jdata
{'results': [{'types': ['street_address'], 'address_components': [{'types': ['street_number'], 'long_name': '1600', 'short_name': '1600'}, {'types': ['route'], 'long_name': 'Amphitheatre Parkway', 'short_name': 'Amphitheatre Pkwy'}, {'types': ['locality', 'political'], 'long_name': 'Mountain View', 'short_name': 'Mountain View'}, {'types': ['administrative_area_level_2', 'political'], 'long_name': 'Santa Clara County', 'short_name': 'Santa Clara County'}, {'types': ['administrative_area_level_1', 'political'], 'long_name': 'California', 'short_name': 'CA'}, {'types': ['country', 'political'], 'long_name': 'United States', 'short_name': 'US'}, {'types': ['postal_code'], 'long_name': '94043', 'short_name': '94043'}], 'formatted_address': '1600 Amphitheatre Parkway, Mountain View, CA 94043, USA', 'geometry': {'location_type': 'ROOFTOP', 'viewport': {'northeast': {'lng': -122.0828811197085, 'lat': 37.4236854802915}, 'southwest': {'lng': -122.0855790802915, 'lat': 37.4209875197085}}, 'location': {'lng': -122.0842301, 'lat': 37.4223365}}, 'place_id': 'ChIJ2eUgeAK6j4ARbn5u_wAGqWA'}], 'status': 'OK'}

And there you have the decoded JSON string as a dictionary. The formatted address is available as:

>>> jdata['results'][0]['formatted_address']
'1600 Amphitheatre Parkway, Mountain View, CA 94043, USA'

There is a better way to do this: use requests:

import requests

address="1600+Amphitheatre+Parkway,+Mountain+View,+CA"
url="https://maps.googleapis.com/maps/api/geocode/json?address=%s" % address

r = requests.get(url)
jdata = r.json()

>>> jdata['results'][0]['formatted_address']
'1600 Amphitheatre Parkway, Mountain View, CA 94043, USA'

Much better!

4
Geotob On

use

jsongeocode = str(response.read())
jdata = json.loads(jsongeocode)

json.load() is for file-like objects, as described here: https://docs.python.org/2/library/json.html#json.load

0
jeff.yu On
this is my jsongeocode:

 {
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "1600",
               "short_name" : "1600",
               "types" : [ "street_number" ]
            },
            {
               "long_name" : "Amphitheatre Parkway",
               "short_name" : "Amphitheatre Pkwy",
               "types" : [ "route" ]
            },
            {
               "long_name" : "Mountain View",
               "short_name" : "Mountain View",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Santa Clara County",
               "short_name" : "Santa Clara County",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "California",
               "short_name" : "CA",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "United States",
               "short_name" : "US",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "94043",
               "short_name" : "94043",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA",
         "geometry" : {
            "location" : {
               "lat" : 37.4223365,
               "lng" : -122.0842301
            },
            "location_type" : "ROOFTOP",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.4236854802915,
                  "lng" : -122.0828811197085
               },
               "southwest" : {
                  "lat" : 37.4209875197085,
                  "lng" : -122.0855790802915
               }
            }
         },
         "place_id" : "ChIJ2eUgeAK6j4ARbn5u_wAGqWA",
         "types" : [ "street_address" ]
      }
   ],
   "status" : "OK"
}

you can find the difference

by the way: you can send http request use Requests module like that:

import requests

address="1600+Amphitheatre+Parkway,+Mountain+View,+CA"
url="https://maps.googleapis.com/maps/api/geocode/json?address=%s" % address

response = requests.get(url)
jsongeocode = response.text