2008-09-23 12 views
64

Ich möchte wissen, ob ich eine URL in Python normalisieren.Wie kann ich eine URL in Python normalisieren

Zum Beispiel, wenn ich eine URL-Zeichenfolge wie habe: „http://www.example.com/foo goo/bar.html“

Ich brauche eine Bibliothek in Python, die den zusätzlichen Platz (oder irgendein andere nicht normalisierte Zeichen) zu einem richtigen verwandeln URL

+0

Es gibt eine mehr up-to-date Antwort auf StackOverflow hier: http://stackoverflow.com/questions/10584861/canonize-normali ze-an-url-in-python/15629657 – stuckintheshuck

+1

Ich glaube nicht, dass das besser ist ... –

Antwort

10
import urlparse, urllib 
def myquote(url): 
    parts= urlparse.urlparse(url) 
    return urlparse.urlunparse(parts[:2] + urllib.quote(parts[2]) + parts[3:]) 

Dies zitiert nur die Pfadkomponente.

Andernfalls könnten Sie tun: urllib.quote(url, safe=":/")

+2

Das nur alle Zeichen zitieren. Das wird ihm nicht helfen. –

+0

In diesem Beispiel würde auch das Zeichen ":" (nicht alle) zitiert. Danke für den Kommentar. – tzot

21

Verwendung urllib.quote oder urllib.quote_plus

Vom urllib documentation:

Zitat (string [, safe])

ersetzen Sonderzeichen in der Zeichenkette mit dem "% xx" escape. Buchstaben, Ziffern, und die Zeichen "_.-" sind nie zitiert. Der optionale sichere Parameter gibt zusätzliche Zeichen an, die nicht in Anführungszeichen gesetzt werden sollen. - der Standardwert ist '/'. Beispiel: quote('/~connolly/') ergibt '/%7econnolly/'.

quote_plus (string [, safe])

Wie quote(), sondern ersetzt auch Leerzeichen durch Pluszeichen, je nach Bedarf für die Quotierung HTML-Formular Werte. Plus-Zeichen in der ursprünglichen Zeichenfolge sind escaped, es sei denn sie sind in Safe enthalten. Es hat auch nicht sicheren Standard auf "/".

EDIT: Mit urllib.quote oder urllib.quote_plus auf die gesamte URL wird es mangle, wie @ ΤΖΩΤΖΙΟΥ betont:

>>> quoted_url = urllib.quote('http://www.example.com/foo goo/bar.html') 
>>> quoted_url 
'http%3A//www.example.com/foo%20goo/bar.html' 
>>> urllib2.urlopen(quoted_url) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "c:\python25\lib\urllib2.py", line 124, in urlopen 
    return _opener.open(url, data) 
    File "c:\python25\lib\urllib2.py", line 373, in open 
    protocol = req.get_type() 
    File "c:\python25\lib\urllib2.py", line 244, in get_type 
    raise ValueError, "unknown url type: %s" % self.__original 
ValueError: unknown url type: http%3A//www.example.com/foo%20goo/bar.html 

@ ΤΖΩΤΖΙΟΥ bietet eine Funktion, die urlparse.urlparse and urlparse.urlunparse die URL zu analysieren verwendet und kodiere nur den Pfad. Dies kann für Sie nützlicher sein. Wenn Sie jedoch die URL aus einem bekannten Protokoll und Host mit einem fehlerverdächtigen Pfad erstellen, können Sie wahrscheinlich genauso gut urlparse vermeiden und einfach den verdächtigen Teil der URL angeben, mit dem verkettet werden soll bekannte sichere Teile.

+2

Also, was gibt urllib.quote in der Beispiel-URL der Frage zurück? – tzot

+1

Müll. Warum wird eine offensichtlich falsche Antwort als Lösung akzeptiert? –

+0

@ ΤΖΩΤΖΙΟΥ: ausgezeichneter Punkt. Adressiert @Armin Ronacher: möglicherweise, weil der Antworter und der Accepter das Problem nicht wussten - nicht alle Probleme sind für alle offensichtlich. –

66

