【问题标题】:Cannot upload images using Python requests无法使用 Python 请求上传图像
【发布时间】:2021-05-08 12:41:45
【问题描述】:

我在使用 python 请求上传一些图片时遇到问题。我要上传照片的网站是myauto.

当我单击它并选择图像时,我可以在浏览器网络选项卡中看到在此端点上发送的请求:

https://static.my.ge/

这是从浏览器发送的表单数据。

要查看完整源代码:

首先我尝试使用此脚本发布数据:

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 = {
    '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"
}

但我一直收到以下回复:

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

这是所需的输出:

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

然后我尝试生成相同的 Webkit 表单边界并将该原始字符串传递给数据,但始终得到相同的结果。我也尝试发送图像 blob 或 base64 格式,但仍然出现同样的错误。

然后我尝试使用邮递员在此端点上发送请求,它成功返回了我期望的数据。我在正文部分选择了表单数据格式,并通过邮递员上传了文件。然后我尝试查看请求的日志并尝试从邮递员复制它并使用python脚本运行,但没有成功,仍然出现同样的错误。最后,我尝试从邮递员代码生成器中复制代码 sn-p,但仍然没有运气。我不明白发生了什么并且没有想法。

编辑:

这里是邮递员脚本:

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)

另外,发现这就是图像在请求中的表示方式。不知道如何在 python 代码中做同样的事情:

更新: 试图修改邮递员生成的脚本:

   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--"
    )

试图用 base64 和二进制图像代替 f{"image"}。但是从服务器收到了新的错误消息,不确定它是否有帮助。

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
}

【问题讨论】:

  • 你有那个 REST 端点的 API 文档吗?
  • 不,我没有

标签: python python-requests http-post


【解决方案1】:
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())

结果:

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

【讨论】:

    【解决方案2】:

    您是否尝试将文件上传到不同的 api?我会尝试将它上传到一个简约的烧瓶应用程序。以下代码来自烧瓶文档 (https://flask.palletsprojects.com/en/1.1.x/patterns/fileuploads/)。

    只需将 UPLOAD_FOLDER 调整到您计算机上的文件夹,然后您可以尝试向http://127.0.0.1:5000/ 发送您的帖子请求。它应该将文件保存到定义的上传文件夹。如果这可行,您就知道您至少对请求做了正确的事情。

    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()
    

    【讨论】:

    • 感谢您的建议。
    【解决方案3】:

    我发现这是在做一些研究:https://serverfault.com/questions/694660/python-requests-image-upload-http-post

    您可以使用 requests.post 的 files 参数尝试该方法。

    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
    )
    

    【讨论】:

    • 您的代码中的"self" 是什么?只需在发布之前检查您的代码。
    • 这是从原始问题中复制的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    • 2015-11-20
    • 2015-05-20
    • 1970-01-01
    • 2017-05-30
    • 1970-01-01
    • 2020-08-25
    相关资源
    最近更新 更多