如何在python中发送多部分/表单数据请求?怎么发文件,我懂,但是怎么用这种方法发表单数据就不懂了。


当前回答

下面是使用请求上传带有附加参数的单个文件的简单代码片段:

url = 'https://<file_upload_url>'
fp = '/Users/jainik/Desktop/data.csv'

files = {'file': open(fp, 'rb')}
payload = {'file_id': '1234'}

response = requests.put(url, files=files, data=payload, verify=False)

请注意,您不需要显式地指定任何内容类型。

注:想评论上述答案之一,但不能因为低声誉,所以起草了一个新的回应在这里。

其他回答

发送multipart/form-data键和值

curl命令:

curl -X PUT http://127.0.0.1:8080/api/xxx ...
-H 'content-type: multipart/form-data; boundary=----xxx' \
-F taskStatus=1

python请求-更复杂的POST请求:

    updateTaskUrl = "http://127.0.0.1:8080/api/xxx"
    updateInfoDict = {
        "taskStatus": 1,
    }
    resp = requests.put(updateTaskUrl, data=updateInfoDict)

发送多部分/表单数据文件

curl命令:

curl -X POST http://127.0.0.1:8080/api/xxx ...
-H 'content-type: multipart/form-data; boundary=----xxx' \
-F file=@/Users/xxx.txt

POST一个多部分编码的文件:

    filePath = "/Users/xxx.txt"
    fileFp = open(filePath, 'rb')
    fileInfoDict = {
        "file": fileFp,
    }
    resp = requests.post(uploadResultUrl, files=fileInfoDict)

这是所有。

import requests
# assume sending two files
url = "put ur url here"
f1 = open("file 1 path", 'rb')
f2 = open("file 2 path", 'rb')
response = requests.post(url,files={"file1 name": f1, "file2 name":f2})
print(response)

通过在POST请求中指定files参数,请求的Content-Type被自动设置为multipart/form-data(后面跟着用于分隔multipart负载中的每个主体部分的边界字符串),无论您只发送文件,还是同时发送form-data和文件(因此,在这种情况下,不应该尝试手动设置Content-Type)。然而,如果只发送表单数据,则Content-Type将自动设置为application/x-www-form-urlencoded。

You can print out the Content-Type header of the request to verify the above using the example given below, which shows how to upload multiple files (or a single file) with (optionally) the same key (i.e., 'files' in the case below), as well as with optional form-data (i.e., data=data in the example below). The documentation on how to POST single and multiple files can be found here and here, respectively. In case you need to upload large files without reading them into memory, have a look at Streaming Uploads. For the server side—in case this is needed—please have a look at this answer, from which the code snippet below has been taken, and which uses the FastAPI web framework.

import requests

url = 'http://127.0.0.1:8000/submit'
files = [('files', open('a.txt', 'rb')), ('files', open('b.txt', 'rb'))]
#file = {'file': open('a.txt','rb')} # to send a single file
data ={"name": "foo", "point": 0.13, "is_accepted": False}
r = requests.post(url=url, data=data, files=files) 
print(r.json())
print(r.request.headers['content-type'])
import json
import os
import requests
from requests_toolbelt import MultipartEncoder

AUTH_API_ENDPOINT = "http://localhost:3095/api/auth/login"

def file_upload(path_img, token ):
    url = 'http://localhost:3095/api/shopping/product/image'
    name_img = os.path.basename(path_img)

    mp_encoder = MultipartEncoder(
        fields={
            'email': 'mcm9@gmail.com',
            'source': 'tmall',
            'productId': 'product_0001',
            'image': (name_img, open(path_img, 'rb'), 'multipart/form-data')
        #'spam': ('spam.txt', open('spam.txt', 'rb'), 'text/plain'),
        }
    )

    head = {'Authorization': 'Bearer  {}'.format(token),
            'Content-Type': mp_encoder.content_type}

    with requests.Session() as s:
        result = s.post(url, data=mp_encoder, headers=head)

    return result

def do_auth(username, password, url=AUTH_API_ENDPOINT):
    data = {
        "email": username,
        "password": password
    }

    # sending post request and saving response as response object
    r = requests.post(url=url, data=data)

    # extracting response text
    response_text = r.text

    d = json.loads(response_text)
    # print(d)

    return d


if __name__ == '__main__':
    result = do_auth('mcm4@gmail.com','123456')
    token = result.get('data').get('payload').get('token')
    print(token)
    result = file_upload('/home/mcm/Pictures/1234.png',token)
    print(result.json())

即使不需要上传任何文件,也需要使用files参数发送多部分表单POST请求。

从原始请求来源:

def request(method, url, **kwargs):
    """Constructs and sends a :class:`Request <Request>`.

    ...
    :param files: (optional) Dictionary of ``'name': file-like-objects``
        (or ``{'name': file-tuple}``) for multipart encoding upload.
        ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``,
        3-tuple ``('filename', fileobj, 'content_type')``
        or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``,
        where ``'content-type'`` is a string
        defining the content type of the given file
        and ``custom_headers`` a dict-like object 
        containing additional headers to add for the file.

file-tuple可以是a:

2元组(文件名,fileobj) 3-tuple (filename, fileobj, content_type) 4元组(文件名,fileobj, content_type, custom_headers)。

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \

基于以上,最简单的多部分表单请求,包括要上传的文件和表单字段,将如下所示:

import requests

multipart_form_data = {
    'upload': ('custom_file_name.zip', open('myfile.zip', 'rb')),
    'action': (None, 'store'),
    'path': (None, '/path1')
}

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

print(response.content)

注意None作为纯文本字段的元组中的第一个参数——这是文件名字段的占位符,仅用于文件上传,但对于文本字段,为了提交数据,必须将None作为第一个参数。

具有相同名称的多个字段

如果你需要发布多个具有相同名称的字段,那么你可以将你的有效负载定义为元组的列表(或元组):

multipart_form_data = (
    ('file2', ('custom_file_name.zip', open('myfile.zip', 'rb'))),
    ('action', (None, 'store')),
    ('path', (None, '/path1')),
    ('path', (None, '/path2')),
    ('path', (None, '/path3')),
)

流媒体请求API

如果上面的API对你来说不够python化,那么可以考虑使用requests toolbelt (pip install requests_toolbelt),它是核心请求模块的扩展,提供了对文件上传流的支持,以及可以用来代替文件的MultipartEncoder,它还允许你将负载定义为字典、元组或列表。

MultipartEncoder可以用于有或没有实际上传字段的多部分请求。它必须分配给data参数。

import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder

multipart_data = MultipartEncoder(
    fields={
            # a file upload field
            'file': ('file.zip', open('file.zip', 'rb'), 'text/plain')
            # plain text fields
            'field0': 'value0', 
            'field1': 'value1',
           }
    )

response = requests.post('http://httpbin.org/post', data=multipart_data,
                  headers={'Content-Type': multipart_data.content_type})

如果你需要发送多个相同名称的字段,或者如果表单字段的顺序很重要,那么可以使用元组或列表来代替字典:

multipart_data = MultipartEncoder(
    fields=(
            ('action', 'ingest'), 
            ('item', 'spam'),
            ('item', 'sausage'),
            ('item', 'eggs'),
           )
    )