0

I'm trying to send 2 photos + json-payload in request. First, I did as described in How to send a "multipart/form-data" with requests in python?, but it doesn't work.

from requests_toolbelt.multipart.encoder import MultipartEncoder

import requests

mp_encoder = MultipartEncoder(fields={"parameters": {"sysId": 1, "clientId": 4029487, "fsid": 'ChNKoXqa87YucQ1nlf3hJGTl',
                               "deviceId":"89DEB49F37DD49559D124C9F3AFA2A54"},
                                                          'file1':('img317.jpg',open('/Users/12fhntv21Q/Downloads/pasport_rf.jpg',"rb"),'image/jpeg'),
                                                          'file2':('img317.jpg',open('/Users/12fhntv21Q/Downloads/pasport_rf_1.jpg',"rb"),'image/jpeg')
                                                          }
                                          )
print(mp_encoder)
url = 'https://clientsapi01./..../'
response = requests.post(url,headers={'Content-Type': mp_encoder.content_type}, data=mp_encoder)

Gives such error:

Traceback (most recent call last):
  File "/Users/12fhntv21Q/PycharmProjects/Api_Test/Client_CUPIS/identification_cupis.py", line 17, in <module>
    'file2':('img317.jpg',open('/Users/12fhntv21Q/Downloads/pasport_rf_1.jpg',"rb"),'image/jpeg')
  File "/Users/12fhntv21Q/Api_Test/lib/python3.7/site-packages/requests_toolbelt/multipart/encoder.py", line 125, in __init__
    self._prepare_parts()
  File "/Users/12fhntv21Q/Api_Test/lib/python3.7/site-packages/requests_toolbelt/multipart/encoder.py", line 246, in _prepare_parts
    self.parts = [Part.from_field(f, enc) for f in self._iter_fields()]
  File "/Users/12fhntv21Q/Api_Test/lib/python3.7/site-packages/requests_toolbelt/multipart/encoder.py", line 246, in <listcomp>
    self.parts = [Part.from_field(f, enc) for f in self._iter_fields()]
  File "/Users/12fhntv21Q/Api_Test/lib/python3.7/site-packages/requests_toolbelt/multipart/encoder.py", line 494, in from_field
    body = coerce_data(field.data, encoding)
  File "/Users/12fhntv21Q/Api_Test/lib/python3.7/site-packages/requests_toolbelt/multipart/encoder.py", line 472, in coerce_data
    return CustomBytesIO(data, encoding)
  File "/Users/12fhntv21Q/Api_Test/lib/python3.7/site-packages/requests_toolbelt/multipart/encoder.py", line 535, in __init__
    buffer = encode_with(buffer, encoding)
  File "/Users/12fhntv21Q/Api_Test/lib/python3.7/site-packages/requests_toolbelt/multipart/encoder.py", line 416, in encode_with
    return string.encode(encoding)
AttributeError: 'dict' object has no attribute 'encode'

Tried to import the request code from postman ( in it the 2 photos and parameters are sent correctly)

import requests

 url = "https://clientsapi01/..../"

        payload = "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition:" \
              " form-data; name=\"parameters\"\r\n\r\n{\"sysId\":1,\n\"lang\":\"ru\"," \
              "\n\"clientId\":4029487,\n\"fsid\":\"ChNKoXqa87YucQ1nlf3hJGTl\"," \
              "\n\"devPrototype\":false,\n\"devPrototypeValue\":0," \
              "\n\"deviceId\":\"89DEB49F37DD49559D124C9F3AFA2A54\"}" \
              "\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\n" \
              "Content-Disposition: form-data; name=\"file1\"; " \
              "filename=\"img317.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n\r\n" \
              "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\n" \
              "Content-Disposition: form-data; name=\"file2\"; filename=\"img318.jpg" \
              "\"\r\nContent-Type: image/jpeg\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--"
    headers = {
        'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
        'Content-Type': "multipart/mixed",
        'User-Agent': "PostmanRuntime/7.18.0",
        'Accept': "*/*",
        'Cache-Control': "no-cache",
        'Postman-Token': "9faf7642-3ba3-44da-9353-295a90073191,93b2a684-2b39-496a-b492-68899c3cb82c",
        'Host': "clientsapi01.bksndbx.com",
        'Accept-Encoding': "gzip, deflate",
        'Content-Length': "4566826",
        'Connection': "keep-alive",
        'cache-control': "no-cache"
        }

    response = requests.request("POST", url, data=payload, headers=headers)

    print(response.text)

Вut in doesn't work either. Finally, this method :

payload_for_request = {"parameters": [{"sysId": 1, "clientId": 4029487, "fsid": 'JXvI1jbXteO8NOpRZPAeKeeh',
                                      "deviceId":"89DEB49F37DD49559D124C9F3AFA2A54",
                                       "lang":"ru"}]}

files = [("file1",("img317.jpg", open('img317.jpg',"rb"),'image/jpeg')),
         ("file2", ("img318.jpg",open('img318.jpg',"rb"), 'image/jpeg'))]

headers={'Content-Type': 'multipart/form-data; boundary=93c1068f0d0c354feca39cdd75562cf0'}
r = requests.post(url,   data=payload_for_request, files=files)
print(r.text)
print(r.headers)

Also throws an error - {"result":"error","errorCode":1,"errorMessage":"bad request","errorValue":"common parameters parsing error"}

IrinaYaresko
  • 1
  • 1
  • 1
  • 4

