Python请求:在单个请求中发布JSON和文件

时间:2013-10-18 01:11:32

标签: python json urllib2

我需要进行API调用以上传文件以及带有该文件详细信息的JSON字符串。

我正在尝试使用python请求lib来执行此操作:

import requests

info = {
    'var1' : 'this',
    'var2'  : 'that',
}

data = json.dumps({
    'token' : auth_token,
    'info'  : info,
})

headers = {'Content-type': 'multipart/form-data'}

files = {'document': open('file_name.pdf', 'rb')}

r = requests.post(url, files=files, data=data, headers=headers)

这会引发以下错误:

    raise ValueError("Data must not be a string.")
 ValueError: Data must not be a string

如果我删除了'文件'从请求,它的工作原理 如果我删除了'数据'从请求,它的工作原理 如果我不将数据编码为JSON,它就可以工作。

出于这个原因,我认为错误与在同一请求中发送JSON数据和文件有关。

有关如何使其发挥作用的任何想法?

6 个答案:

答案 0 :(得分:18)

不要使用json进行编码。

import requests

info = {
    'var1' : 'this',
    'var2'  : 'that',
}

data = {
    'token' : auth_token,
    'info'  : info,
}

headers = {'Content-type': 'multipart/form-data'}

files = {'document': open('file_name.pdf', 'rb')}

r = requests.post(url, files=files, data=data, headers=headers)

请注意,这可能不一定是您想要的,因为它将成为另一个表单数据部分。

答案 1 :(得分:11)

请参阅此帖子How to send JSON as part of multipart POST-request

不要自行设置Content-type标头,将其留给pyrequests生成

def send_request():
payload = {"param_1": "value_1", "param_2": "value_2"}
files = {
     'json': (None, json.dumps(payload), 'application/json'),
     'file': (os.path.basename(file), open(file, 'rb'), 'application/octet-stream')
}

r = requests.post(url, files=files)
print(r.content)

答案 2 :(得分:2)

我认为您不能在多部分编码文件中发送数据和文件,因此您还需要将数据设为“文件”:

files = {
    'data' : data,
    'document': open('file_name.pdf', 'rb')
}

r = requests.post(url, files=files, headers=headers)

答案 3 :(得分:0)

更重要的是:

files = {
    'document': open('file_name.pdf', 'rb')
}

只有当您的文件位于脚本所在的目录时才会有效。

如果你想从不同的目录追加文件,你应该这样做:

files = {
    'document': open(os.path.join(dir_path, 'file_name.pdf'), 'rb')
}

dir_path 'file_name.pdf'文件的目录。

但是如果你想发送多个PDF怎么办?

您只需创建一个自定义函数即可返回所需文件列表(在您的情况下,只能使用 .pdf 扩展名)。这还包括子目录中的文件(递归搜索文件):

def prepare_pdfs():
    return sorted([os.path.join(root, filename) for root, dirnames, filenames in os.walk(dir_path) for filename in filenames if filename.endswith('.pdf')])

然后你可以打电话给它:

my_data = prepare_pdfs()

用简单的循环:

for file in my_data:

    pdf = open(file, 'rb')

    files = {
        'document': pdf
    }

    r = requests.post(url, files=files, ...)

答案 4 :(得分:0)

为了发送Facebook Messenger API,我将所有有效负载字典值更改为字符串。然后,我可以将有效负载作为data参数传递。

import requests

ACCESS_TOKEN = ''

url = 'https://graph.facebook.com/v2.6/me/messages'
payload = {
        'access_token' : ACCESS_TOKEN,
        'messaging_type' : "UPDATE",
        'recipient' : '{"id":"1111111111111"}',
        'message' : '{"attachment":{"type":"image", "payload":{"is_reusable":true}}}',
}
files = {'filedata': (file, open(file, 'rb'), 'image/png')}
r = requests.post(url, files=files, data=payload)

答案 5 :(得分:0)

我一直在使用my @vulnerabilities = ($g ~~ m:g/\s+("Low"||"Medium"||"High")\s+/);

对我来说,以下代码有效。

requests==2.22.0