问题:使用Python的urllib2发布数据时,所有数据都经过URL编码并作为Content-Type发送:application/x-www-form-urlencoded.上传文件时,应将Content-Type设置为multipart/form-data,并将内容编码为MIME.这个问题的讨论在这里:http: //code.activestate.com/recipes/146306/
为了解决这个限制,一些敏锐的程序员创建了一个名为MultipartPostHandler的库,它创建了一个OpenerDirector,您可以使用urllib2来主要使用multipart/form-data自动POST.此库的副本位于:http: //peerit.blogspot.com/2007/07/multipartposthandler-doesnt-work-for.html
我是Python的新手,无法让这个库工作.我基本上写了下面的代码.当我在本地HTTP代理中捕获它时,我可以看到数据仍然是URL编码的,而不是多部分MIME编码.请帮我弄清楚我做错了什么或更好的方法来完成这件事.谢谢 :-)
FROM_ADDR = 'my@email.com' try: data = open(file, 'rb').read() except: print "Error: could not open file %s for reading" % file print "Check permissions on the file or folder it resides in" sys.exit(1) # Build the POST request url = "http://somedomain.com/?action=analyze" post_data = {} post_data['analysisType'] = 'file' post_data['executable'] = data post_data['notification'] = 'email' post_data['email'] = FROM_ADDR # MIME encode the POST payload opener = urllib2.build_opener(MultipartPostHandler.MultipartPostHandler) urllib2.install_opener(opener) request = urllib2.Request(url, post_data) request.set_proxy('127.0.0.1:8080', 'http') # For testing with Burp Proxy # Make the request and capture the response try: response = urllib2.urlopen(request) print response.geturl() except urllib2.URLError, e: print "File upload failed..."
编辑1:谢谢你的回复.我知道ActiveState httplib解决方案(我上面链接到它).我宁愿抽象出问题,并使用最少量的代码继续使用urllib2我是怎么做的.知道为什么没有安装和使用开瓶器?
似乎解决这个问题的最简单和最兼容的方法是使用'poster'模块.
# test_client.py from poster.encode import multipart_encode from poster.streaminghttp import register_openers import urllib2 # Register the streaming http handlers with urllib2 register_openers() # Start the multipart/form-data encoding of the file "DSC0001.jpg" # "image1" is the name of the parameter, which is normally set # via the "name" parameter of the HTML tag. # headers contains the necessary Content-Type and Content-Length # datagen is a generator object that yields the encoded parameters datagen, headers = multipart_encode({"image1": open("DSC0001.jpg")}) # Create the Request object request = urllib2.Request("http://localhost:5000/upload_image", datagen, headers) # Actually do the request, and get the response print urllib2.urlopen(request).read()
这完美无缺,我不需要使用httplib.该模块可在此处获取:http: //atlee.ca/software/poster/index.html
找到此配方httplib
直接发布multipart (不涉及外部库)
import httplib import mimetypes def post_multipart(host, selector, fields, files): content_type, body = encode_multipart_formdata(fields, files) h = httplib.HTTP(host) h.putrequest('POST', selector) h.putheader('content-type', content_type) h.putheader('content-length', str(len(body))) h.endheaders() h.send(body) errcode, errmsg, headers = h.getreply() return h.file.read() def encode_multipart_formdata(fields, files): LIMIT = '----------lImIt_of_THE_fIle_eW_$' CRLF = '\r\n' L = [] for (key, value) in fields: L.append('--' + LIMIT) L.append('Content-Disposition: form-data; name="%s"' % key) L.append('') L.append(value) for (key, filename, value) in files: L.append('--' + LIMIT) L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename)) L.append('Content-Type: %s' % get_content_type(filename)) L.append('') L.append(value) L.append('--' + LIMIT + '--') L.append('') body = CRLF.join(L) content_type = 'multipart/form-data; boundary=%s' % LIMIT return content_type, body def get_content_type(filename): return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
只需使用python-requests,它将设置正确的标头并为您上传:
import requests files = {"form_input_field_name": open("filename", "rb")} requests.post("http://httpbin.org/post", files=files)