web-dev-qa-db-fra.com

Python - Comment valider une URL dans python? (Malformé ou non)

J'ai url de l'utilisateur et je dois répondre avec le code HTML récupéré.

Comment puis-je vérifier si l'URL est malformée ou non?

Par exemple :

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

Comment pouvons-nous y parvenir ?

87
Yugal Jindle

Adresse regex de validation des URLs Django:

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

En fait, je pense que c'est la meilleure façon.

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

Si vous définissez verify_exists à True, il vérifiera que l'URL existe, sinon il vérifiera s'il est correctement formé.

modifier: ah oui, cette question est une copie de ceci: Comment puis-je vérifier si une URL existe avec les validateurs de Django?

119
Drekembe

Utilisez le package validators :

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

Installez le depuis PyPI avec pip (pip install validators).

95
Jabba

Une version True ou False, basée sur la réponse @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))

Donne:

True
True
False
True
39
alemol

De nos jours, j'utilise ce qui suit, basé sur la réponse de Padam:

$ python --version
Python 3.6.5

Et voici à quoi ça ressemble:

from urllib.parse import urlparse

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

Il suffit d'utiliser is_url("http://www.asdf.com").

J'espère que ça aide!

11
jonaprieto

note - Lepl n'est plus pris en charge, désolé (vous pouvez l'utiliser, et je pense que le code ci-dessous fonctionne, mais il ne va pas en arriver mises à jour).

la RFC 3696 http://www.faqs.org/rfcs/rfc3696.html définit comment procéder (pour les URL http et les courriels). J'ai implémenté ses recommandations dans python en utilisant lepl (une bibliothèque d'analyse)), voir http://acooke.org/lepl/rfc3696.html

utiliser:

> easy_install lepl
...
> python
...
>>> from lepl.apps.rfc3696 import HttpUrl
>>> validator = HttpUrl()
>>> validator('google')
False
>>> validator('http://google')
False
>>> validator('http://google.com')
True
8
andrew cooke

J'ai atterri sur cette page en essayant de trouver un moyen sain de valider les chaînes en tant qu'URL "valides". Je partage ici ma solution en utilisant python3. Aucune bibliothèque supplémentaire requise.

Voir https://docs.python.org/2/library/urlparse.html si vous utilisez python2.

Voir https://docs.python.org/3.0/library/urllib.parse.html si vous utilisez python3 tel que je suis.

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

La chaîne 'dkakasdkjdjakdjadjfalskdjfalk' n'a ni schéma ni netloc.

' https://stackoverflow.com ' est probablement une URL valide.

Voici une fonction plus concise:

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

[~ # ~] éditer [~ # ~]

Comme l'a souligné @Kwame, le code ci-dessous valide l'URL même si le .com Ou le .co Etc. ne sont pas présents.

également souligné par @Blaise, les URL telles que https://www.google est une URL valide et vous devez effectuer une vérification DNS pour vérifier si le problème est résolu ou non, séparément.

C'est simple et ça marche:

Ainsi, min_attr Contient le jeu de base de chaînes qui doit être présent pour définir la validité d'une URL, à savoir une partie http:// Et une partie google.com.

urlparse.scheme Stocke http:// Et

urlparse.netloc Stocke le nom de domaine 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() renvoie true si toutes les variables qu'il contient renvoient true. Donc, si result.scheme Et result.netloc Sont présents, c’est-à-dire qu’ils ont une certaine valeur, l’URL est valide et renvoie donc True.

4
Padam Sethia

Valider l'URL avec urllib et une expression rationnelle de type Django

Le regex de validation d'URL Django était en fait assez bon, mais je devais le modifier légèrement pour mon cas d'utilisation. N'hésitez pas à l'adapter au vôtre!

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

Explication

  • Le code ne valide que les parties scheme et netloc d'une URL donnée. (Pour le faire correctement, j'ai divisé l'URL avec urllib.parse.urlparse() dans les deux parties correspondantes, qui sont ensuite comparées aux termes de regex correspondants.)
  • La partie netloc s'arrête avant la première occurrence d'une barre oblique /, De sorte que les chiffres port font toujours partie de la netloc, par exemple:

    https://www.google.com:80/search?q=python
    ^^^^^   ^^^^^^^^^^^^^^^^^
      |             |      
      |             +-- netloc (aka "domain" in my code)
      +-- scheme
    
  • Les adresses IPv4 sont également validées

Prise en charge IPv6

Si vous souhaitez que le validateur d'URL fonctionne également avec les adresses IPv6, procédez comme suit:

  • Ajoutez is_valid_ipv6(ip) de réponse de Markus Jarderot , qui a un très bon regex validateur IPv6
  • Ajouter and not is_valid_ipv6(domain) au dernier if

Exemples

Voici quelques exemples de regex pour la partie netloc (alias domain) en action:

0
winklerrr