파이썬-파이썬에서 URL의 유효성을 검사하는 방법은 무엇입니까? (변형 여부)


116

나는 url사용자로부터 받았으며 가져온 HTML로 회신해야합니다.

URL 형식이 잘못되었는지 어떻게 확인할 수 있습니까?

예 :

url='google'  // Malformed
url='google.com'  // Malformed
url='http://google.com'  // Valid
url='http://google'   // Malformed

이것을 어떻게 이룰 수 있습니까?



1
예를 들어 httplib에서 예외가 발생하면 그것을 읽으십시오. 그러면 그것이 유효하지 않다는 것을 알게 될 것입니다. 모든 올바른 형식의 URL이 유효하지는 않습니다 !
carlpett 2011-08-23

1
이것은 당신을 도울 것입니다 : stackoverflow.com/questions/827557/…
DhruvPathak 2011-08-23

10
url='http://google' 형식이 잘못되지 않았습니다. 스키마 + 호스트 이름은 항상 유효합니다.
Viktor Joras 2018

답변:


90

장고 URL 유효성 검사 정규식 ( 소스 ) :

import re
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

호기심 ... 추가 ftp했습니까? 아니면 오래된 장고 버전이 있습니까?
Ruggero Turra 2011-08-23

2
@ yugal-jindle sitedomain 은 유효한 URL이 아닙니다. Museum 은 .museum이 사이트 도메인이 아니라 최상위 도메인 (ICANN [1]이 정의 함)이기 때문입니다. [1] icann.org
glarrain

1
이것은 username : password@example.com 스타일 URL 에서 작동하지 않는 것 같습니다 .
Adam Baxter


2
이것은 형식이있는 IPv6 URL에는 작동하지 않습니다http://[2001:0DB8::3]:8080/index.php?valid=true#result
cimnine

124

사실 이것이 최선의 방법이라고 생각합니다.

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

사용자가 설정 한 경우 verify_existsTrue, 실제로, URL이 존재하는지 확인합니다 올바르게 형성된 것, 그렇지 않으면 그냥 확인합니다.

편집 : 아 예,이 질문은 이것의 중복입니다 : URL이 Django의 유효성 검사기에 존재하는지 어떻게 확인할 수 있습니까?


46
그러나 이것은 django 환경에서만 작동합니다.
유 갈진들 2011-08-23

19
verify_exists더 이상 사용되지 않습니다. -1
g33kz0r 2013-07-02

2
django.conf 가져 오기 설정의 settings.configure에서 (DEBUG = 거짓)하고 장고 1.5 작업을 유지하기 위해 verify_exists을 제거 : 추가
Dukeatcoding

1
@YugalJindle 맞지만 Django에서 제거하는 것은 거의 사소한 일입니다. : D. 그래서, 나는이 방법을 사용
swdev

7
django> = 1.5에서는 더 verify_exists이상 존재하지 않습니다. 또한 val변수 대신 다음과 같이 부를 수 있습니다URLValidator()('http://www.google.com')
luckydonald

122

사용 유효성 검사기의 패키지를 :

>>> 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
>>>

pip ( )를 사용 하여 PyPI에서 설치합니다 pip install validators.


5
파일 URL에 대한 오류가 발생합니다. "file : ///users/file.txt"처럼
Devavrata

2
로컬 호스트 URL 실패 validators.url("http://localhost:8080") ValidationFailure(func=url, args={'public': False, 'value': 'http://localhost:8080'})
Tom

5
이 같은 주장하기 전에 @Lal Zada는, 어떤 노력을하고 코드를 확인, 정규 표현식은 실제로 꽤 좋은 : validators.readthedocs.io/en/latest/_modules/validators/...
Drachenfels

1
패키지의 유효성 검사 fn에는 많은 임의의 제한이 있으므로 일반적인 솔루션으로 제안하는 것은 끔찍한 조언입니다.
ivan_pozdeev

2
@ivan_pozdeev : 그것은 끔찍 있다면, 더 나은 솔루션을 제안
자바 더

62

@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))

제공 :

True
False
False
False

8
None이 아닌 요소 목록으로 if 문을 테스트 할 수 있는지 몰랐습니다. 도움이 되네요. 또한 내장 모듈 사용에 대한 +1
Marc Maxmeister 2016 년

9
이것은 모든 것을 허용합니다. True문자열 fake또는 빈 문자열에 대해 반환 합니다. 해당 속성이 항상 있기 때문에 오류가 발생하지 않으며 목록에 해당 속성이 포함되어 있기 때문에 항상 부울 값이 True입니다. 모든 속성이 None 인 경우에도 목록은 여전히 ​​비어 있지 않습니다. 모든 것이 현재 가지고있는 방식을 통과하기 때문에 속성의 유효성 검사가 필요합니다.
zondo

