2015-01-16 6 views
0

Недавно я использовал API для загрузки некоторых данных с платформы, которую я использую.Преобразование неизвестной структуры данных в известную структуру данных в Python

Но проблема в том, что данные, которые я вытащил, не являются признанной структурой данных.

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

Мне нужно знать, как преобразовать его в распознанную структуру данных. Мне не обязательно нужен код для этого, только север на том, что мне нужно для изучения, будет полезен уже. Я новичок в Python, и у меня нет большого опыта в кодировании.

У меня есть файл с этими данными в каждой строке, это пример строки из файла:

[<OrderProducts at 0x24333f0, {'price_ex_tax': '99.0000', 'event_date': '', 'wrapping_name': '', 'price_tax': '0.0000', 'id': 3, 'cost_price_tax': '0.0000', 'bin_picking_number': '', 'ebay_transaction_id': '', 'wrapping_cost_ex_tax': '0.0000', 'base_total': '99.0000', 'quantity': 1, 'ebay_item_id': '', 'type': 'physical', 'product_id': 83, 'price_inc_tax': '99.0000', 'base_wrapping_cost': '0.0000', 'parent_order_product_id': None, 'option_set_id': 15, 'wrapping_message': '', 'weight': '3.0000', 'refund_amount': '0.0000', 'applied_discounts': [{'amount': 99, 'id': 'total-coupon'}], 'event_name': None, 'cost_price_ex_tax': '0.0000', 'base_price': '99.0000', 'wrapping_cost_tax': '0.0000', 'total_inc_tax': '99.0000', 'total_ex_tax': '99.0000', 'quantity_shipped': 0, 'fixed_shipping_cost': '0.0000', 'total_tax': '0.0000', 'sku': 'S-TIM-BAC-STD', 'return_id': 0, 'wrapping_cost_inc_tax': '0.0000', 'cost_price_inc_tax': '0.0000', 'name': 'University of Timbuktu Bachelor Set', 'is_bundled_product ': False, 'order_id': 614534, 'configurable_fields': [], 'order_address_id': 2, 'is_refunded': False, 'product_options': [{'display_style': 'Pick list', 'type': 'Product list', 'product_option_id': 95, 'display_value': 'Cambridge-Style Bachelor Gown, Size L', 'id': 2, 'option_id': 19, 'value': '77', 'display_name': 'Gown size', 'name': 'Bachelor gown size', 'order_product_id': 3}, {'display_style': 'Pick list', 'type': 'Product list', 'product_option_id': 97, 'display_value': 'Bachelor and Masters Trencher, Size L', 'id': 3, 'option_id': 20, 'value': '80', 'display_name': 'Trencher size', 'name': 'Trencher size', 'order_product_id': 3}], 'base_cost_price': '0.0000'}>, <OrderProducts at 0x2433420, {'price_ex_tax': '0.0000', 'event_date': '', 'wrapping_name': '', 'price_tax': '0.0000', 'id': 4, 'cost_price_tax': '0.0000', 'bin_picking_number': '', 'ebay_transaction_id': '', 'wrapping_cost_ex_tax': '0.0000', 'base_total': '0.0000', 'quantity': 1, 'ebay_item_id': '', 'type': 'physical', 'product_id': 80, 'price_inc_tax': '0.0000', 'base_wrapping_cost': '0.0000', 'parent_order_product_id': 3, 'option_set_id': None, 'wrapping_message': '', 'weight': '0.0000', 'refund_amount': '0.0000', 'applied_discounts': [], 'event_name': None, 'cost_price_ex_tax': '0.0000', 'base_price': '0.0000', 'wrapping_cost_tax': '0.0000', 'total_inc_tax': '0.0000', 'total_ex_tax': '0.0000', 'quantity_shipped': 0, 'fixed_shipping_cost': '0.0000', 'total_tax': '0.0000', 'sku': 'G-CAM-BAC-L', 'return_id': 0, 'wrapping_cost_inc_tax': '0.0000', 'cost_price_inc_tax': '0.0000', 'name': 'Cambridge-Style Bachelor Gown, Size L', 'is_bundled_product ': True, 'order_id': 614534, 'configurable_fields': [], 'order_address_id': 2, 'is_refunded': False, 'product_options': [], 'base_cost_price': '0.0000'}>, <OrderProducts at 0x2433450, {'price_ex_tax': '0.0000', 'event_date': '', 'wrapping_name': '', 'price_tax': '0.0000', 'id': 5, 'cost_price_tax': '0.0000', 'bin_picking_number': '', 'ebay_transaction_id': '', 'wrapping_cost_ex_tax': '0.0000', 'base_total': '0.0000', 'quantity': 1, 'ebay_item_id': '', 'type': 'physical', 'product_id': 87, 'price_inc_tax': '0.0000', 'base_wrapping_cost': '0.0000', 'parent_order_product_id': 3, 'option_set_id': None, 'wrapping_message': '', 'weight': '0.0000', 'refund_amount': '0.0000', 'applied_discounts': [], 'event_name': None, 'cost_price_ex_tax': '0.0000', 'base_price': '0.0000', 'wrapping_cost_tax': '0.0000', 'total_inc_tax': '0.0000', 'total_ex_tax': '0.0000', 'quantity_shipped': 0, 'fixed_shipping_cost': '0.0000', 'total_tax': '0.0000', 'sku': 'C-STD-B&M-L', 'return_id': 0, 'wrapping_cost_inc_tax': '0.0000', 'cost_price_inc_tax': '0.0000', 'name': 'Bachelor and Masters Trencher, Size L', 'is_bundled_product ': True, 'order_id': 614534, 'configurable_fields': [], 'order_address_id': 2, 'is_refunded': False, 'product_options': [], 'base_cost_price': '0.0000'}>] 