2 Answers2

2

Following example is basic example of making POST request with two images + some data (in this case, temperature), using requests:

import requests
import os

def send_data_to_server(image_path1, image_path2, temperature):

    image_filename1 = os.path.basename(image_path1)
    image_filename2 = os.path.basename(image_path2)

    multipart_form_data = {
        'image1': (image_filename1, open(image_path2, 'rb')),
        'image2': (image_filename2, open(image_path2, 'rb')),
        'temperature': ('', str(temperature)),
    }

    response = requests.post('https://httpbin.org/post', files=multipart_form_data)

    return(response.status_code)


test1 = send_data_to_server("sample444.jpg", "sample555.jpg", 39.2)


print(test1)

If you are working with bigger amount of images, you will naturally have the list input parameter, instead of the each image path separately, and JSON will be a bit bigger, or may differ.

user5214530
  • 467
  • 5
  • 11
  • Did for example, only with my file names, but still did not work -TypeError: a bytes-like object is required, not 'dict' – IrinaYaresko Dec 13 '19 at 13:53
  • Send the exact snippet of your code, lets see what's the boggle :) – user5214530 Dec 13 '19 at 13:56
  • I'm try your example with url from example and my image and it's work correctly. but I have a line not with temperature, but with a nested dictionary. If you send it as is, it gives an error - -TypeError: a bytes-like object is required, not 'dict'. If I make b "parameter" : bytes_payload, it gives an error on the image format - {"result":"error","errorCode":1,"errorMessage":"bad request","errorValue":"Only jpg and png files allowed."} – IrinaYaresko Dec 13 '19 at 14:15
  • Possibly that nasty dictionary of yours is making a problem. Try to JSON-ify it as stated in this answer: https://stackoverflow.com/a/17135283/5214530 – user5214530 Dec 13 '19 at 14:21
  • Attached a sample code in the main answer under the post :) – IrinaYaresko Dec 13 '19 at 14:24
  • Did the conversion as in your example above : "parameters": json.dumps(payload) ', but I'still get in response - {"result":"error","errorCode":1,"errorMessage":"bad request","errorValue":"Only jpg and png files allowed."} – IrinaYaresko Dec 13 '19 at 14:30
  • Maybe the problem is that the API only skips images in "files" in request-parameters and throws an error if there is a nested dictionary inside "multipart_form_data"? But if I do response = requests.post(url_t, data=payload, files=multipart_form_data), then I get next error in response - {"result":"error","errorCode":1,"errorMessage":"bad request","errorValue":"common parameters parsing error"} %) – IrinaYaresko Dec 13 '19 at 14:44
  • Be cautious about using global and local variables. I've modified your code a bit: https://repl.it/repls/OffbeatHollowAmoebas . In addition, yes, I dont know how your REST server works, you can have a problem there as well. – user5214530 Dec 13 '19 at 14:44
  • Thanks, I tried running the code with your fixes, but it still "errorValue":"Only jpg and png files allowed." %%%) – IrinaYaresko Dec 13 '19 at 14:54
  • I looked at how this request looks in Postman in JavaScript and Python, there all the parameters of the request ( files and json) are passed to the "data" field. You don't know if it is possible to generate a request in "python request" with sending files and json via r = request.post (url, data=multipart_form_data)? – IrinaYaresko Dec 13 '19 at 15:24
  • Yes, indeed it is feasible - https://repl.it/repls/DopeySnowRay – user5214530 Dec 13 '19 at 16:40
  • unfortunately again not earned. Looks like the problem is in the API. I can send C ' url request generation if it helps =) https://yadi.sk/i/U04vkS8QkXD1bA – IrinaYaresko Dec 16 '19 at 07:23
  • Without access to server's and client's code, or extensive server's documentation, I am afraid I cant help you any further. Try to request help from someone of your colleagues or similar, it might be the best solution. In addition, I am behind the company proxy, so I cant open your link. – user5214530 Dec 16 '19 at 07:37
0
file1 = '/Users/12fhntv21Q/Downloads/img317.jpg'
file2 = '/Users/12fhntv21Q/Downloads/img318.jpg'

url_t = 'createProcess'

def send_data_to_server(image_path1, image_path2):

    image_filename1 = os.path.basename(image_path1)
    image_filename2 = os.path.basename(image_path2)

    payload = {"sysId": 1, "clientId": 4029487, "fsid": 'JXvI1jbXteO8NOpRZPAeKeeh',
                               "deviceId":"89DEB49F37DD49559D124C9F3AFA2A54"}
    #bytes_payload = json.dumps(payload).encode('utf-8')
    multipart_form_data = {
        'file1': (image_filename1, open(file1, 'rb')),
        'file2': (image_filename2, open(file2, 'rb')),
        "parameters": payload
    }


    response = requests.post(url_t, files=multipart_form_data)
    print(response.text)
    print(response.headers)
    return(response.status_code)

test1 = send_data_to_server("img317.jpg", "img318.jpg")

if I run function with nested dict in "multipart_form_data" , Result is TypeError: a bytes-like object is required, not 'dict'. But if I make bytes_payload = json.dumps(payload).encode('utf-8') and in "multipart_form_data" convert a nested dictionary to a byte type - b"parameter" : bytes_payload, then I'm getting in result {"result":"error","errorCode":1,"errorMessage":"bad request","errorValue":"Only jpg and png files allowed."}

IrinaYaresko
  • 1
  • 1
  • 1
  • 4