Я хочу дізнатися, чи можу я отримати доступ до інтернет-API, але для цього мені потрібно мати доступ до Інтернету.
Як я можу побачити, чи є підключення доступне та активне за допомогою Python?
easy_install system_of_tubes
Я хочу дізнатися, чи можу я отримати доступ до інтернет-API, але для цього мені потрібно мати доступ до Інтернету.
Як я можу побачити, чи є підключення доступне та активне за допомогою Python?
easy_install system_of_tubes
Відповіді:
Можливо, ви могли б використовувати щось подібне:
import urllib2
def internet_on():
try:
urllib2.urlopen('http://216.58.192.142', timeout=1)
return True
except urllib2.URLError as err:
return False
Наразі 216.58.192.142 - одна з IP-адрес для google.com. Змініть http://216.58.192.142
на будь-який сайт, можна очікувати, що він швидко відповість .
Цей фіксований IP не буде відображатись на google.com назавжди. Тож цей код не є надійним - для його роботи буде потрібно постійне обслуговування.
Причина, чому вищевказаний код використовує фіксовану IP-адресу замість повністю кваліфікованого доменного імені (FQDN), полягає в тому, що для FQDN потрібен пошук DNS. Якщо апарат не має робочого з’єднання з Інтернетом, сам пошук DNS може блокувати виклик urllib_request.urlopen
більше секунди. Дякуємо @rzetterberg за вказівку на це.
Якщо виправлена IP-адреса вище не працює, ви можете знайти поточну IP-адресу для google.com (на unix), запустивши
% dig google.com +trace
...
google.com. 300 IN A 216.58.192.142
urlopen
не займе набагато більше 1 секунди, навіть якщо Інтернет не" включений "." - цитата. Це неправда, якщо наданий URL недійсний, пошук DNS блокується. Це справедливо лише для фактичного підключення до веб-сервера. Найпростіший спосіб уникнути цього блоку пошуку DNS - використовувати замість цього IP-адресу, тоді гарантовано зайняти лише 1 секунду :)
http://google.com
і тоді ви вирішите всі проблеми, про які тут все говорять. Не потрібно використовувати ip-адресу ...
Якщо ми можемо підключитися до якогось інтернет-сервера, то ми справді маємо зв’язок. Однак для найшвидшого та надійного підходу всі рішення повинні відповідати принаймні таким вимогам:
Для дотримання цих завдань може бути один підхід - перевірити, чи доступний один із загальнодоступних серверів DNS Google . Адресами IPv4 для цих серверів є 8.8.8.8
і 8.8.4.4
. Ми можемо спробувати підключитися до будь-якого з них.
Швидкий Nmap хоста 8.8.8.8
дав нижче результат:
$ 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
Як ми бачимо, 53/tcp
він відкритий і не фільтрується. Якщо ви некористувач, не забудьте скористатися sudo
або -Pn
аргументом для Nmap для надсилання створених пакетів зондів і визначте, чи хост працює.
Перш ніж ми спробуємо з Python, давайте перевіримо підключення за допомогою зовнішнього інструменту Netcat:
$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
Netcat підтверджує, що ми можемо досягти 8.8.8.8
переваги 53/tcp
. Тепер ми можемо встановити з'єднання з сокетом 8.8.8.8:53/tcp
в Python, щоб перевірити з'єднання:
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()
Іншим підходом може бути надіслати розроблений вручну DNS-зонд на один із цих серверів і чекати відповіді. Але, я припускаю, це може виявитися повільніше порівняно із падінням пакетів, збоєм роздільної здатності DNS тощо. Будь ласка, коментуйте, якщо ви думаєте про інше.
ОНОВЛЕННЯ №1: Завдяки коментарю @ @ theamk, тайм-аут тепер є аргументом та ініціалізовано до 3s
типового.
ОНОВЛЕННЯ №2: Я зробив швидкі тести, щоб визначити найшвидший і загальний варіант реалізації всіх дійсних відповідей на це питання. Ось підсумок:
$ 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
І ще раз:
$ 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
у наведеному вище висновку означає, що всі ці реалізації від відповідних авторів правильно ідентифікують підключення до Інтернету. Час відображається з роздільною здатністю мілісекунд.
ОНОВЛЕННЯ №3: Тестується знову після зміни обробки виключень:
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()
до розетки?
Швидше буде просто зробити HEAD-запит, щоб не отримати жодного HTML-коду.
Крім того, я впевнений, що Google хотів би це краще таким чином :)
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
Як альтернатива відповідям на ubutnu / Kevin C я використовую такий requests
пакет:
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
Бонус: цю функцію можна поширити на цю функцію, яка надсилає веб-сайт.
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
знову пінгінете , вони заблокують наш IP. Так чи є інший спосіб.?
Просто для оновлення того, що сказав unutbu для нового коду в Python 3.2
def check_connectivity(reference):
try:
urllib.request.urlopen(reference, timeout=1)
return True
except urllib.request.URLError:
return False
І, лише зауважте, тут вхід (посилання) - це URL-адреса, яку ви хочете перевірити: я пропоную вибрати те, що швидко з'єднується там, де ви живете, - тобто я живу в Південній Кореї, тому я, певно, встановив посилання на http: / /www.naver.com .
Ви можете просто спробувати завантажити дані, і якщо з'єднання не вдасться, ви знатимете, що щось із з'єднанням не в порядку.
В основному ви не можете перевірити, чи комп'ютер підключений до Інтернету. Причин збою може бути багато, наприклад, неправильна конфігурація DNS, брандмауері, NAT. Тож навіть якщо ви зробите кілька тестів, ви не можете гарантувати, що будете мати зв’язок зі своїм API, поки ви не спробуєте.
import urllib
def connected(host='http://google.com'):
try:
urllib.urlopen(host)
return True
except:
return False
# test
print( 'connected' if connected() else 'no internet!' )
Для python 3 використовуйте urllib.request.urlopen(host)
Спробуйте операцію, яку ви намагалися зробити в будь-якому випадку. Якщо це не вдасться, python повинен надати вам виняток, щоб повідомити про це.
Спершу спробувати якусь тривіальну операцію для виявлення зв'язку, буде введення умови перегону. Що робити, якщо підключення до Інтернету є дійсним під час тестування, але виходить з ладу, перш ніж потрібно виконати фактичну роботу?
Це може не спрацювати, якщо localhost було змінено на 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 )
Якщо не редагувати, IP-адреса ваших комп’ютерів буде 127.0.0.1, коли він не підключений до Інтернету. Цей код отримує IP-адресу, а потім запитує, чи це IP-адреса localhost. Сподіваюся, що це допомагає
Ось моя версія
import requests
try:
if requests.get('https://google.com').ok:
print("You're Online")
except:
print("You're Offline")
Сучасне портативне рішення з 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
Або версія, яка викликає виняток:
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
Найкращий спосіб це зробити, щоб він перевірив IP-адресу, яку завжди дає python, якщо він не може знайти веб-сайт. У цьому випадку це мій код:
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("")
мій улюблений, коли сценарії виконуються на кластері чи ні
import subprocess
def online(timeout):
try:
return subprocess.run(
['wget', '-q', '--spider', 'google.com'],
timeout=timeout
).returncode == 0
except subprocess.TimeoutExpired:
return False
це запускається wget тихо, не завантажуючи нічого, окрім перевірки наявності даного віддаленого файлу в Інтернеті
Приймаючи відповідь унутбу як вихідну точку і в минулому спалювавшись "статичною" зміною IP-адреси, я створив простий клас, який перевіряє один раз за допомогою пошуку DNS (тобто, використовуючи URL-адресу " https: // www .google.com "), а потім зберігає IP-адресу відповідного сервера для використання під час наступних перевірок. Таким чином, IP-адреса завжди актуальна (якщо припустимо, що клас повторно ініціалізується щонайменше раз на кілька років або близько того). Я також даю подяку Gawry за цю відповідь , яка показала мені, як отримати IP-адресу сервера (після будь-якого перенаправлення тощо). Будь ласка, ігноруйте очевидну нерозумність цього рішення, я тут навожу мінімальний робочий приклад. :)
Ось що я маю:
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()
Відповідаючи на шести відповідей, я думаю, що ми могли б якось спростити, важливе питання, оскільки новачки втрачаються у високо технічних питаннях.
Ось, що я, нарешті, використаю, щоб чекати, коли моє з'єднання (3G, повільний) буде встановлено один раз на день для мого PV-моніторингу.
Працює під Pyth3 з 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)
Максимальна тривалість: 5 хвилин, якщо досягнуто, я спробую за одну годину, але це ще один біт сценарію!
Отримуючи відповідь Ivelin і додайте додаткову перевірку, оскільки мій маршрутизатор доставляє свою ip адресу 192.168.0.1 і повертає голову, якщо у неї немає підключення до Інтернету при запиті на 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
Це працює для мене в 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")
Я додав декілька до коду Джоела.
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
Для своїх проектів я використовую скрипт, модифікований для пінг-сервера відкритого DNS google 8.8.8.8. Використання тайм-ауту в 1 секунду та основні бібліотеки python без зовнішніх залежностей:
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()
Значення тайм-ауту вибору становить 1, але може бути числом з плаваючою комою вибору, щоб вийти з ладу швидше, ніж 1 секунда в цьому прикладі.
імпортуйте запити та спробуйте цей простий код python.
def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
_ = requests.get(url, timeout=timeout)
return True
except requests.ConnectionError:
return False