Verificando a conexão de rede

133

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?

aF.
fonte
se você estiver em python, quase certamente lançará uma exceção no caso de uma falha de conexão ou tempo limite. Você pode tentar capturar isso ou deixá-lo aparecer.
precisa saber é o seguinte
1
@ Triptych: Espero que tenha sido uma piada, porque não funciona
InspectorG4dget
1
@ inspectorG4dget:easy_install system_of_tubes
S.Lott
2
@aF: Veja a solução da Unutbu. Ele mostra (da maneira mais rápida possível) como verificar se você consegue acessar o google.com. Se o seu problema estiver relacionado ao acesso à API, por que não tentar acessá-la, definindo timeout = 1? Isso informará exatamente se a API que você deseja acessar está acessível. Depois que você souber disso, poderá acessar a API ou aguardar um momento em que possa acessá-la.
inspectorG4dget
Como eu disse, eu só precisava de uma coisa simples como a unutbu disse. Você não precisa se preocupar tanto com isso ..
aF.

Respostas:

132

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.142para 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.urlopenpor 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
unutbu
fonte
1
Apenas uma nota sobre "a chamada para urlopennã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 :)
rzetterberg
8
Isso não funciona mais. Em setembro de 2013, 74.125.113.99 atingia o tempo limite após um longo período de tempo, portanto, essa função sempre retornará Falso. Suponho que o Google mudou sua rede está configurada.
theamk
4
Agora o resto é simples. Google para "74.125.113.99 urllib". Ele retornará milhares de projetos de código aberto que incorporaram o código incorreto. (para mim, apenas a primeira página contém pelo menos 5: nvpy, sweekychebot, malteseDict, upy, checkConnection). Eles estão todos quebrados agora.
Theamk 19/09/13
4
Se não estiver claro, NÃO RECOMENDO usar esse método. IP antigo foi bom por menos de 3 anos. O novo IP funciona hoje. Coloque-o em seu projeto, e ele poderá ser misteriosamente interrompido em menos de 3 anos.
theamk
1
Er ... apenas abra http://google.come então você resolve todos os problemas que todo mundo continua falando aqui. Não há necessidade de usar um endereço IP ...
Jason C
106

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:

  • Evite a resolução do DNS (precisaremos de um IP conhecido e garantido que esteja disponível a maior parte do tempo)
  • Evite conexões da camada de aplicativo (conectando-se a um serviço HTTP / FTP / IMAP)
  • Evite chamadas para utilitários externos do Python ou outro idioma de escolha (precisamos encontrar uma solução independente de idioma que não dependa de soluções de terceiros)

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.8e 8.8.4.4. Podemos tentar conectar-se a qualquer um deles.

Um Nmap rápido do host 8.8.8.8deu 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 sudoou o -Pnargumento 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.8mais 53/tcp. Agora podemos configurar uma conexão de soquete 8.8.8.8:53/tcpno 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 3spor 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

Truena 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
7h3rAm
fonte
6
Esta é a melhor resposta, evitando a resolução de DNS, e, ironicamente, consultar o serviço de DNS do Google na porta 53.
m3nda
1
@AviMehenwal O Google fornece esse IP como parte de seu serviço gratuito de resolução de nomes DNS. O IP não deve mudar, a menos que o Google decida de outra forma. Estou usando-o como um servidor DNS alternativo há alguns anos sem problemas.
7h3rAm
1
@ Lucas Obrigado por apontar isso. Atualizei a resposta para informar os usuários sobre a exceção e retornar False como resposta padrão.
7h3rAm
2
@JasonC A conexão ao TCP / 53 é diferente da conexão DNS pela porta 53. Seguindo a sua analogia, todas as portas TCP usadas por um aplicativo serão classificadas como conexão de protocolo no nível do aplicativo. Não Isso não é verdade. Conectar-se através de um soquete TCP a uma porta NÃO É uma conexão no nível do aplicativo. Não estou fazendo uma pesquisa de DNS, mas apenas um aperto de mão meio TCP. Não é a mesma coisa que fazer uma pesquisa completa no DNS.
precisa saber é o seguinte
2
Não devemos chamar close()o soquete?
brk
60

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
Ivelin
fonte
8
Leva apenas 20 mili segundos enquanto a resposta superior leva 1 segundo.
Wally
8
+1 Não faz sentido baixar a página inteira se você quiser apenas verificar se o servidor está acessível e está respondendo. Faça o download do conteúdo se você precisa do conteúdo
thatsIch
Por nenhuma razão, o uso do URL '8.8' ainda funciona, o que obviamente, '8.8' ou ' 8.8 ' não funciona em um navegador da Web real.
Polv 17/08/19
2 horas à procura de uma solução de trabalho e, em seguida, eu encontrei este ... limpo e simples
Pedro Serpa
21

Como alternativa às respostas do ubutnu / Kevin C, eu uso o requestspacote 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
Def_Os
fonte
1
Request é uma ótima biblioteca. No entanto, diferentemente de muitos exemplos aqui, eu usaria o example.com da IANA ou o example.org como uma opção mais confiável a longo prazo, pois é totalmente controlada pela ICANN .
Chirale 6/05
Existe outra maneira de verificar o status de execução da Internet. Porque se você google.comvoltar a tentar novamente, eles bloquearão nosso IP. Então, existe alguma outra maneira?
21319 Sanjiv
15

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 .

Kevin C
fonte
Vou esperar 30 segundos se não houver um servidor DNS disponível.
Viktor Joras
10

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.

Tomasz Wysocki
fonte
2
"É mais fácil pedir perdão do que permissão"
cobbal
isso não precisa ser tão bom. Eu só preciso tentar conectar-me a um site ou fazer ping em algo e se der tempo limite voilá. Como eu posso fazer isso?
aF.
Existe algum motivo para você não poder simplesmente tentar se conectar à API? Por que você deve verificá-lo antes da conexão real?
Tomasz Wysocki
Eu faço uma página html usando python. A página html depende dos argumentos que eu dou no programa python. Eu só preciso colocar algum código html se eu puder acessar a API. É por isso que eu preciso saber antes.
aF.
6
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!' )

Para python 3, use urllib.request.urlopen(host)

Aziz Alto
fonte
4

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?

mluebke
fonte
3

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


fonte
Essa é uma verificação interessante, embora apenas identifique se você está conectado a uma rede. Se é a Internet ou uma sub-rede NAT, continuará sendo uma questão.
7h3rAm
@ 7h3rAm, esse é um bom ponto, o DCHP não requer conexão com a internet, meu erro.
Isso requer apenas uma conexão NIC de rede que recebeu um IP atribuído. Ao contrário de todas as outras respostas, ele não requer uma conexão com a LAN, roteador, firewall, ISP até outro sistema. Ele ainda falha em mostrar que a NIC está conectada se é um endereço atribuído não DHCP (estático)
user150471
@ user150471, já indicado, obrigado pela sua contribuição.
3

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")
Mujeeb Ishaque
fonte
1
Eu gosto deste, mas seria melhor se ele excluísse um erro de tempo limite ou conexão específico gerado a partir de solicitações. Como é, um Ctrl-C rápido como um raio é impresso offline.
user2561747
2

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
Adam Erickson
fonte
1

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("")
lunar_kitsune
fonte
1

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

neok
fonte
0

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()
Jared B.
fonte
0

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!

Seylione
fonte
seu essai var não se acostuma, não é?
kidCoder
0

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
monok
fonte
0

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")
Rajiv Sharma
fonte
0

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
Soum Axetuirk
fonte
0

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.

Luv
fonte
0

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
Raushan Kumar
fonte