EDIT: Это код, который я получил:

import ast 
import re 

order_item = re.compile("<OrderProducts at 0x[\da-f]+, ({.*?})>", re.I) 

with open('allOrderProducts2') as inf: 
    for line in inf: 
     order = [ast.literal_eval(op) for op in re.findall(order_item, line)] 
     # ta-da! Now do something with the order 
     f = open("test", "w", encoding='utf-8') 
     f.write("\n".join(map(lambda x: str(x), order))) 
     f.close() 
+1

Похоже, данные JSON - проверьте модуль 'json'. –

+0

[literal_eval] (https://docs.python.org/2/library/ast.html#ast.literal_eval) может быть полезна для этого случая. – Marcin

+0

@Marcin Пробовал, все еще получая синтаксическую ошибку. Проверка модуля 'json'. –

ответ

1

Что у вас есть список ([ ... ]), содержащие три OrderProducts объектов, которые при печати, представляют себя как словари ({ key1: value1, key2: value2 }).


Edit: хорошо, у вас есть строковое представление из трех OrderProducts и т.д.

Так первым делом для преобразования фактических структур данных Python, например, так:

import ast 
import re 

order_items = re.compile("<OrderProducts at 0x[\da-f]+, ({.*?})>", re.I).findall 

with open(FILENAME) as inf: 
    for line in inf: 
     order = [ast.literal_eval(op) for op in order_items(line)] 
     # ta-da! Now do something with the order 

затем продолжают, как и раньше:


Edit2:

Подчищены немного:

import re 

DATA = "allOrderProducts2" 
RESULT = "test" 

order_items = re.compile("<OrderProducts at 0x[\da-f]+, ({.*?})>", re.I).findall 

with open(DATA) as inf, open(RESULT, "w", "utf-8") as outf: 
    # Instead of reading each line separately, 
    # we can just parse the whole file in one gulp 
    for item_str in order_items(inf.read()): 
     # Also no need to convert the data 
     # just to cast it back to a string again 
     outf.write(item_str + "\n") 

Затем при чтении файла РЕЗУЛЬТАТ обратно, вы можете передать каждую строку ast.literal_eval, чтобы превратить его обратно в Словаре.


Глядя на id и parent_order_product_id полей, похоже, что у вас есть это «Университет Тимбукту Bachelor Набор» состоящий из «Cambridge-Style Bachelor платье, размер L» и «Бакалавр и Магистр траншеекопатель, Размер L "с ценой пакета 99,0 (единицы неизвестны) и без налога.

Я написал небольшой скрипт, чтобы выяснить, что по умолчанию OrderProduct выглядит следующим образом:

from collections import Counter 
from pprint import pprint as pp 

data = [ 
    {'price_ex_tax': '99.0000', 'event_date': '', 'wrapping_name': '', 'price_tax': '0.0000', 'id': 3, 'cost_price_tax': '0.0000', 'bin_picking_number': '', 'ebay_transaction_id': '', 'wrapping_cost_ex_tax': '0.0000', 'base_total': '99.0000', 'quantity': 1, 'ebay_item_id': '', 'type': 'physical', 'product_id': 83, 'price_inc_tax': '99.0000', 'base_wrapping_cost': '0.0000', 'parent_order_product_id': None, 'option_set_id': 15, 'wrapping_message': '', 'weight': '3.0000', 'refund_amount': '0.0000', 'applied_discounts': [{'amount': 99, 'id': 'total-coupon'}], 'event_name': None, 'cost_price_ex_tax': '0.0000', 'base_price': '99.0000', 'wrapping_cost_tax': '0.0000', 'total_inc_tax': '99.0000', 'total_ex_tax': '99.0000', 'quantity_shipped': 0, 'fixed_shipping_cost': '0.0000', 'total_tax': '0.0000', 'sku': 'S-TIM-BAC-STD', 'return_id': 0, 'wrapping_cost_inc_tax': '0.0000', 'cost_price_inc_tax': '0.0000', 'name': 'University of Timbuktu Bachelor Set', 'is_bundled_product ': False, 'order_id': 614534, 'configurable_fields': [], 'order_address_id': 2, 'is_refunded': False, 'product_options': [{'display_style': 'Pick list', 'type': 'Product list', 'product_option_id': 95, 'display_value': 'Cambridge-Style Bachelor Gown, Size L', 'id': 2, 'option_id': 19, 'value': '77', 'display_name': 'Gown size', 'name': 'Bachelor gown size', 'order_product_id': 3}, {'display_style': 'Pick list', 'type': 'Product list', 'product_option_id': 97, 'display_value': 'Bachelor and Masters Trencher, Size L', 'id': 3, 'option_id': 20, 'value': '80', 'display_name': 'Trencher size', 'name': 'Trencher size', 'order_product_id': 3}], 'base_cost_price': '0.0000'}, 
    {'price_ex_tax': '0.0000', 'event_date': '', 'wrapping_name': '', 'price_tax': '0.0000', 'id': 4, 'cost_price_tax': '0.0000', 'bin_picking_number': '', 'ebay_transaction_id': '', 'wrapping_cost_ex_tax': '0.0000', 'base_total': '0.0000', 'quantity': 1, 'ebay_item_id': '', 'type': 'physical', 'product_id': 80, 'price_inc_tax': '0.0000', 'base_wrapping_cost': '0.0000', 'parent_order_product_id': 3, 'option_set_id': None, 'wrapping_message': '', 'weight': '0.0000', 'refund_amount': '0.0000', 'applied_discounts': [], 'event_name': None, 'cost_price_ex_tax': '0.0000', 'base_price': '0.0000', 'wrapping_cost_tax': '0.0000', 'total_inc_tax': '0.0000', 'total_ex_tax': '0.0000', 'quantity_shipped': 0, 'fixed_shipping_cost': '0.0000', 'total_tax': '0.0000', 'sku': 'G-CAM-BAC-L', 'return_id': 0, 'wrapping_cost_inc_tax': '0.0000', 'cost_price_inc_tax': '0.0000', 'name': 'Cambridge-Style Bachelor Gown, Size L', 'is_bundled_product ': True, 'order_id': 614534, 'configurable_fields': [], 'order_address_id': 2, 'is_refunded': False, 'product_options': [], 'base_cost_price': '0.0000'}, 
    {'price_ex_tax': '0.0000', 'event_date': '', 'wrapping_name': '', 'price_tax': '0.0000', 'id': 5, 'cost_price_tax': '0.0000', 'bin_picking_number': '', 'ebay_transaction_id': '', 'wrapping_cost_ex_tax': '0.0000', 'base_total': '0.0000', 'quantity': 1, 'ebay_item_id': '', 'type': 'physical', 'product_id': 87, 'price_inc_tax': '0.0000', 'base_wrapping_cost': '0.0000', 'parent_order_product_id': 3, 'option_set_id': None, 'wrapping_message': '', 'weight': '0.0000', 'refund_amount': '0.0000', 'applied_discounts': [], 'event_name': None, 'cost_price_ex_tax': '0.0000', 'base_price': '0.0000', 'wrapping_cost_tax': '0.0000', 'total_inc_tax': '0.0000', 'total_ex_tax': '0.0000', 'quantity_shipped': 0, 'fixed_shipping_cost': '0.0000', 'total_tax': '0.0000', 'sku': 'C-STD-B&M-L', 'return_id': 0, 'wrapping_cost_inc_tax': '0.0000', 'cost_price_inc_tax': '0.0000', 'name': 'Bachelor and Masters Trencher, Size L', 'is_bundled_product ': True, 'order_id': 614534, 'configurable_fields': [], 'order_address_id': 2, 'is_refunded': False, 'product_options': [], 'base_cost_price': '0.0000'} 
] 

def get_defaults(lst_of_dct): 
    defaults = {} 
    majority = (len(data) + 1) // 2 
    for key in lst_of_dct[0]: 
     try: 
      ctr = Counter(d[key] for d in lst_of_dct) 
      value,count = ctr.most_common(1)[0] 
      defaults[key] = value if count >= majority else "" 
     except TypeError: 
      # Counter doesn't like unhashable type ie lists 
      defaults[key] = [] 
    return defaults 

defaults = get_defaults(data) 
pp(defaults) 

который дает

{'applied_discounts': [], 
'base_cost_price': '0.0000', 
'base_price': '0.0000', 
'base_total': '0.0000', 
'base_wrapping_cost': '0.0000', 
'bin_picking_number': '', 
'configurable_fields': [], 
'cost_price_ex_tax': '0.0000', 
'cost_price_inc_tax': '0.0000', 
'cost_price_tax': '0.0000', 
'ebay_item_id': '', 
'ebay_transaction_id': '', 
'event_date': '', 
'event_name': None, 
'fixed_shipping_cost': '0.0000', 
'id': '', 
'is_bundled_product ': True, 
'is_refunded': False, 
'name': '', 
'option_set_id': None, 
'order_address_id': 2,   # should be 0 
'order_id': 614534,    # should be 0 
'parent_order_product_id': 3, # should be 0 
'price_ex_tax': '0.0000', 
'price_inc_tax': '0.0000', 
'price_tax': '0.0000', 
'product_id': '', 
'product_options': [], 
'quantity': 1,     # should be 0 
'quantity_shipped': 0, 
'refund_amount': '0.0000', 
'return_id': 0, 
'sku': '', 
'total_ex_tax': '0.0000', 
'total_inc_tax': '0.0000', 
'total_tax': '0.0000', 
'type': 'physical', 
'weight': '0.0000', 
'wrapping_cost_ex_tax': '0.0000', 
'wrapping_cost_inc_tax': '0.0000', 
'wrapping_cost_tax': '0.0000', 
'wrapping_message': '', 
'wrapping_name': ''} 

После ручной проверки и исправления некоторых плохих значений по умолчанию,

def strip_defaults(dct, defaults): 
    return {key:value for key,value in dct.items() if value != defaults[key]} 

res = [strip_defaults(d, defaults) for d in data] 
pp(res) 

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

[{'applied_discounts': [{'amount': 99, 'id': 'total-coupon'}], 
    'base_price': '99.0000', 
    'base_total': '99.0000', 
    'id': 3, 
    'is_bundled_product ': False, 
    'name': 'University of Timbuktu Bachelor Set', 
    'option_set_id': 15, 
    'order_address_id': 2, 
    'order_id': 614534, 
    'price_ex_tax': '99.0000', 
    'price_inc_tax': '99.0000', 
    'product_id': 83, 
    'product_options': [{'display_name': 'Gown size', 
         'display_style': 'Pick list', 
         'display_value': 'Cambridge-Style Bachelor Gown, ' 
             'Size L', 
         'id': 2, 
         'name': 'Bachelor gown size', 
         'option_id': 19, 
         'order_product_id': 3, 
         'product_option_id': 95, 
         'type': 'Product list', 
         'value': '77'}, 
         {'display_name': 'Trencher size', 
         'display_style': 'Pick list', 
         'display_value': 'Bachelor and Masters Trencher, ' 
             'Size L', 
         'id': 3, 
         'name': 'Trencher size', 
         'option_id': 20, 
         'order_product_id': 3, 
         'product_option_id': 97, 
         'type': 'Product list', 
         'value': '80'}], 
    'quantity': 1, 
    'sku': 'S-TIM-BAC-STD', 
    'total_ex_tax': '99.0000', 
    'total_inc_tax': '99.0000', 
    'weight': '3.0000'}, 
{'id': 4, 
    'name': 'Cambridge-Style Bachelor Gown, Size L', 
    'order_address_id': 2, 
    'order_id': 614534, 
    'parent_order_product_id': 3, 
    'product_id': 80, 
    'quantity': 1, 
    'sku': 'G-CAM-BAC-L'}, 
{'id': 5, 
    'name': 'Bachelor and Masters Trencher, Size L', 
    'order_address_id': 2, 
    'order_id': 614534, 
    'parent_order_product_id': 3, 
    'product_id': 87, 
    'quantity': 1, 
    'sku': 'C-STD-B&M-L'}] 
+0

Это кажется правильным, но я не могу полагаться на ручное удаление ненужных частей. В настоящее время у меня есть файл с более чем тысячей строк, каждый с линией, подобной той, которую я разместил, и я буду продолжать извлекать больше данных, поэтому мне нужен способ их автоматического удаления. –

+0

@iamfbpt: вы должны уметь читать каждую строку, используйте re.findall, чтобы вытащить каждую строку dict, затем ast.literal_eval, чтобы преобразовать ее в структуру данных Python; пример кода, который следует в ближайшее время. –

+0

Спасибо, теперь он имеет больше смысла :) –

