Read JSON data from UTF-8 encoded byte string - python

I have a script that sends a JSON UTF-8 encoded Byte string to a socket. (A github project: https://github.com/alios/raildriver). Now I'm writing the python script that needs to read the incoming data. Right now I can receive the data and print it to the terminal. With the following script: https://www.binarytides.com/code-telnet-client-sockets-python/
Output:
data = '{"Current": 117.42609405517578, "Accelerometer": -5.394751071929932, "SpeedometerKPH": 67.12493133544922, "Ammeter": 117.3575210571289, "Amp": 117.35590362548828, "Acceleration": -0.03285316377878189, "TractiveEffort": -5.394751071929932, "Effort": 48.72163772583008, "RawTargetDistance": 3993.927734375, "TargetDistanceBar": 0.9777777791023254, "TargetDistanceDigits100": -1.0, "TargetDistanceDigits1000": -1.0}'
The problem is that I can't find how to read the JSON array. For example read "Ammeter" and return its value 117.357521057289 to a new variable.
All the data is being received in the variable data
The code I have right now:
decodedjson = data.decode('utf-8')
dumpedjson = json.dumps(decodedjson)
loadedjson = json.loads(dumpedjson)
Can you please help me?

You are encoding to JSON then decoding again. SImply not encode, remove the second line:
decodedjson = data.decode('utf-8')
loadedjson = json.loads(decodedjson)
If you are using Python 3.6 or newer, you don't actually have to decode from UTF-8, as the json.loads() function knows how to deal with UTF-encoded JSON data directly. The same applies to Python 2:
loadedjson = json.loads(data)
Demo using Python 3.7:
>>> data = b'{"Current": 117.42609405517578, "Accelerometer": -5.394751071929932, "SpeedometerKPH": 67.12493133544922, "Ammeter": 117.3575210571289, "Amp": 117.35590362548828, "Acceleration": -0.03285316377878189, "TractiveEffort": -5.394751071929932, "Effort": 48.72163772583008, "RawTargetDistance": 3993.927734375, "TargetDistanceBar": 0.9777777791023254, "TargetDistanceDigits100": -1.0, "TargetDistanceDigits1000": -1.0}'
>>> loadedjson = json.loads(data)
>>> loadedjson['Ammeter']
117.3575210571289

Related

why type(JSON) is str in python?

I got some data from an API with requests:
r = requests.get(...)
a = r.text
print(type(a))
str2JSON = json.dumps(a,indent=4)
print(type(str2JSON))
The result is:
class 'str'
class 'str'
Then I try loads instead of dumps:
str2JSON_2 = json.loads(a)
print(type(str2JSON_2))
And I get class list!!!
Why is that behaviour?
If you dump a string into JSON and you don’t get an error, does it automatically mean that the JSON is well parsed? Shouldn't that be a JSON class?
The thing you get back from requests is a str value containing a JSON encoded value.
dumps takes that str and produces another string containing the JSON-encoded version of the original (JSON-encoded) string.
You need loads to decode the string into a value.
json2str = json.loads(a,indent=4) # name change to reflect the direction of the operation
Consider:
>>> s = '"foo"' # A JSON string value
>>> json.dumps(s)
'"\\"foo\\""'
>>> json.loads(s)
'foo'
The string may, of course, encode a value other than a simple string:
>>> json.loads('3') # Compare to json.loads('"3"') returning '3'
3
>>> json.loads('[1,2,3]')
[1,2,3]
>>> json.loads('{"foo": 6}')
{'foo': 6}
requests, though, doesn't actually require you to remember which direction dumps and loads go (although you should make it a point to learn). A Response object has a json method which decodes the text attribute for you.
json2str = r.json() # equivalent to json2str = json.loads(r.text)
you are using requests. it provides convince method to parse your response as json (i.e. it loads it for you) you want a = r.json(). This way a would be JSON object and you can dump it as string later on. That is assuming you get valid json as response.
here is an example
import requests
import json
url = 'https://reqres.in/api/users' # dummy resposnse
resp = requests.get(url)
my_json = resp.json()
#print example user
print(my_json['data'][0])
json_string = json.dumps(my_json, indent=4)
print(json_string)
json.dumps returns a JSON formatted python string object.
Below the is the statement you can notice in actual implementation file for def dumps
"""Serialize obj to a JSON formatted str.

Reading JSON file from S3 with AWS Lambda

First of all, I'm new to AWS so I apologize if the question is very simple or not explained properly.
I'm trying to read a JSON file stored in a S3 bucket with an AWS lambda function.
My main problem is that I am completely unable to extract the information from it.
This is my code:
**
import json
import boto3
def lambda_handler(event, context):
BUCKET = 'BUCKET'
KEY = 'KEY.json'
client = boto3.client('s3')
result = client.get_object(Bucket=BUCKET, Key=KEY)
# Read the object
text = result['Body'].read()#.decode('utf-8')
#convert to string
text_str = str(text)
text_str = text_str.replace('\r\n', '')
print(text_str)
**
If i use decode('utf-8'), I get: "errorMessage": "'utf-8' codec can't decode byte 0xba in position 976: invalid start byte".
If i don't, i get the JSON file but like this:
'{\r\n "id": 0,\r\n "uid": "uid",\r\n "name": "User",\r\n "last": "Candidate"}'
I am stuck here, because the .replace doesn't work and I don't know how to use what i get and access to it as in a standard JSON.
Thank you in advance.
Update: looks like the main problem is that I have ASCii characters like 'á' in the JSON file. Now, I get something like this (I just show a part of the json):
'{"id": 0,"uid": "uid","name": "User","last": "Candidate"}'
I've tried ast.literal_eval to get rid of the '' and access the dictionary, and also json.dumps to try to avoid the problem with the ASCii characters, but nothing has worked.

Python requests module - POST failing - invalid character 'o'

I am trying to convert a raw curl command to use Python Request Module with no luck. This is a simple request to query JBoss Mgmt interface but it does not parse my JSON correctly.
16:34:26,868 DEBUG [org.jboss.as.domain.http.api] (HttpManagementService-threads - 15) Unable to construct ModelNode 'Invalid character: o'
Python version
Python 2.7.6
Working raw cURL command:
/usr/bin/curl --digest -v -L -D - 'http://brenn:!12rori#localhost:9990/management' --header Content-Type:application/json '-d {"operation":"read-attribute","name":"server-state","json.pretty":1}'
In python code i read in my REST/cURL payload like so
import requests
----
def readconfigfile():
with open('jboss_modification.cfg') as f:
lines = f.readlines()
return lines
The config file looks like so
{"operation":"read-attribute","name":"server-state","json.pretty":1}
I convert the str format from readconfigfile() to a dictionary as follows
def converttodictionary(incominglines):
commands = []
for lin in incominglines:
#dumps = json.dumps(lin)
obj = json.loads(lin)
commands.append(obj)
return commands
The python code to execute this request is as follows
def applyconfig(lines):
url="http://localhost:9990/management"
auth=HTTPBasicAuth('brenn', '!12rori')
s = requests.Session()
re=s.get(url, auth=HTTPDigestAuth('brenn', '!12rori')) ##200 RESP
s.headers.update({'Content-Type': 'application/json'})
for line in lines:
payload=line
r=s.post(url,payload)
print(r.text)
Any help much appreciated?
Note: This question has been updated a few times as I resolved other issues....
The issues was...
Initial JSON requestfailed because when i read it from file python interpreted as a str.
Converted to dictionary using json.loads and server accepted request but could not parse the JSON with illegal character error
Converted this json back to a str using json.dumps -- which to my mind looks like what i was trying to do in the first place -- and this now works
read JSON file as per def readconfigfile(): above
convert to json/dictionary as per def converttodictionary above: json.loads(lin)
Convert this json "back" to a string using json.dumps and POST as follows
payload = json.dumps(command)
r = session.post(url, payload,auth=HTTPDigestAuth('brenn', '!12rori')
)

Parse multipart/form-data file in UTF-8

I am parsing a multipart/form input with Python's cgi module:
body_file = StringIO.StringIO(self.request.body)
pdict = {'boundary': 'xYzZY'}
httpbody = cgi.parse_multipart(body_file, pdict)
text = self.trim(httpbody['text'])
and I want to print some elements of httpbody that are the UTF-8 encoded.
I tried text.decode('utf-8') and unicode(text, encoding='utf-8'), but nothing seems to work. Am I missing something here?
Try the following:
text = self.trim(httpbody['text'])
text.encode('utf-8')
I'm assuming the text variable is in string, if not sure str(). Otherwise, you'll get another error thrown at you.

ValueError: need more than 1 value to unpack, PoolManager request

The following code in utils.py
manager = PoolManager()
data = json.dumps(dict) #takes in a python dictionary of json
manager.request("POST", "https://myurlthattakesjson", data)
Gives me ValueError: need more than 1 value to unpack when the server is run. Does this most likely mean that the JSON is incorrect or something else?
Your Json data needs to be URLencoded for it to be POST (or GET) safe.
# import parser
import urllib.parse
manager = PoolManager()
# stringify your data
data = json.dumps(dict) #takes in a python dictionary of json
# base64 encode your data string
encdata = urllib.parse.urlencode(data)
manager.request("POST", "https://myurlthattakesjson", encdata)
I believe in python3 they made some changes that the data needs to be binary. See unable to Post data to a login form using urllib python v3.2.1

Categories