【问题标题】:POST two form inputs with same name but different typePOST 两个具有相同名称但类型不同的表单输入
【发布时间】:2021-07-28 01:40:49
【问题描述】:

我有一个网页,它在一个表单中提交两个输入。我的浏览器的 POST 如下所示。
第一个输入是当前上传到站点的文件的路径(type="hidden");第二个输入是要上传的新文件(type="file")。

-----------------------------334620328614915644833547167693
Content-Disposition: form-data; name="image1"

data/file.jpg
-----------------------------334620328614915644833547167693
Content-Disposition: form-data; name="image1"; filename=""
Content-Type: application/octet-stream

这些输入具有相同的名称但类型不同,这导致我对requests 库的理解出现问题。据我所知,要提交数据,您需要发布一个包含输入名称及其新值的字典。

data = {}

form = get_all_forms(url)[1] #function returns list of forms gained using requests.get() - we select the correct form
formDetails = get_form_details(form) #uses BeautifulSoup to find all input values
for inputTag in formDetails["inputs"]:
  if inputTag["type"] == "file":
    pass #doesn't send anything
  else:
    data[inputTag["name"]] = inputTag["value"] #sets to current value

res = requests.post(url, data=data)

以上代码将发布带有'image1':'data/file.jpg' 的字典。不幸的是,页面现在认为有一个名为data/file.jpg 的新文件正在上传,当找不到该文件时,它会删除当前图像。

如何为 type="file"type="hidden" 发布单独的值?

【问题讨论】:

    标签: python post python-requests


    【解决方案1】:

    首先,只是一个建议:考虑为您的表单字段使用不同的、更重要的name 属性(强调不同!)。在你的情况下,这样的事情会更有意义:

    <input type="hidden" name="old-file-path" value="data/file.jpg"/>
    <input type="file" name="new-file"/>
    

    现在,进入实际问题,您可以使用requests.post()data=files= 参数来实现您想要的,如下所示:

    new_file = open('path/to/new/file.jpg', 'wb')
    data     = {'image1': 'data/file.jpg'}
    files    = {'image1': new_file}
    
    requests.post(url, data=data, files=files)
    

    应该生成这样的请求:

    ...
    Content-Type: multipart/form-data; boundary=d64ebc3e14a4909699c6f01dd1473855
    
    --d64ebc3e14a4909699c6f01dd1473855
    Content-Disposition: form-data; name="image1"
    
    data/file.jpg
    --d64ebc3e14a4909699c6f01dd1473855
    Content-Disposition: form-data; name="image1"; filename="file.jpg"
    ...
    

    这里的重点是使用files=作为要上传的新文件,使用data=作为旧文件名。

    如果您还想显式设置新文件的名称和 Content-Type,您可以在 files= dict 中传递一个 3 项元组,如下所示:

    new_file = open('path/to/new/file.jpg', 'wb')
    data     = {'image1': 'data/file.jpg'}
    files    = {'image1': ('NEW_FILE_NAME', new_file, 'application/octet-stream')}
    
    requests.post(url, data=data, files=files)
    

    结果:

    ...
    Content-Type: multipart/form-data; boundary=d64ebc3e14a4909699c6f01dd1473855
    
    --d64ebc3e14a4909699c6f01dd1473855
    Content-Disposition: form-data; name="image1"
    
    data/file.jpg
    --d64ebc3e14a4909699c6f01dd1473855
    Content-Disposition: form-data; name="image1"; filename="NEW_FILE_NAME"
    Content-Type: application/octet-stream
    ...
    

    或者如果你想从内存而不是磁盘发送文件,甚至是空文件,你可以使用:

    from io import BytesIO
    new_file = BytesIO(b'...file content here...')
    
    # ... same code as above
    

    将此调整为您现有的代码,整个事情应该变成:

    data = {}
    files = {}
    new_file = ... # obtain the new file somehow
    
    for inputTag in formDetails["inputs"]:
        if inputTag["type"] == "file":
            files[inputTag["name"]] = ("NEW_FILE_NAME", new_file, "application/octect-stream")
        elif inputTag["type"] == "hidden":
            data[inputTag["name"]] = inputTag["value"]
    
    requests.post(url, data=data, files=files)
    

    最后,在你的赏金评论中,我看到你说:

    [...] 当我只需要相同输入名称的多个值时。

    在这种情况下,您必须使用list 而不是data= 的字典,如下所示:

    data = [('image1', 'A'), ('image1', 'B')]
    # ...
    requests.post(url, data=data)
    

    结果会是这样的:

    --9cc0d413be5d2ed2ba8c80a2e7b54442
    Content-Disposition: form-data; name="image1"
    
    A
    --9cc0d413be5d2ed2ba8c80a2e7b54442
    Content-Disposition: form-data; name="image1"
    
    B
    

    这是否有意义取决于您来决定,因为这取决于服务器端实现以及多次使用相同名称时字段的含义。

    【讨论】:

    • data 在上传到服务器时似乎会覆盖 files。可能是这个特定服务器的错。
    • 确定是^;将其标记为已接受。
    • 仔细检查文档我注意到this,据说它允许您为一个name提交多个values;您将如何确定该订单?
    • @Corsaka 感谢您的链接,不知道这一点,这是有道理的。我已经更新了我的答案。不确定“您将如何识别订单”是什么意思;如果您指的是请求正文中的部分顺序,requests 似乎尊重data= 列表的顺序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-28
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 2011-05-14
    相关资源
    最近更新 更多