2012-05-14 28 views
9

Estoy buscando una función de biblioteca para normalizar una URL en Python, es decir, eliminar partes "./" o "../" de la ruta, o agregar un puerto predeterminado o escapar de caracteres especiales, etc. El resultado debe ser una cadena que sea única para dos URL que apuntan a la misma página web. Por ejemplo, http://google.com y http://google.com:80/a/../ devolverán el mismo resultado.Canonicalizar/normalizar una URL?

Preferiría Python 3 y ya revisé el módulo urllib. Ofrece funciones para dividir URL pero nada para canonicalizarlas. Java tiene la función URI.normalize() que hace algo similar (aunque no considera que el puerto predeterminado 80 sea igual a ningún puerto determinado), pero ¿hay algo como esto es python?

+0

Como nota al margen, un recurso como el 'http: // google.com /' no es lo mismo que 'http: // google .com: 80/a /../ '. Es decir, si '/ a' no existe, entonces la segunda ruta fallará. Al "canonicalizarlo", pierdes ese caso especial y terminas con un URI válido cuando comenzaste con un inválido ... –

Respuesta

0

Siguiendo el good start, compuse un método que se adapta a la mayoría de los casos que se encuentran comúnmente en la web.

def urlnorm(base, link=''): 
    '''Normalizes an URL or a link relative to a base url. URLs that point to the same resource will return the same string.''' 
    new = urlparse(urljoin(base, url).lower()) 
    return urlunsplit((
    new.scheme, 
    (new.port == None) and (new.hostname + ":80") or new.netloc, 
    new.path, 
    new.query, 
    '')) 
4

¿Qué tal esto:

In [1]: from urllib.parse import urljoin 

In [2]: urljoin('http://example.com/a/b/c/../', '.') 
Out[2]: 'http://example.com/a/b/' 

Inspirado por respuestas a this question. No normaliza los puertos, pero debería ser sencillo activar una función que sí lo hace.

+0

No tengo 'urllib.parse', pero tengo' urlparse'. – osa

+3

'urllib.parse' es la ubicación de Python 3 - la pregunta original fue hecha sobre Py 3. –

4

Esto es lo que uso y hasta ahora ha funcionado. Puedes obtener urlnorm de pip.

Tenga en cuenta que ordeno los parámetros de consulta. He encontrado que esto es esencial.

from urlparse import urlsplit, urlunsplit, parse_qsl 
from urllib import urlencode 
import urlnorm 

def canonizeurl(url): 
    split = urlsplit(urlnorm.norm(url)) 
    path = split[2].split(' ')[0] 

    while path.startswith('/..'): 
     path = path[3:] 

    while path.endswith('%20'): 
     path = path[:-3] 

    qs = urlencode(sorted(parse_qsl(split.query))) 
    return urlunsplit((split.scheme, split.netloc, path, qs, '')) 
+0

nice, elimina directorios principales no válidos – hoju

+0

Necesita reemplazar' split [2] .split ('') [0] 'con' urllib.parse.quote (split [2]) '- en algunos casos, tener espacios en una URL es completamente normal, y de hecho es obligatorio. Además, urlnorm es py2k solo –

+0

Además, está descartando el fragmento, que en realidad puede ser un componente de URL requerido, en algunos casos inusuales. Sí, hay un número distinto de cero de páginas web donde 'blah.com/# wat' es una página completamente diferente y luego' blah.com/'. Generalmente se hace con javascript, y es un enorme PITA, pero existe. –

2

El módulo urltools normaliza múltiples barras, . y .. componentes sin estropear la doble barra en http://.

Una vez hecho pip install urltools el uso es el siguiente:

print urltools.normalize('http://domain.com:80/a////b/../c') 
>>> 'http://domain.com/a/c'