Schauen Sie sich dieses Modul an: werkzeug.utils.(Jetzt in werkzeug.urls)

Die Funktion die Sie suchen, ist "url_fix" genannt und funktioniert wie folgt:

>>> url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffsklärung)') 
'http://de.wikipedia.org/wiki/Elf%20%28Begriffskl%C3%A4rung%29' 

Es in Werkzeug implementiert ist wie folgt:

import urllib 
import urlparse 

def url_fix(s, charset='utf-8'): 
    """Sometimes you get an URL by a user that just isn't a real 
    URL because it contains unsafe characters like ' ' and so on. This 
    function can fix some of the problems in a similar way browsers 
    handle data entered by the user: 

    >>> url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffsklärung)') 
    'http://de.wikipedia.org/wiki/Elf%20%28Begriffskl%C3%A4rung%29' 

    :param charset: The target charset for the URL if the url was 
        given as unicode string. 
    """ 
    if isinstance(s, unicode): 
     s = s.encode(charset, 'ignore') 
    scheme, netloc, path, qs, anchor = urlparse.urlsplit(s) 
    path = urllib.quote(path, '/%') 
    qs = urllib.quote_plus(qs, ':&=') 
    return urlparse.urlunsplit((scheme, netloc, path, qs, anchor)) 
+0

Während dies von einer http rfc2616 wahrscheinlich die genauere Lösung ist, denke ich, es ist Overkill, oder vermisse ich etwas? –

+1

Ja. Du hast die Frage wahrscheinlich verpasst. Er hat eine URL aus Benutzereingaben und möchte diese korrekt in eine echte URL umwandeln. (Aka: tun was die firefox location bar tut) –

+3

'url_fix' befindet sich jetzt bei' werkzeug.urls' – sebpiq

55

Real fix in Python 2.7 for that problem

Richtige Lösung war:

# percent encode url, fixing lame server errors for e.g, like space 
# within url paths. 
fullurl = quote(fullurl, safe="%/:=&?~#+!$,;'@()*[]") 

Weitere Informationen Issue918368: "urllib doesn't correct server returned urls"

+4

Ausgezeichnete Antwort, prägnant und hilfreich. Da diese Änderung innerhalb von urllib erfolgte, sollte Code, der das gleiche tun möchte, "urllib importieren" und "urllib.quote()" mit den obigen Parametern aufrufen. –

+0

Das barrt auf dem Buchstaben ä, aber ich gebe es meine Stimme, weil es einfach ist, und nicht noch einen weiteren Import erfordert. – mlissner

+0

arbeitete wie Charme! exaclty was ich gesucht habe –

12

Da diese Seite ein Top-Ergebnis zu sehen ist für Google zum Thema sucht, ich denke, es lohnt sich einige Arbeit zu erwähnen, die mit Python auf URL Normalisierung durchgeführt wurde, die über urlencoding Leerzeichen geht. Zum Beispiel, Umgang mit Standard-Ports, Zeichenfall, fehlende Schrägstriche, etc.

Als das Atom-Syndication-Format entwickelt wurde, gab es einige Diskussionen darüber, wie URLs in kanonisches Format zu normalisieren; dies ist in dem Artikel PaceCanonicalIds auf dem Atom/Pie Wiki dokumentiert. Dieser Artikel bietet einige gute Testfälle.

Ich glaube, dass ein Ergebnis dieser Diskussion war Mark Nottinghams urlnorm.py Bibliothek, die ich mit guten Ergebnissen auf ein paar Projekte verwendet habe. Dieses Skript funktioniert jedoch nicht mit der in dieser Frage angegebenen URL. Eine bessere Wahl könnte also Sam Ruby's version of urlnorm.py sein, die diese URL behandelt, und alle oben genannten Testfälle aus dem Atom-Wiki.

1

ich so ein Problem auftreten sollte.

fullurl = quote(fullurl, safe="%/:=&?~#+!$,;'@()*[]") Hilfe, aber es ist zu kompliziert.

Also habe ich einen einfachen Weg verwendet: url = url.replace(' ', '%20'), es ist nicht perfekt, aber es ist der einfachste Weg und es funktioniert für diese Situation.