Как получить не-ASCII URL с помощью urlopen?
Я столкнулся с проблемой при попытке получить данные по URL, содержащему не-ASCII символы. Используя urllib2.urlopen
, я получаю ошибку:
UnicodeEncodeError: 'ascii' codec can't encode character u'\u0131' in position 26: ordinal not in range(128)
Я понимаю, что URL не соответствует стандартам, но у меня нет возможности его изменить.
Как мне получить доступ к ресурсу по URL, содержащему не-ASCII символы, используя Python?
Дополнение: В других словах, как можно использовать urlopen
для открытия URL, похожего на следующий:
http://example.org/Ñöñ-ÅŞÇİİ/
5 ответ(ов)
В Python 3 для кодирования не-ASCII строки в URL вы можете использовать функцию urllib.parse.quote
. Вот пример, как это сделать для китайского текста:
from urllib.request import urlopen
from urllib.parse import quote
chinese_wikipedia = 'http://zh.wikipedia.org/wiki/Wikipedia:' + quote('首页')
response = urlopen(chinese_wikipedia)
В этом коде строка '首页' кодируется в безопасный формат для использования в URL. Функция quote
заменяет специальные символы и пробелы на соответствующие коды. После этого вы можете использовать urlopen
, чтобы открыть сгенерированный URL.
В Python 3 есть библиотеки, которые могут помочь в такой ситуации. Используйте urllib.parse.urlsplit
, чтобы разбить URL на его компоненты, urllib.parse.quote
, чтобы корректно закодировать/эскейпировать символы Unicode, и urllib.parse.urlunsplit
, чтобы объединить его обратно.
Пример кода:
>>> import urllib.parse
>>> url = 'http://example.com/unicodè'
>>> url = urllib.parse.urlsplit(url)
>>> url = list(url)
>>> url[2] = urllib.parse.quote(url[2])
>>> url = urllib.parse.urlunsplit(url)
>>> print(url)
http://example.com/unicod%C3%A8
Этот код возьмет ваш исходный URL, разобьет его на части, закодирует участок с символами Unicode и затем снова соберет URL. Надеюсь, это поможет!
В ответ на вопрос о преобразовании IRI в URI на Python, основываясь на ответе пользователя @darkfeline, вот функция, которая реализует это преобразование:
from urllib.parse import urlsplit, urlunsplit, quote
def iri2uri(iri):
"""
Преобразует IRI в URI (Python 3).
"""
uri = ''
if isinstance(iri, str):
(scheme, netloc, path, query, fragment) = urlsplit(iri)
scheme = quote(scheme)
netloc = netloc.encode('idna').decode('utf-8')
path = quote(path)
query = quote(query)
fragment = quote(fragment)
uri = urlunsplit((scheme, netloc, path, query, fragment))
return uri
Эта функция принимает строку iri
, разбивает ее на компоненты с помощью urlsplit
, затем кодирует каждую часть (схема, сетевая часть, путь, запрос и фрагмент) с использованием quote
, чтобы обработать специальные символы. Для сетевой части используется кодировка IDNA, чтобы гарантировать правильное представление имен. В конечном итоге, все части объединяются обратно в строку URI с использованием urlunsplit
.
Чтобы закодировать unicode
в UTF-8, а затем выполнить URL-кодирование, вы можете использовать следующий подход в Python:
- Сначала преобразуем строку в байты UTF-8.
- Затем используем функцию для URL-кодирования.
Вот пример кода:
import urllib.parse
# Ваш юникодный текст
unicode_text = "ваш текст на юникоде"
# Шаг 1: Кодируем в UTF-8
utf8_encoded = unicode_text.encode('utf-8')
# Шаг 2: Выполняем URL-кодирование
url_encoded = urllib.parse.quote(utf8_encoded)
print(url_encoded)
Объяснение шагов:
unicode_text.encode('utf-8')
выполняет кодирование строки в байты UTF-8.urllib.parse.quote()
берет эти байты и выполняет URL-кодирование, заменяя неподходящие символы на их эквиваленты в формате%XX
.
После выполнения этого кода вы получите строку, которая правильно закодирована как в UTF-8, так и в URL-формате.
Вы можете использовать метод iri2uri
из библиотеки httplib2
, который выполняет те же функции, что и решение, предложенное Bobin (он/она автор этого?). Этот метод преобразует IRI (Internationalized Resource Identifier) в URI (Uniform Resource Identifier), что может быть полезно, когда вам нужно обеспечить корректное использование ссылок с символами, выходящими за пределы стандартного ASCII.
Чтобы использовать iri2uri
, просто импортируйте его из библиотеки httplib2
и передайте IRI в качестве аргумента. Например:
from httplib2 import iri2uri
iri = "http://example.com/path/to/resource?query=тест"
uri = iri2uri(iri)
print(uri)
Обратите внимание, что iri2uri
корректно обработает все недопустимые символы, преобразуя их в допустимый формат для URI.
UnicodeEncodeError: 'ascii' кодек не может закодировать символ u'\xa0' на позиции 20: номер не в диапазоне (128)
UnicodeDecodeError: Кодек 'charmap' не может декодировать байт X в позиции Y: символ отображается как <неопределённый>
Как лучше всего удалить акценты (нормализовать) в строке Unicode Python?
Python DictWriter: Запись UTF-8 закодированных CSV файлов
Python UnicodeDecodeError - Неправильно ли я понимаю кодировку?