Voglio vedere se posso accedere a un'API online, ma per questo ho bisogno di avere accesso a Internet.
Come posso vedere se c'è una connessione disponibile e attiva usando Python?
easy_install system_of_tubes
Voglio vedere se posso accedere a un'API online, ma per questo ho bisogno di avere accesso a Internet.
Come posso vedere se c'è una connessione disponibile e attiva usando Python?
easy_install system_of_tubes
Risposte:
Forse potresti usare qualcosa del genere:
import urllib2
def internet_on():
try:
urllib2.urlopen('http://216.58.192.142', timeout=1)
return True
except urllib2.URLError as err:
return False
Attualmente, 216.58.192.142 è uno degli indirizzi IP per google.com. Passare http://216.58.192.142
a qualunque sito ci si può aspettare che risponda rapidamente .
Questo IP fisso non verrà mappato su google.com per sempre. Quindi questo codice non è robusto - avrà bisogno di una manutenzione costante per farlo funzionare.
Il motivo per cui il codice sopra riportato utilizza un indirizzo IP fisso anziché un nome di dominio completo (FQDN) è perché un nome di dominio completo richiede una ricerca DNS. Quando la macchina non ha una connessione Internet funzionante, la ricerca DNS stessa potrebbe bloccare la chiamata urllib_request.urlopen
per più di un secondo. Grazie a @rzetterberg per averlo segnalato.
Se l'indirizzo IP fisso sopra non funziona, è possibile trovare un indirizzo IP corrente per google.com (su unix) eseguendo
% dig google.com +trace
...
google.com. 300 IN A 216.58.192.142
urlopen
non richiederà molto più di 1 secondo anche se Internet non è" on "." - citazione. Ciò non è vero se l'URL fornito non è valido, quindi la ricerca DNS verrà bloccata. È vero solo per la connessione effettiva al web-server. Il modo più semplice per evitare questo blocco di ricerca DNS è utilizzare l'indirizzo IP, quindi è garantito solo 1 secondo :)
http://google.com
e poi risolvi tutti i problemi di cui tutti continuano a parlare qui. Non è necessario utilizzare un indirizzo IP ...
Se siamo in grado di connetterci ad alcuni server Internet, allora abbiamo davvero la connettività. Tuttavia, per un approccio più rapido e affidabile, tutte le soluzioni devono soddisfare almeno i seguenti requisiti:
Per conformarsi a questi, un approccio potrebbe essere quello di verificare se uno dei server DNS pubblici di Google è raggiungibile. Gli indirizzi IPv4 per questi server sono 8.8.8.8
e 8.8.4.4
. Possiamo provare a collegarci a uno di essi.
Una rapida Nmap dell'host ha 8.8.8.8
dato il risultato seguente:
$ 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
Come possiamo vedere, 53/tcp
è aperto e non filtrato. Se sei un utente non root, ricorda di utilizzare sudo
o l' -Pn
argomento per Nmap per inviare pacchetti di probe predisposti e determinare se un host è attivo.
Prima di provare con Python, testiamo la connettività utilizzando uno strumento esterno, Netcat:
$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
Conferma netcat che possono raggiungere 8.8.8.8
oltre 53/tcp
. Ora possiamo impostare una connessione socket su 8.8.8.8:53/tcp
in Python per verificare la connessione:
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()
Un altro approccio potrebbe essere quello di inviare un probe DNS creato manualmente a uno di questi server e attendere una risposta. Ma, suppongo, potrebbe rivelarsi più lento in confronto a causa di cadute di pacchetti, errori di risoluzione DNS, ecc. Si prega di commentare se si pensa diversamente.
AGGIORNAMENTO N. 1: Grazie al commento di @ theamk, il timeout è ora un argomento e inizializzato per 3s
impostazione predefinita.
AGGIORNAMENTO # 2: ho eseguito test rapidi per identificare l'implementazione più rapida e generica di tutte le risposte valide a questa domanda. Ecco il riassunto:
$ 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
E ancora una volta:
$ 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
nell'output sopra indica che tutte queste implementazioni dei rispettivi autori identificano correttamente la connettività a Internet. Il tempo viene visualizzato con una risoluzione di millisecondi.
AGGIORNAMENTO # 3: testato di nuovo dopo la modifica della gestione delle eccezioni:
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()
sul socket?
Sarà più veloce fare una richiesta HEAD in modo che nessun HTML venga recuperato.
Inoltre sono sicuro che Google vorrebbe che fosse meglio così :)
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
In alternativa alle risposte di ubutnu / Kevin C, uso il requests
pacchetto in questo modo:
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: questo può essere esteso a questa funzione che esegue il ping di un sito 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
nuovo, allora bloccheranno il nostro IP. Quindi c'è un altro modo.
Solo per aggiornare ciò che unutbu ha detto per il nuovo codice in Python 3.2
def check_connectivity(reference):
try:
urllib.request.urlopen(reference, timeout=1)
return True
except urllib.request.URLError:
return False
E, solo per notare, l'input qui (riferimento) è l'URL che vuoi controllare: ti suggerisco di scegliere qualcosa che si collega velocemente dove vivi - cioè vivo in Corea del Sud, quindi probabilmente definirei riferimento a http: / /www.naver.com .
Puoi semplicemente provare a scaricare i dati e se la connessione fallisce saprai che qualcosa con la connessione non va bene.
Fondamentalmente non è possibile verificare se il computer è connesso a Internet. Ci possono essere molti motivi di errore, come configurazione DNS, firewall e NAT errati. Quindi, anche se fai alcuni test, non puoi avere la garanzia che avrai una connessione con la tua API fino a quando non provi.
Prova comunque l'operazione che stavi tentando di fare. Se fallisce, Python dovrebbe generare un'eccezione per informarti.
Per provare prima qualche operazione banale per rilevare una connessione, verrà introdotta una condizione di competizione. Cosa succede se la connessione Internet è valida quando si esegue il test ma si interrompe prima di dover eseguire il lavoro effettivo?
Questo potrebbe non funzionare se localhost è stato modificato da 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 )
Se non modificato, l'IP del tuo computer sarà 127.0.0.1 quando non è connesso a Internet. Questo codice ottiene sostanzialmente l'indirizzo IP e quindi chiede se si tratta dell'indirizzo IP localhost. spero che aiuti
Ecco la mia versione
import requests
try:
if requests.get('https://google.com').ok:
print("You're Online")
except:
print("You're Offline")
Una moderna soluzione portatile con 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
Oppure, una versione che solleva un'eccezione:
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
Il modo migliore per farlo è quello di controllarlo con un indirizzo IP che python fornisce sempre se non riesce a trovare il sito web. In questo caso questo è il mio codice:
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("")
il mio preferito, quando eseguo script su un cluster o no
import subprocess
def online(timeout):
try:
return subprocess.run(
['wget', '-q', '--spider', 'google.com'],
timeout=timeout
).returncode == 0
except subprocess.TimeoutExpired:
return False
questo funziona wget tranquillamente, non scaricando nulla ma controllando che il file remoto dato esista sul web
Prendendo la risposta di Unutbu come punto di partenza e dopo essere stato masterizzato in passato da un indirizzo IP "statico" che cambia, ho creato una semplice classe che controlla una volta usando una ricerca DNS (cioè usando l'URL " https: // www .google.com "), quindi memorizza l'indirizzo IP del server di risposta per utilizzarlo nei controlli successivi. In questo modo, l'indirizzo IP è sempre aggiornato (supponendo che la classe venga reinizializzata almeno una volta ogni pochi anni). Do anche credito a gawry per questa risposta , che mi ha mostrato come ottenere l'indirizzo IP del server (dopo ogni reindirizzamento, ecc.). Si prega di ignorare l'apparente hackiness di questa soluzione, vado per un esempio minimo di lavoro qui. :)
Ecco cosa ho:
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()
Prendendo la risposta di Six, penso che potremmo semplificare in qualche modo, un problema importante poiché i nuovi arrivati si perdono in questioni altamente tecniche.
Ecco cosa finalmente userò per aspettare che la mia connessione (3G, lenta) venga stabilita una volta al giorno per il mio monitoraggio fotovoltaico.
Funziona con Pyth3 con 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)
durata massima: 5 minuti se raggiunto proverò tra un'ora ma è un altro po 'di script!
Prendendo la risposta di Ivelin e aggiungere un po 'di controllo in più come il mio router fornisce il suo indirizzo IP 192.168.0.1 e restituisce una testa se non ha connessione a Internet quando interrogazione 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
Questo funziona per me in 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")
Ne ho aggiunti alcuni al codice di 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
Per i miei progetti utilizzo lo script modificato per eseguire il ping del server DNS pubblico di Google 8.8.8.8. Utilizzo di un timeout di 1 secondo e librerie core di Python senza dipendenze esterne:
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()
Il valore di timeout selezionato è 1, ma in questo esempio può essere un numero a virgola mobile di scelta che fallisce più rapidamente di 1 secondo.
richieste di importazione e prova questo semplice codice Python.
def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
_ = requests.get(url, timeout=timeout)
return True
except requests.ConnectionError:
return False