Python:如何解析包含“..”的URL

时间:2010-11-30 18:41:20

标签: python url

我需要唯一识别和存储一些网址。问题是,如果我没有错,有时它们会包含像http://somedomain.com/foo/bar/../../some/url这样的“..”,基本上是http://somedomain.com/some/url

是否有Python函数或解决此URL的棘手方法?

6 个答案:

答案 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)