如何使用Python urlopen获取非ascii url?

2024-04-24 06:07:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要从具有非ascii字符的URL获取数据,但urllib2.URL open拒绝打开资源并引发:

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

我知道这个网址不符合标准,但我没有机会改变它。

使用Python访问由包含非ascii字符的URL指向的资源的方法是什么?

编辑:换句话说,URL open可以/如何打开如下URL:

http://example.org/Ñöñ-ÅŞÇİİ/

Tags: inurlasciiposition资源openurllib2字符
3条回答

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

严格地说,uri不能包含非ASCII字符;您所拥有的是一个IRI

要将IRI转换为纯ASCII URI,请执行以下操作:

  • 地址主机名部分的非ASCII字符必须使用基于Punycode的IDNA算法进行编码;

  • 根据Ignacio的回答,路径中的非ASCII字符以及地址的大多数其他部分必须使用UTF-8和%编码。

所以:

import re, urlparse

def urlEncodeNonAscii(b):
    return re.sub('[\x80-\xFF]', lambda c: '%%%02x' % ord(c.group(0)), b)

def iriToUri(iri):
    parts= urlparse.urlparse(iri)
    return urlparse.urlunparse(
        part.encode('idna') if parti==1 else urlEncodeNonAscii(part.encode('utf-8'))
        for parti, part in enumerate(parts)
    )

>>> iriToUri(u'http://www.a\u0131b.com/a\u0131b')
'http://www.xn--ab-hpa.com/a%c4%b1b'

(从技术上讲,在一般情况下,这仍然不够好,因为urlparse没有拆分主机名上的任何user:pass@前缀或:port后缀。只有主机名部分应该是IDNA编码的。在构建URL时,使用普通的urllib.quote.encode('idna')编码要比分离IRI容易得多。)

在python3中,对非ascii字符串使用urllib.parse.quote函数:

>>> from urllib.request import urlopen                                                                                                                                                            
>>> from urllib.parse import quote                                                                                                                                                                
>>> chinese_wikipedia = 'http://zh.wikipedia.org/wiki/Wikipedia:' + quote('首页')
>>> urlopen(chinese_wikipedia)

相关问题 更多 >