1

I'm using in a web application that uses service api generates JSON response. The following part of the function works fine and returns JSON text output:

def get_weather(query = 'london'):
    api_url = "http://api.openweathermap.org/data/2.5/weather?q={}&units=metric&appid=XXXXX****2a6eaf86760c"
    query = urllib.request.quote(query)
    url = api_url.format(query)
    response = urllib.request.urlopen(url)
    data = response.read()    
    return data

The output returned is:

{"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"base":"cmc stations","main":{"temp":12.95,"pressure":1030,"humidity":68,"temp_min":12.95,"temp_max":12.95,"sea_level":1039.93,"grnd_level":1030},"wind":{"speed":5.11,"deg":279.006},"clouds":{"all":76},"dt":1462290955,"sys":{"message":0.0048,"country":"GB","sunrise":1462249610,"sunset":1462303729},"id":2643743,"name":"London","cod":200}

This mean that data is a string, does not it?

However, commenting the return data and then adding the following two lines:

jsonData = json.loads(data)
return jsonData

generates the following error:

TypeError: the JSON object must be str, not 'bytes'

What's wrong? data, the JSON object, previously returned as a string! I need to know where is the mistake?

SaidbakR
  • 13,303
  • 20
  • 101
  • 195

1 Answers1

6

The data returned by request library is a binary string while json.loads accepts strings so you need to convert the data (decode) to a string using the encoding that your request returns (which is usually ok to assume that it is UTF-8).

You should be able to just change your code to this:

return json.loads(data.decode("utf-8"))

PS: Storing the variable right before returning it is redundant so I simplified things

Srdjan Grubor
  • 2,605
  • 15
  • 17
  • It generates this error: `TypeError: 'dict' object is not callable` – SaidbakR May 03 '16 at 17:15
  • Hmm... let me try the code – Srdjan Grubor May 03 '16 at 17:16
  • So testing this seems to work in basic interpreter so you should have a `dict` returned after running the line I've added here. If the caller is expecting just a `str` instead of a `dict`, change it to `return data.decode("utf-8")` but you might have some bigger problems as the error indicates that you're trying to _call_ the returned data (i.e. `get_weather_result()`) – Srdjan Grubor May 03 '16 at 17:24
  • The type error you see is not happening at the `json.loads` but at something you're doing **after** the data is converted into a dict. What are you doing after? Quick test: `>>> def retjson():` `... name = b'{"id": 20}'` `... return json.loads(name.decode('utf-8'))` `... ` `>>> print(retjson())` `{'id': 20}` –  May 03 '16 at 17:27
  • There is nothing after! It is just `return`! @monchitos82 – SaidbakR May 03 '16 at 17:31