Python Requests - POST file with additional paramas - python

So I have this code that send API request to upload a file to a server, after searching the web I came up with something like that where 'payload' is additional params I need to send and 'files' is a path to the file I want to upload :
def sendAPIRequest2(self, env, object, method, params, files):
apiPath = "/api/secure/jsonws"
headers = {'content-type': 'multipart/form-data'}
url = env + apiPath + object
payload = {
"method": method,
"params": params,
"jsonrpc": "2.0"
}
data = json.dumps(payload)
myFile = {'file': open(files,'rb')}
try:
r = requests.post(url, files=myFile, data=data, headers=headers,
auth=HTTPBasicAuth(self.user, self.password), verify=False)
print r.text
resjson = json.loads(r.text)
except:
print "no Valid JSON has returned from"+object+" API"
sys.exit(1)
return resjson
I get:
ValueError: Data must not be a string.
What am I doing wrong?

Related

Trying to Retrieve Report from Amazon Ads API

I am trying to retrieve a report that I generated, and shows a 'status' of 'successful'.
When I run the script below, I receive a 200 response. However, per the docs:
"A successful call returns a 307 redirect response. The redirect link points you to the S3 bucket where you can download your report file. The report file downloads as JSON compressed in gzip format."
headers = {
'Amazon-Advertising-API-ClientId': clientid,
'Authorization': access,
'Amazon-Advertising-API-Scope':scope,
'Content-Type':'application/json'
}
response = requests.get(
'https://advertising-api.amazon.com/v1/reports/amzn1.clicksAPI.v1.p1.624466CD.4b8dcbb2-bbc6-4936-a760-c632216a4a5e/download',
headers = headers
)
print(response.json)
response:
<bound method Response.json of <Response [200]
import gzip # unzip compressed file
import io # read binary
import requests
import pandas as pd
headers = {
"Authorization": f"Bearer {access_code}",
"Amazon-Advertising-API-Scope": profile_id,
"Amazon-Advertising-API-ClientId": client_id
}
response = requests.get(report_url, headers=headers)
if response.ok:
json_resp = response.json()
status = json_resp['status']
if status == 'IN_PROGRESS':
# check again
elif status == 'SUCCESS':
# initiate download
location = json_resp['location']
dl_response = requests.get(location, headers=headers, allow_redirects=True)
if dl_response.ok:
compressed_file = io.BytesIO(response.content) # extract .gz file
decompressed_file = gzip.GzipFile(fileobj=compressed_file) # unzip .gz file
output = pd.read_json(decompressed_file)
elif status == 'FAILURE':
# failure response

"Bad Gateway" error using Python requests module with multipart encoded file POST

I am getting the error message "Bad Gateway
The proxy server received an invalid
response from an upstream server" with the following code:
import requests
url = "https://apis.company.com/v3/media"
attachments = 'media': ('x.mp3', open('x.mp3', 'r'))}
headers = {'content-type': "multipart/form-data",'cache-control': "no-cache"
'Authorization':"Bearer zzz" }
response = requests.post(url, files=attachments, headers = headers)
print response.text
I'm following the example in the requests Quickstart documentation, where it says "You can also pass a list of tuples to the data argument": http://docs.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file
What is causing this error and how can I fix it?
The main problem was that I set the content-type in the header. This code works:
import requests
url = 'https://apis.company.com/v3/media'
token = 'token-goes-here'
headers = { 'Authorization' : 'Bearer ' + token }
filename = 'x.mp3'
with open(filename, 'rb') as media_file:
attachments = {
'media': (filename, media_file, 'application/octet-stream')
}
response = requests.post(url, files = attachments, headers = headers)
print response.text

Python - Microsoft Cognitive Verify API (params)

