Python Загрузка UTF-8 JSON

У меня есть следующий JSON (для простоты я буду использовать только один, но на самом деле записей 100):

{
    "Active": false, 
    "Book": "US Derivat. London, Mike Übersax/Michael Jealous", 
    "ExpirationDate": "2006-10-12", 
    "Isin": "CH0013096497", 
    "IssueDate": "2001-10-09", 
    "KbForXMonths": "0", 
    "KbPeriodDay": "Period", 
    "KbType": "Prozent", 
    "KbYear": "0.5", 
    "Keyinvest_IssueRetro": "0.50%", 
    "Keyinvest_RecurringRetro": "1.00% pro rata temporis", 
    "Keyinvest_RetroPayment": "Every month", 
    "LastImportDate": "2008-12-31", 
    "LiberierungDate": "1900-01-01", 
    "NominalCcy": "USD", 
    "NominalStueck": "5,000", 
    "PrimaryCCR": "0", 
    "QuoteType": "Nominal", 
    "RealValor": "0", 
    "Remarks": "", 
    "RwbeProductId_CCR": "034900", 
    "RwbeProductId_EFS": "034900", 
    "SecName": "Cliquet GROI on Nasdaq", 
    "SecType": "EQ", 
    "SubscriptionEndDate": "1900-01-01", 
    "TerminationDate": "2003-10-19", 
    "TradingCcy": "USD", 
    "Valor": 1309649
}

Я пытаюсь прочитать этот JSON, чтобы сохранить его как .csv (чтобы я мог импортировать его в базу данных)

Однако, когда я пытаюсь записать эти данные JSON в виде csv, например:

with codecs.open('EFSDUMP.csv', 'w', 'utf-8-sig') as csv_file:
    content_writer = csv.writer(csv_file, delimiter=',')
    content_writer.writerow(data.values())

Я получаю сообщение об ошибке:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xdc' in position 25: ordinal not in range(128)

Это потому, что в JSON есть умляут (см. атрибут «Книга»).

Я пытаюсь прочитать JSON следующим образом:

data = json.loads(open('EFSDUMP.json').read().decode('utf-8-sig'))

Что интересно, это:

print data

Дает мне это:

{u'PrimaryCCR': u'0', u'SecType': u'EQ', u'Valor': 1309649, u'KbType': u'Prozent', u'Book': u'US Derivat. London, Mike \xdcbersax/Michael Jealous', u'Keyinvest_RecurringRetro': u'1.00% pro rata temporis', u'TerminationDate': u'2003-10-19', u'RwbeProductId_CCR': u'034900', u'SubscriptionEndDate': u'1900-01-01', u'ExpirationDate': u'2006-10-12', u'Keyinvest_RetroPayment': u'Every month', u'Keyinvest_IssueRetro': u'0.50%', u'QuoteType': u'Nominal', u'KbYear': u'0.5', u'LastImportDate': u'2008-12-31', u'Remarks': u'', u'RealValor': u'0', u'SecName': u'Cliquet GROI on Nasdaq', u'Active': False, u'KbPeriodDay': u'Period', u'Isin': u'CH0013096497', u'LiberierungDate': u'1900-01-01', u'IssueDate': u'2001-10-09', u'KbForXMonths': u'0', u'NominalCcy': u'USD', u'RwbeProductId_EFS': u'034900', u'TradingCcy': u'USD', u'NominalStueck': u'5,000'}

Ясно, что умлаут превратился в '\ xdc'

Однако, когда я делаю это:

print data['Book']

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

US Derivat. London, Mike Übersax/Michael Jealous

Таким образом, умлаут снова является настоящим умлаутом.

Я почти уверен, что JSON - это UTF-8 без спецификации (так утверждает Notepad++)

Я уже безуспешно пробовал все предложения здесь: Python загрузить файл json с заголовком спецификации UTF-8

Как я могу правильно прочитать файл JSON UTF-8, чтобы иметь возможность записать его как .csv?

Любая помощь приветствуется.

Версия Python: 2.7.2


person emazzotta    schedule 13.03.2014    source источник


Ответы (1)


В Python 2 модуль csv не поддерживает запись Unicode. Вам нужно закодировать его здесь вручную, так как в противном случае ваши значения Unicode будут закодированы для вас с использованием ASCII (именно поэтому вы получили исключение кодирования).

Это также означает, что вам нужно написать спецификацию UTF-8 вручную, но только если она вам действительно нужна. UTF-8 может быть записан только одним способом, метка порядка байтов не требуется для чтения файлов UTF-8. Microsoft любит добавлять его в файлы, чтобы упростить задачу определения кодировки файлов для своих инструментов, но спецификация UTF-8 может фактически затруднить правильную работу других инструментов, поскольку они не будут игнорировать дополнительный начальный символ.

Использовать:

with open('EFSDUMP.csv', 'wb') as csv_file:
    csv_file.write(codecs.BOM_UTF8)
    content_writer = csv.writer(csv_file)
    content_writer.writerow([unicode(v).encode('utf8') for v in data.values()])

Обратите внимание, что это запишет ваши значения в произвольном (словарном) порядке. Вызов unicode() сначала преобразует нестроковые типы в строки Unicode перед кодированием.

Чтобы быть явным: вы отлично загрузили данные JSON. Вам не удалось написать CSV.

person Martijn Pieters    schedule 13.03.2014
comment
Большое спасибо за разъяснение, где я терплю неудачу :). Однако теперь я получаю сообщение об ошибке content_writer.writerow(v.encode('utf8') for v in data.values()). _csv.Error: sequence expected. Обратите внимание, что в JSON есть логическое значение, а также целое число, поэтому кодирование может дать сбой. - person emazzotta; 13.03.2014
comment
@ gta99: в этом случае ваш объект data пуст. Убедитесь, что у вас действительно есть непустой словарь data. - person Martijn Pieters; 13.03.2014
comment
data не пусто, но кодирование, похоже, не работает для логического и целочисленного значения - person emazzotta; 13.03.2014
comment
@ gta99: это было бы другое исключение (AttributeError: 'bool' object has no attribute 'encode'). Используйте unicode(v).encode('utf8'), если у вас есть не только строки. Я вижу, что у вас есть целочисленное значение в вашем образце ввода, я обновил код, чтобы обработать это. - person Martijn Pieters; 13.03.2014
comment
print [unicode(v).encode('utf8') for v in data.values()] на самом деле дает мне значения, однако при использовании content_writer.writerow(unicode(v).encode('utf8') for v in data.values()) в следующей строке я получаю _csv.Error: sequence expected - person emazzotta; 13.03.2014
comment
@gta99: ах, действительно, моя ошибка. Python 2 csv.writer.writerow() не может обрабатывать итераторы. Будет обновляться. - person Martijn Pieters; 13.03.2014