python中使用urllib2上传文件

python代码实现

上传文件是以multipart/form-data的方式将文件内容POST到服务器端,python的HTTP通信库(urllib、urllib2之类)默认不支持multipart协议,但可以按协议格式自行实现:

class MultiPartForm():
    def __init__(self):
        self.form_fields = []
        self.files = []
        self.boundary = mimetools.choose_boundary()

    def add_field(self, name, value):
        """添加field数据到form表单"""
        self.form_fields.append((name, value))

    def add_file(self, fieldname, filename, file_obj, mimetype=None):
        """添加文件到表单"""
        if not mimetype:
            mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
        self.files.append((fieldname, filename, mimetype, file_obj.read()))
    def __str__(self):
        """拼接form报文"""
        parts = []
        part_boundary = "--%s" % self.boundary

        # 添加fields
        parts.extend(
            [part_boundary,
            'Content-Disposition: form-data; name="%s"' %name,
            '',
            value,] for name, value in self.form_fields
            )

        # 添加要上传的files
        parts.extend(
            [part_boundary,
            'Content-Disposition: file; name="%s"; filename="%s"' % (field_name, filename),
            'Content-Type: %s' % content_type,
            '',
            body,] for field_name, filename, content_type, body in self.files
            )

        # 压平parts添加boundary终止符
        flattened = list(itertools.chain(*parts))
        flattened.append('--%s--' % self.boundary)
        flattened.append('')
        return '\r\n'.join(flattened)

该类的使用例子:

if __name__ == '__main__':

    filename = './images/a.jpg'
    form = MultiPartForm()

    form.add_file('image', 'a.jpg', file_obj = open(filename))
    request = urllib2.Request('http://url.com/s/api?cmd=Image.add')

    body = str(form)
    request.add_header('Content-type', 'multipart/form-data; boundary=%s' % form.boundary)
    request.add_header('Content-length', len(body))
    request.add_header('Cookie', 'SPSSID=xxxxxxxxxx')
    request.add_data(body)

    print(urllib2.urlopen(request).read())

wget实现

wget当前不支持multipart,不过,也可以采用添加multipart头,并手动修改上传文件的方式实现。mutlipart头例如:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryR5xMWIPvfrpzmD5S

wget的--post-file参数并不是指定要上传的文件,而是指定存有query串的文本,也就是说你可以--post-data "name=abc&age=100",也可以将"name=abc&age=100"存在文件tmp.txt里,然后--post-file "tmp.txt"。所以将要编辑要上传的二进制文件成如下格式:

------WebKitFormBoundaryR5xMWIPvfrpzmD5S
Content-Disposition: form-data; name="image"; filename="a.jpg"
Content-Type: image/jpeg

[二进制文件内容]
------WebKitFormBoundaryR5xMWIPvfrpzmD5S
Content-Disposition: form-data; name="cmd"

Image.add
------WebKitFormBoundaryR5xMWIPvfrpzmD5S--

特别注意:此处的回车换行必须依据HTTP规定,使用"\r\n"。

curl实现

curl直接就支持了multipart,使用起来就是一个参数而已,非常方便:

curl -X POST -b "SESSIONID=xxxxx"  -F "image=@a.jpg" "http://example.com/s/api?cmd=Image.add"

如果不上传文件,只是普通post提交数据,命令举例如下:

curl -X POST -b "SESSONID=xxxxx" -d "cmd=Archive.del&userId=101&archiveId=100" "http://example.com/s/api"

POST内容来自于文件:

curl -X POST 'http://example.com/update/' -d @data.json

 

发表于 2015年08月21日 01:48   评论:0   阅读:5715  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo