如何在python中规范化URL

时间:2020-03-06 14:35:55  来源:igfitidea点击:

我想知道我是否在python中标准化URL。

例如,如果我有一个网址字符串,例如:" http://www.example.com/foo goo / bar.html"

我需要python中的库,该库会将多余的空间(或者任何其他非规范化的字符)转换为正确的URL。

解决方案

import urlparse, urllib
def myquote(url):
    parts= urlparse.urlparse(url)
    return urlparse.urlunparse(parts[:2] + urllib.quote(parts[2]) + parts[3:])

这仅引用路径组件。

否则,我们可以执行以下操作:urllib.quote(url,safe =":/")`

使用urllib.quote或者urllib.quote_plus

从urllib文档中:

quote(string[, safe])
  
  Replace special characters in string
  using the "%xx" escape. Letters,
  digits, and the characters "_.-" are
  never quoted. The optional safe
  parameter specifies additional
  characters that should not be quoted
  -- its default value is '/'.
  
  Example: quote('/~connolly/') yields '/%7econnolly/'. 
  
  quote_plus(string[, safe])
  
  Like quote(), but also replaces spaces
  by plus signs, as required for quoting
  HTML form values. Plus signs in the
  original string are escaped unless
  they are included in safe. It also
  does not have safe default to '/'.

编辑:在整个URL上使用urllib.quote或者urllib.quote_plus会使其混乱,如@指出:

>>> quoted_url = urllib.quote('http://www.example.com/foo goo/bar.html')
>>> quoted_url
'http%3A//www.example.com/foo%20goo/bar.html'
>>> urllib2.urlopen(quoted_url)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\python25\lib\urllib2.py", line 124, in urlopen
    return _opener.open(url, data)
  File "c:\python25\lib\urllib2.py", line 373, in open
    protocol = req.get_type()
  File "c:\python25\lib\urllib2.py", line 244, in get_type
    raise ValueError, "unknown url type: %s" % self.__original
ValueError: unknown url type: http%3A//www.example.com/foo%20goo/bar.html

@提供了一个使用urlparse.urlparse和urlparse.urlunparse的函数来解析url并且仅对路径进行编码。这可能对我们更有用,尽管如果我们是从已知的协议和主机构建URL但带有可疑路径的,则可能也可以避免urlparse并引用URL的可疑部分,并与已知的安全零件。

看一下以下模块:werkzeug.utils。 (现在位于" werkzeug.urls"中)

我们要查找的函数称为" url_fix",其工作方式如下:

>>> url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffskl?rung)')
'http://de.wikipedia.org/wiki/Elf%20%28Begriffskl%C3%A4rung%29'

它在Werkzeug中的实现如下:

import urllib
import urlparse

def url_fix(s, charset='utf-8'):
    """Sometimes you get an URL by a user that just isn't a real
    URL because it contains unsafe characters like ' ' and so on.  This
    function can fix some of the problems in a similar way browsers
    handle data entered by the user:

    >>> url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffskl?rung)')
    'http://de.wikipedia.org/wiki/Elf%20%28Begriffskl%C3%A4rung%29'

    :param charset: The target charset for the URL if the url was
                    given as unicode string.
    """
    if isinstance(s, unicode):
        s = s.encode(charset, 'ignore')
    scheme, netloc, path, qs, anchor = urlparse.urlsplit(s)
    path = urllib.quote(path, '/%')
    qs = urllib.quote_plus(qs, ':&=')
    return urlparse.urlunsplit((scheme, netloc, path, qs, anchor))

Python 2.7中的实际修复程序可解决该问题

正确的解决方案是:

# percent encode url, fixing lame server errors for e.g, like space
 # within url paths.
 fullurl = quote(fullurl, safe="%/:=&?~#+!$,;'@()*[]")

有关更多信息,请参见Issue918368:" urllib无法更正服务器返回的URL"

由于此页面是Google在该主题上搜索的最佳结果,因此,我认为值得一提的是使用Python对URL规范化所做的一些工作,这些工作超出了对字符进行字符编码的范围。例如,处理默认端口,字符大小写,缺少尾部斜杠等。

在开发Atom联合格式时,就如何将URL规范化为规范格式进行了一些讨论。在Atom / Pie Wiki上的PaceCanonicalIds文章中对此进行了记录。那篇文章提供了一些很好的测试案例。

我相信,这次讨论的结果是Mark Nottingham的urlnorm.py库,我在几个项目中都用到了很好的结果。但是,该脚本不适用于此问题中给出的URL。因此,更好的选择可能是Sam Ruby的urlnorm.py版本(可处理该URL)以及Atom Wiki中的所有上述测试用例。

仅供参考,urlnorm已移至github:
http://gist.github.com/246089