我想发出一个POST请求,使用Python将文件上传到web服务(并获得响应)。例如,我可以使用curl执行以下POST请求
curl -F "file=@style.css" -F output=json http://jigsaw.w3.org/css-validator/validator如何使用python urllib/urllib2发出相同的请求?到目前为止,我得到的最接近的是:
with open("style.css", 'r') as f:
content = f.read()
post_data = {"file": content, "output": "json"}
request = urllib2.Request("http://jigsaw.w3.org/css-validator/validator", \
data=urllib.urlencode(post_data))
response = urllib2.urlopen(request)我从上面的代码中得到了一个HTTP错误500。但是既然我的curl命令成功了,那一定是我的python请求出了什么问题?
我对这个话题很陌生,我的问题可能有非常简单的答案或错误。
发布于 2014-11-21 08:13:13
经过一番钻研,this post似乎解决了我的问题。事实证明,我需要正确设置多部分编码器。
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2
register_openers()
with open("style.css", 'r') as f:
datagen, headers = multipart_encode({"file": f})
request = urllib2.Request("http://jigsaw.w3.org/css-validator/validator", \
datagen, headers)
response = urllib2.urlopen(request)发布于 2014-11-21 06:08:58
就我个人而言,我认为你应该考虑使用requests库来发布文件。
url = 'http://jigsaw.w3.org/css-validator/validator'
files = {'file': open('style.css')}
response = requests.post(url, files=files)使用http://pymotw.com/2/urllib2/#uploading-files上传文件并非不可能,但却是一项相当复杂的任务
发布于 2018-07-18 14:07:17
嗯,有多种方法可以做到这一点。如上所述,您可以在"multipart/form-data“中发送文件。但是,目标服务可能不需要这种类型,在这种情况下,您可以尝试更多方法。
传递文件对象
urllib2可以接受文件对象作为data。当您传递此类型时,库将文件作为二进制流读取并将其发送出去。但是,它不会设置正确的Content-Type报头。此外,如果Content-Length头文件丢失,它将尝试访问对象的len属性,该属性对于文件是不存在的。也就是说,您必须同时提供Content-Type和Content-Length标头才能使该方法正常工作:
import os
import urllib2
filename = '/var/tmp/myfile.zip'
headers = {
'Content-Type': 'application/zip',
'Content-Length': os.stat(filename).st_size,
}
request = urllib2.Request('http://localhost', open(filename, 'rb'),
headers=headers)
response = urllib2.urlopen(request)包装文件对象
为了不处理长度问题,可以创建一个简单的包装器对象。如果将文件加载到内存中,只需稍作更改,就可以将其调整为从字符串中获取内容。
class BinaryFileObject:
"""Simple wrapper for a binary file for urllib2."""
def __init__(self, filename):
self.__size = int(os.stat(filename).st_size)
self.__f = open(filename, 'rb')
def read(self, blocksize):
return self.__f.read(blocksize)
def __len__(self):
return self.__size将内容编码为base64
另一种方法是通过base64.b64encode编码data并提供Content-Transfer-Type: base64报头。但是,此方法需要服务器端的支持。根据实现的不同,服务可以接受文件并错误地存储它,也可以返回HTTP 400。例如,GitHub接口不会抛出错误,但上传的文件会被损坏。
https://stackoverflow.com/questions/27050399
复制相似问题