Как десериализовать разделенные данные JSON - PullRequest
1 голос
/ 13 июня 2019

Я передаю данные через Server Send Event и получаю около 500.000 datasets, но вместо того, чтобы получить один json, я получаю это (пример 2 из 500 000 наборов данных) (это выглядит как открытие его в gedit, все вопросительные знаки \ "и все новые строки \ n):

data:{\"data\":[\"Kendrick\",\"Lamar\"]}\n\ndata:{\"data\":[\"David\",\"Bowie\"]}\n\n
... -

Моя цель - поместить это в базу данных. Я на самом деле думал, что я поместил это в словарь, а затем создал отснятый кадр данных для панд, и теперь я смогу поместить его в базу данных. Но это оказывается довольно громоздким. Я закончил что-то вроде этого:

c1 = data_json[1:-1]
c2 = c1.replace('{data:{', '{\"data\":{')
c3 = c2.replace('}data:{', ', ')
c4 = '{' + c3 + '}' 

но даже здесь у меня есть некоторые проблемы, так как я должен добавить / n / n для новых строк. Но как только я изменяю c3 на c2.replace('}\n\ndata:{', ', '), я получаю Process finished with exit code 137 (interrupted by signal 9: SIGKILL). Исходя из .NET, я мог бы справиться с этим довольно легко с десериализатором, и мне интересно, есть ли подобный способ десериализации данных. Я получаю данные через sseclient и смогу хранить их как байты вместо строки, если это поможет, просто к сведению.

Есть предложения?

Ответы [ 2 ]

1 голос
/ 14 июня 2019

Жонглирование с заменами, конечно, запутанный путь - язык имеет встроенные парсеры для этого вида экранирования - более простой из которых будет передача строки, содержащей JSON, через вызов eval. Но eval редко требуется, и его следует избегать в большинстве случаев как «не элегантный» - если не совсем небезопасный (но будучи небезопасным, на самом деле применяется только тогда, когда у вас нет контроля над входными данными - и даже ими, ast.literal_eval вместо простых eval может смягчить это). В любом случае, есть другие проблемы с форматом, которые не позволят eval работать напрямую - например, пропущенные кавычки data:.

Случайные ранты друг от друга, если содержимое вашего файла на самом деле:

data:{\"data\":[\"Kendrick\",\"Lamar\"]}\n\ndata:{\"data\":[\"David\",\"Bowie\"]}\n\n

У него есть две проблемы: "занижение" из самых крайних data и «переброс» внутренних данных.

В интерактивном сеансе Python, используя маркер «необработанная строка», я могу ввести строку примера, так как она будет прочитана из файла:

In [263]: a = r"""data:{\"data\":[\"Kendrick\",\"Lamar\"]}\n\ndata:{\"data\":[\"David\",\"Bowie\"]}\n\n"""                                             

In [264]: print(a)                                                                                                                                     
data:{\"data\":[\"Kendrick\",\"Lamar\"]}\n\ndata:{\"data\":[\"David\",\"Bowie\"]}\n\n

Итак, для удаления одного уровня обратной косой черты - в Python есть кодировка текста "unicode_escape", но она работает только с байтами-объектами. Затем мы прибегаем к кодировке «latin1», поскольку она обеспечивает побайтное преобразование литерала Юникода в «a» в байты, а затем применяем unicode_escape для удаления «\»:

In [266]: b = a.encode("latin1").decode("unicode_escape")  

In [267]: print(b, "\n", repr(b))                                                                                                                      
data:{"data":["Kendrick","Lamar"]}

data:{"data":["David","Bowie"]}


 'data:{"data":["Kendrick","Lamar"]}\n\ndata:{"data":["David","Bowie"]}\n\n'

теперь легко разобрать: Мы разделяем полученную строку на "\ n \ n" и получаем один список с одной записью (те, которые вы называете "набор данных") для каждого элемента. Тогда мы прибегаем к струне манипуляции, чтобы избавиться от начального "data:" и, наконец, json.load может работать на оставшуюся часть.

так:

import json

raw_data = open("mystrangefile.pseudo_json").read()
data = data.encode("latin1").decode("unicode_escape")
records = [json.loads(record.split(":", 1)[-1]) for record in data.split("\n\n")]

И "записи" теперь должны содержать словари объектов Python с хорошим поведением, которые вы можете поместить в базу данных. (Если Pandas не может обеспечить автоматическое сопоставление столбцов с базами данных, этот шаг кажется ненужным - необработанного connection.executemany(""" INSERT ...""", records) с надлежащим открытым подключением к БД должно быть достаточно.

Кроме того, в сообщении, которое вы упомянули, вы можете легко справиться с этим с помощью десериализатора .NET: это только в том случае, если ваши файлы не так повреждены, как вы показали нам, - ни один из возможных стандартных сериализаторов не может знать, как обрабатывать такие специфические ошибки. формат данных из коробки. Но, если вы на самом деле более эффективны в этом на другом языке / технологии, вы можете просто написать конвертер из сломанного ввода в правильно закодированный файл и использовать его в качестве промежуточного шага.

0 голосов
/ 14 июня 2019

Я не совсем уверен, правильно ли я понял формат, в котором вы получаете строку, поэтому, пожалуйста, поправьте меня, если я ошибаюсь:

data_json = 'data:{\\"data\\":[\\"Kendrick\\",\\"Lamar\\"]}\\n\\ndata:{\\"data\\":[\\"David\\",\\"Bowie\\"]}\\n\\n'

Ваш первыйСтрока, кажется, лишает первого и последнего символа, который я не вижу.Есть ли какие-либо дополнительные символы, которые вы здесь удаляете?

Две следующие замены подстрок, кажется, не имеют никакого эффекта, так как подстроки отсутствуют в исходной строке (если я правильно понял в первую очередь).

И, наконец, в последней строке вы оборачиваете свой результат { и }, что неправильно для списков в json.Это должно быть [...]

Хотя я не могу точно сказать, почему вы получите SIGKILL здесь.Он не выдаёт мне ошибок, он просто не делает то, что вы хотите.Может быть, вам не хватает памяти со всеми примерами 500 Кбайт?

Однако это было бы рабочим решением (опять же, учитывая, что я правильно получил исходную строку):

c1 = data_json.replace('\\n\\n', '')  # removing escaped newlines
c2 = c1.replace('data:', ',') # replacing the additional 'data:' with json delimiter ','
c3 = c2.replace('\\', '') # removing artificial escapes
c4 = c3[1:-1] # removing leading ',' (introduced in c2) and trailing newline
c5 = '[' + c4 + ']' # wrapping as list

Теперь вы должны иметь возможность json.loads(c5) или все, что вам нужно сделать с этой строкой.

...