Запросы декодирования URL

Я пытаюсь получить исходный URL-адрес от requests. Вот что у меня есть до сих пор:

res = requests.get(...)
url = urllib.unquote(res.url).decode('utf8') 

Затем я получаю сообщение об ошибке:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 60-61: ordinal not in range(128)

Исходный URL, который я запросил:

https://www.microsoft.com/de-at/store/movies/american-pie-pr\xc3\xa4sentiert-nackte-tatsachen/8d6kgwzl63ql

И вот что происходит, когда я пытаюсь распечатать:

>>> print '111', res.url
111 https://www.microsoft.com/de-at/store/movies/american-pie-pr%C3%A4sentiert-nackte-tatsachen/8d6kgwzl63ql
>>> print '222', urllib.unquote( res.url )
222 https://www.microsoft.com/de-at/store/movies/american-pie-präsentiert-nackte-tatsachen/8d6kgwzl63ql
>>> print '333', urllib.unquote(res.url).decode('utf8') 
UnicodeEncodeError: 'ascii' codec can't encode characters in position 60-61: ordinal not in range(128)

Почему это происходит и как мне это исправить?


person David542    schedule 27.12.2015    source источник
comment
какую операционную систему вы используете?   -  person artscan    schedule 27.12.2015
comment
Кажется, ОП продублировал этот вопрос: stackoverflow.com /вопросы/34477799/   -  person Alastair McCormack    schedule 27.12.2015


Ответы (1)


UnicodeEncodeError: 'ascii' codec can't encode characters

Вы пытаетесь декодировать строку, которая уже является Unicode. Он вызывает AttributeError на Python 3 (строка юникода не имеет там метода .decode()). Python 2 пытается закодировать строку в байты, сначала используя sys.getdefaultencoding() ('ascii'), а затем передать ее в .decode('utf8'), что приводит к UnicodeEncodeError.

Короче говоря, не вызывайте .decode() для строк Unicode, вместо этого используйте это:

print urllib.unquote(res.url.encode('ascii')).decode('utf-8')

Без вызова .decode() код печатает байты (при условии, что строка байтов передается в unquote()), что может привести к моджибаке, если кодировка символов, используемая в вашей среде, не является utf-8. Чтобы избежать моджибаке, всегда печатайте Unicode (не печатайте текст как байты), не программируйте жестко кодировку символов вашей среды внутри вашего скрипта, т. е. здесь необходимо .decode().


В urllib.unquote() есть ошибка, если вы передаете ему строку Unicode:

>>> print urllib.unquote(u'​%C3%A4')
ä
>>> print urllib.unquote('​%C3%A4') # utf-8 output
ä

Передать строки байтов в unquote() на Python 2.

person jfs    schedule 27.12.2015
comment
type(urllib.unquote("https://www.microsoft.com/de-at/store/movies/american-pie-pr%C3%A4sentiert-nackte-tatsachen/8d6kgwzl63ql")) == <type 'str'>. Я думаю проблема в его локали - person Alastair McCormack; 27.12.2015
comment
Неважно наверняка. OP не получает исключения от urllib.unquote( res.url ), и я не получаю исключения, если использую Unicode: urllib.unquote(u"https://www.microsoft.com/de-at/store/movies/american-pie-‌​pr%C3%A4sentiert-nackte-tatsachen/8d6kgwzl63ql") - person Alastair McCormack; 27.12.2015
comment
@AlastairMcCormack: здесь есть 3 отдельные проблемы. И решение, которое устраняет все 3 проблемы, состоит в том, чтобы .encode(), а затем .decode(), как показано в ответе. type(res.url) — это юникод в вопросе, иначе мы не увидим UnicodeEncodeError, а urllib.unquote() не работает для URL-адресов в юникоде. - person jfs; 27.12.2015
comment
Извините, вы правы. Я ошибся концом палки :) - person Alastair McCormack; 27.12.2015
comment
@AlastairMcCormack: не извиняйтесь за это, я благодарен за обратную связь. Все делают ошибки, вот мой недавний отказ мозга. - person jfs; 27.12.2015