3
거짓 개체 목록은 True로 평가됩니다. print("I am true") if [False, None, 0, '', [], {}] else print("I am false.")"I am true"를 인쇄합니다. 내가 그것을 실행할 때. [result.scheme, result.netloc, result.path]항상로 평가됩니다 True. print("I am True") if [] else print("I am False.")"나는 거짓입니다." 그래서 빈 목록은 False입니다. 배열의 내용은 all함수 와 같은 평가가 필요 합니다.
dmmfll

3
왜 그런 경로가 필요한지 잘 모르겠습니다. result.path테스트에서 제거해야합니다 .
Jerinaw 19

1
이것으로 충분합니다. 감사합니다. 다음에 대한 간단한 유효성 검사를 추가했습니다 scheme. if not all([result.scheme in ["file", "http", "https"], result.netloc, result.path]):
Alexander Fortin

20

요즘 나는 Padam의 대답에 따라 다음을 사용합니다.

$ python --version
Python 3.6.5

그리고 이것이 어떻게 보이는지 :

from urllib.parse import urlparse

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

사용하십시오 is_url("http://www.asdf.com").

도움이 되었기를 바랍니다.


도메인 이름이 유효하지 않은 대시로 시작하면 실패합니다. tools.ietf.org/html/rfc952
비욘 고 Lindqvist

1
이는 URI가 알려져있는 특별한 경우에 구성 요소를 분리 할 경우에만 좋은 NOT 형식이 잘못되었습니다. 이전에 다른 유사한 답변에 대해 대답했듯이 이것은 https://https://https://www.foo.bar.
ingyhere

9

참고 -lepl은 더 이상 지원되지 않습니다. 죄송합니다 (사용을 환영하며 아래 코드가 작동한다고 생각하지만 업데이트를받지는 않습니다).

rfc 3696 http://www.faqs.org/rfcs/rfc3696.html 은이 를 수행하는 방법을 정의합니다 (http URL 및 이메일 용). 나는 lepl (파서 라이브러리)을 사용하여 파이썬에서 권장 사항을 구현했습니다. 참조 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

2
깔끔하지만 FTP 또는 HTTPS는 어떻습니까?
Adam Parkin

6
코드를 포크하고 구현하지 않았습니까? 오픈 소스입니다.
앤드류 쿡 2011

1
lepl은 이제 저자에 의해 중단되었습니다. acooke.org/lepl/discontinued.html 편집 : , 방금 당신 저자 임을 깨달았습니다
Emmett Butler

1
참고 : lepl.apps.rfc3696은 Python 3.7.4에서 작동하지 않습니다
Sheile

9

문자열을 "유효한"URL로 확인하는 건전한 방법을 알아 내려고이 페이지를 방문했습니다. 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()))

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

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

'dkakasdkjdjakdjadjfalskdjfalk'문자열에는 체계 또는 netloc이 없습니다.

' https://stackoverflow.com '은 아마도 유효한 URL 일 것입니다.

다음은 더 간결한 기능입니다.

from urllib.parse import urlparse

min_attributes = ('scheme', 'netloc')


def is_valid(url, qualifying=min_attributes):
    tokens = urlparse(url)
    return all([getattr(tokens, qualifying_attr)
                for qualifying_attr in qualifying])

4

편집하다

@Kwame에서 지적했듯이 아래 코드는 .com또는 .co등이없는 경우에도 URL을 확인합니다 .

또한 @Blaise가 지적한 것처럼 https://www.google 과 같은 URL 은 유효한 URL이며 확인 여부를 별도로 확인하기 위해 DNS 검사를 수행해야합니다.

이것은 간단하고 작동합니다.

