Ho provato a utilizzare os.normpath
per convertire http://example.com/a/b/c/../
in http://example.com/a/b/
ma non funziona su Windows perché converte la barra in barra rovesciata.Come posso normalizzare/comprimere percorsi o URL in Python in modo indipendente dal SO?
risposta
Ecco come farlo
>>> import urlparse
>>> urlparse.urljoin("ftp://domain.com/a/b/c/d/", "../..")
'ftp://domain.com/a/b/'
>>> urlparse.urljoin("ftp://domain.com/a/b/c/d/e.txt", "../..")
'ftp://domain.com/a/b/'
Ricordate che urljoin
considerano un percorso/directory tutto fino all'ultimo /
- dopo questo è il nome del file, se presente.
Inoltre, non aggiungere uno /
leader al secondo parametro, altrimenti non si otterrà il risultato previsto.
os.path
modulo dipende dalla piattaforma ma per i percorsi dei file che utilizzano solo barre ma non URL è possibile utilizzare posixpath,normpath
.
adottato dal modulo os "- os.path è uno dei moduli posixpath, o ntpath", nel tuo caso esplicitamente utilizzando posixpath.
>>> import posixpath
>>> posixpath.normpath("https://stackoverflow.com/a/b/../c")
'/a/c'
>>>
'posixpath.normpath' fa cose inutili come rimuovere le barre finali e consentire la doppia barra iniziale. Sostituisce anche il percorso vuoto con '.'. –
Né urljoin
né posixpath.normpath
fare il lavoro correttamente. urljoin
ti costringe a unirti a qualcosa, e non gestisce correttamente i percorsi assoluti o eccessivi ..
. posixpath.normpath
elimina più barre e rimuove le barre finali, entrambe cose che gli URL non dovrebbero fare.
La seguente funzione risolve completamente URL, trattare sia .
s e ..
s, in modo corretto secondo RFC 3986.
try:
# Python 3
from urllib.parse import urlsplit, urlunsplit
except ImportError:
# Python 2
from urlparse import urlsplit, urlunsplit
def resolve_url(url):
parts = list(urlsplit(url))
segments = parts[2].split('/')
segments = [segment + '/' for segment in segments[:-1]] + [segments[-1]]
resolved = []
for segment in segments:
if segment in ('../', '..'):
if resolved[1:]:
resolved.pop()
elif segment not in ('./', '.'):
resolved.append(segment)
parts[2] = ''.join(resolved)
return urlunsplit(parts)
È quindi possibile chiamare su un URL completo come segue.
>>> resolve_url("http://example.com/dir/../../thing/.")
'http://example.com/thing/'
Per ulteriori informazioni sulle considerazioni che devono essere fatte durante la risoluzione degli URL, vedere a similar answer I wrote earlier on the subject.
Al contrario: se il secondo parametro ha un prefisso '/', restituirà 'ftp: //domain.com /../ ..'. Correzione. –