web-dev-qa-db-fra.com

Comment puis-je normaliser une URL dans python

J'aimerais savoir si je normalise une URL en python.

Par exemple, si j'ai une chaîne d'URL comme: " http://www.example.com/foo goo/bar.html"

J'ai besoin d'une bibliothèque en python qui transformera l'espace supplémentaire (ou tout autre caractère non normalisé) en une URL correcte.

70
Tom Feiner

Jetez un œil à ce module: werkzeug.utils . (maintenant en werkzeug.urls)

La fonction que vous recherchez s'appelle "url_fix" et fonctionne comme ceci:

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

Il est implémenté à Werkzeug comme suit:

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))
68
Armin Ronacher

vrai correctif dans Python 2.7 pour ce problème

La bonne solution était:

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

Pour plus d'informations, voir Issue918368: "urllib ne corrige pas les URL renvoyées par le serveur"

58
Oleg Sakharov

utilisez urllib.quote ou urllib.quote_plus

De la documentation urllib :

quote (chaîne [ sûr])

Remplacez les caractères spéciaux dans la chaîne à l'aide de l'échappement "% xx". Les lettres, les chiffres et les caractères "_.-" ne sont jamais cités. Le paramètre optionnel sûr spécifie des caractères supplémentaires qui ne doivent pas être cités - sa valeur par défaut est '/'.

Exemple: quote('/~connolly/') donne '/%7econnolly/'.

quote_plus (chaîne [ sûr])

Comme quote (), mais remplace également les espaces par des signes plus, comme requis pour citer des valeurs de formulaire HTML. Les signes plus dans la chaîne d'origine sont échappés sauf s'ils sont inclus dans le coffre-fort. Il n'a pas non plus de valeur par défaut sûre pour '/'.

EDIT: L'utilisation de urllib.quote ou urllib.quote_plus sur l'URL entière le gâchera, comme le souligne @ ΤΖΩΤΖΙΟΥ:

>>> 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

@ ΤΖΩΤΖΙΟΥ fournit une fonction qui utilise rlparse.urlparse et urlparse.urlunparse pour analyser l'url et encoder uniquement le chemin. Cela peut être plus utile pour vous, bien que si vous créez l'URL à partir d'un protocole et d'un hôte connus mais avec un chemin suspect, vous pourriez probablement faire tout aussi bien pour éviter l'analyse d'url et simplement citer la partie suspecte de l'URL, concaténée avec parties sûres connues.

24
Blair Conrad

Étant donné que cette page est le meilleur résultat pour les recherches Google sur le sujet, je pense qu'il vaut la peine de mentionner certains travaux qui ont été effectués sur la normalisation des URL avec Python qui va au-delà du codage url des caractères d'espace. Par exemple, le traitement avec ports par défaut, casse de caractères, manque de barres obliques, etc.

Lorsque le format de syndication Atom était en cours de développement, il y avait une discussion sur la façon de normaliser les URL au format canonique; cela est documenté dans l'article PaceCanonicalIds sur Atom/Pie Cet article fournit de bons cas de test.

Je crois que l'un des résultats de cette discussion a été la bibliothèque rlnorm.py de Mark Nottingham, que j'ai utilisée avec de bons résultats sur quelques projets. Cependant, ce script ne fonctionne pas avec l'URL indiquée dans cette question. Donc, un meilleur choix pourrait être la version de Sam Ruby de urlnorm.py , qui gère cette URL, et tous les cas de test susmentionnés du wiki Atom wiki.

13
cobra libre

Py3

from urllib.parse import urlparse, urlunparse, quote
def myquote(url):
    parts = urlparse(url)
    return urlunparse(parts._replace(path=quote(parts.path)))

>>> myquote('https://www.example.com/~user/with space/index.html?a=1&b=2')
'https://www.example.com/~user/with%20space/index.html?a=1&b=2'

Py2

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

>>> myquote('https://www.example.com/~user/with space/index.html?a=1&b=2')
'https://www.example.com/%7Euser/with%20space/index.html?a=1&b=2'

Cela ne cite que le composant chemin.

9
tzot

Juste pour info, urlnorm est passé à github: http://Gist.github.com/246089

4
Mark Nottingham

Valable pour Python 3.5:

import urllib.parse

urllib.parse.quote([your_url], "\./_-:")

exemple:

import urllib.parse

print(urllib.parse.quote("http://www.example.com/foo goo/bar.html", "\./_-:"))

la sortie sera http://www.example.com/foo%20goo/bar.html

Police: https://docs.python.org/3.5/library/urllib.parse.html?highlight=quote#urllib.parse.quote

2
Hélder Lima

Je rencontre un tel problème: besoin de citer uniquement l'espace.

fullurl = quote(fullurl, safe="%/:=&?~#+!$,;'@()*[]") aide, mais c'est trop compliqué.

J'ai donc utilisé un moyen simple: url = url.replace(' ', '%20'), ce n'est pas parfait, mais c'est le moyen le plus simple et cela fonctionne pour cette situation.

1
WKPlus