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 ?
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
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?
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
).
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
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!
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
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])
[~ # ~] é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
.
urllib
et une expression rationnelle de type DjangoLe 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!
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
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
Si vous souhaitez que le validateur d'URL fonctionne également avec les adresses IPv6, procédez comme suit:
is_valid_ipv6(ip)
de réponse de Markus Jarderot , qui a un très bon regex validateur IPv6and not is_valid_ipv6(domain)
au dernier if
Voici quelques exemples de regex pour la partie netloc
(alias domain
) en action: