Sharmiko
Sharmiko

Reputation: 623

Cannot upload images using Python requests

I am having problem uploading some images using python requests. The website I am trying to upload a photo is myauto.enter image description here

When I click on it and select image, I can see in the browser network tab that on this endpoint is the request sent:

https://static.my.ge/

This is form data that is sent from browser.
enter image description here

And to see the full source: enter image description here

First I tried to post the data using this script:

image_data = (
    # 'Files[]: (binary)
    ('do', 'Files'),
    ('Func', 'UploadPhotos'),
    ('SiteID', 1),
    ('UserID', 4134977),
    ('IP', 'XX.XX.XX.XX'),
    ('UploadedFiles', 0)
)
# NOTE - we can have multiple `Files[]`
image_urls = tuple()
image_urls += (('Files[]', 'some_image.jpg'),)
response = requests.request(
    method='POST',
    url='https://static.my.ge/',
    data=self.image_data + image_urls,
    headers=headers
)

Headers I am using:

headers = {
    'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
    'Accept-Encoding': "gzip, deflate, br",
    'Accept': "*/*",
    'Connection': "keep-alive",
    'Host': "static.my.ge",
    'Origin': "https://www.myauto.ge",
    'Referer': "https://www.myauto.ge/ka/add",
    'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="90", "GoogleChrome";v="90"',
    'sec-ch-ua-mobile': "?0",
    'Sec-Fetch-Dest': "empty",
    'Sec-Fetch-Mode': "cors",
    'Sec-Fetch-Site': "cross-site",
    'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    'cache-control': "no-cache"
}

But I get the following response all the time:

{'StatusID': 0, 'StatusCode': 0, 'Message': 'Incorrect Func'}

And this is the desired output:

"StatusID": 0,
"StatusCode": 1,
"Message": "Error occurred during the operation",
"Data": {
    "FilesList": [
        "https://static.my.ge/tmp/6db262b3d7a2f9bfd56618640b6deed8_thumbs.jpg"
    ],
    "imgKey": [
        "6db262b3d7a2f9bfd56618640b6deed8"
    ]
}

Then I tried to generate same Webkit Form Boundry and pass that raw string to data, but get the same result all the time. I also tried to send image blob or base64 format, but still got same error.

Then I tried to send request on this endpoint using postman, and It successfully returned the data I was expecting. I chose form-data format in body section and uploaded file through postman. Then I tried to see the logs of the requests and tried to copy it from postman and run using python script, but no success, still got same error. Finally, I tried to copy code snippet from postman code generator, but still no luck. I don't understand what is happening and ran out of ideas.

Edit:

Here is the postman script:

url = "https://static.my.ge"

payload = (
    "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
    "form-data; name=\"Files[]\"; filename=\"some_image.jpg\"\r\n"
    "Content-Type: image/jpeg\r\n\r\n\r\n"
    "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
    "form-data; name=\"do\"\r\n\r\nFiles\r\n"
    "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
    "form-data; name=\"SiteID\"\r\n\r\n1\r\n"
    "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
    "form-data; name=\"UserID\"\r\n\r\n1902119\r\n"
    "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
    "form-data; name=\"IP\"\r\n\r\nXX.XX.XX.XX\r\n"
    "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
    "form-data; name=\"UploadedFiles\"\r\n\r\n0\r\n"
    "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
    "form-data; name=\"Func\"\r\n\r\nUploadPhotos\r\n"
    "------WebKitFormBoundary7MA4YWxkTrZu0gW--"
)
response = requests.request("POST", url, data=payload, headers=headers)

Also, found out that this is how image is represented in the request. Not sure how to do same in python code: enter image description here

Update: Tried to modify postman generated script:

   payload = (
        "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
        "form-data; name=\"Files[]\"; filename=\"blob\"\r\n"
        "Content-Type: image/jpg\r\n\r\n"
        f"{image}\r\n"
        "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
        "form-data; name=\"do\"\r\n\r\nFiles\r\n"
        "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
        "form-data; name=\"SiteID\"\r\n\r\n1\r\n"
        "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
        "form-data; name=\"UserID\"\r\n\r\n1902119\r\n"
        "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
        "form-data; name=\"IP\"\r\n\r\nXX.XX.XX.XX\r\n"
        "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
        "form-data; name=\"UploadedFiles\"\r\n\r\n0\r\n"
        "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: "
        "form-data; name=\"Func\"\r\n\r\nUploadPhotos\r\n"
        "------WebKitFormBoundary7MA4YWxkTrZu0gW--"
    )

