如何使用 `urlparse` 检查 URL 是否有效?
我想在打开一个网址读取数据之前,先检查一下这个网址是否有效。
我之前使用的是来自urlparse
这个包里的urlparse
函数:
if not bool(urlparse.urlparse(url).netloc):
# do something like: open and read using urllin2
但是,我发现有些有效的网址却被当作无效的,比如:
url = upload.wikimedia.org/math/8/8/d/88d27d47cea8c88adf93b1881eda318d.png
这个网址是有效的(我可以用我的浏览器打开它)。
有没有更好的方法来检查网址是否有效呢?
4 个回答
没有协议的链接其实是不合法的,你的浏览器很聪明,会自动帮你加上http://这个协议。一个好的做法是先检查一下链接是否有协议(可以用not re.match(r'^[a-zA-Z]+://', url)
这个方法),如果没有,就在前面加上http://
。
你可以试试下面这个函数,它会检查在解析网址后得到的 scheme
、netloc
和 path
变量。这个函数支持 Python 2 和 3。
try:
# python 3
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
def url_validator(url):
try:
result = urlparse(url)
components = [result.scheme, result.path]
if result.netloc != "":
components.append(result.netloc)
return all(components)
except:
return False
你可以检查一下这个网址是否有协议:
>>> url = "no.scheme.com/math/12345.png"
>>> parsed_url = urlparse.urlparse(url)
>>> bool(parsed_url.scheme)
False
如果有的话,你可以把这个协议替换掉,这样就能得到一个真正有效的网址:
>>> parsed_url.geturl()
"no.scheme.com/math/12345.png"
>>> parsed_url = parsed_url._replace(**{"scheme": "http"})
>>> parsed_url.geturl()
'http:///no.scheme.com/math/12345.png'
总结一下:其实你是无法做到的。之前给出的每个答案都漏掉了一个或多个情况。
- 字符串是 google.com(无效,因为没有协议,虽然浏览器默认会假设是http)。用Urlparse解析时会缺少协议和网络位置。所以
all([result.scheme, result.netloc, result.path])
在这种情况下似乎能正常工作。 - 字符串是 http://google(无效,因为缺少.com)。用Urlparse解析时只会缺少路径。同样,
all([result.scheme, result.netloc, result.path])
似乎能捕捉到这个情况。 - 字符串是 http://google.com/(正确)。用Urlparse解析时会填充协议、网络位置和路径。所以在这种情况下
all([result.scheme, result.netloc, result.path])
工作得很好。 - 字符串是 http://google.com(正确)。用Urlparse解析时只会缺少路径。所以在这种情况下
all([result.scheme, result.netloc, result.path])
似乎会给出错误的结果。
从以上情况可以看出,最接近解决方案的是 all([result.scheme, result.netloc, result.path])
。但这只在URL包含路径的情况下有效(即使那个路径是/)。
即使你试图强制添加路径(比如 urlparse(urljoin(your_url, "/"))
),在第二种情况下你仍然会得到错误的结果。
也许可以考虑更复杂的方式,比如
final_url = urlparse(urljoin(your_url, "/"))
is_correct = (all([final_url.scheme, final_url.netloc, final_url.path])
and len(final_url.netloc.split(".")) > 1)
也许你还想跳过协议检查,如果没有协议就假设是http。但即便如此,这也只能解决到一定程度。虽然它覆盖了上述情况,但并没有完全涵盖URL包含IP而不是主机名的情况。对于这种情况,你需要验证这个IP是否是正确的IP。而且还有更多的场景。可以参考 https://en.wikipedia.org/wiki/URL 来思考更多的情况。