Python - 如何验证python中的url?(畸形与否)

Yug*_*dle 93 python url malformedurlexception

url来自用户,我必须回复提取的HTML.

如何检查URL是否格式错误?

例如 :

url='google'  // Malformed
url='google.com'  // Malformed
url='http://google.com'  // Valid
url='http://google'   // Malformed
Run Code Online (Sandbox Code Playgroud)

我们怎样才能做到这一点?

Dre*_*mbe 123

实际上,我认为这是最好的方式.

from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

val = URLValidator(verify_exists=False)
try:
    val('http://www.google.com')
except ValidationError, e:
    print e
Run Code Online (Sandbox Code Playgroud)

如果设置verify_existsTrue,它将实际验证URL是否存在,否则它将检查它是否正确形成.

编辑:啊是的,这个问题与此重复:如何检查Django的验证器是否存在URL?

  • 但这只会在django环境中起作用. (38认同)
  • 不推荐使用`verify_exists`.-1 (12认同)
  • 注意,使用django> = 1.5时,不再有`verify_exists`.而不是`val`变量,你可以称之为`URLValidator()('http://www.google.com') (6认同)
  • 添加:从django.conf导入设置settings.configure(DEBUG = False)并删除verify_exists以使其与django 1.5一起使用 (2认同)

Jab*_*bba 105

使用验证器包:

>>> import validators
>>> validators.url("http://google.com")
True
>>> validators.url("http://google")
ValidationFailure(func=url, args={'value': 'http://google', 'require_tld': True})
>>> if not validators.url("http://google"):
...     print "not valid"
... 
not valid
>>>
Run Code Online (Sandbox Code Playgroud)

使用pip()从PyPI安装它pip install validators.

  • 它将为文件URL引发错误.像"file:///users/file.txt" (5认同)
  • @Lal Zada,在您声明这样的事情之前,付出了一些努力并检查代码,regexp实际上非常好:http://validators.readthedocs.io/en/latest/_modules/validators/url.html (5认同)
  • 该包的验证 fn 有许多任意限制,因此建议将其作为通用解决方案是一个糟糕的建议。 (3认同)
  • 找不到localhost网址```validators.url(“ http:// localhost:8080”)ValidationFailure(func = url,args = {'public':False,'value':'http:// localhost:8080'} )``` (2认同)
  • 对“http://www.google”、“http://google.www”有效。这只是检查“http://”和“两个单词之间的点 (.)” (2认同)
  • @ivan_pozdeev:如果很糟糕,请提出一个更好的解决方案 (2认同)
  • 这个包没有被积极维护 (2认同)

cet*_*ver 76

django url验证正则表达式:

regex = re.compile(
        r'^(?:http|ftp)s?://' # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' #domain...
        r'localhost|' #localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
        r'(?::\d+)?' # optional port
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)

print re.match(regex, "http://www.example.com") is not None   # True
print re.match(regex, "example.com") is not None              # False
Run Code Online (Sandbox Code Playgroud)

  • 好奇……你添加了`ftp`吗?或者我有一个旧的django版本? (2认同)
  • @ yugal-jindle http://www.sitedomain不是有效的网址.http://www.museum/是因为.museum是顶级域名(ICANN [1]定义它们),而不是sitedomain.[1] http://www.icann.org/ (2认同)
  • 这不适用于格式为http://[2001:0DB8::3]:8080/index.php?valid=true#result的IPv6网址。 (2认同)

ale*_*mol 41

一个真或假的版本,基于@DMfll答案:

try:
    # python2
    from urlparse import urlparse
except:
    # python3
    from urllib.parse import urlparse

a = 'http://www.cwi.nl:80/%7Eguido/Python.html'
b = '/data/Python.html'
c = 532
d = u'dkakasdkjdjakdjadjfalskdjfalk'

def uri_validator(x):
    try:
        result = urlparse(x)
        return all([result.scheme, result.netloc, result.path])
    except:
        return False

print(uri_validator(a))
print(uri_validator(b))
print(uri_validator(c))
print(uri_validator(d))
Run Code Online (Sandbox Code Playgroud)

得到:

True
True
False
True
Run Code Online (Sandbox Code Playgroud)

  • 这允许一切.它返回字符串`fake`的"True"或甚至是空字符串.永远不会有任何错误,因为这些属性总是存在,并且列表将始终具有布尔值True,因为它包含这些属性.即使所有属性都是None,列表仍然是非空的.您需要对属性进行一些验证,因为一切都按照您现在的方式进行. (8认同)
  • 我不知道你可以测试带有非None元素列表的if语句.这很有帮助.使用内置模块也是+1 (5认同)
  • 虚假对象列表评估为True:`print("我是真的")如果[False,None,0,'',[],{}]打印("我是假的.")`打印"我是真的".当我运行它.`[result.scheme,result.netloc,result.path]`总是计算为'True`.`print("我是真的")如果[] else打印("我是假的.")`打印"我是假的." 所以空列表是假的.数组的内容需要使用类似`all`函数的评估. (3认同)
  • 不知道为什么你需要这样的路径。您应该从测试中删除 `result.path`。 (3认同)
  • 这对我来说已经足够了,谢谢。我刚刚为 `scheme` 添加了一个简单的验证:`if not all([result.scheme in ["file", "http", "https"], result.netloc, result.path]):` (2认同)
  • 烂算法。这会验证格式错误的 URI,例如 `https://https://https://www.foo.bar` 为 `ParseResult(scheme='https', netloc='https:', path='//https:// /www.foo.bar', params='', query='',fragment='')`。**换句话说,它传递了损坏的 URI。** (2认同)
  • 我已将示例更新为不需要路径,因为这不是必需的 (2认同)

jon*_*eto 13

如今,我根据Padam的回答使用以下内容:

$ python --version
Python 3.6.5
Run Code Online (Sandbox Code Playgroud)

这就是它的样子:

from urllib.parse import urlparse

def is_url(url):
  try:
    result = urlparse(url)
    return all([result.scheme, result.netloc])
  except ValueError:
    return False
Run Code Online (Sandbox Code Playgroud)

只是用is_url("http://www.asdf.com").

希望能帮助到你!

  • 这仅适用于在已知 URI **不** 格式错误的特殊情况下拆分组件。正如我之前回复其他类似答案一样,这会验证格式错误的 URI,例如“https://https://https://www.foo.bar”。 (2认同)

and*_*oke 9

注意 - 不再支持lepl,抱歉(欢迎您使用它,我认为下面的代码有效,但它不会得到更新).

rfc 3696 http://www.faqs.org/rfcs/rfc3696.html定义了如何执行此操作(对于http网址和电子邮件).我使用lepl(一个解析器库)在python中实现了它的建议.见http://acooke.org/lepl/rfc3696.html

使用:

> easy_install lepl
...
> python
...
>>> from lepl.apps.rfc3696 import HttpUrl
>>> validator = HttpUrl()
>>> validator('google')
False
>>> validator('http://google')
False
>>> validator('http://google.com')
True
Run Code Online (Sandbox Code Playgroud)

  • 你没有分叉代码并实现它们?它是开源的. (6认同)
  • 整洁,但是FTP或HTTPS呢? (2认同)

DMf*_*fll 7

我登陆此页面试图找出一种将字符串验证为"有效"网址的合理方法.我在这里使用python3分享我的解决方案.无需额外的库.

如果您使用的是python2,请参阅https://docs.python.org/2/library/urlparse.html.

如果你像我一样使用python3,请参阅https://docs.python.org/3.0/library/urllib.parse.html.

import urllib
from pprint import pprint

invalid_url = 'dkakasdkjdjakdjadjfalskdjfalk'
valid_url = 'https://stackoverflow.com'
tokens = [urllib.parse.urlparse(url) for url in (invalid_url, valid_url)]

for token in tokens:
    pprint(token)

min_attributes = ('scheme', 'netloc')  # add attrs to your liking
for token in tokens:
    if not all([getattr(token, attr) for attr in min_attributes]):
        error = "'{url}' string has no scheme or netloc.".format(url=token.geturl())
        print(error)
    else:
        print("'{url}' is probably a valid url.".format(url=token.geturl()))
Run Code Online (Sandbox Code Playgroud)

ParseResult(scheme ='',netloc ='',path ='dkakasdkjdjakdjadjfalskdjfalk',params ='',query ='',fragment ='')

ParseResult(scheme ='https',netloc ='stackoverflow.com',path ='',params ='',query ='',fragment ='')

'dkakasdkjdjakdjadjfalskdjfalk'字符串没有方案或netloc.

' https://stackoverflow.com '可能是一个有效的网址.

这是一个更简洁的功能:

import urllib

min_attributes = ('scheme', 'netloc')


def is_valid(url, qualifying=None):
    qualifying = min_attributes if qualifying is None else qualifying
    token = urllib.parse.urlparse(url)
    return all([getattr(token, qualifying_attr)
                for qualifying_attr in qualifying])
Run Code Online (Sandbox Code Playgroud)


小智 5

编辑

正如@Kwame 所指出的,即使.comor.co等不存在,以下代码也会验证 url 。

@Blaise 还指出,像https://www.google 这样的 URL 是一个有效的 URL,您需要单独进行 DNS 检查以检查它是否解析。

这很简单并且有效:

Somin_attr包含需要存在以定义 URL 有效性的基本字符串集,即http://部分和google.com部分。

urlparse.scheme商店http://

urlparse.netloc 存储域名 google.com

from urlparse import urlparse
def url_check(url):

    min_attr = ('scheme' , 'netloc')
    try:
        result = urlparse(url)
        if all([result.scheme, result.netloc]):
            return True
        else:
            return False
    except:
        return False
Run Code Online (Sandbox Code Playgroud)

all()如果其中的所有变量都返回 true,则返回 true。因此,如果result.schemeresult.netloc存在即具有某些值,则该 URL 有效并因此返回True


Dom*_*rro 5

这是一个正则表达式解决方案,因为投票最高的正则表达式不适用于顶级域等奇怪的情况。下面是一些测试用例。

regex = re.compile(
    r"(\w+://)?"                # protocol                      (optional)
    r"(\w+\.)?"                 # host                          (optional)
    r"(([\w-]+)\.(\w+))"        # domain
    r"(\.\w+)*"                 # top-level domain              (optional, can have > 1)
    r"([\w\-\._\~/]*)*(?<!\.)"  # path, params, anchors, etc.   (optional)
)
Run Code Online (Sandbox Code Playgroud)
cases = [
    "http://www.google.com",
    "https://www.google.com",
    "http://google.com",
    "https://google.com",
    "www.google.com",
    "google.com",
    "http://www.google.com/~as_db3.2123/134-1a",
    "https://www.google.com/~as_db3.2123/134-1a",
    "http://google.com/~as_db3.2123/134-1a",
    "https://google.com/~as_db3.2123/134-1a",
    "www.google.com/~as_db3.2123/134-1a",
    "google.com/~as_db3.2123/134-1a",
    # .co.uk top level
    "http://www.google.co.uk",
    "https://www.google.co.uk",
    "http://google.co.uk",
    "https://google.co.uk",
    "www.google.co.uk",
    "google.co.uk",
    "http://www.google.co.uk/~as_db3.2123/134-1a",
    "https://www.google.co.uk/~as_db3.2123/134-1a",
    "http://google.co.uk/~as_db3.2123/134-1a",
    "https://google.co.uk/~as_db3.2123/134-1a",
    "www.google.co.uk/~as_db3.2123/134-1a",
    "google.co.uk/~as_db3.2123/134-1a",
    "https://...",
    "https://..",
    "https://.",
    "https://.google.com",
    "https://..google.com",
    "https://...google.com",
    "https://.google..com",
    "https://.google...com",
    "https://...google..com",
    "https://...google...com",
    ".google.com",
    ".google.co.",
    "https://google.co."
]
for c in cases:
    if regex.match(c):
        print(c, regex.match(c).span()[1] - regex.match(c).span()[0] == len(c))
    else:
        print(c, False)
Run Code Online (Sandbox Code Playgroud)

编辑:按照 nickh 的建议将连字符添加到域中。

  • 最后一行的错误已修复:`print(c, x.span()[1] - x.span()[0] == len(c) if (x := regex.match(c)) else False)` (2认同)