Python - Python'da bir url nasıl doğrulanır? (Yanlış biçimlendirilmiş ya da değil)


117

Ben urlkullanıcıdan ve ben getirilen HTML ile cevap vermek gerekir.

URL’nin bozuk olup olmadığını nasıl kontrol edebilirim?

Örneğin :

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

Bunu nasıl başarabiliriz ?



1
Sadece okumaya çalışın, örneğin httplib bir istisna atarsa, geçersiz olduğunu anlarsınız. İyi biçimlendirilmiş tüm url'ler geçerli değildir !
carlpett

1
bu size yardımcı olacaktır: stackoverflow.com/questions/827557/…
DhruvPathak

10
url='http://google' kusurlu değil. Şema + ana bilgisayar adı her zaman geçerlidir.
Viktor Joras

Yanıtlar:


90

django url doğrulama normal ifadesi ( kaynak ):

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

bir merak ... eklediniz ftpmi? Yoksa eski bir django versiyonum mu var?
Ruggero Turra

2
@ yugal-jindle sitedomain geçerli bir url değil. museum çünkü .museum bir üst düzey alan adıdır (ICANN [1] bunları tanımlar) ve bir site hakimiyeti değildir. [1] icann.org
glarrain

1
Bu, kullanıcı adı: password@example.com tarzı URL'ler ile çalışmıyor gibi görünüyor
Adam Baxter


2
Bu,http://[2001:0DB8::3]:8080/index.php?valid=true#result
cimnine

124

Aslında bence en iyi yol bu.

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

Eğer ayarlarsanız verify_existsiçin True, aslında, URL varolduğunu doğrular doğru oluşmuş eğer aksi takdirde sadece kontrol edecektir.

edit: ah evet, bu soru bunun bir kopyası: Django'nun doğrulayıcılarında bir URL'nin var olup olmadığını nasıl kontrol edebilirim?


46
Ancak bu sadece django ortamında işe yarayacaktır, aksi halde.
Yugal Jindle

19
verify_existskullanımdan kaldırıldı. -1
g33kz0r

2
Ekle: django.conf içinden içe aktarma ayarları settings.configure (DEBUG = False) ve django 1.5 ile çalışmasını sağlamak için doğrulama_exists'i kaldırın
Dukeatcoding

1
@YugalJindle Doğru, ancak Django'dan çıkarmak neredeyse önemsiz: D. Bu yüzden, bu yöntemi kullanıyorum
swdev

7
Dikkat, django> = 1.5 ile artık verify_existsyok. Ayrıca valdeğişken yerine şöyle diyebilirsinizURLValidator()('http://www.google.com')
luckydonald

122

Doğrulayıcılar paketini kullanın :

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

PyPI'den pip ( pip install validators) ile kurun .


5
Dosya url'leri için hata atar. "File: ///users/file.txt" gibi
Devavrata

2
Localhost url'leri başarısız validators.url("http://localhost:8080") ValidationFailure(func=url, args={'public': False, 'value': 'http://localhost:8080'})
Tom

5
@Lal Zada, böyle bir şey iddia etmeden önce biraz çaba sarf edip kodu kontrol edin, regexp aslında oldukça iyidir: validators.readthedocs.io/en/latest/_modules/validators/…
Drachenfels

1
Paketin doğrulaması fn'nin birçok keyfi sınırlaması vardır, bu nedenle bunu genel bir çözüm olarak önermek korkunç bir tavsiye.
ivan_pozdeev

2
@ivan_pozdeev: Korkunçsa, daha iyi bir çözüm önerin
Jabba

62

@DMfll cevabına dayalı bir Doğru veya Yanlış sürüm:

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

verir:

True
False
False
False

8
Hiçbiri olmayan öğeler listesiyle bir if ifadesini test edebileceğinizi bilmiyordum. Bu yardımcı olur. Ayrıca yerleşik bir modül kullanmak için +1
Marc Maxmeister

9
Bu her şeye izin verir. TrueDize için fakeveya boş bir dize için döner . Hiçbir zaman hata olmayacak çünkü bu öznitelikler her zaman oradadır ve listenin boole değeri her zaman True olacaktır çünkü bu öznitelikleri içerir. Tüm öznitelikler Yok olsa bile, liste yine de boş olmayacaktır. Niteliklerin bazı doğrulamalarına ihtiyacınız var çünkü her şey şu anda sahip olduğunuz yoldan geçiyor.
zondo

3
Yanlış nesnelerin listeleri True olarak değerlendirilir: print("I am true") if [False, None, 0, '', [], {}] else print("I am false.")"Doğruyum" yazdırır. çalıştırdığımda. [result.scheme, result.netloc, result.path]her zaman için değerlendirir True. print("I am True") if [] else print("I am False.")"Ben yanlışım" yazar. bu yüzden boş listeler Yanlış. Dizinin içeriğinin allişlev gibi bir şeyle değerlendirilmesi gerekiyor .
dmmfll

3
Neden böyle bir yola ihtiyaç duyduğundan emin değilim. result.pathTestten çıkarmanız gerekir .
Jerinaw

1
Bu benim için yeterince iyi, teşekkürler. Şunun için basit bir doğrulama ekledim scheme: if not all([result.scheme in ["file", "http", "https"], result.netloc, result.path]):
Alexander Fortin

20

Bugünlerde Padam'ın cevabına göre şunları kullanıyorum:

$ python --version
Python 3.6.5

Ve şu şekilde görünüyor:

from urllib.parse import urlparse

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

Sadece kullan is_url("http://www.asdf.com").

Umarım yardımcı olur!


