非ASCII文字を含むURLからデータをフェッチする必要がありますが、urllib2.urlopenはリソースを開くことを拒否し、発生します。
UnicodeEncodeError: 'ascii' codec can't encode character u'\u0131' in position 26: ordinal not in range(128)
URLが標準に準拠していないことはわかっていますが、変更する機会はありません。
Pythonを使用して非ASCII文字を含むURLが指すリソースにアクセスする方法は何ですか?
編集:言い換えると、/ urlopenは次のようなURLを開くことができますか?
http://example.org/Ñöñ-ÅŞÇİİ/
厳密に言うと、URIに非ASCII文字を含めることはできません。 [〜#〜] iri [〜#〜] があります。
IRIをプレーンなASCII URIに変換するには:
アドレスのホスト名部分の非ASCII文字は、 Punycode ベースのIDNAアルゴリズムを使用してエンコードする必要があります。
パス内の非ASCII文字、およびアドレスの他のほとんどの部分は、Ignacioの回答に従って、UTF-8および%-encodingを使用してエンコードする必要があります。
そう:
_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エンコード。IRIを分離する必要があるよりも、URLの構築時に通常の_urllib.quote
_および.encode('idna')
を使用してエンコードする方が簡単です。)
Python3では、urllib.parse.quote
非ASCII文字列の関数:
>>> from urllib.request import urlopen
>>> from urllib.parse import quote
>>> chinese_wikipedia = 'http://zh.wikipedia.org/wiki/Wikipedia:' + quote('首页')
>>> urlopen(chinese_wikipedia)
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
unicode
をUTF-8にエンコードしてから、URLエンコードします。
使用する iri2uri
のメソッドhttplib2
。それはボビンと同じものになります(彼/彼女はその作者ですか?)
@darkfelineの回答に基づく:
from urllib.parse import urlsplit, urlunsplit, quote
def iri2uri(iri):
"""
Convert an IRI to a 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
承認された@bobinceの回答が示唆するよりも複雑です。
これがすべてのブラウザが機能する方法です。 https://url.spec.whatwg.org/ で指定されています-これを参照してください example 。 A Python実装はw3libにあります(これはScrapyが使用しているライブラリです);参照 w3lib.url.safe_url_string :
from w3lib.url import safe_url_string
url = safe_url_string(u'http://example.org/Ñöñ-ÅŞÇİİ/', encoding="<page encoding>")
URLエスケープ実装が正しくない/不完全であるかどうかを確認する簡単な方法は、「ページエンコーディング」引数が提供されているかどうかを確認することです。
Urllibに厳密に依存していない場合、1つの実用的な代替策は requests で、これはIRIを「そのまま」使用します。
たとえば、http://bücher.ch
:
>>> import requests
>>> r = requests.get(u'http://b\u00DCcher.ch')
>>> r.status_code
200
私はこの奇妙な性格から避けられなかったが、結局私はそれを通り抜けた。
import urllib.request
import os
url = "http://www.fourtourismblog.it/le-nuove-tendenze-del-marketing-tenere-docchio/"
with urllib.request.urlopen(url) as file:
html = file.read()
with open("marketingturismo.html", "w", encoding='utf-8') as file:
file.write(str(html.decode('utf-8')))
os.system("marketingturismo.html")