Chcę sprawdzić, czy mogę uzyskać dostęp do internetowego interfejsu API, ale do tego potrzebuję dostępu do Internetu.
Jak mogę sprawdzić, czy jest dostępne i aktywne połączenie przy użyciu Pythona?
easy_install system_of_tubes
Chcę sprawdzić, czy mogę uzyskać dostęp do internetowego interfejsu API, ale do tego potrzebuję dostępu do Internetu.
Jak mogę sprawdzić, czy jest dostępne i aktywne połączenie przy użyciu Pythona?
easy_install system_of_tubes
Odpowiedzi:
Być może przydałoby się coś takiego:
import urllib2
def internet_on():
try:
urllib2.urlopen('http://216.58.192.142', timeout=1)
return True
except urllib2.URLError as err:
return False
Obecnie 216.58.192.142 to jeden z adresów IP w witrynie google.com. Zmień http://216.58.192.142
witrynę, w której można oczekiwać szybkiej reakcji .
Ten stały adres IP nie będzie na zawsze mapowany na google.com. Więc ten kod nie jest solidny - będzie wymagał ciągłej konserwacji, aby działał.
Powodem, dla którego powyższy kod używa stałego adresu IP zamiast w pełni kwalifikowanej nazwy domeny (FQDN), jest to, że nazwa FQDN wymagałaby wyszukiwania DNS. Gdy komputer nie ma działającego połączenia internetowego, samo wyszukiwanie DNS może blokować wywołanie urllib_request.urlopen
na dłużej niż sekundę. Dzięki @rzetterberg za wskazanie tego.
Jeśli powyższy stały adres IP nie działa, możesz znaleźć aktualny adres IP dla google.com (w systemie unix), uruchamiając
% dig google.com +trace
...
google.com. 300 IN A 216.58.192.142
urlopen
numerem nie zajmie dużo więcej niż 1 sekundę, nawet jeśli Internet nie jest włączony”. - cytat. Nie jest to prawdą, jeśli podany adres URL jest nieprawidłowy, wyszukiwanie DNS zostanie zablokowane. Dotyczy to tylko rzeczywistego połączenia z serwerem WWW. Najprostszym sposobem uniknięcia tego bloku wyszukiwania DNS jest użycie zamiast tego adresu IP, wtedy gwarantowane zajmie tylko 1 sekundę :)
http://google.com
a potem rozwiąż wszystkie problemy, o których wszyscy tu mówią. Nie ma potrzeby używania adresu IP ...
Jeśli możemy połączyć się z jakimś serwerem internetowym, to rzeczywiście mamy łączność. Jednak aby uzyskać najszybsze i najbardziej niezawodne podejście, wszystkie rozwiązania powinny spełniać co najmniej następujące wymagania:
Aby spełnić te wymagania, jednym z podejść może być sprawdzenie, czy jeden z publicznych serwerów DNS Google jest osiągalny. Adresy IPv4 tych serwerów to 8.8.8.8
i 8.8.4.4
. Możemy spróbować połączyć się z dowolnym z nich.
Szybki Nmap hosta 8.8.8.8
dał następujący wynik:
$ 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
Jak widać, 53/tcp
jest otwarty i niefiltrowany. Jeśli jesteś użytkownikiem niż root, należy pamiętać, aby używać sudo
lub -Pn
argumentem dla Nmap wysłać spreparowane pakiety sondy i ustalić, czy komputer jest w górę.
Zanim spróbujemy z Pythonem, przetestujmy łączność za pomocą zewnętrznego narzędzia, Netcat:
$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
Netcat potwierdza, że możemy osiągnąć 8.8.8.8
w ciągu 53/tcp
. Teraz możemy skonfigurować połączenie przez gniazdo 8.8.8.8:53/tcp
w Pythonie, aby sprawdzić połączenie:
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()
Innym podejściem może być wysłanie ręcznie spreparowanej sondy DNS na jeden z tych serwerów i oczekiwanie na odpowiedź. Zakładam jednak, że może się to okazać wolniejsze w porównaniu z powodu zrzucania pakietów, błędu rozpoznawania nazw DNS itp. Jeśli myślisz inaczej, skomentuj.
UPDATE # 1: Dzięki komentarzowi @ theamk, timeout jest teraz argumentem i 3s
jest domyślnie inicjowany .
AKTUALIZACJA # 2: Zrobiłem szybkie testy, aby zidentyfikować najszybszą i najbardziej ogólną implementację wszystkich prawidłowych odpowiedzi na to pytanie. Oto podsumowanie:
$ 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
I jeszcze raz:
$ 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
w powyższym wyniku oznacza, że wszystkie te implementacje od poszczególnych autorów poprawnie identyfikują łączność z Internetem. Czas jest wyświetlany z rozdzielczością milisekund.
AKTUALIZACJA # 3: Przetestowano ponownie po zmianie obsługi wyjątków:
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()
do gniazdka?
Szybciej będzie po prostu wykonać żądanie HEAD, więc żaden kod HTML nie zostanie pobrany.
Jestem też pewien, że Google polubiłoby to lepiej :)
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
Jako alternatywę dla odpowiedzi ubutnu / Kevina C używam tego requests
pakietu:
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: można to rozszerzyć na tę funkcję, która pinguje stronę internetową.
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
znowu będziesz tęsknić , zablokują nasze IP. Więc czy jest jakiś inny sposób.?
Wystarczy zaktualizować to, co powiedział unutbu dla nowego kodu w Pythonie 3.2
def check_connectivity(reference):
try:
urllib.request.urlopen(reference, timeout=1)
return True
except urllib.request.URLError:
return False
I, dla przypomnienia, dane wejściowe tutaj (odniesienie) to adres URL, który chcesz sprawdzić: Proponuję wybrać coś, co łączy się szybko w miejscu Twojego zamieszkania - tj. Mieszkam w Korei Południowej, więc prawdopodobnie ustawiłbym odniesienie na http: / /www.naver.com .
Możesz po prostu spróbować pobrać dane, a jeśli połączenie się nie powiedzie, będziesz wiedział, że coś z połączeniem nie jest w porządku.
Zasadniczo nie możesz sprawdzić, czy komputer jest podłączony do Internetu. Przyczyn niepowodzenia może być wiele, np. Zła konfiguracja DNS, zapory sieciowe, NAT. Więc nawet jeśli wykonasz kilka testów, nie możesz zagwarantować, że będziesz mieć połączenie z interfejsem API, dopóki nie spróbujesz.
Spróbuj wykonać operację, którą mimo wszystko próbujesz wykonać. Jeśli to się nie powiedzie, Python powinien zgłosić wyjątek, aby Cię powiadomić.
Aby najpierw wypróbować jakąś trywialną operację w celu wykrycia połączenia, należy wprowadzić stan wyścigu. Co się stanie, jeśli połączenie internetowe jest prawidłowe podczas testu, ale znika, zanim będziesz musiał wykonać rzeczywistą pracę?
To może nie działać, jeśli localhost został zmieniony z 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 )
O ile nie jest edytowany, adres IP twojego komputera będzie 127.0.0.1, gdy nie jest podłączony do Internetu. Ten kod w zasadzie pobiera adres IP, a następnie pyta, czy jest to adres IP lokalnego hosta. Mam nadzieję, że to pomoże
Oto moja wersja
import requests
try:
if requests.get('https://google.com').ok:
print("You're Online")
except:
print("You're Offline")
Nowoczesne przenośne rozwiązanie z 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
Lub wersja, która zgłasza wyjątek:
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
Najlepszym sposobem na to jest sprawdzenie adresu IP, który Python zawsze podaje, jeśli nie może znaleźć witryny. W tym przypadku jest to mój kod:
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("")
mój ulubiony, gdy uruchamiam skrypty w klastrze lub nie
import subprocess
def online(timeout):
try:
return subprocess.run(
['wget', '-q', '--spider', 'google.com'],
timeout=timeout
).returncode == 0
except subprocess.TimeoutExpired:
return False
to uruchamia wget cicho, niczego nie pobiera, tylko sprawdza, czy dany plik zdalny istnieje w sieci
Biorąc odpowiedź unutbu za punkt wyjścia i będąc w przeszłości spalonym przez „statyczną” zmianę adresu IP, stworzyłem prostą klasę, która sprawdza raz za pomocą wyszukiwania DNS (tj. Używając adresu URL „ https: // www .google.com ”), a następnie przechowuje adres IP serwera odpowiadającego do wykorzystania podczas kolejnych kontroli. W ten sposób adres IP jest zawsze aktualny (zakładając, że klasa jest ponownie inicjowana co najmniej raz na kilka lat). Daję również uznanie Gawry'emu za tę odpowiedź , która pokazała mi, jak uzyskać adres IP serwera (po każdym przekierowaniu itp.). Proszę zignorować pozorną hacking tego rozwiązania, posłużę się tutaj minimalnym działającym przykładem. :)
Oto co mam:
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()
Biorąc odpowiedź Six, myślę, że moglibyśmy w jakiś sposób uprościć, ważna kwestia, ponieważ nowicjusze gubią się w wysoce technicznych sprawach.
Tutaj w końcu będę czekał, aż moje połączenie (3G, wolne) zostanie ustanowione raz dziennie do monitorowania PV.
Działa pod Pyth3 z 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)
maksymalny bieg: 5 minut jeśli osiągnę spróbuję za godzinę, ale to kolejny kawałek skryptu!
Biorąc odpowiedź Ivelina i dodając dodatkowe sprawdzenie, ponieważ mój router dostarcza swój adres IP 192.168.0.1 i zwraca głowę, jeśli nie ma połączenia z Internetem podczas wysyłania zapytania do 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
To działa dla mnie w Pythonie 3.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")
Dodałem kilka do kodu Joela.
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
W moich projektach używam zmodyfikowanego skryptu do pingowania publicznego serwera DNS Google 8.8.8.8. Korzystanie z limitu czasu wynoszącego 1 sekundy i podstawowych bibliotek Pythona bez zewnętrznych zależności:
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()
Wybierz wartość limitu czasu wynosi 1, ale może być liczbę zmiennoprzecinkową wyboru niepowodzenie łatwiej niż 1 sekundę w tym przykładzie.
importuj żądania i wypróbuj ten prosty kod w Pythonie.
def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
_ = requests.get(url, timeout=timeout)
return True
except requests.ConnectionError:
return False