Python parsing Json - "X is None" doesn't catch empty objects - python

I am new to Python and I am trying to parse a Json file using Python.
The Json file is a nested file. While I am trying to exact the "conversation_id" item, the list that contains this item, and the list above sometimes can be empty. I am hoping to replace empty list as string "N/A", otherwise grab the item. Code I am using is as following:
for log in data['logs']:
print("Processing log "+log['log_id'])
logcolumns=[]
if log['request'] is None:
logcolumns.append("N/A")
elif log['request']['context'] is None:
logcolumns.append("N/A")
else:
logcolumns.append(log['request']['context']['conversation_id'])
try:
print("\t".join(logcolumns),file = conv_tsv)
except KeyError:pass
del logcolumns
Traceback error I got is
Processing log cafa1077-f479-4c55-ac34-3bc3ebbb41fc
Traceback (most recent call last):
File "conversation_log_2.py", line 43, in <module>
logcolumns.append(log['request']['context']['conversation_id'])
KeyError: 'conversation_id'
The "request" list that is associated with this log id is shown as below in the json file:
{"request": {"input": {}, "context": {}},
A full request list would be like this:
{"request": {"input": {"text": "haha"}, "context": {"conversation_id": "328d2320-f488-4f46-b71f-6cdfb1b79106", "system": {"dialog_stack": [{"dialog_node_s": "root"}], "dialog_turn_counter": 1, "dialog_request_counter": 1, "_node_output_map_s": "{\"Welcome\":[0,1,0]}", "branch_exited_s": "true", "branch_exited_reason_s": "completed"}}},
When I went to the output file, which is conv.tsv, there is N/A in the output.

You seem to have the syntax quite moodled up. Is the try/except supposed to be wrapping the if/elif? Do you actually want if/elifs?
Note that log['request'] is None does not test that the key's value is an empty dict.
You can use the .get method that returns a default when the key is not found:
logcolumns.append(log.get('request', {}).get('context', {}).get('conversation', 'N/A'))
Or better still, use a try/except to append the default value if any of the keys in missing:
try:
logcolumns.append(log['request']['context']['conversation_id'])
except KeyError:
logcolumns.append('N/A')

Related

How to to access different JSON keys?

I have a JSON file as the following, and I'm trying to access those different keys with Python.
My JSON file format:
{
"spider":[
{
"t":"Spider-Man: No Way Home (2021)",
"u":"movie\/spider-man-no-way-home-2021",
"i":"c2NJbHBJYWNtbW1ibW12Tmptb1JjdndhY05FbXZhS1A"
},
{
"t":"Spider-Man: Far from Home (2019)",
"u":"movie\/spider-man-far-from-home-2019",
"i":"c2NJbHBJYWNtTGNtdm1qbXZtYm1FRWNtcEV4bWJ4bWJteGo"
},
{
"t":"Spider-Man: Homecoming (2017)",
"u":"movie\/spider-man-homecoming-2017",
"i":"c2NJbHBJYWN2TllqbVRibXVjbWJ2d3h2dGNtam1idmM"
},
{
"t":"Spider-Man: Into the Spider-Verse (2018)",
"u":"movie\/spider-man-into-the-spider-verse-2018",
"i":"c2NJbHBJYWNtVEVtdnZjbXZtdm1qRWNtYnhtR1VURXZjY3c"
},
{
"t":"Spider-Man (2002)",
"u":"movie\/spider-man-2002",
"i":"c2NJbHBJYWNtam1ZanZjbWptakVjbXZtdm1oenh2Y3htSQ"
},
{
"t":"The Spiderwick Chronicles (2008)",
"u":"movie\/the-spiderwick-chronicles-2008",
"i":"c2NJbHBJYWNtVG9Oam1qbWJFY21ibWJ2d1BtYm1tbUhj"
}
]
}
How I can access the t, u, and i keys?
I tried:
print(json_file['t'])
Nothing helped with the error:
Traceback (most recent call last):
File "/home/werz/Desktop/trying/programming/nutflix/flask-nutflix/test.py", line 38, in <module>
print (json_file['t'])
KeyError: 't'
Try indexing for printing like
print(json_file["spider"][1]["t"])
You can try for loop to print all
You can use python's builtin JSON module, and iterate through the spider key of your json object.
import json#import the builtin json library
with open('file_path') as file:#open the file
text=f.read()#read the contents of the file
json_data=json.loads(text)#turn the file into a json object
t=[]#List of the t
u=[]#List of the u
i=[]#List of the i
for film in json_data['spider']:#iterate through films
t.append(film['t'])#store the data for these films
u.append(film['u'])
i.append(film['i'])
You can use Json module to load and read json files. Please find the example where i am getting 't' values. Write the same for 'u' and 'i'.
import json
# Opening JSON file
f = open('myJson.json', )
# returns JSON object as a dictionary
data = json.load(f)
# Iterating through the json list
for i in data['spider'][:]:
print(i['t'])
# Closing file
f.close()
Hope this will help. :)

TypeError when trying to get data from JSON

I would like to print specific data in a JSON but I get the following error:
Traceback (most recent call last):
File "script.py", line 47, in <module>
print(link['data.file.url.short'])
TypeError: 'int' object has no attribute '__getitem__'
Here is the JSON:
{
"status":true,
"data":{
"file":{
"url":{
"full":"https://anonfile.com/y000H35fn3/yuh_txt",
"short":"https://anonfile.com/y000H35fn3"
},
"metadata":{
"id":"y000H35fn3",
"name":"yuh.txt",
"size":{
"bytes":0,
"readable":"0 Bytes"
}
}
}
}
}
I'm trying to get data.file.url.short which is the short value of the url
Here is the script in question:
post = os.system('curl -F "file=#' + save_file + '" https://anonfile.com/api/upload')
link = json.loads(str(post))
print(link['data.file.url.short'])
Thanks
Other than os.system() return value mentioned by #John Gordon I think correct syntax to access data.file.url.short is link['data']['file']['url']['short'], since json.loads returns dict.
os.system() does not return the output of the command; it returns the exit status of the command, which is an integer.
If you want to capture the command's output, see this question.
You are capturing the return code of the process created by os.system which is an integer.
Why dont you use the request class in the urllib module to perform that action within python?
import urllib.request
import json
urllib.request.urlretrieve('https://anonfile.com/api/upload', save_file)
json_dict = json.load(save_file)
print(json_dict['data']['file']['url']['short']) # https://anonfile.com/y000H35fn3
Or if you don't need to save the file you can use the requests library:
import requests
json_dict = requests.get('https://anonfile.com/api/upload').json()
print(json_dict['data']['file']['url']['short']) # https://anonfile.com/y000H35fn3

Parse Json if a certain value exists

I need to parse "order" from below JSON , if only value of "success" = 'true' , else raise an exception.
Tried below, but not sure how to include the 'true' check in try:
{
"success":true,
"order":"123345"
}
below is the code , I am trying , which is not giving any result from print as well.
import json
from pprint import pprint
data = json.load(open('data.json'))
#pprint(data)
try:
check_key = data['success']
except KeyError:
#continue
print(check_key)
#print(data['order'])
You should evaluate data['success'] in a condition, whether it is false, then you raise your exception.
import json
data = json.load(open('data.json'))
if data['success'] is not True:
raise Exception("Success is false")
order = data['order']
print(order)
I need to parse "order" from below JSON , if only value of "success" = 'true' , else raise an exception.
There's no function that will automatically raise an exception if a value is False; you need to write that yourself.
But it's dead easy:
check_key = data.get('success')
if not check_key:
raise MyKindOfError(f'response success was {check_key}')
do_stuff(data['order'])
(You don't actually need to use get there; you could let data['success'] raise a KeyError if it's not present, and then separately check the value for falsiness and raise your own error. But I assume you probably want to handle a missing success the same way as false, and the error you want to raise probably isn't KeyError, in which case this is simpler.)
As a side note, you've already parsed the JSON at this point. What you have is a dict.
The fact that it originally came from parsing JSON doesn't make any difference; it's a plain old Python dict, with all the same methods, etc., as any other dict. So, it really isn't helpful to think of "how do I … with JSON …"; that just misleads you into forgetting about how easy dicts are to use.

Exception handling a Key/Attribute Error does not properly configure Tkinter message widget [duplicate]

This question already has answers here:
Catch multiple exceptions in one line (except block)
(6 answers)
Closed 6 years ago.
I am trying to handle a KeyError/AttributeError in my news feed program that parses the Yahoo! Finance RSS API and outputs key data in a Tkinter GUI.
I have excepted the error/s, but when I try to output an error message to the message widget, it does not configure. I know that it excepts the error however as I have coded a simple print message.
MY QUESTION IS: How do I fix the message widget configuration, so that the error message is output to it, as right now, nothing occurs.
Any advice or criticism to what I am doing wrong would be great.
Thank you for your time, here is my code:
def parse_company_feed(news_feed_message, rss_url):
''' This function parses the Yahoo! RSS API for data of the latest five articles, and writes it to the company news text file'''
# Define the RSS feed to parse from, as the url passed in of the company the user chose
feed = feedparser.parse(rss_url)
try:
# Define the file to write the news data to the company news text file
with open('C:\\Users\\nicks_000\\PycharmProjects\\untitled\\SAT\\GUI\\Text Files\\companyNews.txt', mode='w') as outFile:
# Create a list to store the news data parsed from the Yahoo! RSS
news_data_write = []
# Initialise a count
count = 0
news_data_write.append((feed['feed']['description'])+'\n')
# For the number of articles to append to the file, append the article's title, link, and published date to the news_elements list
for count in range(10):
news_data_write.append(feed['entries'][count].title)
news_data_write.append(feed['entries'][count].published)
article_link = (feed['entries'][count].link)
article_link = article_link.split('*')[1]
news_data_write.append(article_link)
# Add one to the count, so that the next article is parsed
count+=1
# For each item in the news_elements list, convert it to a string and write it to the company news text file
for item in news_data_write:
item = str(item)
outFile.write(item+'\n')
# For each article, write a new line to the company news text file, so that each article's data is on its own line
outFile.write('\n')
# Clear the news_elements list so that data is not written to the file more than once
del(news_data_write[:])
except KeyError and AttributeError:
news_feed_message.configure(text = 'That company does not exist. Please enter another ticker.')
print('nah m8, no feed')
else:
outFile.close()
read_news_file(news_feed_message)
The syntax you are using is wrong. It should be:
except (KeyError, AttributeError):
not:
except KeyError and AttributeError: # <- wrong!
As you can see if you try to run this code:
>>> try:
... raise KeyError
... except (KeyError,AttributeError):
... print('raised')
...
raised
>>> try:
... raise KeyError
... except KeyError and AttributeError:
... print('raised')
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyError
In the second case what happens is that the expression KeyError and AttributeError is evaluated. And the result is:
>>> KeyError and AttributeError
<class 'AttributeError'>
because both KeyError and AttributeError are truthy values, and and returns the last truthy value it finds when the result is true (the first false one if the result is false). So basically that except statement is equivalent to just using except AttributeError:.

How to avoid or skip error 400 in python while calling the API

Note:- I have written my code after referring to few examples in stack overflow but still could not get the required output
I have a python script in which loop iterates with an Instagram API. I give the user_id as an input to the API which gets the no of posts, no of followers and no of following. Each time it gets a response, I load it into a JSON schema and append to lists data1, data2 and data3.
The issue is:= Some accounts are private accounts and the API call is not allowed to it. When I run the script in IDLE Python shell, its gives the error
Traceback (most recent call last):
File "<pyshell#144>", line 18, in <module>
beta=json.load(url)
File "C:\Users\rnair\AppData\Local\Programs\Python\Python35\lib\site- packages\simplejson-3.8.2-py3.5-win-amd64.egg\simplejson\__init__.py", line 455, in load
return loads(fp.read(),
File "C:\Users\rnair\AppData\Local\Programs\Python\Python35\lib\tempfile.py", line 483, in func_wrapper
return func(*args, **kwargs)
**ValueError: read of closed file**
But the JSON contains this:-
{
"meta": {
"error_type": "APINotAllowedError",
"code": 400,
"error_message": "you cannot view this resource"
}
}
My code is:-
for r in range(307,601):
var=r,sheet.cell(row=r,column=2).value
xy=var[1]
ij=str(xy)
if xy=="Account Deleted":
data1.append('null')
data2.append('null')
data3.append('null')
continue
myopener=Myopen()
try:
url=myopener.open('https://api.instagram.com/v1/users/'+ij+'/?access_token=641567093.1fb234f.a0ffbe574e844e1c818145097050cf33')
except urllib.error.HTTPError as e: // I want the change here
data1.append('Private Account')
data2.append('Private Account')
data3.append('Private Account')
continue
beta=json.load(url)
item=beta['data']['counts']
data1.append(item['media'])
data2.append(item['followed_by'])
data3.append(item['follows'])
I am using Python version 3.5.2. The main question is If the loop runs and a particular call is blocked and getting this error, how to avoid it and keep running the next iterations? Also, if the account is private, I want to append "Private account" to the lists.
Looks like the code that is actually fetching the URL is within your custom type - "Myopen" (which is not shown). It also looks like its not throwing the HTTPError you are expecting since your "json.load" line is still being executed (and leading to the ValueError that is being thrown).
If you want your error handling block to fire, you would need to check the response status code to see if its != 200 within Myopen and throw the HTTPError you are expecting instead of whatever its doing now.
I'm not personally familiar with FancyURLOpener, but it looks like it supports a getcode method. Maybe try something like this instead of expecting an HTTPError:
url = myopener.open('yoururl')
if url.getcode() == 400:
data1.append('Private Account')
data2.append('Private Account')
data3.append('Private Account')
continue

Categories