Domanda

ho bisogno di recuperare i dati da un URL con caratteri non-ASCII, ma urllib2.urlopen rifiuta di aprire la risorsa e rilanci:

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

So che l'URL non è conforme agli standard, ma non ho alcuna possibilità di cambiarlo.

Qual è il modo per accedere a una risorsa indicato da un URL che contiene caratteri non-ASCII utilizzando Python?

modifica In altre parole, può / come urlopen aprire un URL del tipo:

http://example.org/Ñöñ-ÅŞÇİİ/
È stato utile?

Soluzione

URI In senso stretto non possono contenere caratteri non ASCII; quello che ci hai è un IRI .

Per convertire un IRI ad un ASCII URI:

  • caratteri non-ASCII nella parte hostname di indirizzo devono essere codificati utilizzando il Punycode basata su algoritmo IDNA;

  • caratteri non ASCII nel percorso, e la maggior parte delle altre parti dell'indirizzo devono essere codificati con UTF-8 e% -encoding, come per la risposta di Ignacio.

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'

(Tecnicamente questo non è ancora abbastanza buono abbastanza, nel caso generale, perché urlparse non si divide via qualsiasi prefisso o suffisso user:pass@ :port sul nome host. Solo la parte hostname dovrebbe essere codificato IDNA. E 'più facile codificare con una normale urllib.quote e .encode('idna') al momento si sta costruendo un URL che avere a tirare un IRI a parte).

Altri suggerimenti

Python 3 ha le librerie per gestire questa situazione. Uso urllib.parse.urlsplit di dividere l'URL nei suoi componenti, e urllib.parse.quote correttamente preventivo / sfuggire ai caratteri Unicode e urllib.parse.urlunsplit a unirsi di nuovo insieme.

>>> 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, utilizzare la funzione urllib.parse.quote sulla corda non ASCII:

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

Codifica il unicode a UTF-8, quindi la codifica URL.

Utilizzare il metodo iri2uri di httplib2. Fa la stessa cosa da Bobin (è lui / lei l'autore di questo?)

E 'più complessa di quanto la risposta accettato di @ bobince suggerisce:

  • netloc deve essere codificato usando IDNA;
  • non-ascii percorso URL deve essere codificato in UTF-8 e poi cento escape;
  • parametri di query non-ASCII deve essere codificato per la codifica di un URL della pagina è stato estratto da (o per gli usi del server di codifica), allora per cento di escape.

Questo è come funzionano tutti i browser; si precisa in https://url.spec.whatwg.org/ - vedere questo esempio . implementazione un pitone può essere trovato in w3lib (Questa è la libreria Scrapy sta usando); vedi w3lib.url.safe_url_string :

from w3lib.url import safe_url_string
url = safe_url_string(u'http://example.org/Ñöñ-ÅŞÇİİ/', encoding="<page encoding>")

Un modo semplice per verificare se un URL sfuggire implementazione non è corretto / incompleto è quello di verificare se fornisce 'pagina encoding' argomento o no.

Per chi non è in funzione strettamente urllib, una pratica alternativa è href="http://docs.python-requests.org/en/master/" richieste , che maniglie Iris "out of the box".

Per esempio, con http://bücher.ch:

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

In base a risposta @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

funziona! infine

I non ha potuto evitare da questo strano personaggi, ma alla fine ho venire attraverso di esso.

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")
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top