我想知道我是否可以在 python 中规范化 URL。
例如,如果我有一个像
http://www.example.com/foo goo/bar.html
这样的 url 字符串
我需要一个 python 库,它将多余的空格(或任何其他非标准化字符)转换为正确的 URL。
看看这个模块:werkzeug.utils。 (现在在
werkzeug.urls
)
您正在寻找的函数称为“url_fix”,其工作原理如下:
>>> from werkzeug.urls import 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))
正确的解决方案是:
# percent encode url, fixing lame server errors for e.g, like space
# within url paths.
fullurl = quote(fullurl, safe="%/:=&?~#+!$,;'@()*[]")
有关更多信息,请参阅 Issue918368:“urllib 未更正服务器返回的 url”
使用
urllib.quote
或 urllib.quote_plus
来自 urllib 文档:
引用(字符串[,安全])
替换字符串中的特殊字符 使用“%xx”转义符。信件, 数字,字符“_.-”是 从未引用过。可选的保险箱 参数指定附加 不应被引用的字符 -- 它的默认值为 '/'。
示例:
产生quote('/~connolly/')
。'/%7econnolly/'
quote_plus(字符串[,安全])
与 quote() 类似,但也替换空格 按引用要求用加号 HTML 表单值。加号在 原始字符串被转义,除非 它们包含在保险箱中。它还 没有安全的默认值“/”。
编辑:在整个 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
@ΤΖΩΤΖIΟΥ 提供了一个函数,使用 urlparse.urlparse 和 urlparse.urlunparse 来解析 url,并且只对路径进行编码。这可能对您更有用,尽管如果您从已知协议和主机构建 URL 但具有可疑路径,您可能也可以避免 urlparse 并仅引用 URL 的可疑部分,并与已知的安全部件。
因为此页面是有关该主题的 Google 搜索的最高结果,所以我认为值得一提的是使用 Python 在 URL 规范化方面所做的一些工作,这些工作超出了 urlencoding 空格字符的范围。 例如,处理默认端口、字符大小写、缺少尾部斜杠等。
在开发 Atom 联合格式时,对如何将 URL 规范化为规范格式进行了一些讨论;这在 Atom/Pie wiki 上的文章 PaceCanonicalIds 中有记录。 那篇文章提供了一些很好的测试用例。
我相信这次讨论的结果之一是 Mark Nottingham 的 urlnorm.py 库,我在几个项目中使用它并取得了良好的效果。 但是,该脚本不适用于此问题中给出的 URL。 因此,更好的选择可能是 Sam Ruby 版本的 urlnorm.py,它处理该 URL,以及来自 Atom wiki 的所有上述测试用例。
from urllib.parse import urlparse, urlunparse, quote
def myquote(url):
parts = urlparse(url)
return urlunparse(parts._replace(path=quote(parts.path)))
>>> myquote('https://www.example.com/~user/with space/index.html?a=1&b=2')
'https://www.example.com/~user/with%20space/index.html?a=1&b=2'
import urlparse, urllib
def myquote(url):
parts = urlparse.urlparse(url)
return urlparse.urlunparse(parts[:2] + (urllib.quote(parts[2]),) + parts[3:])
>>> myquote('https://www.example.com/~user/with space/index.html?a=1&b=2')
'https://www.example.com/%7Euser/with%20space/index.html?a=1&b=2'
这仅引用路径组件。
仅供参考,urlnorm 已移至 github: http://gist.github.com/246089
这里的很多答案都讨论引用 URL,而不是标准化它们。
在 Python IMO 中规范化 url(用于重复数据删除等)的最佳工具是 w3lib 的
w3lib.url.canonicalize_url
util。
摘自官方文档:
Canonicalize the given url by applying the following procedures:
- sort query arguments, first by key, then by value
percent encode paths ; non-ASCII characters are percent-encoded using UTF-8 (RFC-3986)
- percent encode query arguments ; non-ASCII characters are percent-encoded using passed encoding (UTF-8 by default)
- normalize all spaces (in query arguments) ‘+’ (plus symbol)
- normalize percent encodings case (%2f -> %2F)
- remove query arguments with blank values (unless keep_blank_values is True)
- remove fragments (unless keep_fragments is True)
- List item
The url passed can be bytes or unicode, while the url returned is always a native str (bytes in Python 2, unicode in Python 3).
>>> import w3lib.url
>>>
>>> # sorting query arguments
>>> w3lib.url.canonicalize_url('http://www.example.com/do?c=3&b=5&b=2&a=50')
'http://www.example.com/do?a=50&b=2&b=5&c=3'
>>>
>>> # UTF-8 conversion + percent-encoding of non-ASCII characters
>>> w3lib.url.canonicalize_url('http://www.example.com/r\u00e9sum\u00e9')
'http://www.example.com/r%C3%A9sum%C3%A9'
在广泛爬行网络时,我使用此实用程序取得了巨大成功,以避免由于较小的 url 差异(不同的参数顺序、锚点等)而导致重复请求
适用于 Python 3.5:
import urllib.parse
urllib.parse.quote([your_url], "\./_-:")
示例:
import urllib.parse
print(urllib.parse.quote("http://www.example.com/foo goo/bar.html", "\./_-:"))
输出将是 http://www.example.com/foo%20goo/bar.html
字体:https://docs.python.org/3.5/library/urllib.parse.html?highlight=quote#urllib.parse.quote
我遇到这样的问题:只需引用空格即可。
fullurl = quote(fullurl, safe="%/:=&?~#+!$,;'@()*[]")
确实有帮助,但太复杂了。
所以我用了一个简单的方法:
url = url.replace(' ', '%20')
,它并不完美,但它是最简单的方法,并且适合这种情况。