Tried to put base64 and binary images in place of f{"image"}. But got new error message from server, not sure if it's helpful.

object(Exception)#4 (7) {
  ["message":protected]=>
  string(34) "Invalid image file: /tmp/phpFMI89k"
  ["string":"Exception":private]=>
  string(0) ""
  ["code":protected]=>
  int(7)
  ["file":protected]=>
  string(58) "/datastore/web/static.my.ge/htdocs/libs/SimpleImageNew.php"
  ["line":protected]=>
  int(130)
  ["trace":"Exception":private]=>
  array(3) {
    [0]=>
    array(6) {
      ["file"]=>
      string(44) "/datastore/web/static.my.ge/htdocs/index.php"
      ["line"]=>
      int(1300)
      ["function"]=>
      string(8) "fromFile"
      ["class"]=>
      string(14) "SimpleImageNew"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(1) {
        [0]=>
        string(14) "/tmp/phpFMI89k"
      }
    }
    [1]=>
    array(6) {
      ["file"]=>
      string(44) "/datastore/web/static.my.ge/htdocs/index.php"
      ["line"]=>
      int(494)
      ["function"]=>
      string(12) "UploadPhotos"
      ["class"]=>
      string(7) "_Static"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(0) {
      }
    }
    [2]=>
    array(6) {
      ["file"]=>
      string(44) "/datastore/web/static.my.ge/htdocs/index.php"
      ["line"]=>
      int(3066)
      ["function"]=>
      string(7) "SetFunc"
      ["class"]=>
      string(7) "_Static"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(0) {
      }
    }
  }
  ["previous":"Exception":private]=>
  NULL
}

Upvotes: 1

Views: 2304

Answers (3)

schilli
schilli

Reputation: 1838

I found this doing some research: https://serverfault.com/questions/694660/python-requests-image-upload-http-post

You could try that approach with the files parameter of requests.post.

image_data = (
    # 'Files[]: (binary)
    ('do', 'Files'),
    ('Func', 'UploadPhotos'),
    ('SiteID', 1),
    ('UserID', 4134977),
    ('IP', 'XX.XX.XX.XX'),
    ('UploadedFiles', 0)
)
response = requests.post(
    url='https://static.my.ge/',
    data=image_data,
    files={'Files[]': open("some_image.jpeg",'rb')},
    headers=headers
)
# Maybe the param name should be "Files" and it's value a list.
# Just try both.
response = requests.post(
    url='https://static.my.ge/',
    data=image_data,
    files={'Files': [open("some_image.jpeg",'rb')]},
    headers=headers
)

Upvotes: 1

jizhihaoSAMA
jizhihaoSAMA

Reputation: 12672

import requests

files = {'Files[]': ("1.png", open(r"your/image/path", 'rb'), "image/png", {})}

data = {
    'Func': "UploadPhotos",
    "SiteID": "1",
    "UserID": "xx",  # your user ID here
    "IP": "xx",  # your IP here
    "UploadedFiles": 0
}

response = requests.post('https://static.my.ge/', files=files, data=data)

print(response.json())

And the result:

{'StatusID': 0, 'StatusCode': 1, 'Message': 'Error occurred during the operation', 'Data': {'FilesList': ['xxxx.jpg'], 'imgKey': ['xxxx']}}

Upvotes: 2

schilli
schilli

Reputation: 1838

Did you try to upload the file to a different api? I'd try to upload it to a minimalistic flask app. The following code is from the flask docs (https://flask.palletsprojects.com/en/1.1.x/patterns/fileuploads/).

Just adapt the UPLOAD_FOLDER to a folder on your machine, then you could try to do your post request to http://127.0.0.1:5000/. It should save the file to the defined upload folder. If that works, you know that you are at least doing the right thing with requests.

import os
from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename

UPLOAD_FOLDER = '/path/to/uploads/folder'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # check if the post request has the file part
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        # if user does not select file, browser also
        # submit an empty part without filename
        if file.filename == '':
            flash('No selected file')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('uploaded_file',
                                    filename=filename))
    return '''
    <!doctype html>
    <title>Upload new File</title>
    <h1>Upload new File</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

if __name__ == "__main__":
    print("hello")
    app.run()

Upvotes: 1

Related Questions