Quero ver se consigo acessar uma API online, mas para isso preciso ter acesso à Internet.
Como posso ver se há uma conexão disponível e ativa usando o Python?
easy_install system_of_tubes
Quero ver se consigo acessar uma API online, mas para isso preciso ter acesso à Internet.
Como posso ver se há uma conexão disponível e ativa usando o Python?
easy_install system_of_tubes
Respostas:
Talvez você possa usar algo como isto:
import urllib2
def internet_on():
try:
urllib2.urlopen('http://216.58.192.142', timeout=1)
return True
except urllib2.URLError as err:
return False
Atualmente, 216.58.192.142 é um dos endereços IP do google.com. Mude http://216.58.192.142
para qualquer site que possa responder rapidamente .
Esse IP fixo não será mapeado para google.com para sempre. Portanto, esse código não é robusto - ele precisará de manutenção constante para mantê-lo funcionando.
O motivo pelo qual o código acima usa um endereço IP fixo em vez de um nome de domínio totalmente qualificado (FQDN) é porque um FQDN exigiria uma pesquisa de DNS. Quando a máquina não possui uma conexão com a Internet, a própria pesquisa de DNS pode bloquear a chamada urllib_request.urlopen
por mais de um segundo. Obrigado a @rzetterberg por apontar isso.
Se o endereço IP fixo acima não estiver funcionando, você poderá encontrar um endereço IP atual para google.com (no unix) executando
% dig google.com +trace
...
google.com. 300 IN A 216.58.192.142
urlopen
não levará muito mais que 1 segundo, mesmo que a internet não esteja" ligada "." - citação. Isso não é verdade se o URL fornecido for inválido; a pesquisa de DNS será bloqueada. Isso é verdadeiro apenas para a conexão real com o servidor da web. A maneira mais simples de evitar esse bloco de pesquisa de DNS é usar o endereço IP em vez disso, então é garantido para ter apenas um segundo :)
http://google.com
e então você resolve todos os problemas que todo mundo continua falando aqui. Não há necessidade de usar um endereço IP ...
Se pudermos nos conectar a algum servidor da Internet, teremos realmente conectividade. No entanto, para uma abordagem mais rápida e confiável, todas as soluções devem atender aos seguintes requisitos, no mínimo:
Para cumpri-las, uma abordagem seria: verificar se um dos servidores DNS públicos do Google está acessível. Os endereços IPv4 para esses servidores são 8.8.8.8
e 8.8.4.4
. Podemos tentar conectar-se a qualquer um deles.
Um Nmap rápido do host 8.8.8.8
deu o resultado abaixo:
$ 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
Como podemos ver, 53/tcp
é aberto e não filtrado. Se você é um usuário não root, lembre-se de usar sudo
ou o -Pn
argumento para o Nmap enviar pacotes de análise criados e determinar se um host está ativo.
Antes de tentarmos com o Python, vamos testar a conectividade usando uma ferramenta externa, Netcat:
$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
Confirma NetCAT que podemos alcançar 8.8.8.8
mais 53/tcp
. Agora podemos configurar uma conexão de soquete 8.8.8.8:53/tcp
no Python para verificar a conexão:
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()
Outra abordagem poderia ser enviar um probe DNS criado manualmente para um desses servidores e aguardar uma resposta. Mas, suponho, pode ser mais lento em comparação devido a quedas de pacotes, falha na resolução de DNS etc. Por favor, comente se você pensa de outra forma.
ATUALIZAÇÃO # 1: Graças ao comentário de @ theamk, o tempo limite agora é um argumento e inicializado 3s
por padrão.
ATUALIZAÇÃO # 2: fiz testes rápidos para identificar a implementação mais rápida e genérica de todas as respostas válidas para esta pergunta. Aqui está o resumo:
$ 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 mais uma vez:
$ 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
na saída acima, significa que todas essas implementações dos respectivos autores identificam corretamente a conectividade com a Internet. O tempo é mostrado com resolução de milissegundos.
ATUALIZAÇÃO # 3: testado novamente após a alteração no tratamento de exceções:
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()
o soquete?
Será mais rápido fazer uma solicitação HEAD, para que nenhum HTML seja buscado.
Também tenho certeza que o google gostaria desta maneira :)
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
Como alternativa às respostas do ubutnu / Kevin C, eu uso o requests
pacote assim:
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
Bônus: isso pode ser estendido a essa função que faz ping em um site.
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
voltar a tentar novamente, eles bloquearão nosso IP. Então, existe alguma outra maneira?
Apenas para atualizar o que o unutbu disse para o novo código no Python 3.2
def check_connectivity(reference):
try:
urllib.request.urlopen(reference, timeout=1)
return True
except urllib.request.URLError:
return False
E, apenas para observar, a entrada aqui (referência) é o URL que você deseja verificar: sugiro escolher algo que se conecte rapidamente onde você mora - ou seja, eu moro na Coréia do Sul, então provavelmente definiria a referência http: / /www.naver.com .
Você pode apenas tentar fazer o download de dados e, se a conexão falhar, você saberá que algumas coisas com a conexão não estão bem.
Basicamente, você não pode verificar se o computador está conectado à Internet. Pode haver muitas razões para a falha, como configuração de DNS incorreta, firewalls, NAT. Portanto, mesmo se você fizer alguns testes, não poderá ter certeza de que terá conexão com sua API até tentar.
Tente a operação que você estava tentando fazer de qualquer maneira. Se falhar, o python deve lançar uma exceção para você saber.
Tentar alguma operação trivial primeiro para detectar uma conexão introduzirá uma condição de corrida. E se a conexão à Internet for válida quando você testar, mas cair antes de precisar fazer um trabalho real?
Isso pode não funcionar se o host local tiver sido alterado de 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 )
A menos que editado, o IP do seu computador será 127.0.0.1 quando não estiver conectado à Internet. Esse código basicamente obtém o endereço IP e pergunta se é o endereço IP do host local. espero que ajude
Aqui está a minha versão
import requests
try:
if requests.get('https://google.com').ok:
print("You're Online")
except:
print("You're Offline")
Uma solução portátil moderna com 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, uma versão que gera uma exceção:
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
A melhor maneira de fazer isso é fazer a verificação em um endereço IP que o python sempre fornece, caso não consiga encontrar o site. Nesse caso, este é o meu código:
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("")
meu favorito, ao executar scripts em um cluster ou não
import subprocess
def online(timeout):
try:
return subprocess.run(
['wget', '-q', '--spider', 'google.com'],
timeout=timeout
).returncode == 0
except subprocess.TimeoutExpired:
return False
isso executa o wget silenciosamente, sem baixar nada, mas verificando se o arquivo remoto fornecido existe na web
Tomando a resposta do unutbu como ponto de partida e tendo sido queimado no passado por uma alteração de endereço IP "estático", criei uma classe simples que verifica uma vez usando uma pesquisa DNS (ou seja, usando o URL " https: // www .google.com ") e, em seguida, armazena o endereço IP do servidor que responde para uso nas verificações subsequentes. Dessa forma, o endereço IP está sempre atualizado (assumindo que a classe seja reinicializada pelo menos uma vez a cada poucos anos). Também dou crédito a gawry por esta resposta , que me mostrou como obter o endereço IP do servidor (após qualquer redirecionamento, etc.). Por favor, desconsidere o aparente hackiness desta solução, estou indo para um exemplo de trabalho mínimo aqui. :)
Aqui está o que eu tenho:
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()
Tomando a resposta de Six, acho que poderíamos simplificar de alguma forma, uma questão importante, pois os recém-chegados se perdem em questões altamente técnicas.
Aqui, o que eu finalmente usarei para aguardar que minha conexão (3G, lenta) seja estabelecida uma vez por dia para meu monitoramento fotovoltaico.
Funciona no Pyth3 com 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)
duração máxima: 5 minutos, se atingido, tentarei em uma hora, mas é outro script!
Tomando a resposta de Ivelin e adicionando uma verificação extra, meu roteador entrega seu endereço IP 192.168.0.1 e retorna uma cabeça se não tiver conexão com a Internet ao consultar o 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
Isso funciona para mim no 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")
Eu adicionei alguns ao código 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
Para meus projetos, uso o script modificado para executar ping no servidor DNS público do Google 8.8.8.8. Usando um tempo limite de 1 segundo e bibliotecas python principais sem dependências externas:
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()
O valor do tempo limite de seleção é 1, mas pode ser um número de ponto flutuante preferido para falhar mais rapidamente do que o segundo neste exemplo.
importe solicitações e tente este código python simples.
def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
_ = requests.get(url, timeout=timeout)
return True
except requests.ConnectionError:
return False