Analizar una cadena de datos multiparte

Tengo una cadena (base64 descodificada aquí) que se parece a esto:

----------------------------212550847697339237761929 Content-Disposition: form-data; name="preferred_name"; filename="file1.rtf" Content-Type: application/rtf {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf830 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \margl1440\margr1440\vieww10800\viewh8400\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \f0\fs24 \cf0 testing123FILE1} ----------------------------212550847697339237761929 Content-Disposition: form-data; name="to_process"; filename="file2.rtf" Content-Type: application/rtf {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf830 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \margl1440\margr1440\vieww10800\viewh8400\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \f0\fs24 \cf0 testing123FILE212341234} ----------------------------212550847697339237761929-- 

Lo genero en una página web simple que carga un par de archivos en un script de AWS Lambda a través de una solicitud PUT con la puerta de enlace API. Cabe señalar que lo que obtengo de la puerta de enlace API es una cadena Base64 que luego decodifico en la cadena anterior.

La cadena de arriba es la información que mi script Lambda recibe de la puerta de enlace API. Lo que me gustaría hacer es analizar esta cadena para recuperar los datos contenidos en Python 2.7. He experimentado con la clase cgi y usando el método cgi.parse_multipart() , sin embargo, no puedo encontrar una manera de convertir una cadena a los argumentos requeridos. ¿Algun consejo?

Comentario : ¿es robusto y compatible con las especificaciones?

Mientras sus datos sigan estas condiciones previas:

  • La primera línea es el límite
  • El siguiente encabezado se termina con una línea vacía
  • Cada parte del mensaje se termina con el límite

Comentario : ¿Qué sucede si el contenido es binario como una transmisión JPEG?

Es probable que se rompa, ya que se utilizan métodos de cadena y leer el contenido usa .readline() que depende de la nueva línea .
Por lo tanto, ¡para decode desde BASE64 y luego unpack Multipart es el enfoque incorrecto !


Comentario : si hay una versión reutilizando una librería común.

Si puede proporcionar sus datos como mensaje MIME estándar, puede utilizar lo siguiente:

 import email msg = email.message_from_string(mimeHeader+data) print('is_multipart:{}'.format(msg.is_multipart())) for part in msg.walk(): if part.get_content_maintype() == 'multipart': continue filename = part.get_filename() payload = part.get_payload(decode=True) print('{} filename:{}\n{}'.format(part.get_content_type(), filename, payload)) 

Salida :

 is_multipart:True application/rtf filename:file1.rtf b'{\rtf1\x07nsi\x07nsicpg1252\\cocoartf1504\\cocoasubrtf830\n{\x0conttbl\x0c0\x0cswiss\x0ccharset0'... (omitted for brevity) application/rtf filename:file2.rtf b'{\rtf1\x07nsi\x07nsicpg1252\\cocoartf1504\\cocoasubrtf830\n{\x0conttbl\x0c0\x0cswiss\x0ccharset0'... (omitted for brevity) 

Pregunta : Analizar una cadena de datos multiparte

Solución de Python puro, por ejemplo:

 import re, io with io.StringIO(data) as fh: parts = [] part_line = [] part_fname = None new_part = None robj = re.compile('.+filename=\"(.+)\"') while True: line = fh.readline() if not line: break if not new_part: new_part = line[:-1] if line.startswith(new_part): if part_line: parts.append({'filename':part_fname, 'content':''.join(part_line)}) part_line = [] while line and line != '\n': _match = robj.match(line) if _match: part_fname = _match.groups()[0] line = fh.readline() else: part_line.append(line) for part in parts: print(part) 

Salida :

 {'filename': 'file1.rtf', 'content': '{\rtf1\x07nsi\x07nsicpg1252\\cocoartf1504\\cocoasubrtf830\n... (omitted for brevity) {'filename': 'file2.rtf', 'content': '{\rtf1\x07nsi\x07nsicpg1252\\cocoartf1504\\cocoasubrtf830\n... (omitted for brevity) 

Probado con Python: 3.4.2

Si está trabajando con una API, es mejor usar datos con formato json. Puede usar el módulo de solicitudes para enviar una solicitud PUT a la API y le devolverá el objeto de respuesta desde el cual puede recuperar los datos json fácilmente usando el método response.json ()