Good afternoon.
I'm getting json from a provider, but for some reason it converts the data to a list format, not a dict
Provider return json
def bal(number, token):
headers = {
'Authorization': 'Bearer ' + token,
'Accept': 'application/json'
}
response = requests.get('https://api.provider.com/idS' + number, headers=headers)
return response.json()
# parsing json
def parce_bal(jsonnn):
f = json.dumps(jsonnn)
f = json.loads(f)
#for key,value in f.item():
# if key is 'accountNo':
# out_date = value
out_date = type(f)
return out_date
balance_json = balance(numberPhone, token)
f = parce_balane(balance_json)
PS W:\Python\MTS> & W:/Python/P3.10/python.exe w:/Python/Mobile/main.py <class 'list'>
Often you can guess the kind of response you will obtain by looking at the name of the endpoint.
Here you hit the endpoint https://api.provider.com/idS.
With S at the end for plural.
In this case you're likely to expect a response with many items, returned as a JSON Array.
Related
How can the JSON output be formatting in a way that doesn't include the \n text, and instead shows these as new lines as intended? This is what the saved output file looks like:
But, this is how it looks when I use print, which is what it should look like:
import requests
import json
def get_all_time_entries():
url_address = "***"
headers = {
"Authorization": "***",
"api-version": "2020-01-31"
}
# find out total number of pages
r = requests.get(url=url_address, headers=headers).json()
total_pages = 605
# results will be appended to this list
all_time_entries = []
# loop through all pages and return JSON object
for page in range(1, total_pages):
url = "***"+str(page)
response = requests.get(url=url, headers=headers).json()
all_time_entries.append(response)
page += 1
# prettify JSON
data = json.dumps(all_time_entries, sort_keys=True, indent=4)
return data
#print(get_all_time_entries())
with open('appointmentsHistory.json', 'w', encoding='utf-8') as f:
# note that I use dump method, not dumps
json.dump(get_all_time_entries(), f, sort_keys=True, indent=4)
json.dumps() transforms the data dictionary into a string, and then json.dump() writes the JSON representation of that string to the file.
To resolve, remove json.dumps() from the get_all_time_entries() method. json.dump() will take the dictionary in directly and transform it into a JSON string for you.
import requests
import json
def get_all_time_entries():
url_address = "***"
headers = {
"Authorization": "***",
"api-version": "2020-01-31"
}
# find out total number of pages
r = requests.get(url=url_address, headers=headers).json()
total_pages = 605
# results will be appended to this list
all_time_entries = []
# loop through all pages and return JSON object
for page in range(1, total_pages):
url = "***"+str(page)
response = requests.get(url=url, headers=headers).json()
all_time_entries.append(response)
page += 1
return data
with open('appointmentsHistory.json', 'w', encoding='utf-8') as f:
# note that I use dump method, not dumps
json.dump(get_all_time_entries(), f, sort_keys=True, indent=4)
json.dump() takes an object, you seem to be passing it a JSON-like string.
I am working with an API to pull back data using python. My functions work fine but I feel like I am repeating myself over and over again and there is probably something I should be doing to make this more efficient.
What each one does is gets the number of results then hits the api back up to bring back the exact number of records.
First function:
def get_categories():
headers = {"Authorization": "Bearer " + access_token} # auth plus token
response = requests.get("https://api.destination.com/categories", headers=headers) # response
data = json.loads(response.text) # load the json data
records = str(data['totalResults']) # get number of results for next call
response = requests.get("https://api.destination.com/categories?$skip=0&$top="+records, headers=headers)
all_data = json.loads(response.text) # load the json data
list_of_dict = all_data['resources'] # get rid of all but lists of dictionaries
df = pd.DataFrame.from_records(list_of_dict) # create dataframe
df['links'] = df['links'].str[0].str['href'] # just grab the links(key) items
return df # return the final dataframe
Second function:
def get_groups():
headers = {"Authorization": "Bearer " + access_token} # auth plus token
response = requests.get("https://api.destination.com/groups", headers=headers) # response
data = json.loads(response.text) # load the json data
records = str(data['totalResults']) # get number of results
response = requests.get("https://api.destination.com/groups?$skip=0&$top="+records, headers=headers)
all_data = json.loads(response.text) # load the json data
list_of_dict = all_data['resources'] # get rid of all but lists of dictionaries
df = pd.DataFrame.from_records(list_of_dict) # create dataframe
df['links'] = df['links'].str[0].str['href'] # just grab the links(key) items
return df # return the final dataframe
And 3 more functions like users that do the same thing. The only difference between them as you can see is the getlike https://api.destination.com/categories vs https://api.destination.com/groups and the number of records returned for each will be different. Is there a way to combine these and call it a certain way?
Looks like you already know how to make functions, just extend it one step further to abstract away everything that is common amongst the functions.
BASE_URL = "https://api.destination.com/{}"
def make_headers():
headers = {"Authorization": "Bearer " + access_token}
return headers
def make_params(recs):
params = {'$skip': 0, '$top': recs}
return params
def make_df(data):
list_of_dict = data['resources']
df = pd.DataFrame.from_records(list_of_dict)
df['links'] = df['links'].str[0].str['href']
return df
def process(process):
headers = make_headers()
url = BASE_URL.format(process)
resp = requests.get(url, headers=headers)
data = resp.json()
records = data['totalResults']
params = make_params(records)
resp = requests.get(url, headers=headers, params=params)
all_data = resp.json()
return make_df(all_data)
Then you can call it like the following:
process('groups')
process('categories')
You can break it up further, but you get the idea.
You can just add a parameter to this function.
As an example:
def get_categories():
headers = {"Authorization": "Bearer " + access_token} # auth plus token
response = requests.get("https://api.destination.com/categories", headers=headers) # response
data = json.loads(response.text) # load the json data
records = str(data['totalResults']) # get number of results for next call
response = requests.get("https://api.destination.com/categories?$skip=0&$top="+records, headers=headers)
all_data = json.loads(response.text) # load the json data
list_of_dict = all_data['resources'] # get rid of all but lists of dictionaries
df = pd.DataFrame.from_records(list_of_dict) # create dataframe
df['links'] = df['links'].str[0].str['href'] # just grab the links(key) items
return df # return the final dataframe
You can just refactor to:
def get_elements(element):
if element is None:
return 'not found' #defaults to 404 error.
headers = {"Authorization": "Bearer " + access_token} # auth plus token
response = requests.get("https://api.destination.com/{}".format(element), headers=headers) # response
data = json.loads(response.text) # load the json data
records = str(data['totalResults']) # get number of results for next call
response = requests.get("https://api.destination.com/{}?$skip=0&$top={}".format(element,records), headers=headers)
all_data = json.loads(response.text) # load the json data
list_of_dict = all_data['resources'] # get rid of all but lists of dictionaries
df = pd.DataFrame.from_records(list_of_dict) # create dataframe
df['links'] = df['links'].str[0].str['href'] # just grab the links(key) items
return df # return the final dataframe
I have python dictionary class that is generated from API call returning below result
{'url': 'https://propertypro.zendesk.com/api/v2/tickets/4249.json',
'id': 4249,
'external_id': None}
{'url': 'https://propertypro.zendesk.com/api/v2/tickets/4089.json',
'id': 4089,
'external_id': None}
the code as follow;
from urllib.parse import urlencode
import requests
credentials = 'some email', 'some password'
session = requests.Session()
session.auth = credentials
params = {
'query': 'type:ticket tags:test_python',
'sort_order': 'asc'
}
url = 'https://propertypro.zendesk.com/api/v2/search.json?' + urlencode(params)
response = session.get(url)
if response.status_code != 200:
print('Status:', response.status_code,
'Problem with the request. Exiting.')
exit()
# Print the subject of each ticket in the results
data = response.json()
I iterate the data in order to get all values from key 'id' to be assigned to variable id_merged as String with comma separated
for result in data['results']:
# Ticket to update
id_merged = (result['id'])
but get only one result instead of 2, the var gets overwritten in the loop?
from test_search import data
import json
import requests
# Iterate the search result
for result in data['results']:
# Ticket to update
id_merged = (result['id'])
print("**Start**")
print(id)
body = 'Test ticket'
# Package the data in a dictionary matching the expected JSON
data_comment = {'ticket': {'comment': {'body': body}}}
# Encode the data to create a JSON payload
payload = json.dumps(data_comment)
# Set the request parameters
url = 'https://propertypro.zendesk.com/api/v2/tickets/update_many.json?' + \
'ids=' + str(id_merged)
user = 'some email'
pwd = 'some password'
headers = {'content-type': 'application/json'}
# Do the HTTP put request
response = requests.put(url, data=payload,
auth=(user, pwd), headers=headers)
# Check for HTTP codes other than 200
if response.status_code != 200:
print('Status:', response.status_code,
'Problem with the request. Exiting.')
exit()
# Report success
print('Successfully added comment to ticket #{}'.format(id))
I'd like to get a result like 'https://propertypro.zendesk.com/api/v2/tickets/update_many.json?' + \
'ids=' + 4249,4089 .
How do I get this?
If you want to turn the values of id into a comma delimited string, you can do the following.
','.join(id.values())
So change your code to
url = 'str,' + 'str1:' + ','.join(id.values())
For completeness, if you wanted to do the same thing with the dictionary keys, you'd just use
','.join(id)
Looks like you are getting list of list in dict values, in that case you can flatten the list and join on string "," like:
>>> import itertools
>>> ",".join(map(str, list(itertools.chain(*[[1,2,3],[4,5]]))))
'1,2,3,4,5'
I have a query to an job board API using Python Requests. It then writes to a table, that is included in a web page. Sometimes the request will return no data(if there are no open jobs). If so, I want to write a string to the included file instead of the table. What is the best way to identify a response of no data? Is it as simple as: if response = "", or something along those lines?
Here is my Python code making the API request:
#!/usr/bin/python
import requests
import json
from datetime import datetime
import dateutil.parser
url = "https://data.usajobs.gov/api/Search"
querystring = {"Organization":"LF00","WhoMayApply":"All"}
headers = {
'authorization-key': "ZQbNd1iLrQ+rPN3Rj2Q9gDy2Qpi/3haXSXGuHbP1SRk=",
'user-agent': "jcarroll#fec.gov",
'host': "data.usajobs.gov",
'cache-control': "no-cache",
}
response = requests.request("GET", url, headers=headers, params=querystring)
responses=response.json()
with open('/Users/jcarroll/work/infoweb_branch4/rep_infoweb/trunk/fec_jobs.html', 'w') as jobtable:
jobtable.write("Content-Type: text/html\n\n")
table_head="""<table class="job_table" style="border:#000">
<tbody>
<tr>
<th>Vacancy</th>
<th>Grade</th>
<th>Open Period</th>
<th>Who May Apply</th>
</tr>"""
jobtable.write(table_head)
for i in responses['SearchResult']['SearchResultItems']:
start_date = dateutil.parser.parse(i['MatchedObjectDescriptor']['PositionStartDate'])
end_date = dateutil.parser.parse(i['MatchedObjectDescriptor']['PositionEndDate'])
jobtable.write("<tr><td><strong><a href='" + i['MatchedObjectDescriptor']['PositionURI'] + "'>" + i['MatchedObjectDescriptor']['PositionID'] + ", " + i['MatchedObjectDescriptor']['PositionTitle'] + "</a></strong></td><td>" + i['MatchedObjectDescriptor']['JobGrade'][0]['Code'] + "-" + i['MatchedObjectDescriptor']['UserArea']['Details']['LowGrade']+ " - " + i['MatchedObjectDescriptor']['UserArea']['Details']['HighGrade'] + "</td><td>" + start_date.strftime('%b %d, %Y')+ " - " + end_date.strftime('%b %d, %Y')+ "</td><td>" + i['MatchedObjectDescriptor']['UserArea']['Details']['WhoMayApply']['Name'] + "</td></tr>")
jobtable.write("</tbody></table>")
jobtable.close
You have a couple of options depending on what the response actually is. I assume, case 3 applies best:
# 1. Test if response body contains sth.
if response.text: # body as str
# ...
# body = response.content: # body as bytes, useful for binary data
# 2. Handle error if deserialization fails (because of no text or bad format)
try:
json_data = response.json()
# ...
except ValueError:
# no JSON returned
# 3. check that .json() did NOT return an empty dict/list
if json_data:
# ...
# 4. safeguard against malformed/unexpected data structure
try:
data_point = json_data[some_key][some_index][...][...]
except (KeyError, IndexError, TypeError):
# data does not have the inner structure you expect
# 5. check if data_point is actually something useful (truthy in this example)
if data_point:
# ...
else:
# data_point is falsy ([], {}, None, 0, '', ...)
If your APIs has been written with correct status codes, then
200 means successful response with a body
204 means successful response without body.
In python you can check your requirement as simply as the following
if 204 == response.status_code :
# do something awesome
I'm trying to send a string array to the bing translate api, which I have received and encoded as UTF-8.
However, when I make the call with the variable the service spits out an error:
"There was an error deserializing the object of type System.String[]. Encountered unexpected character 'ï'."
If I manually add the string array as a string not within a variable, it works. I'm using the Requests module, so I'm thinking it's encoding the url... I have no idea.
class getLanguages(apiFunctions):
def GET(self):
#get the access token
data = self.accessToken()
token = data['access_token']
codes = self.getCodes(token)
languageNames = self.getLanguageNames(token,codes)
codesList = ast.literal_eval(codes)
return languageNames + codes
def getCodes(self,token):
url = 'http://api.microsofttranslator.com/V2/Ajax.svc/GetLanguagesForTranslate'
auth_header = {'Authorization': 'Bearer ' + token}
r = requests.get(url, headers=auth_header)
return r.text.encode('utf-8')
def getLanguageNames(self,token,codes):
url = 'http://api.microsofttranslator.com/V2/Ajax.svc/GetLanguageNames'
#this is where I add the language codes string to the query
payload = {'locale': 'en', 'languageCodes': codes}
auth_header = {'Authorization': 'Bearer ' + token}
r = requests.post(url, params=payload, headers=auth_header)
return r.text.encode('utf-8')
And this is the string:
["ar","bg","ca","zh-CHS","zh-CHT","cs","da","nl","en","et","fi","fr","de","el","ht","he","hi","mww","hu","id","it","ja","tlh","tlh-Qaak","ko","lv","lt","ms","mt","no","fa","pl","pt","ro","ru","sk","sl","es","sv","th","tr","uk","ur","vi","cy"]