urllib2实现文件上传

本文介绍了如何使用urllib2库进行文件上传,重点在于理解boundary的使用,它作为POST请求中数据的分隔符,确保服务器能正确解析上传的内容。文章通过代码示例展示了如何构造带有文件上传的POST请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需要做什么?

如果使用get方法向服务器发送如下数据:

name: zhangsan
from: beijing

content-type为application/x-www-form-urlencoded,则会传输数据:

name=zhangsan&from=beijing

可以看到两组数据被&分割,这样服务器就能够正确解析客户端上传的数据。那当使用post方法提交数据时,应该使用什么样的分割符呢? boundary


怎么做?

  1. boundary不能与form表单的其他数据重复。
  2. boundary在整个请求中要保持一致。

拼接如下表单:

—xxx—
Content-Disposition: form-data; name=”name”

zhangsan
—xxx—
Content-Disposition: form-data; name=”from”

beijing
—xxx—
Content-Disposition: file; name=”record”; filename=”record.txt”
Content-Type: text/plain

file upload blog.


代码实现

# encoding: utf-8
# client.py
import itertools
import mimetools
import mimetypes
from cStringIO import StringIO 
import urllib
import urllib2

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__':
    form = MultiPartForm()
    form.add_field('name', 'zhangsan')
    form.add_field('from', 'beijing')

    form.add_file('record', 'record.txt', file_obj = StringIO('urllib2 file upload.'))

    request = urllib2.Request('http://localhost:8080/')
    body = str(form)
    request.add_header('Content-type', 'multipart/form-data; boundary=%s' % form.boundary)
    request.add_header('Content-length', len(body))
    request.add_data(body)

    print
    print 'Request'
    print request.get_data()

    print 
    print 'Response'
    print urllib2.urlopen(request).read()
# server.py
# framework 'web.py'
import web

urls = (
    '/', 'hello'
)
app = web.application(urls, globals())

class hello:        
    def POST(self):
        form = web.input()
        return '\r\n'.join(['%s=%s' %(k,v) for k,v in form.items()])

if __name__ == "__main__":
    app.run()
# result
python urllib2_upload_files.py 

Request
--127.0.1.1.1000.31866.1426991278.082.1
Content-Disposition: form-data; name="name"

zhangsan
--127.0.1.1.1000.31866.1426991278.082.1
Content-Disposition: form-data; name="from"

beijing
--127.0.1.1.1000.31866.1426991278.082.1
Content-Disposition: file; name="record"; filename="record.txt"
Content-Type: text/plain

urllib2 file upload.
--127.0.1.1.1000.31866.1426991278.082.1--


Response
record=urllib2 file upload.
from=beijing
name=zhangsan
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值