Не удается открыть URL Unicode с помощью Python

Используя Python 2.5.2 и Linux Debian, я пытаюсь получить контент с испанского URL, который содержит испанский символ 'í':

import urllib
url = u'http://mydomain.es/índice.html'
content = urllib.urlopen(url).read()

Я получаю эту ошибку:

UnicodeEncodeError: кодек "ascii" не может кодировать символ u '\ xe1' в позиции 8: порядковый номер не в диапазоне (128)

Я пытался использовать перед передачей URL, чтобы urllib это:

url = urllib.quote(url)

и это:

url = url.encode('UTF-8')

но они не работали.

Можете ли вы сказать мне, что я делаю не так?

Ответ 1

В соответствии с применимым стандартом RFC 1378, URL-адреса могут содержать только символы ASCII. Хорошее объяснение здесь, и я цитирую:

"... Только буквенные символы [0-9a-zA-Z], специальные символы" $-_. +! * '(), "[не включая кавычки], и зарезервированные символы, используемые для их зарезервированные цели могут быть использованы unencoded в URL-адресе."

В качестве URL-адресов, которые я вам объяснил, это, вероятно, означает, что вам придется заменить этот "строчный ящик с острым акцентом" на "% ED".

Ответ 2

Это работает для меня:

#!/usr/bin/env python
# define source file encoding, see: http://www.python.org/dev/peps/pep-0263/
# -*- coding: utf-8 -*-

import urllib
url = u'http://example.com/índice.html'
content = urllib.urlopen(url.encode("UTF-8")).read()

Ответ 3

Кодирование URL-адреса как utf-8 должно работать. Интересно, правильно ли закодирован ваш исходный файл и знает ли его интерпретатор. Если ваш исходный файл python сохраняется, например, как UTF-8, то вы должны иметь

# coding=UTF-8

как первая или вторая строка.

import urllib
url = u'http://mydomain.es/índice.html'
content = urllib.urlopen(url.encode('utf-8')).read()

работает для меня.

Изменить: также помните, что текст Unicode в интерактивном сеансе Python (будь то через IDLE или консоль) чреват сложностью, связанной с кодированием. В этих случаях вы должны использовать литералы Юникода (например, в вашем случае).

Ответ 4

Это работает для меня. Убедитесь, что вы используете довольно недавнюю версию Python, и ваша кодировка файла верна. Здесь мой код:

# -*- coding: utf-8 -*-
import urllib
url = u'http://mydomain.es/índice.html'
url = url.encode('utf-8')
content = urllib.urlopen(url).read()

(mydomain.es не существует, поэтому поиск DNS не выполняется, но к этому моменту нет проблем с unicode.)

Ответ 5

У меня сейчас похожий случай. Я пытаюсь загрузить изображения. Я получаю URL-адреса с сервера в файле JSON. Некоторые изображения содержат символы не ASCII. Это выдает ошибку:

for image in product["images"]: 
    filename = os.path.basename(image) 
    filepath = product_path + "/" + filename 
    urllib.request.urlretrieve(image, filepath) # error!

UnicodeEncodeError: кодек "ascii" не может кодировать символ "\ xc7" в позиции...


Я пытался использовать .encode("UTF-8"), но не могу сказать, что это помогло:

# coding=UTF-8
import urllib
url = u"http://example.com/wp-content/uploads/2018/09/İMAGE-1.png"
url = url.encode("UTF-8")
urllib.request.urlretrieve(url, "D:\image-1.jpg")

Это просто добавляет еще одну ошибку:

TypeError: нельзя использовать строковый шаблон для байтовоподобного объекта


Затем я дал urllib.parse.quote(url) попробовать:

import urllib
url = "http://example.com/wp-content/uploads/2018/09/İMAGE-1.png"
url = urllib.parse.quote(url)
urllib.request.urlretrieve(url, "D:\image-1.jpg")

и снова это выдает еще одну ошибку:

ValueError: неизвестный тип URL: 'http% 3A//example.com/wp-content/uploads/2018/09/% C4% B0MAGE-1.png'

В : "http://..." также сбежал, и я думаю, что это является причиной проблемы.

Итак, я нашел обходной путь. Я просто цитирую/избегаю пути, а не весь URL.

import urllib.request
import urllib.parse
url = "http://example.com/wp-content/uploads/2018/09/İMAGE-1.png"
url = urllib.parse.urlparse(url)
url = url.scheme + "://" + url.netloc + urllib.parse.quote(url.path)
urllib.request.urlretrieve(url, "D:\image-1.jpg")

Вот как выглядит URL: "http://example.com/wp-content/uploads/2018/09/%C4%B0MAGE-1.png", и теперь я могу загрузить изображение.