2009-08-13 4 views
18

Я хотел бы получить данные POST multipart/form-data. Я нашел внешний модуль, который делает это: http://atlee.ca/software/poster/index.html Однако я бы предпочел избежать этой зависимости. Есть ли способ сделать это, используя стандартные библиотеки?Стандартная библиотека Python для POST multipart/form-data закодированных данных

благодаря

ответ

17

Стандартная библиотека does not currently support that. Существует cookbook recipe, который включает в себя довольно короткий фрагмент кода, который вы только что захотите скопировать, но вместе с длинными обсуждениями альтернатив.

5

Вы не можете сделать это с помощью stdlib быстро. Howevewr, см. Класс MultiPartForm в этом PyMOTW. Вы, вероятно, можно использовать или изменить, что для достижения все, что нужно:

8

Это старая нить, но все еще популярный один, так вот мой вклад, используя только стандартные модули.

Идея такая же, как у here, но поддержка Python 2.x и Python 3.x. Он также имеет генератор корпуса, чтобы избежать ненужного использования памяти.

import codecs 
import mimetypes 
import sys 
import uuid 
try: 
    import io 
except ImportError: 
    pass # io is requiered in python3 but not available in python2 

class MultipartFormdataEncoder(object): 
    def __init__(self): 
     self.boundary = uuid.uuid4().hex 
     self.content_type = 'multipart/form-data; boundary={}'.format(self.boundary) 

    @classmethod 
    def u(cls, s): 
     if sys.hexversion < 0x03000000 and isinstance(s, str): 
      s = s.decode('utf-8') 
     if sys.hexversion >= 0x03000000 and isinstance(s, bytes): 
      s = s.decode('utf-8') 
     return s 

    def iter(self, fields, files): 
     """ 
     fields is a sequence of (name, value) elements for regular form fields. 
     files is a sequence of (name, filename, file-type) elements for data to be uploaded as files 
     Yield body's chunk as bytes 
     """ 
     encoder = codecs.getencoder('utf-8') 
     for (key, value) in fields: 
      key = self.u(key) 
      yield encoder('--{}\r\n'.format(self.boundary)) 
      yield encoder(self.u('Content-Disposition: form-data; name="{}"\r\n').format(key)) 
      yield encoder('\r\n') 
      if isinstance(value, int) or isinstance(value, float): 
       value = str(value) 
      yield encoder(self.u(value)) 
      yield encoder('\r\n') 
     for (key, filename, fd) in files: 
      key = self.u(key) 
      filename = self.u(filename) 
      yield encoder('--{}\r\n'.format(self.boundary)) 
      yield encoder(self.u('Content-Disposition: form-data; name="{}"; filename="{}"\r\n').format(key, filename)) 
      yield encoder('Content-Type: {}\r\n'.format(mimetypes.guess_type(filename)[0] or 'application/octet-stream')) 
      yield encoder('\r\n') 
      with fd: 
       buff = fd.read() 
       yield (buff, len(buff)) 
      yield encoder('\r\n') 
     yield encoder('--{}--\r\n'.format(self.boundary)) 

    def encode(self, fields, files): 
     body = io.BytesIO() 
     for chunk, chunk_len in self.iter(fields, files): 
      body.write(chunk) 
     return self.content_type, body.getvalue() 

Demo

# some utf8 key/value pairs 
fields = [('প্রায়', 42), ('bar', b'23'), ('foo', 'ން:')] 
files = [('myfile', 'image.jpg', open('image.jpg', 'rb'))] 

# iterate and write chunk in a socket 
content_type, body = MultipartFormdataEncoder().encode(fields, files) 
+0

Наконец решение, которое работает на Python 3 только в стандартной библиотеке. –