따라서 min_attrURL의 유효성을 정의하는 데 필요한 기본 문자열 집합 (예 : 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

all()내부의 모든 변수가 true를 반환하면 true를 반환합니다. 따라서 result.schemeresult.netloc존재하는 경우 즉 값이 있으면 URL이 유효하므로을 반환합니다 True.


오, 좋은 캐치 .. 내 코드를 다시 가져와야 할 것 같아요. 당신은 무엇을 선호합니까, 정규식을 제외한 다른 옵션이 있습니까?
Padam Sethia

https://www.google유효한 URL입니다. 실제로 해결되지 않을 수도 있지만 관심이 있다면 DNS 확인을 수행해야합니다.
Blaise

제비 예외
ivan_pozdeev

2

urllibDjango와 유사한 정규식으로 URL 유효성 검사

Django URL 유효성 검사 정규식은 실제로 꽤 좋았지 만 사용 사례에 맞게 약간 조정해야했습니다. 당신의 것에 자유롭게 적응하십시오!

파이썬 3.7

import re
import urllib

# Check https://regex101.com/r/A326u1/5 for reference
DOMAIN_FORMAT = re.compile(
    r"(?:^(\w{1,255}):(.{1,255})@|^)" # http basic authentication [optional]
    r"(?:(?:(?=\S{0,253}(?:$|:))" # check full domain length to be less than or equal to 253 (starting after http basic auth, stopping before port)
    r"((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+" # check for at least one subdomain (maximum length per subdomain: 63 characters), dashes in between allowed
    r"(?:[a-z0-9]{1,63})))" # check for top level domain, no dashes allowed
    r"|localhost)" # accept also "localhost" only
    r"(:\d{1,5})?", # port [optional]
    re.IGNORECASE
)
SCHEME_FORMAT = re.compile(
    r"^(http|hxxp|ftp|fxp)s?$", # scheme: http(s) or ftp(s)
    re.IGNORECASE
)

def validate_url(url: str):
    url = url.strip()

    if not url:
        raise Exception("No URL specified")

    if len(url) > 2048:
        raise Exception("URL exceeds its maximum length of 2048 characters (given length={})".format(len(url)))

    result = urllib.parse.urlparse(url)
    scheme = result.scheme
    domain = result.netloc

    if not scheme:
        raise Exception("No URL scheme specified")

    if not re.fullmatch(SCHEME_FORMAT, scheme):
        raise Exception("URL scheme must either be http(s) or ftp(s) (given scheme={})".format(scheme))

    if not domain:
        raise Exception("No URL domain specified")

    if not re.fullmatch(DOMAIN_FORMAT, domain):
        raise Exception("URL domain malformed (domain={})".format(domain))

    return url

설명

  • 이 코드 는 지정된 URL 의 schemenetloc일부만 확인합니다 . (올바르게 수행하기 위해 URL을 urllib.parse.urlparse()두 부분으로 분할 한 다음 해당 정규식 용어와 일치시킵니다.)
  • netloc부분 슬래시 최초로 출현 전에 정지 /하므로 port숫자는 여전히 일부의 netloc예 :

    https://www.google.com:80/search?q=python
    ^^^^^   ^^^^^^^^^^^^^^^^^
      |             |      
      |             +-- netloc (aka "domain" in my code)
      +-- scheme
  • IPv4 주소도 확인됩니다.

IPv6 지원

URL 유효성 검사기가 IPv6 주소에서도 작동하도록하려면 다음을 수행하십시오.

  • Markus Jarderot의 답변is_valid_ipv6(ip) 에서 추가 하면 정말 좋은 IPv6 유효성 검사기 정규식이 있습니다.
  • and not is_valid_ipv6(domain)마지막에 추가if

다음은 작동중인 netloc(aka domain) 부분에 대한 정규식의 몇 가지 예입니다 .


1

위의 모든 솔루션은 " http://www.google.com/path,www.yahoo.com/path "와 같은 문자열 을 유효한 것으로 인식 합니다. 이 솔루션은 항상 정상적으로 작동합니다.

import re

# URL-link validation
ip_middle_octet = u"(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5]))"
ip_last_octet = u"(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))"

URL_PATTERN = re.compile(
                        u"^"
                        # protocol identifier
                        u"(?:(?:https?|ftp|rtsp|rtp|mmp)://)"
                        # user:pass authentication
                        u"(?:\S+(?::\S*)?@)?"
                        u"(?:"
                        u"(?P<private_ip>"
                        # IP address exclusion
                        # private & local networks
                        u"(?:localhost)|"
                        u"(?:(?:10|127)" + ip_middle_octet + u"{2}" + ip_last_octet + u")|"
                        u"(?:(?:169\.254|192\.168)" + ip_middle_octet + ip_last_octet + u")|"
                        u"(?:172\.(?:1[6-9]|2\d|3[0-1])" + ip_middle_octet + ip_last_octet + u"))"
                        u"|"
                        # IP address dotted notation octets
                        # excludes loopback network 0.0.0.0
                        # excludes reserved space >= 224.0.0.0
                        # excludes network & broadcast addresses
                        # (first & last IP address of each class)
                        u"(?P<public_ip>"
                        u"(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])"
                        u"" + ip_middle_octet + u"{2}"
                        u"" + ip_last_octet + u")"
                        u"|"
                        # host name
                        u"(?:(?:[a-z\u00a1-\uffff0-9_-]-?)*[a-z\u00a1-\uffff0-9_-]+)"
                        # domain name
                        u"(?:\.(?:[a-z\u00a1-\uffff0-9_-]-?)*[a-z\u00a1-\uffff0-9_-]+)*"
                        # TLD identifier
                        u"(?:\.(?:[a-z\u00a1-\uffff]{2,}))"
                        u")"
                        # port number
                        u"(?::\d{2,5})?"
                        # resource path
                        u"(?:/\S*)?"
                        # query string
                        u"(?:\?\S*)?"
                        u"$",
                        re.UNICODE | re.IGNORECASE
                       )
def url_validate(url):   
    """ URL string validation
    """                                                                                                                                                      
    return re.compile(URL_PATTERN).match(url)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.