I'm trying to use the Microsoft Cognitive Verify API with python 2.7: https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f3039523a
The code is:
import httplib, urllib, base64
headers = {
# Request headers
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': 'my key',
}
params = '{\'faceId1\': \'URL.jpg\',\'faceId2\': \'URL.jpg.jpg\'}'
try:
conn = httplib.HTTPSConnection('api.projectoxford.ai')
conn.request("POST", "/face/v1.0/verify?%s" % params, "{body}", headers)
response = conn.getresponse()
data = response.read()
print(data)
conn.close()
except Exception as e:
print("[Errno {0}] {1}".format(e.errno, e.strerror))
I tried letting the conn.request line like this:
conn.request("POST", "/face/v1.0/verify?%s" % params, "", headers)
The error is:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request</h2>
<hr><p>HTTP Error 400. The request is badly formed.</p>
</BODY></HTML>
I alrealy tried to follow and make work the following codes:
https://github.com/Microsoft/Cognitive-Emotion-Python/blob/master/Jupyter%20Notebook/Emotion%20Analysis%20Example.ipynb
Using Project Oxford's Emotion API
However I just can't make this one work. I guess there is something wrong with the params or body argument.
Any help is very appreciated.
You can refer to this question.
Obviously you did not understand the code. "{body}" means you should replace it with your body which contains your request url, just like the site says:
So you can use this api this way:
body = {
"url": "http://example.com/1.jpg"
}
…………
conn = httplib.HTTPSConnection('api.projectoxford.ai')
conn.request("POST", "/face/v1.0/detect?%s" % params, str(body), headers)
Dawid's comment looks like it should fix it (double quoting), try this for python 2.7:
import requests
url = "https://api.projectoxford.ai/face/v1.0/verify"
payload = "{\n \"faceId1\":\"A Face ID\",\n \"faceId2\":\"A Face ID\"\n}"
headers = {
'ocp-apim-subscription-key': "KEY_HERE",
'content-type': "application/json"
}
response = requests.request("POST", url, data=payload, headers=headers)
print(response.text)
for python 3:
import http.client
conn = http.client.HTTPSConnection("api.projectoxford.ai")
payload = "{\n\"faceId1\": \"A Face ID\",\n\"faceId2\": \"Another Face ID\"\n}"
headers = {
'ocp-apim-subscription-key': "keyHere",
'content-type': "application/json"
}
conn.request("POST", "/face/v1.0/verify", payload, headers)
res = conn.getresponse()
data = res.read()
There are a couple issues with your script:
You must pass face Ids and not URLs or file objects to the REST API.
You must correctly formulate the HTTP request.
However, you may find it easier to use the Python API and not the REST API. For example, once you have the face ids, you can just run result = CF.face.verify(faceid1, another_face_id=faceid2) instead of worrying about setting up the correct POST request.
You will probably need to install cognitive_face with pip. I use this API to get the face Ids for some bonus instruction.
To make this simpler, let's assume you have img1.jpg and img2.jpg on disk.
Here is an example using the REST API:
import cognitive_face as CF
from io import BytesIO
import json
import http.client
# Setup
KEY = "your subscription key"
# Get Face Ids
def get_face_id(img_file):
f = open(img_file, 'rb')
data = f.read()
f.close()
faces = CF.face.detect(BytesIO(data))
if len(faces) != 1:
raise RuntimeError('Too many faces!')
face_id = faces[0]['faceId']
return face_id
# Initialize API
CF.Key.set(KEY)
faceId1 = get_face_id('img1.jpg')
faceId2 = get_face_id('img2.jpg')
# Now that we have face ids, we can setup our request
headers = {
# Request headers
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': KEY
}
params = {
'faceId1': faceId1,
'faceId2': faceId2
}
# The Content-Type in the header specifies that the body will
# be json so convert params to json
json_body = json.dumps(params)
try:
conn = httplib.HTTPSConnection('https://eastus.api.cognitive.microsoft.com')
conn.request("POST", "/face/v1.0/verify", body=json_body, headers=headers)
response = conn.getresponse()
data = response.read()
data = json.loads(data)
print(data)
conn.close()
except Exception as e:
print("[Errno {0}] {1}".format(e.errno, e.strerror))

Response' object is not subscriptable Python http post request

I am trying to post a HTTP request. I have managed to get the code to work but I am struggling returning some of the result.
The result looks like this
{
"requestId" : "8317cgs1e1-36hd42-43h6be-br34r2-c70a6ege3fs5sbh",
"numberOfRequests" : 1893
}
I am trying to get the requestId but I keep getting the error Response' object is not subscriptable
import json
import requests
workingFile = 'D:\\test.json'
with open(workingFile, 'r') as fh:
data = json.load(fh)
url = 'http://jsontest'
username = 'user'
password = 'password123'
requestpost = requests.post(url, json=data, auth=(username, password))
print(requestpost["requestId"])
The response object contains much more information than just the payload. To get the JSON data returned by the POST request, you'll have to access response.json() as described in the example:
requestpost = requests.post(url, json=data, auth=(username, password))
response_data = requestpost.json()
print(response_data["requestId"])
You should convert your response to a dict:
requestpost = requests.post(url, json=data, auth=(username, password))
res = requestpost.json()
print(res["requestId"])
the response is not readable so you need to convert that into a readable format,
I was using python http.client
conn = http.client.HTTPConnection('localhost', 5000)
payload = json.dumps({'username': "username", 'password': "password"})
headers = {'Content-Type': 'application/json'}
conn.request('POST', '/api/user/register', payload, headers)
response = conn.getresponse()
print("JSON - ", response.read())
and for request, you can see the answers above
sometimes you have to use json.loads() function to convert the appropriate format.

