Python 请求:在单个请求中发布 JSON 和文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19439961/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python Requests: Post JSON and file in single request
提问by oznu
I need to do a API call to upload a file along with a JSON string with details about the file.
我需要调用 API 来上传文件以及包含文件详细信息的 JSON 字符串。
I am trying to use the python requests lib to do this:
我正在尝试使用 python 请求库来执行此操作:
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)
This throws the following error:
这会引发以下错误:
raise ValueError("Data must not be a string.")
ValueError: Data must not be a string
If I remove the 'files' from the request, it works.
If I remove the 'data' from the request, it works.
If I do not encode data as JSON it works.
如果我从请求中删除“文件”,它就可以工作。
如果我从请求中删除“数据”,它就可以工作。
如果我不将数据编码为 JSON,它就可以工作。
For this reason I think the error is to do with sending JSON data and files in the same request.
出于这个原因,我认为错误与在同一请求中发送 JSON 数据和文件有关。
Any ideas on how to get this working?
关于如何让这个工作的任何想法?
采纳答案by proteneer
Don't encode using json.
不要使用 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)
Note that this may not necessarily be what you want, as it will become another form-data section.
请注意,这可能不一定是您想要的,因为它将成为另一个表单数据部分。
回答by AChampion
I'm don't think you can send both data and files in a multipart encoded file, so you need to make your data a "file" too:
我不认为您可以在多部分编码的文件中同时发送数据和文件,因此您也需要将数据设为“文件”:
files = {
'data' : data,
'document': open('file_name.pdf', 'rb')
}
r = requests.post(url, files=files, headers=headers)
回答by ralf htp
See this thread How to send JSON as part of multipart POST-request
请参阅此线程如何将 JSON 作为多部分 POST 请求的一部分发送
Do not set the Content-type header yourself, leave that to pyrequests to generate
不要自己设置 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)
回答by tc_qa
What is more:
更:
files = {
'document': open('file_name.pdf', 'rb')
}
That will only work if your file is at the same directory where your script is.
只有当您的文件位于脚本所在的同一目录中时,这才有效。
If you want to append file from different directory you should do:
如果你想从不同的目录追加文件,你应该这样做:
files = {
'document': open(os.path.join(dir_path, 'file_name.pdf'), 'rb')
}
Where dir_pathis a directory with your 'file_name.pdf'file.
其中dir_path是包含“file_name.pdf”文件的目录。
But what if you'd like to send multiple PDFs ?
但是如果您想发送多个 PDF 怎么办?
You can simply make a custom function to return a list of files you need (in your case that can be only those with .pdfextension). That also includes files in subdirectories (search for files recursively):
您可以简单地创建一个自定义函数来返回您需要的文件列表(在您的情况下,只能是那些扩展名为.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')])
Then you can call it:
然后你可以调用它:
my_data = prepare_pdfs()
And with simple loop:
并使用简单的循环:
for file in my_data:
pdf = open(file, 'rb')
files = {
'document': pdf
}
r = requests.post(url, files=files, ...)
回答by wannik
For sending Facebook Messenger API, I changed all the payload dictionary values to be strings. Then, I can pass the payload as data
parameter.
为了发送 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)
回答by SuperNova
I have been using requests==2.22.0
我一直在使用 requests==2.22.0
For me , the below code worked.
对我来说,下面的代码有效。
import requests
data = {
'var1': 'this',
'var2': 'that'
}
r = requests.post("http://api.example.com/v1/api/some/",
files={'document': open('doocument.pdf', 'rb')},
data=data,
headers={"Authorization": "Token jfhgfgsdadhfghfgvgjhN"}. #since I had to authenticate for the same
)
print (r.json())