質問

ASSASCII以外の文字を使用して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/Ñöñ-ÅŞÇİİ/
役に立ちましたか?

解決

厳密に言えば、ウリスは非ASCII文字を含めることはできません。あなたがそこに持っているものはあります IRI.

IRIを単純なASCII URIに変換するには:

  • アドレスのホスト名部分の非ASCII文字は、 パニコード- ベースのIDNAアルゴリズム。

  • パス内の非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エンコードされる必要があります。通常の使用を使用してエンコードする方が簡単です urllib.quote.encode('idna') IRIを引き離す必要があるよりも、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

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)

をエンコードします unicode UTF-8に、次にURL-Encode。

使用する iri2uri の方法 httplib2. 。それはボビンと同じものを作ります(彼/彼女はそれの著者ですか?)

それは受け入れられた @ボビンスの答えよりも複雑です:

  • NetlocはIDNAを使用してエンコードする必要があります。
  • 非ASCII URLパスは、UTF-8にエンコードし、その後パーセントエスケープにエンコードする必要があります。
  • 非ASCIIクエリパラメーターは、ページURLのエンコードにエンコードされている必要があります(またはエンコーディングサーバーの使用)から抽出され、その後パーセントエスケープです。

これがすべてのブラウザの動作です。で指定されています https://url.spec.whatwg.org/ - これを参照してください . 。 Pythonの実装はW3LIBにあります(これはスクラピーが使用しているライブラリです)。見る 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つの実用的な選択肢は リクエスト, 、「箱から出して」アイリスを処理します。

たとえば、 http://bücher.ch:

>>> import requests
>>> r = requests.get(u'http://b\u00DCcher.ch')
>>> r.status_code
200

@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

働く!ついに

私はこの奇妙なキャラクターから避けることができませんでしたが、最後に私はそれを通り抜けます。

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")
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top