Alan adının geçerli olmayan bir kısa çizgi ile başlaması durumunda başarısız olur. tools.ietf.org/html/rfc952
Björn Lindqvist

1
Bu URI'siyle bilinmektedir ki özel durumda bileşenleri bölmek sadece iyidir DEĞİL bozuk olmasına. Diğer benzer yanıta daha önce yanıtladığım gibi, bu, gibi hatalı biçimlendirilmiş URI'leri doğrular https://https://https://www.foo.bar.
ingyhere

9

not - lepl artık desteklenmiyor, üzgünüm (bunu kullanabilirsiniz ve aşağıdaki kodun çalıştığını düşünüyorum, ancak güncelleme almayacaktır).

rfc 3696 http://www.faqs.org/rfcs/rfc3696.html bunun nasıl yapılacağını tanımlar (http url'leri ve e-posta için). lepl (bir ayrıştırıcı kitaplığı) kullanarak önerilerini python'da gerçekleştirdim. bkz. http://acooke.org/lepl/rfc3696.html

kullanmak:

> 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
Düzgün, peki ya FTP veya HTTPS?
Adam Parkin

6
kodu çatallayıp uygulamadınız mı? açık kaynak.
Andrew cooke

1
lepl şimdi yazar tarafından kesilir acooke.org/lepl/discontinued.html EDIT: heh, sadece fark vardır yazar
Emmett Butler

1
not: lepl.apps.rfc3696 Python 3.7.4'te çalışmıyor
Sheile

9

Dizeleri "geçerli" URL'ler olarak doğrulamanın mantıklı bir yolunu bulmaya çalışırken bu sayfaya geldim. Burada python3 kullanarak çözümümü paylaşıyorum. Ekstra kitaplık gerekmez.

Bkz. Https://docs.python.org/2/library/urlparse.htmlPython2 kullanıyorsanız .

Benim gibi python3 kullanıyorsanız https://docs.python.org/3.0/library/urllib.parse.html bakın .

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 (şema = '', netloc = '', yol = 'dkakasdkjdjakdjadjfalskdjfalk', params = '', sorgu = '', parça = '')

ParseResult (şema = 'https', netloc = 'stackoverflow.com', yol = '', params = '', sorgu = '', parça = '')

'dkakasdkjdjakdjadjfalskdjfalk' dizesinin şeması veya netloc'u yok.

' https://stackoverflow.com ' muhtemelen geçerli bir url'dir.

İşte daha kısa bir fonksiyon:

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

DÜZENLE

@Kwame tarafından belirtildiği gibi, aşağıdaki kod, .comveya .coetc mevcut olmasa bile url'yi doğrular .

@Blaise tarafından da belirtildiği gibi, https://www.google gibi URL'ler geçerli bir URL'dir ve çözülüp çözülmediğini kontrol etmek için ayrı ayrı bir DNS kontrolü yapmanız gerekir.

Bu basit ve işe yarıyor:

Bu nedenle min_attr, bir URL'nin geçerliliğini tanımlamak için mevcut olması gereken temel dizi kümesini içerir, yani http://kısım ve google.comkısım.

urlparse.schememağazalar http://ve

urlparse.netloc alan adını sakla 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()içindeki tüm değişkenler true olursa doğru döndürür. Öyleyse result.schemeve varsa result.netloc, yani bir değeri varsa, URL geçerlidir ve dolayısıyla geri döner True.


Güzel yakaladım .. Sanırım kodumu geri almalıyım. Neyi tercih edersiniz, regex dışında başka seçenekler var mı?
Padam Sethia

https://www.googlegeçerli bir URL'dir. Aslında çözülmeyebilir, ancak bunu önemsiyorsanız bir DNS kontrolü yapmanız gerekir.
Blaise

istisnaları yutar
ivan_pozdeev

2

URL'yi urllibDjango benzeri regex ile doğrulayın

Django URL doğrulama normal ifadesi aslında oldukça iyiydi, ancak kullanım durumum için biraz ince ayar yapmam gerekiyordu. Sizinkine uyarlamaktan çekinmeyin!

Python 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

açıklama

  • Kod, belirli bir URL'nin yalnızca schemeve netlockısmını doğrular . (Bunu düzgün bir şekilde yapmak için URL'yiurllib.parse.urlparse() daha sonra karşılık gelen normal ifade terimleriyle eşleştirilen iki parçaya bölerim.)
  • netlocBölüm eğik çizgi ilk geçtiği önce duruyor /, böylece portsayılar yine bir parçasıdır netloc, örneğin:

    https://www.google.com:80/search?q=python
    ^^^^^   ^^^^^^^^^^^^^^^^^
      |             |      
      |             +-- netloc (aka "domain" in my code)
      +-- scheme
  • IPv4 adresleri de doğrulanır

IPv6 Desteği

URL doğrulayıcının IPv6 adresleriyle de çalışmasını istiyorsanız, aşağıdakileri yapın:

  • Ekle is_valid_ipv6(ip)dan Markus Jarderot cevabı gerçekten iyi IPv6 doğrulayıcı regex vardır,
  • Ekle and not is_valid_ipv6(domain)Sonuncusunaif

Örnekler

İşte netloc(aka domain) işlemdeki bölüm için bazı normal ifade örnekleri :


2

Yukarıdaki çözümlerin tümü, " http://www.google.com/path,www.yahoo.com/path " gibi bir dizeyi geçerli olarak tanır . Bu çözüm her zaman olması gerektiği gibi çalışır

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)

google.com/path,www.yahoo.com/path olduğunu geçerlidir. Bkz. RFC 3986 : a path, biri olabilecek s segment' pcharden oluşturulan' lerden yapılmıştır . sub-delims","
Anders Kaseorg
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.