Python Requests: Post JSON and file in single request

I need to do a API call to upload a file along with a JSON string with details about the file.
I am trying to use the python requests lib to do this:
import requests
info = {
'var1' : 'this',
'var2' : 'that',
}
data = json.dumps({
'token' : auth_token,
'info' : info,
})
headers = {'Content-type': 'multipart/form-data'}
files = {'document': open('file_name.pdf', 'rb')}
r = requests.post(url, files=files, data=data, headers=headers)
This throws the following error:
raise ValueError("Data must not be a string.")
ValueError: Data must not be a string
If I remove the 'files' from the request, it works.
If I remove the 'data' from the request, it works.
If I do not encode data as JSON it works.
For this reason I think the error is to do with sending JSON data and files in the same request.
Any ideas on how to get this working?
See this thread How to send JSON as part of multipart POST-request
Do not set the Content-type header yourself, leave that to pyrequests to generate
def send_request():
payload = {"param_1": "value_1", "param_2": "value_2"}
files = {
'json': (None, json.dumps(payload), 'application/json'),
'file': (os.path.basename(file), open(file, 'rb'), 'application/octet-stream')
}
r = requests.post(url, files=files)
print(r.content)
Don't encode using json.
import requests
info = {
'var1' : 'this',
'var2' : 'that',
}
data = {
'token' : auth_token,
'info' : info,
}
headers = {'Content-type': 'multipart/form-data'}
files = {'document': open('file_name.pdf', 'rb')}
r = requests.post(url, files=files, data=data, headers=headers)
Note that this may not necessarily be what you want, as it will become another form-data section.
I'm don't think you can send both data and files in a multipart encoded file, so you need to make your data a "file" too:
files = {
'data' : data,
'document': open('file_name.pdf', 'rb')
}
r = requests.post(url, files=files, headers=headers)
I have been using requests==2.22.0
For me , the below code worked.
import requests
data = {
'var1': 'this',
'var2': 'that'
}
r = requests.post("http://api.example.com/v1/api/some/",
files={'document': open('doocument.pdf', 'rb')},
data=data,
headers={"Authorization": "Token jfhgfgsdadhfghfgvgjhN"}. #since I had to authenticate for the same
)
print (r.json())
For sending Facebook Messenger API, I changed all the payload dictionary values to be strings. Then, I can pass the payload as data parameter.
import requests
ACCESS_TOKEN = ''
url = 'https://graph.facebook.com/v2.6/me/messages'
payload = {
'access_token' : ACCESS_TOKEN,
'messaging_type' : "UPDATE",
'recipient' : '{"id":"1111111111111"}',
'message' : '{"attachment":{"type":"image", "payload":{"is_reusable":true}}}',
}
files = {'filedata': (file, open(file, 'rb'), 'image/png')}
r = requests.post(url, files=files, data=payload)
1. Sending request
import json
import requests
cover = 'superneat.jpg'
payload = {'title': 'The 100 (2014)', 'episodes': json.dumps(_episodes)}
files = [
('json', ('payload.json', json.dumps(payload), 'application/json')),
('cover', (cover, open(cover, 'rb')))
]
r = requests.post("https://superneatech.com/store/series", files=files)
print(r.text)
2. Receiving request
You will receive the JSON data as a file, get the content and continue...
Reference: View Here
What is more:
files = {
'document': open('file_name.pdf', 'rb')
}
That will only work if your file is at the same directory where your script is.
If you want to append file from different directory you should do:
files = {
'document': open(os.path.join(dir_path, 'file_name.pdf'), 'rb')
}
Where dir_path is a directory with your 'file_name.pdf' file.
But what if you'd like to send multiple PDFs ?
You can simply make a custom function to return a list of files you need (in your case that can be only those with .pdf extension). That also includes files in subdirectories (search for files recursively):
def prepare_pdfs():
return sorted([os.path.join(root, filename) for root, dirnames, filenames in os.walk(dir_path) for filename in filenames if filename.endswith('.pdf')])
Then you can call it:
my_data = prepare_pdfs()
And with simple loop:
for file in my_data:
pdf = open(file, 'rb')
files = {
'document': pdf
}
r = requests.post(url, files=files, ...)

Categories

Resources