我需要唯一识别和存储一些网址。问题是,如果我没有错,有时它们会包含像http://somedomain.com/foo/bar/../../some/url
这样的“..”,基本上是http://somedomain.com/some/url
。
是否有Python函数或解决此URL的棘手方法?
答案 0 :(得分:11)
使用urlparse有一个简单的解决方案.urljoin:
>>> import urlparse
>>> urlparse.urljoin('http://www.example.com/foo/bar/../../baz/bux/', '.')
'http://www.example.com/baz/bux/'
但是,如果没有尾部斜杠(最后一个组件是文件,而不是目录),则将删除最后一个组件。
此修复程序使用urlparse函数提取路径,然后使用({3}}的posixpath版本来规范化组件。补偿os.path,然后将URL重新加入。以下是doctest
能够:
import urlparse
import posixpath
def resolveComponents(url):
"""
>>> resolveComponents('http://www.example.com/foo/bar/../../baz/bux/')
'http://www.example.com/baz/bux/'
>>> resolveComponents('http://www.example.com/some/path/../file.ext')
'http://www.example.com/some/file.ext'
"""
parsed = urlparse.urlparse(url)
new_path = posixpath.normpath(parsed.path)
if parsed.path.endswith('/'):
# Compensate for issue1707768
new_path += '/'
cleaned = parsed._replace(path=new_path)
return cleaned.geturl()
答案 1 :(得分:3)
这些是文件路径。看看os.path.normpath:
>>> import os
>>> os.path.normpath('/foo/bar/../../some/url')
'/some/url'
修改强>
如果这是在Windows上,您的输入路径将使用反斜杠而不是斜杠。在这种情况下,您仍然需要os.path.normpath
来摆脱..
模式(以及//
和/./
以及其他任何冗余的模式),然后将反斜杠转换为正斜杠:
def fix_path_for_URL(path):
result = os.path.normpath(path)
if os.sep == '\\':
result = result.replace('\\', '/')
return result
编辑2:
如果要标准化网址,请使用urlparse模块执行此操作(在剥离方法之前),如the answer to this question所示。
编辑3:
似乎urljoin
没有规范它给出的基本路径:
>>> import urlparse
>>> urlparse.urljoin('http://somedomain.com/foo/bar/../../some/url', '')
'http://somedomain.com/foo/bar/../../some/url'
normpath
本身并没有完全削减它:
>>> import os
>>> os.path.normpath('http://somedomain.com/foo/bar/../../some/url')
'http:/somedomain.com/some/url'
注意最初的双斜线被吃掉了。
所以我们必须让他们联合起来:
def fix_URL(urlstring):
parts = list(urlparse.urlparse(urlstring))
parts[2] = os.path.normpath(parts[2].replace('/', os.sep)).replace(os.sep, '/')
return urlparse.urlunparse(parts)
用法:
>>> fix_URL('http://somedomain.com/foo/bar/../../some/url')
'http://somedomain.com/some/url'
答案 2 :(得分:2)
我想对最高回复中的resolveComponents
功能发表评论。
请注意,如果您的路径为/
,则代码会添加另一个可能有问题的路径。
因此,我将IF
条件更改为:
if parsed.path.endswith( '/' ) and parsed.path != '/':
答案 3 :(得分:1)
front == null
将无法正常工作,因为如果第二个参数不是绝对的(!?)或为空,它只会解析点网段。不仅如此,它还没有根据RFC 3986正确处理过多的urljoin
(它们应该删除; ..
不会这样做)。 urljoin
无法使用(更不用posixpath.normpath
,因为它将一行中的多个斜杠解析为仅一个(例如os.path.normpath)
变为/////
}),这是URL的错误行为。
以下简短函数可以正确解析任何URL路径字符串。但是,不应该与相对路径一起使用,因为需要做出有关其行为的其他决策(在过度/
s上引发错误?删除..
在开始时?保留它们?) - 相反,如果您知道可以处理相对路径,则在解析之前加入URL。没有进一步的麻烦:
.
这会正确处理尾随点段(即没有尾部斜杠)和连续斜杠。要解析整个URL,您可以使用以下包装器(或者只是将路径解析功能内联到其中)。
def resolve_url_path(path):
segments = path.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)
return ''.join(resolved)
然后你可以这样称呼它:
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))
parts[2] = resolve_url_path(parts[2])
return urlunsplit(parts)
正确的URL解析有很多陷阱,事实证明!
答案 4 :(得分:0)
根据RFC 3986,这应该是“相对解决”过程的一部分。所以答案可能是urlparse.urljoin(url, '')
。但是由于bug urlparse.urljoin
在第二个参数为空url时不会删除点段。您可以使用yurl - 替代网址操作库。它是这样做的:
>>> import yurl
>>> print yurl.URL('http://somedomain.com/foo/bar/../../some/url') + yurl.URL()
http://somedomain.com/some/url
答案 5 :(得分:0)
import urlparse
import posixpath
parsed = list(urlparse.urlparse(url))
parsed[2] = posixpath.normpath(posixpath.join(parsed[2], rel_path))
proper_url = urlparse.urlunparse(parsed)