Wie eine Nicht-ASCII-URL mit Python urlopen holen?
-
10-10-2019 - |
Frage
Ich muss die Daten von einer URL mit Nicht-ASCII-Zeichen holen, aber urllib2.urlopen weigert sich, die Ressource und Raises zu öffnen:
UnicodeEncodeError: 'ascii' codec can't encode character u'\u0131' in position 26: ordinal not in range(128)
ich weiß, ist die URL nicht standardkonform, aber ich habe keine Chance, es zu ändern.
Was ist der Weg, um Zugriff auf eine Ressource durch eine URL Nicht-ASCII-Zeichen mit Python enthält, zeigte?
Bearbeiten Mit anderen Worten kann / wie urlopen eine URL geöffnet haben, wie:
http://example.org/Ñöñ-ÅŞÇİİ/
Lösung
Genau genommen URIs kann kein Nicht-ASCII-Zeichen enthalten; was Sie haben, gibt es eine IRI .
Um eine IRI auf eine reine ASCII-URI konvertieren
-
Nicht-ASCII-Zeichen im Hostnamen Teil der Adresse haben codiert werden unter Verwendung des Punycode -basierte IDNA Algorithmus;
-
Nicht-ASCII-Zeichen in dem Weg, und die meisten anderen Teile der Adresse haben codiert werden unter Verwendung von UTF-8 und% -encoding, wie pro Ignacio Antwort.
So:
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'
(Technisch gesehen ist dies immer noch nicht gut genug im allgemeinen Fall, weil urlparse
abgespalten keinen user:pass@
Präfix oder Suffix :port
auf dem Hostnamen. Nur der Host-Name Teil sein sollte IDNA codiert. Es ist einfacher zu kodieren mit normalen urllib.quote
und .encode('idna')
zu der Zeit Sie eine URL ist die Konstruktion als zu haben, eine IRI auseinander zu ziehen.)
Andere Tipps
Python 3 hat Bibliotheken mit dieser Situation zu umgehen. Verwenden
urllib.parse.urlsplit
die URL in ihre Bestandteile aufzuspalten und
urllib.parse.quote
richtig Zitat / entkommen, die Unicode-Zeichen
und urllib.parse.urlunsplit
verbinden sie wieder zusammen.
>>> 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
In python3, verwenden Sie die urllib.parse.quote
Funktion auf der Nicht-ASCII-Zeichenfolge:
>>> from urllib.request import urlopen
>>> from urllib.parse import quote
>>> chinese_wikipedia = 'http://zh.wikipedia.org/wiki/Wikipedia:' + quote('首页')
>>> urlopen(chinese_wikipedia)
Encode die unicode
auf UTF-8, dann URL-kodieren.
Mit iri2uri
Methode von httplib2
. Es macht das Gleiche wie von bobin (ist er / sie der Autor das?)
Es ist komplexer als die akzeptierte @ bobince Antwort schlägt vor:
- Netloc codiert werden sollte IDNA verwendet wird;
- Nicht-ASCII-URL-Pfad zu UTF-8 codiert werden soll, und dann Prozent-escaped;
- Nicht-ASCII-Abfrageparameter sollte auf die Codierung einer Seite URL codiert werden extrahiert aus (oder auf die Codierung Server Anwendungen), dann Prozent-escaped.
Dies ist, wie alle Browser arbeiten; es angegeben ist in https://url.spec.whatwg.org/ - siehe das Beispiel . Eine Python Umsetzung kann in w3lib gefunden werden (dies ist die Bibliothek Scrapy verwendet); finden Sie unter w3lib.url.safe_url_string :
from w3lib.url import safe_url_string
url = safe_url_string(u'http://example.org/Ñöñ-ÅŞÇİİ/', encoding="<page encoding>")
Eine einfache Möglichkeit, zu überprüfen, ob eine URL zu entkommen Implementierung falsch ist / unvollständig ist zu prüfen, ob es "Seitencodierung Argument liefert oder nicht.
Für diejenigen, die nicht streng auf urllib je, eine praktische Alternative ist Anfragen , die Griff IRIs "out of the box".
Zum Beispiel mit http://bücher.ch
:
>>> import requests
>>> r = requests.get(u'http://b\u00DCcher.ch')
>>> r.status_code
200
Basierend auf @darkfeline Antwort:
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
funktioniert! schließlich
Ich konnte nicht von diesen seltsamen Zeichen vermeiden, aber am Ende komme ich durch sie.
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")