我正在使用urljoin来获取页面链接的绝对URL。 在大多数情况下,它在解决相对链接等方面都做得很好,但是我注意到,由于某些原因,它在某些情况下不能去除多余的点。 例如:

>>> urljoin("http://x.com","http://x.com/../../X",False)
'http://x.com/../../X'
>>> urljoin("http://x.com","http://x.com/./../X",False)
'http://x.com/./../X'

如果将这样的URL提供给Web浏览器,它将对其进行更正,但是,如果我尝试使用Python的urlopen(),则会引发异常(urllib2.HTTPError:HTTP错误400:错误请求)。

这是预期的行为吗? 是否有其他Python函数可以正确删除我应该使用的这些点,还是一个bug?

#1楼 票数:2 已采纳

我认为您应该使用绝对base和相对url
如果您这样称呼它,它将去除圆点:

urljoin("http://x.com/a/b/page.html","../../index.html",False)
# result: 'http://x.com/index.html'

urljoin("http://x.com/a/b/page.html","./index.html",False)
# result: 'http://x.com/a/b/index.html'

我在此答案中找到了标准化URL的方法。 例:

urljoin('http://www.example.com/foo/bar/../../baz/bux/', '.')
# result: 'http://www.example.com/baz/bux/'

我认为无效的url处理(太多.. )只能“手动”处理,如下所示:

def remove_extra_dots(url):
    parsed = list(urlparse(url))
    dirs = []
    for name in parsed[2].split("/"):
        if name == "..":
            if len(dirs) > 1:
                dirs.pop()
        else:
            dirs.append(name)
    parsed[2] = "/".join(dirs)
    return urlunparse(parsed)

这会从网址中删除所有.. ,即使是无效的也是如此。 例子:

"http://x.com/a/b/c/../../X"  #->  http://x.com/a/X
"http://x.com/a/b/../../X"    #->  http://x.com/X
"http://x.com/../../X"        #->  http://x.com/X

#2楼 票数:1

有点bug! 根据RFC 3986 ,应删除那些多余的..段。 我没有能够找到的Python标准库函数确实可以正确地完成工作。


遗憾的是,现有的答案在某些方面有些不正确。 URL解析比预期的要复杂一些。

除了urljoin提到的urljoin的缺点(加入绝对路径时,它不能解析URL,也不能处理过多的.. s),而将URL与结合在一起. 将删除最后一段。 例如, urljoin('http://example.com/dir/./wrong/../file.txt', '.')将导致'http://example.com/dir/' ,删除文件,因此您必须将其重新添加。此外, urljoin('http://example.com/dir/..', '.')结果为'http://example.com/dir/' ,这只是您的情况的错误。

不仅如此,提供的remove_extra_dots函数实际上存在一个错误。 如果URL以结尾的句点结尾(上一段中的最后一个bug使得它不可能,但是如果已通过某种方式解决了), 则不会添加结尾的斜杠。 考虑remove_extra_dots('http://example.com/..') 这应该是'http://example.com/' ,但实际上是'http://example.com' (请注意缺少斜杠)。 差异不大,但是很多站点都会在收到丢失的斜杠时进行重定向,因此您可能会得到意想不到的结果。


以下功能可完全解析URL,即两个URL . s和.. s-遵循RFC3986。也不必依赖urljoin

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)

当您拥有完整的URL(在您的情况下,加入后)时,可以按以下方式调用它。

>>> resolve_url("http://example.com/dir/../../thing/.")
'http://example.com/thing/'

有关有效/无效的更多信息,请参阅我在此主题上写的类似答案

  ask by Michael translate from so

未解决问题?本站智能推荐:

2回复

如何使urljoin在Python中按预期工作?

假设我有以下网址: 我想要以下URL: 当我尝试 我得到以下结果: 为什么thing3被剪掉了? 我该如何解决呢? 非常感谢!
2回复

urljoin当绝对路径没有前导斜杠时

像http://www.gilacountyaz.gov/government/assessor/index.php这样的网站有一堆内部链接应该是绝对路径,但是没有前导斜杠。 使用urlparse.urljoin解析它们时,结果如下: 这会导致Web爬网程序无法实现它已访问过页面,并且
1回复

urlparse.urljoin()不处理无效的父目录

有没有办法在从相对的URL构造绝对URL时考虑“无效”父目录,或者我应该只使用.replace() ? 更好的是,在使用Python进行刮擦时,是否有更清洁的方法来清理URL?
6回复

在 Python 中删除 URL

我对python很陌生。 我试图解析一个 URL 文件,只留下 URL 的特定部分(粗体部分)。 以下是我正在使用的一些 URL 示例: 我尝试了一些正则表达式,但它变得非常复杂。 我的想法是从所有网址中删除这个“ http://www.mega.pk/ ”,因为它很常见,然后删除“-”之后的
3回复

如何从Python中的网址中删除“%20”? [重复]

这个问题已经在这里有了答案: 网址在Python中解码UTF-8 2答案 我正在尝试将其转换为字符串后,使用Python(而非C#,PHP或其他工具)从网址中删除%20符号。 但是,无论我尝试使用哪种格式,该符号均保持不变。 这是我尝试的代码: 这是
3回复

从python中的URL中删除GET变量

我有这个网址: 我想要的输出是这样的: 如果我有明智的话 它应该是 和 应该回来 没有任何改变 这就是我尝试过的 但它回来了 有什么建议可以做些什么来获得正确的输出,或者有没有人有更好的想法来完成这项工作?
1回复

如何从Python / Django中的网址中删除%07

这是我在代码逻辑中构建的url。 响应URL使用以下代码构建 此response_url的输出为http:// localhost:8000 / workshop / ccavenue / payment-response / 这是输出URL(重定向URL) http
1回复

如何使用python从http url中删除文件夹[关闭]

关闭。 这个问题需要细节或清晰。 它目前不接受答案。 想改