0

Это Строковое представление python списка объектов. Форма выглядит следующим образом:

[<_Classname_ at _memory_address_, _dict_>, ...] 

Ниже приведены значения словаря.

import ast 

def extract_dicts(data_string): 
    s = data_string.strip() 
    items = [] 
    while True: 
     start = s.index("{") 
     s = s[start:] 
     try: 
      ast.literal_eval(s) 
      raise ValueError("malformed list") 
     except SyntaxError as e: 
      end = e.offset 

     items.append(ast.literal_eval(s[:end-2])) 
     s = s[end-2:] 
     if s == ">]": 
      break 
    return items 
+0

Мне нужны целые словари, а не только значения! –

0

Это выглядит как список OrderProducts списка экземпляров класса, 0x24333f0 это адрес затем, например, в памяти. Это почти бесполезно, поскольку это не структура данных для преобразования данных, а читаемая печать существующего экземпляра в текущей запущенной программе.
Возможно, ваша платформа просто использует print([OrderProducts_instance]), чтобы распечатать это, что не предназначено для преобразования данных, а для чтения. Вы никогда не должны использовать это для преобразования данных, как это только для чтения не для преобразования
Однако, если вы все еще хотите парсер текущих данных, шаг следующим, может быть решение:

  • преобразования в формат JSON
    • вы можете удалить затем [<OrderProducts at 0x24333f0,, только держите контент от { и заканчивайтесь }, который может быть диктором в json.
    • заменить все ' в " в формате JSON только позволяют " цитировать данные
  • Используйте питона json модуль для загрузки данных

Хотя лучшее решение для этого подключения к платформе для нового api для данных pull

+0

Это, к сожалению, единственные данные, к которым я могу подключиться. –

0

Это выглядит как слегка выигрышный вывод из списка классов, которые не определяют метод str или repr. у. Вы, кажется, есть три объекта с содержимым, которое выглядит как словарь (словари и списки), как это:

[<OrderProducts at 0x24333f0, {...}, 
<OrderProducts at 0x2433420, {...}, 
<OrderProducts at 0x2433450, {...}> 
] 

Я предполагаю 0x..., где они были в памяти, когда выход был произведен. Так что, чтобы вы начали (быстрая и грязная, нет гарантии возврата денег)

import ast 
import re 
patt = patt = '<OrderProducts\sat\s0x.......,\s({.*})' 
matches = re.findall(patt, data) 
[ast.literal_eval(match) for match in matches] 

возвращает список словарей с вашими данными в:

[{'applied_discounts': [{'amount': 99, 'id': 'total-coupon'}], 
    'base_cost_price': '0.0000', 
    'base_price': '99.0000', 
    'base_total': '99.0000', 
    'base_wrapping_cost': '0.0000', 
    'bin_picking_number': '', 
    'configurable_fields': [], 

Обратите внимание, что вы не сделали: много из этих полей выглядят так, будто они действительно хотят быть float s или int s, но они все еще струны.