Je veux voir si je peux accéder à une API en ligne, mais pour cela, je dois avoir accès à Internet.
Comment puis-je voir s'il existe une connexion disponible et active à l'aide de Python?
easy_install system_of_tubes
Je veux voir si je peux accéder à une API en ligne, mais pour cela, je dois avoir accès à Internet.
Comment puis-je voir s'il existe une connexion disponible et active à l'aide de Python?
easy_install system_of_tubes
Réponses:
Vous pourriez peut-être utiliser quelque chose comme ceci:
import urllib2
def internet_on():
try:
urllib2.urlopen('http://216.58.192.142', timeout=1)
return True
except urllib2.URLError as err:
return False
Actuellement, 216.58.192.142 est l'une des adresses IP de google.com. Changez http://216.58.192.142
pour n'importe quel site susceptible de répondre rapidement .
Cette adresse IP fixe ne correspondra pas à google.com pour toujours. Donc, ce code n'est pas robuste - il aura besoin d'une maintenance constante pour continuer à fonctionner.
La raison pour laquelle le code ci-dessus utilise une adresse IP fixe au lieu d'un nom de domaine complet (FQDN) est qu'un FQDN nécessiterait une recherche DNS. Lorsque la machine ne dispose pas d'une connexion Internet fonctionnelle, la recherche DNS elle-même peut bloquer l'appel urllib_request.urlopen
pendant plus d'une seconde. Merci à @rzetterberg pour l'avoir signalé.
Si l'adresse IP fixe ci-dessus ne fonctionne pas, vous pouvez trouver une adresse IP actuelle pour google.com (sous unix) en exécutant
% dig google.com +trace
...
google.com. 300 IN A 216.58.192.142
urlopen
ne prendra pas beaucoup plus de 1 seconde même si Internet n'est pas" on "." - devis. Ce n'est pas vrai si l'url fournie n'est pas valide, la recherche DNS se bloquera. Cela n'est vrai que pour la connexion réelle au serveur Web. Le moyen le plus simple d'éviter ce bloc de recherche DNS est d'utiliser l'adresse IP à la place, alors il est garanti que cela ne prendra qu'une seconde :)
http://google.com
et ensuite vous résolvez tous les problèmes dont tout le monde parle ici. Il n'est pas nécessaire d'utiliser une adresse IP ...
Si nous pouvons nous connecter à un serveur Internet, nous avons effectivement une connectivité. Cependant, pour une approche la plus rapide et la plus fiable, toutes les solutions doivent au moins respecter les exigences suivantes:
Pour s'y conformer, une approche pourrait consister à vérifier si l'un des serveurs DNS publics de Google est accessible. Les adresses IPv4 de ces serveurs sont 8.8.8.8
et 8.8.4.4
. Nous pouvons essayer de nous connecter à l'un d'entre eux.
Un rapide Nmap de l'hôte a 8.8.8.8
donné le résultat ci-dessous:
$ sudo nmap 8.8.8.8
Starting Nmap 6.40 ( http://nmap.org ) at 2015-10-14 10:17 IST
Nmap scan report for google-public-dns-a.google.com (8.8.8.8)
Host is up (0.0048s latency).
Not shown: 999 filtered ports
PORT STATE SERVICE
53/tcp open domain
Nmap done: 1 IP address (1 host up) scanned in 23.81 seconds
Comme nous pouvons le voir, 53/tcp
est ouvert et non filtré. Si vous êtes un utilisateur non root, n'oubliez pas d'utiliser sudo
ou l' -Pn
argument pour Nmap pour envoyer des paquets de sonde spécialement conçus et déterminer si un hôte est actif.
Avant d'essayer avec Python, testons la connectivité à l'aide d'un outil externe, Netcat:
$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
Netcat confirme que nous pouvons atteindre 8.8.8.8
plus 53/tcp
. Nous pouvons maintenant configurer une connexion socket 8.8.8.8:53/tcp
en Python pour vérifier la connexion:
import socket
def internet(host="8.8.8.8", port=53, timeout=3):
"""
Host: 8.8.8.8 (google-public-dns-a.google.com)
OpenPort: 53/tcp
Service: domain (DNS/TCP)
"""
try:
socket.setdefaulttimeout(timeout)
socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
return True
except socket.error as ex:
print(ex)
return False
internet()
Une autre approche pourrait consister à envoyer une sonde DNS construite manuellement à l'un de ces serveurs et à attendre une réponse. Mais, je suppose, cela pourrait s'avérer plus lent en comparaison en raison de pertes de paquets, d'un échec de résolution DNS, etc. Veuillez commenter si vous pensez le contraire.
UPDATE # 1: Grâce au commentaire de @ theamk, timeout est maintenant un argument et initialisé 3s
par défaut.
MISE À JOUR # 2: J'ai fait des tests rapides pour identifier l'implémentation la plus rapide et la plus générique de toutes les réponses valides à cette question. Voici le résumé:
$ ls *.py | sort -n | xargs -I % sh -c 'echo %; ./timeit.sh %; echo'
defos.py
True
00:00:00:00.487
iamaziz.py
True
00:00:00:00.335
ivelin.py
True
00:00:00:00.105
jaredb.py
True
00:00:00:00.533
kevinc.py
True
00:00:00:00.295
unutbu.py
True
00:00:00:00.546
7h3rAm.py
True
00:00:00:00.032
Et encore une fois:
$ ls *.py | sort -n | xargs -I % sh -c 'echo %; ./timeit.sh %; echo'
defos.py
True
00:00:00:00.450
iamaziz.py
True
00:00:00:00.358
ivelin.py
True
00:00:00:00.099
jaredb.py
True
00:00:00:00.585
kevinc.py
True
00:00:00:00.492
unutbu.py
True
00:00:00:00.485
7h3rAm.py
True
00:00:00:00.035
True
dans la sortie ci-dessus signifie que toutes ces implémentations des auteurs respectifs identifient correctement la connectivité à Internet. L'heure est affichée avec une résolution en millisecondes.
UPDATE # 3: Testé à nouveau après le changement de gestion des exceptions:
defos.py
True
00:00:00:00.410
iamaziz.py
True
00:00:00:00.240
ivelin.py
True
00:00:00:00.109
jaredb.py
True
00:00:00:00.520
kevinc.py
True
00:00:00:00.317
unutbu.py
True
00:00:00:00.436
7h3rAm.py
True
00:00:00:00.030
close()
la prise?
Il sera plus rapide de simplement faire une requête HEAD afin qu'aucun HTML ne soit récupéré.
De plus, je suis sûr que Google aimerait mieux de cette façon :)
try:
import httplib
except:
import http.client as httplib
def have_internet():
conn = httplib.HTTPConnection("www.google.com", timeout=5)
try:
conn.request("HEAD", "/")
conn.close()
return True
except:
conn.close()
return False
Comme alternative aux réponses ubutnu / Kevin C, j'utilise le requests
package comme ceci:
import requests
def connected_to_internet(url='http://www.google.com/', timeout=5):
try:
_ = requests.get(url, timeout=timeout)
return True
except requests.ConnectionError:
print("No internet connection available.")
return False
Bonus: cela peut être étendu à cette fonction qui pings un site Web.
def web_site_online(url='http://www.google.com/', timeout=5):
try:
req = requests.get(url, timeout=timeout)
# HTTP errors are not raised by default, this statement does that
req.raise_for_status()
return True
except requests.HTTPError as e:
print("Checking internet connection failed, status code {0}.".format(
e.response.status_code))
except requests.ConnectionError:
print("No internet connection available.")
return False
google.com
à nouveau, ils bloqueront notre adresse IP. Alors, y a-t-il un autre moyen.?
Juste pour mettre à jour ce que unutbu a dit pour le nouveau code dans Python 3.2
def check_connectivity(reference):
try:
urllib.request.urlopen(reference, timeout=1)
return True
except urllib.request.URLError:
return False
Et, juste pour noter, l'entrée ici (référence) est l'url que vous voulez vérifier: je suggère de choisir quelque chose qui se connecte rapidement là où vous vivez - c'est-à-dire que je vis en Corée du Sud, donc je mettrais probablement une référence à http: / /www.naver.com .
Vous pouvez simplement essayer de télécharger des données, et si la connexion échoue, vous saurez que quelque chose avec la connexion ne va pas.
En gros, vous ne pouvez pas vérifier si l'ordinateur est connecté à Internet. Il peut y avoir de nombreuses raisons d'échec, comme une mauvaise configuration DNS, des pare-feu, NAT. Donc, même si vous effectuez des tests, vous ne pouvez pas avoir la garantie que vous serez connecté à votre API avant d'essayer.
Essayez malgré tout l'opération que vous tentiez de faire. En cas d'échec, python devrait vous lancer une exception pour vous en informer.
Essayer d'abord une opération triviale pour détecter une connexion introduira une condition de concurrence. Que se passe-t-il si la connexion Internet est valide lorsque vous testez mais tombe en panne avant que vous n'ayez besoin d'effectuer un travail réel?
Cela peut ne pas fonctionner si l'hôte local a été modifié depuis 127.0.0.1
Try
import socket
ipaddress=socket.gethostbyname(socket.gethostname())
if ipaddress=="127.0.0.1":
print("You are not connected to the internet!")
else:
print("You are connected to the internet with the IP address of "+ ipaddress )
Sauf modification, l'adresse IP de votre ordinateur sera 127.0.0.1 lorsqu'elle n'est pas connectée à Internet. Ce code obtient essentiellement l'adresse IP, puis demande s'il s'agit de l'adresse IP de l'hôte local. J'espère que cela pourra aider
Voici ma version
import requests
try:
if requests.get('https://google.com').ok:
print("You're Online")
except:
print("You're Offline")
Une solution portable moderne avec requests
:
import requests
def internet():
"""Detect an internet connection."""
connection = None
try:
r = requests.get("https://google.com")
r.raise_for_status()
print("Internet connection detected.")
connection = True
except:
print("Internet connection not detected.")
connection = False
finally:
return connection
Ou, une version qui lève une exception:
import requests
from requests.exceptions import ConnectionError
def internet():
"""Detect an internet connection."""
try:
r = requests.get("https://google.com")
r.raise_for_status()
print("Internet connection detected.")
except ConnectionError as e:
print("Internet connection not detected.")
raise e
Le meilleur moyen de le faire est de le faire vérifier par rapport à une adresse IP que Python donne toujours s'il ne trouve pas le site Web. Dans ce cas, voici mon code:
import socket
print("website connection checker")
while True:
website = input("please input website: ")
print("")
print(socket.gethostbyname(website))
if socket.gethostbyname(website) == "92.242.140.2":
print("Website could be experiencing an issue/Doesn't exist")
else:
socket.gethostbyname(website)
print("Website is operational!")
print("")
mon préféré, lors de l'exécution de scripts sur un cluster ou non
import subprocess
def online(timeout):
try:
return subprocess.run(
['wget', '-q', '--spider', 'google.com'],
timeout=timeout
).returncode == 0
except subprocess.TimeoutExpired:
return False
cela fonctionne tranquillement, sans rien télécharger mais en vérifiant que le fichier distant donné existe sur le Web
Prenant la réponse d'unutbu comme point de départ, et ayant été gravé dans le passé par un changement d'adresse IP "statique", j'ai créé une classe simple qui vérifie une fois en utilisant une recherche DNS (c'est-à-dire en utilisant l'URL " https: // www .google.com "), puis stocke l'adresse IP du serveur répondant pour une utilisation lors de vérifications ultérieures. De cette façon, l'adresse IP est toujours à jour (en supposant que la classe est réinitialisée au moins une fois tous les quelques années environ). Je remercie également gawry pour cette réponse , qui m'a montré comment obtenir l'adresse IP du serveur (après toute redirection, etc.). Veuillez ne pas tenir compte du piratage apparent de cette solution, je vais ici pour un exemple de travail minimal. :)
Voici ce que j'ai:
import socket
try:
from urllib2 import urlopen, URLError
from urlparse import urlparse
except ImportError: # Python 3
from urllib.parse import urlparse
from urllib.request import urlopen, URLError
class InternetChecker(object):
conn_url = 'https://www.google.com/'
def __init__(self):
pass
def test_internet(self):
try:
data = urlopen(self.conn_url, timeout=5)
except URLError:
return False
try:
host = data.fp._sock.fp._sock.getpeername()
except AttributeError: # Python 3
host = data.fp.raw._sock.getpeername()
# Ensure conn_url is an IPv4 address otherwise future queries will fail
self.conn_url = 'http://' + (host[0] if len(host) == 2 else
socket.gethostbyname(urlparse(data.geturl()).hostname))
return True
# Usage example
checker = InternetChecker()
checker.test_internet()
En prenant la réponse de Six, je pense que nous pourrions simplifier d'une manière ou d'une autre, une question importante car les nouveaux arrivants sont perdus dans des questions hautement techniques.
Voici ce que je vais enfin utiliser pour attendre que ma connexion (3G, lente) soit établie une fois par jour pour ma surveillance PV.
Fonctionne sous Pyth3 avec Raspbian 3.4.2
from urllib.request import urlopen
from time import sleep
urltotest=http://www.lsdx.eu # my own web page
nboftrials=0
answer='NO'
while answer=='NO' and nboftrials<10:
try:
urlopen(urltotest)
answer='YES'
except:
essai='NO'
nboftrials+=1
sleep(30)
fonctionnement maximum: 5 minutes si atteint, j'essaierai dans une heure mais c'est un autre morceau de script!
Prenant la réponse d'Ivelin et ajoutez une vérification supplémentaire car mon routeur fournit son adresse IP 192.168.0.1 et renvoie une tête s'il n'a pas de connexion Internet lors de l'interrogation de google.com.
import socket
def haveInternet():
try:
# first check if we get the correct IP-Address or just the router's IP-Address
info = socket.getaddrinfo("www.google.com", None)[0]
ipAddr = info[4][0]
if ipAddr == "192.168.0.1" :
return False
except:
return False
conn = httplib.HTTPConnection("www.google.com", timeout=5)
try:
conn.request("HEAD", "/")
conn.close()
return True
except:
conn.close()
return False
Cela fonctionne pour moi en Python3.6
import urllib
from urllib.request import urlopen
def is_internet():
"""
Query internet using python
:return:
"""
try:
urlopen('https://www.google.com', timeout=1)
return True
except urllib.error.URLError as Error:
print(Error)
return False
if is_internet():
print("Internet is active")
else:
print("Internet disconnected")
J'en ai ajouté quelques-uns au code de Joel.
import socket,time
mem1 = 0
while True:
try:
host = socket.gethostbyname("www.google.com") #Change to personal choice of site
s = socket.create_connection((host, 80), 2)
s.close()
mem2 = 1
if (mem2 == mem1):
pass #Add commands to be executed on every check
else:
mem1 = mem2
print ("Internet is working") #Will be executed on state change
except Exception as e:
mem2 = 0
if (mem2 == mem1):
pass
else:
mem1 = mem2
print ("Internet is down")
time.sleep(10) #timeInterval for checking
Pour mes projets, j'utilise un script modifié pour envoyer une requête ping au serveur DNS public de google 8.8.8.8. Utilisation d'un délai d'expiration de 1 seconde et des bibliothèques python principales sans dépendances externes:
import struct
import socket
import select
def send_one_ping(to='8.8.8.8'):
ping_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname('icmp'))
checksum = 49410
header = struct.pack('!BBHHH', 8, 0, checksum, 0x123, 1)
data = b'BCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwx'
header = struct.pack(
'!BBHHH', 8, 0, checksum, 0x123, 1
)
packet = header + data
ping_socket.sendto(packet, (to, 1))
inputready, _, _ = select.select([ping_socket], [], [], 1.0)
if inputready == []:
raise Exception('No internet') ## or return False
_, address = ping_socket.recvfrom(2048)
print(address) ## or return True
send_one_ping()
La valeur du délai de sélection est 1, mais peut être un nombre à virgule flottante de choix pour échouer plus facilement que 1 seconde dans cet exemple.
importez les demandes et essayez ce simple code python.
def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
_ = requests.get(url, timeout=timeout)
return True
except requests.ConnectionError:
return False