我想将文件上传到网络服务器。根据我的阅读,最好的方法是在HTTP POST请求中使用multipart / form-data编码类型。
我的研究似乎表明,使用Python标准库没有简单的方法可以做到这一点。我使用的是Python 3。
(注意:请参阅名为requests(PyPI Link)的软件包以轻松完成此操作。
我目前正在使用此方法:
import mimetypes, http.client
boundary = 'wL36Yn8afVp8Ag7AmP8qZ0SA4n1v9T' # Randomly generated
for fileName in fileList:
# Add boundary and header
dataList.append('--' + boundary)
dataList.append('Content-Disposition: form-data; name={0}; filename={0}'.format(fileName))
fileType = mimetypes.guess_type(fileName)[0] or 'application/octet-stream'
dataList.append('Content-Type: {}'.format(fileType))
dataList.append('')
with open(fileName) as f:
# Bad for large files
dataList.append(f.read())
dataList.append('--'+boundary+'--')
dataList.append('')
contentType = 'multipart/form-data; boundary={}'.format(boundary)
body = '\r\n'.join(dataList)
headers = {'Content-type': contentType}
conn = http.client.HTTPConnection('http://...')
req = conn.request('POST', '/test/', body, headers)
print(conn.getresponse().read())
这适用于发送文字。
有两个问题:这只是文本,整个文本文件必须作为一个巨大的字符串存储在内存中。
如何上传任何二进制文件?有没有办法在不将整个文件读入内存的情况下执行此操作?
答案 0 :(得分:2)
我看了一下这个模块
class HTTPConnection:
# ...
def send(self, data): # line 820
"""Send `data' to the server.
``data`` can be a string object, a bytes object, an array object, a
file-like object that supports a .read() method, or an iterable object.
"""
数据完全是正文。 你可以通过这样的迭代器:(我没试过)
def body():
for fileName in fileList:
# Add boundary and header
yield('--' + boundary) + '\r\n'
yield('Content-Disposition: form-data; name={0}; filename= {0}'.format(fileName)) + '\r\n'
fileType = mimetypes.guess_type(fileName)[0] or 'application/octet-stream'
yield('Content-Type: {}'.format(fileType)) + '\r\n'
yield('\r\n')
with open(fileName) as f:
# Bad for large files
yield f.read()
yield('--'+boundary+'--') + '\r\n'
yield('') + '\r\n'
答案 1 :(得分:2)
看看我翻译成python3的小Doug Hellmann's urllib2。
我几乎用这种方式使用它:
import urllib.request
import urllib.parse
from lib.multipart_sender import MultiPartForm
myfile = open('path/to/file', 'rb')
form = MultiPartForm()
form.add_field('token', apipost[mycgi['domain']]._token)
form.add_field('domain', mycgi['domain'])
form.add_file('file', 'logo.jpg', fileHandle=myfile)
form.make_result()
url = 'http://myurl'
req1 = urllib.request.Request(url)
req1.add_header('Content-type', form.get_content_type())
req1.add_header('Content-length', len(form.form_data))
req1.add_data(form.form_data)
fp = urllib.request.urlopen(req1)
print(fp.read()) # to view status
答案 2 :(得分:0)
您可以使用unirest拨打电话。示例代码
import unirest
# consume async post request
def consumePOSTRequestSync():
params = {'test1':'param1','test2':'param2'}
# we need to pass a dummy variable which is open method
# actually unirest does not provide variable to shift between
# application-x-www-form-urlencoded and
# multipart/form-data
params['dummy'] = open('dummy.txt', 'r')
url = 'http://httpbin.org/post'
headers = {"Accept": "application/json"}
# call get service with headers and params
response = unirest.post(url, headers = headers,params = params)
print "code:"+ str(response.code)
print "******************"
print "headers:"+ str(response.headers)
print "******************"
print "body:"+ str(response.body)
print "******************"
print "raw_body:"+ str(response.raw_body)
# post sync request multipart/form-data
consumePOSTRequestSync()
查看博文,了解更多详情http://stackandqueue.com/?p=57