Я использую данные из RESTful API, он возвращает мне строки и целочисленные значения. Однако кажется, что он возвращает некоторые строковые значения, неправильно закодированные/декодированные (вероятно).
Ожидаемая строка:
criança
Получена строка:
criança
Вот мой код:
url = "https://analytics.us.algolia.com/2/searches?index = {index}&startDate = {yesterday}".format(index=index, yesterday=yesterday)
headers = { 'X-Algolia-Application-Id': app_id,
'X-Algolia-API-Key': app_key,
'Content-Type': 'application/json; charset=utf-8'}
response = requests.get(url, headers=headers)
response_json = json.loads(response.text)
print(response_json)
Это для сценария Python 3.6.x, который будет получать данные из RESTful API Algolia и сохранять их в Amazon Redshift. Я пишу этот скрипт на Ubuntu 18.04, мой набор кодировок символов терминала — pt_BR.UTF-8
(echo $LANG
) и UTF-8 (locale charmap
).
Я вижу, что полученные данные неверны, когда я печатаю их перед сохранением в базе данных, которая настроена на использование charset=utf8
. Я также могу видеть эти неправильные данные в базе данных через оператор SELECT
.
Я нашел этот Таблица отладки кодировки UTF-8, он указывает, что, вероятно, это произошло из-за того, что байты UTF-8 интерпретируются как байты Windows-1252 (или ISO 8859-1).
Как я могу лечить это с помощью некоторой функции/библиотеки Python?
Другая возможность состоит в том, что строка верна, но то, как вы чек об оплате, это не так. Если ваш терминал или консоль не настроен на UTF8, байты UTF8 будут отображаться так, как если бы они были символами ASCII, а два байта, представляющие ç
, будут отображаться как ç
. Если вы сохранили данные в файл, возможно, вы читаете их как ASCII вместо UTF8.
@PanagiotisKanavos, спасибо за вашу поддержку. Я проверил свою кодировку символов терминала, она установлена на UTF-8. Есть ли какие-либо настройки, которые я должен сделать явно, чтобы Python работал с UTF-8?
Ничего. Ничего не нужно. Разместите свой код. Каким-то образом Это обрабатывает ответ как ASCII вместо UTF8. Или может случиться так, что ответ имеет неправильный charset
в заголовке Content-Type
. Что происходит, когда вы пытаетесь получить страницу это?
@PanagiotisKanavos технически не печатает ASCII, потому что эти символы находятся за пределами диапазона ASCII. В Python 3.6 все строки должны автоматически декодироваться в Unicode на входе и преобразовываться в соответствующую кодировку на выходе. Я согласен, что нам действительно нужно увидеть код, чтобы увидеть, что происходит.
Я только что отредактировал пост, вот код, ребята.
Что такое заголовок ответа Content-Type? Каковы байты для criança в теле ответа?
@MarkRansom выбери свое имя для single byte codepage
. Независимо от того, что вы выберете, ASCII или ANSI, кто-то всегда скажет, что все наоборот. В итоге я использовал US-ASCII
для 7-битной кодовой страницы, ASCII для всего остального и этот комментарий, когда это необходимо.
@GabrielAtaide Content-Type
разрешено только в запросах PUT/POST. В GET он может отображаться только как заголовок отклик. Используйте Accept-Charset
, чтобы запросить ответ UTF8. Я подозреваю, что служба HTTP, которую вы называете, по умолчанию использует Latin1 (он же 1252, ISO-8859-1)
@GabrielAtaide, несмотря на это, ответ является UTF8 и терминал должен отображают его правильно. Скорее всего проблема в неправильно настроенной среде. Попробуйте установить LC_ALL
на pt_BR.UTF-8
или даже en_US.UTF-8
Библиотека requests
пытается выполнить угадать кодировку ответа.
Возможно, requests
расшифровывает ответ как cp1252
(он же Windows-1252).
Я предполагаю, что если вы возьмете этот текст и закодируете его обратно в cp1252
, а затем декодируете как utf-8
, вы увидите правильный текст:
>>> 'criança'.encode('cp1252').decode('utf-8')
'criança'
Исходя из этого, я предполагаю, что если вы спросите свой объект ответа, какую кодировку он угадал, он скажет вам cp1252
:
>>> response.encoding
'cp1252'
Принуждение requests
к декодированию как utf-8
, как это, вероятно, решит вашу проблему:
>>> response.encoding = 'utf-8'
В Windows нет кодировки по умолчанию, если вы не имеете в виду UTF16. Строки в Windows имеют кодировку UTF16. Локаль пользователя и системы влияет на то, как обрабатывается текст *не*Unicode. В любом случае ОП упомянул, что используется Ubuntu, и переменная среды $LANG
(pt_BR.UTF-8
) не должна вызывать проблем.
@PanagiotisKanavos Я написал это неясно. Я не имел в виду, что кодировка операционной системы имеет значение. Библиотека запросов использует некоторую эвристику для угадывания кодировок (я только что добавил ссылку на документацию об этом). Возможно, он угадал кодировку Windows-1252, вероятно, на основе неправильного заголовка HTTP.
@TreyHunner, спасибо! Это сработало! Тем не менее, когда я получил правильную строку типа criança
, возникло исключение: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe7 in position 5: invalid continuation byte
. Таким образом, мне пришлось добавить try
, чтобы использовать ваше решение, и, для сценария получения правильной строки, except
, содержащий: text = text.encode('cp1252').decode('latin-1').encode('utf-8').decode('utf-8')
. Таким образом, я могу в любом случае обработать ответ как utf-8.
@GabrielAtaide, похоже, вы иногда получаете байты, которые на самом деле правильно закодированы в utf-8. В этом случае это кодирование как cp1252, а затем декодирование как utf-8 приведет к ошибке, подобной той, которую вы связали. Вы можете прочитать response.content
и использовать библиотеку шарде, чтобы угадать кодировку для вас, а затем вручную декодировать байты. Таким образом, вы можете избежать повторного кодирования неправильно угаданных байтов и надеяться на лучшее.
если проблема не устранена, скопируйте проект в другую папку, заново импортируйте проект с другим именем файла проекта. Сначала перезапустите Android Studio, а затем импортируйте проект из другой папки, и проблема должна быть устранена!
Это означает, что ответ был обработан как ASCII вместо UTF8. Дело не в кодировке. Страница, которую вы читаете прямо сейчас, имеет кодировку UTF8, и тем не менее, если вы проверите источник, вы увидите, что кодировка не используется. Пожалуйста, опубликуйте свой код. Скорее всего, там есть вызов, который пытается «декодировать» или преобразовать эту строку во что-то другое, поэтому проблема вызывая