Парсить строку составные данные

у меня есть строка (base64 декодирована здесь), которая выглядит так:

----------------------------212550847697339237761929
Content-Disposition: form-data; name="preferred_name"; filename="file1.rtf"
Content-Type: application/rtf

{rtf1ansiansicpg1252cocoartf1504cocoasubrtf830
{fonttblf0fswissfcharset0 Helvetica;}
{colortbl;red255green255blue255;}
{*expandedcolortbl;;}
margl1440margr1440vieww10800viewh8400viewkind0
pardtx720tx1440tx2160tx2880tx3600tx4320tx5040tx5760tx6480tx7200tx7920tx8640pardirnaturalpartightenfactor0

f0fs24 cf0 testing123FILE1}
----------------------------212550847697339237761929
Content-Disposition: form-data; name="to_process"; filename="file2.rtf"
Content-Type: application/rtf

{rtf1ansiansicpg1252cocoartf1504cocoasubrtf830
{fonttblf0fswissfcharset0 Helvetica;}
{colortbl;red255green255blue255;}
{*expandedcolortbl;;}
margl1440margr1440vieww10800viewh8400viewkind0
pardtx720tx1440tx2160tx2880tx3600tx4320tx5040tx5760tx6480tx7200tx7920tx8640pardirnaturalpartightenfactor0

f0fs24 cf0 testing123FILE212341234}
----------------------------212550847697339237761929--

Я создаю это на простой веб-странице, которая загружает пару файлов в скрипт AWS Lambda через запрос PUT с помощью шлюза API. Следует отметить, что то, что я получаю от шлюза API, является строкой Base64, которую я затем декодирую в строку выше.

строка выше-это данные, которые мой лямбда-скрипт получает от шлюза API. что я хотел бы сделать, это разобрать эту строку чтобы получить данные, содержащиеся в Python 2.7. я экспериментировал с cgi классе и использовать cgi.parse_multipart() метод, однако, я не могу найти способ преобразовать строку в требуемые аргументы. Есть советы?

2 ответов


комментарий: он робастн и спецификации уступчивые?

пока ваши данные следуют этим предварительным условиям:

  • на первый строка граница
  • следующий заголовок завершается с пустой строка
  • каждая часть сообщения завершается с граница

комментарий: что если содержимое бинарном потоке jpeg?

это, вероятно, сломать, как есть строка используемые методы и чтение содержимого используют .readline() которых зависит Новая Строка.
Поэтому к decode из BASE64, а затем unpack Multipart являются неправильно подход!


комментарий: если есть версия, повторно использующая общую библиотеку

если вы можете предоставить свои данные в качестве стандарта МИМ сообщение вы можете использовать следующее:

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))

выход:

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)

вопрос: разбор строки составных данных

чистое решение Python, например:

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)

выход:

{'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)

протестировано с Python: 3.4.2


Если вы работаете с API, лучше использовать данные в формате json. Вы можете использовать модуль запросов для отправки запроса PUT в API, и он вернет вам объект ответа, из которого вы можете легко получить данные json с помощью метода ответ.в JSON()