提问人:aF. 提问时间:9/22/2010 最后编辑:MendelGaF. 更新时间:4/18/2023 访问量:266724
如何查看 Python 中是否有可用且活动的网络连接?
How can I see if there's an available and active network connection in Python?
答:
您可以尝试下载数据,如果连接失败,您将知道连接问题不正常。
基本上,您无法检查计算机是否已连接到互联网。失败的原因可能有很多,例如错误的DNS配置,防火墙,NAT。因此,即使你做了一些测试,你也不能保证你会与你的API建立连接,直到你尝试。
评论
也许你可以使用这样的东西:
from urllib import request
def internet_on():
try:
request.urlopen('http://216.58.192.142', timeout=1)
return True
except request.URLError as err:
return False
对于 Python 2.x,将 import 语句替换为:import urllib2 as request
目前,8.8.8.8 是 Google 的 IP 地址之一。将 http://8.8.8.8
更改为任何可以预期快速响应的网站。
此固定 IP 不会永远映射到 google.com。所以这段代码是 不坚固 - 它需要不断维护以保持其工作。
上述代码使用固定 IP 地址而不是完全限定域名 (FQDN) 的原因是 FQDN 需要 DNS 查找。当计算机没有有效的互联网连接时,DNS 查找本身可能会阻止调用超过一秒钟。感谢 @rzetterberg 指出这一点。urllib_request.urlopen
如果上面的固定 IP 地址不起作用,google.com 您可以通过运行
% dig google.com +trace
...
google.com. 300 IN A 216.58.192.142
评论
urlopen
http://google.com
无论如何,请尝试您尝试执行的操作。如果失败,python 应该抛出一个异常来通知您。
首先尝试一些琐碎的操作来检测连接将引入竞争条件。如果在测试时互联网连接有效,但在需要执行实际工作之前出现故障怎么办?
只是为了更新 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。
评论
作为 ubutnu/Kevin C 答案的替代方案,我使用这样的包:requests
import requests
def connected_to_internet(url='http://www.google.com/', timeout=5):
try:
_ = requests.head(url, timeout=timeout)
return True
except requests.ConnectionError:
print("No internet connection available.")
return False
奖励:这可以扩展到 ping 网站的此功能。
def web_site_online(url='http://www.google.com/', timeout=5):
try:
req = requests.head(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
requests.head()
_ = requests.head...
requests.head...
只发出 HEAD 请求会更快,因此不会获取任何 HTML。
try:
import httplib # python < 3.0
except:
import http.client as httplib
def have_internet() -> bool:
conn = httplib.HTTPSConnection("8.8.8.8", timeout=5)
try:
conn.request("HEAD", "/")
return True
except Exception:
return False
finally:
conn.close()
评论
conn.close()
可以移动到 。这部分将执行无 regadless there is in 或 block。finally
return
try
except
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)
以 unutbu 的答案为起点,过去曾被“静态”IP 地址更改烧毁,我创建了一个简单的类,它使用 DNS 查找(即使用 URL “https://www.google.com”)检查一次,然后存储响应服务器的 IP 地址以供后续检查使用。这样,IP 地址始终是最新的(假设类至少每隔几年重新初始化一次)。我还感谢这个答案,它向我展示了如何获取服务器的 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()
如果我们可以连接到某个Internet服务器,那么我们确实具有连接性。但是,对于最快和最可靠的方法,所有解决方案都应至少符合以下要求:
- 避免DNS解析(我们需要一个众所周知的IP并保证在大部分时间都可用)
- 避免应用层连接(连接到 HTTP/FTP/IMAP 服务)
- 避免从 Python 或其他选择的语言调用外部实用程序(我们需要提出一个不依赖第三方解决方案的与语言无关的解决方案)
为了遵守这些规定,一种方法可能是检查Google的公共DNS服务器之一是否可以访问。这些服务器的 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
正如我们所看到的,是开放的,未经过滤的。如果您是非 root 用户,请记住使用 或 Nmap 的参数来发送构建的探测数据包并确定主机是否已启动。53/tcp
sudo
-Pn
在尝试使用 Python 之前,让我们使用外部工具 Netcat 测试连接:
$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
Netcat 确认我们可以超越 .现在我们可以在 Python 中设置一个套接字连接来检查连接:8.8.8.8
53/tcp
8.8.8.8:53/tcp
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 解析失败等原因,它可能会变慢。如果您不这么认为,请发表评论。
更新 #4:这个公共名称服务器列表是 IP 测试的一个很好的参考。
更新 #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
更新#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
在上面的输出中,表示来自各自作者的所有这些实现都正确地标识了与 Internet 的连接。时间以毫秒分辨率显示。
更新 #1:感谢 @theamk 的评论,timeout 现在是一个参数,并默认初始化为。3s
评论
close()
如果 localhost 已从 Try 更改为 Try,这可能不起作用127.0.0.1
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地址,然后询问它是否是localhost IP地址。 希望能有所帮助
评论
我最喜欢的一个,无论是否在集群上运行脚本
import subprocess
def online(timeout):
try:
return subprocess.run(
['wget', '-q', '--spider', 'google.com'],
timeout=timeout
).returncode == 0
except subprocess.TimeoutExpired:
return False
它会安静地运行 WGET,不下载任何内容,但检查给定的远程文件是否存在于 Web 上
以 Six 的答案为例,我认为我们可以以某种方式简化,这是一个重要的问题,因为新来者在高度技术性的问题中迷失了方向。
在这里,我最终将用来等待我的连接(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 分钟,如果达到,我会在一小时内尝试,但它是另一个脚本!
评论
最好的方法是让它检查 python 在找不到网站时始终给出的 IP 地址。在本例中,这是我的代码:
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("")
接受 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
这是我的版本
import requests
try:
if requests.get('https://google.com').ok:
print("You're Online")
except:
print("You're Offline")
评论
这在 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")
现代便携式解决方案,具有以下特点: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
我在 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
对于我的项目,我使用修改后的脚本来ping谷歌公共DNS服务器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
评论
通过运行
pip install --upgrade pip
使用 requests 软件包安装
pip install requests
import requests
import webbrowser
url = "http://www.youtube.com"
timeout = 6
try:
request = requests.get(url, timeout=timeout)
print("Connected to the Internet")
print("browser is loading url")
webbrowser.open(url)
except (requests.ConnectionError, requests.Timeout) as exception:
print("poor or no internet connection.")
我只想参考 Ivelin 的解决方案,因为我不能在那里发表评论。
在使用旧SSL证书的python 2.7中(在我的情况下,无法更新,这是另一回事),可能会出现证书错误。在这种情况下,将“8.8.8.8”替换为“dns.google”或“8888.google”会有所帮助。
希望这也有人能帮上忙。
try:
import httplib # python < 3.0
except:
import http.client as httplib
def have_internet():
conn = httplib.HTTPSConnection("8888.google", timeout=5)
try:
conn.request("HEAD", "/")
return True
except Exception:
return False
finally:
conn.close()
评论
easy_install system_of_tubes