用 Python ping 一个站点?

Posted

技术标签:

【中文标题】用 Python ping 一个站点?【英文标题】:Ping a site in Python? 【发布时间】:2010-09-23 22:20:24 【问题描述】:

如何使用 Python ping 网站或 IP 地址?

【问题讨论】:

请定义“ping”。您的意思是使用 ICMP ping 协议,还是查看 Web 服务器是否正在运行?还是别的什么? 这对我正在解决的问题更有帮助:***.com/questions/3764291/checking-network-connection 这里是纯python的实现:falatic.com/index.php/39/pinging-with-python 【参考方案1】:

通过Matthew Dixon Cowles 和Jens Diemer 看到这个pure Python ping。另外,请记住 Python 需要 root 才能在 linux 中生成 ICMP(即 ping)套接字。

import ping, socket
try:
    ping.verbose_ping('www.google.com', count=3)
    delay = ping.Ping('www.wikipedia.org', timeout=2000).do()
except socket.error, e:
    print "Ping Error:", e

源代码本身很容易阅读,请参阅verbose_pingPing.do 的实现以获得灵感。

【讨论】:

ping 使用 time.clock 在我的 Linux 机器上不会产生任何有用的东西。 timeit.default_timer(在我的机器上等于time.time)有效。 time.clock -> timeit.default_timer gist.github.com/255009 ping 没有称为 do_one 的方法。我找不到获取 ping 时间的简单方法。 'run' 已重命名为 'count' @ChrisWithers 'ping' 二进制文件通过 'setuid' 位以 root 身份运行。 superuser.com/a/1035983/4706 python-ping GitHub 页面no longer exists 和 PyPI 项目自 2011 年以来一直没有更新。我不建议使用它。【参考方案2】:

根据您想要达到的目标,您可能最容易调用系统 ping 命令..

使用 subprocess 模块是最好的方法,尽管您必须记住 ping 命令在不同的操作系统上是不同的!

import subprocess

host = "www.google.com"

ping = subprocess.Popen(
    ["ping", "-c", "4", host],
    stdout = subprocess.PIPE,
    stderr = subprocess.PIPE
)

out, error = ping.communicate()
print out

您无需担心 shell 转义字符。比如……

host = "google.com; `echo test`

..将执行 echo 命令。

现在,要真正获得 ping 结果,您可以解析 out 变量。示例输出:

round-trip min/avg/max/stddev = 248.139/249.474/250.530/0.896 ms

示例正则表达式:

import re
matcher = re.compile("round-trip min/avg/max/stddev = (\d+.\d+)/(\d+.\d+)/(\d+.\d+)/(\d+.\d+)")
print matcher.search(out).groups()

# ('248.139', '249.474', '250.530', '0.896')

同样,请记住输出会因操作系统(甚至ping 的版本)而异。这并不理想,但它在许多情况下都可以正常工作(您知道脚本将在哪些机器上运行)

【讨论】:

我发现我必须调整您的正则表达式匹配表达式,因为 out 包含编码的 \n 似乎会干扰匹配:matcher = re.compile("\nround-trip min/avg/max/stddev = (\d+.\d+)/(\d+.\d+)/(\d+.\d+)/(\d+.\d+)") @Pierz:就use matcher.search instead without changing the regex。 在 Windows 上,您应该使用 -n 而不是 -c。 (See ePi272314's answer)【参考方案3】:

您可以找到Noah Gift's 演示文稿Creating Agile Commandline Tools With Python。在其中,他结合了子进程、队列和线程来开发能够同时 ping 主机并加快进程的解决方案。以下是他添加命令行解析和其他一些功能之前的基本版本。这个版本和其他版本的代码可以找到here

#!/usr/bin/env python2.5
from threading import Thread
import subprocess
from Queue import Queue

num_threads = 4
queue = Queue()
ips = ["10.0.1.1", "10.0.1.3", "10.0.1.11", "10.0.1.51"]
#wraps system ping command
def pinger(i, q):
    """Pings subnet"""
    while True:
        ip = q.get()
        print "Thread %s: Pinging %s" % (i, ip)
        ret = subprocess.call("ping -c 1 %s" % ip,
            shell=True,
            stdout=open('/dev/null', 'w'),
            stderr=subprocess.STDOUT)
        if ret == 0:
            print "%s: is alive" % ip
        else:
            print "%s: did not respond" % ip
        q.task_done()
#Spawn thread pool
for i in range(num_threads):

    worker = Thread(target=pinger, args=(i, queue))
    worker.setDaemon(True)
    worker.start()
#Place work in queue
for ip in ips:
    queue.put(ip)
#Wait until worker threads are done to exit    
queue.join()

他也是Python for Unix and Linux System Administration的作者

http://ecx.images-amazon.com/images/I/515qmR%2B4sjL._SL500_AA240_.jpg

【讨论】:

不知道这是否真的回答了问题,但这是非常有用的信息! 我知道它来自 PyCon……但它很糟糕。执行系统调用是浪费时间和资源,同时也非常依赖于系统,并且难以解析。您应该选择使用 Python 发送/接收 ICMP 请求的方法,因为该线程上还有其他方法。【参考方案4】:

很难说你的问题是什么,但有一些替代方案。

如果您的意思是使用 ICMP ping 协议执行请求,您可以获取 ICMP 库并直接执行 ping 请求。谷歌“Python ICMP”找到类似icmplib的东西。您可能还想看看scapy。

这将比使用os.system("ping " + ip ) 快得多。

如果您的意思是一般地“ping”一个盒子以查看它是否启动,您可以在端口 7 上使用 echo 协议。

对于 echo,您使用 socket 库打开 IP 地址和端口 7。您在该端口上写一些东西,发送回车 ("\r\n"),然后阅读回复。

如果您要“ping”一个网站以查看该网站是否正在运行,则必须在端口 80 上使用 http 协议。

为了或正确地检查 Web 服务器,您可以使用 urllib2 打开特定的 URL。 (/index.html 总是很受欢迎)并阅读回复。

“ping”还有更多潜在含义,包括“traceroute”和“finger”。

【讨论】:

echo 曾经很普遍,但现在在大多数系统上默认禁用。因此,这不是测试机器是否运行良好的实用方法。【参考方案5】:

我用这种方式做了类似的事情,作为一种灵感:

import urllib
import threading
import time

def pinger_urllib(host):
  """
  helper function timing the retrival of index.html 
  TODO: should there be a 1MB bogus file?
  """
  t1 = time.time()
  urllib.urlopen(host + '/index.html').read()
  return (time.time() - t1) * 1000.0


def task(m):
  """
  the actual task
  """
  delay = float(pinger_urllib(m))
  print '%-30s %5.0f [ms]' % (m, delay)

# parallelization
tasks = []
URLs = ['google.com', 'wikipedia.org']
for m in URLs:
  t = threading.Thread(target=task, args=(m,))
  t.start()
  tasks.append(t)

# synchronization point
for t in tasks:
  t.join()

【讨论】:

很高兴您远离外部库和subprocess 没有index.html怎么办? 更重要的是,如果没有网络服务器怎么办? 确实没必要把那个/index.html拼接起来;在实际上有一个名为index.html 的文档的任何站点中,它就在服务器根目录中。相反,您将 预先添加 http://https:// 到主机 虽然这并不是一个真正的 ICMP ping,而是 TCP 端口 80“ping”+ HTTP 测试,但最好执行 HEAD(或 OPTIONS)请求,因为您不会实际接收任何内容,因此带宽对其影响较小。如果您想要更多空闲的东西,您可以尝试打开一个 TCP 80 到主机的套接字并立即关闭它。【参考方案6】:

这是一个使用subprocess 的简短sn-p。 check_call 方法要么返回 0 表示成功,要么引发异常。这样,我不必解析 ping 的输出。我使用shlex 来拆分命令行参数。

  import subprocess
  import shlex

  command_line = "ping -c 1 www.google.comsldjkflksj"
  args = shlex.split(command_line)
  try:
      subprocess.check_call(args,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
      print "Website is there."
  except subprocess.CalledProcessError:
      print "Couldn't get a ping."

【讨论】:

警告:不能在windows上工作(-c那里是-n,返回码的逻辑不同)【参考方案7】:

最简单的答案是:

import os
os.system("ping google.com") 

【讨论】:

【参考方案8】:

我开发了一个我认为可以帮助你的库。它被称为 icmplib(与 Internet 上可以找到的任何其他同名代码无关),是 ICMP 协议在 Python 中的纯实现。

它完全面向对象,具有简单的功能,例如经典的 ping、multiping 和 traceroute,以及低级类和套接字,供希望基于 ICMP 协议开发应用程序的人使用。

以下是其他一些亮点:

可以在没有 root 权限的情况下运行。 您可以自定义许多参数,例如 ICMP 数据包的负载和流量类别 (QoS)。 跨平台:在 Linux、macOS 和 Windows 上测试。 与使用子进程进行的调用不同,速度快且需要很少的 CPU/RAM 资源。 轻量级且不依赖任何其他依赖项。

安装它(需要 Python 3.6+):

pip3 install icmplib

下面是一个简单的 ping 函数示例:

host = ping('1.1.1.1', count=4, interval=1, timeout=2, privileged=True)

if host.is_alive:
    print(f'host.address is alive! avg_rtt=host.avg_rtt ms')
else:
    print(f'host.address is dead')

如果您想在没有 root 权限的情况下使用库,请将“privileged”参数设置为 False。

您可以在项目页面上找到完整的文档: https://github.com/ValentinBELYN/icmplib

希望你会发现这个库很有用。

【讨论】:

版主说明:这个答案follows our requirements for self-promotion 不是主动提供的(问题要求使用 ping 的 Python 解决方案),不是垃圾邮件 根据我们对术语的定义。【参考方案9】:

读取一个文件名,该文件每行一个url,如下所示:

http://www.poolsaboveground.com/apache/hadoop/core/
http://mirrors.sonic.net/apache/hadoop/core/

使用命令:

python url.py urls.txt

得到结果:

Round Trip Time: 253 ms - mirrors.sonic.net
Round Trip Time: 245 ms - www.globalish.com
Round Trip Time: 327 ms - www.poolsaboveground.com

源代码(url.py):

import re
import sys
import urlparse
from subprocess import Popen, PIPE
from threading import Thread


class Pinger(object):
    def __init__(self, hosts):
        for host in hosts:
            hostname = urlparse.urlparse(host).hostname
            if hostname:
                pa = PingAgent(hostname)
                pa.start()
            else:
                continue

class PingAgent(Thread):
    def __init__(self, host):
        Thread.__init__(self)        
        self.host = host

    def run(self):
        p = Popen('ping -n 1 ' + self.host, stdout=PIPE)
        m = re.search('Average = (.*)ms', p.stdout.read())
        if m: print 'Round Trip Time: %s ms -' % m.group(1), self.host
        else: print 'Error: Invalid Response -', self.host


if __name__ == '__main__':
    with open(sys.argv[1]) as f:
        content = f.readlines() 
    Pinger(content)

【讨论】:

【参考方案10】:
import subprocess as s
ip=raw_input("Enter the IP/Domain name:")
if(s.call(["ping",ip])==0):
    print "your IP is alive"
else:
    print "Check ur IP"

【讨论】:

【参考方案11】:

如果你想要在 Python 中实际使用的东西,你可以玩,看看 Scapy:

from scapy.all import *
request = IP(dst="www.google.com")/ICMP()
answer = sr1(request)

在我看来,这比一些时髦的子进程调用要好得多(并且完全跨平台)。您还可以根据需要获得关于答案(序列 ID .....)的尽可能多的信息,就像您拥有数据包本身一样。

【讨论】:

【参考方案12】:

您可以找到上述脚本的更新版本,该脚本适用于 Windows 和 Linux here

【讨论】:

链接代码在 Python 3.8 上失败。 "SyntaxError: 无效语法"【参考方案13】:

使用系统 ping 命令 ping 主机列表:

import re
from subprocess import Popen, PIPE
from threading import Thread


class Pinger(object):
    def __init__(self, hosts):
        for host in hosts:
            pa = PingAgent(host)
            pa.start()

class PingAgent(Thread):
    def __init__(self, host):
        Thread.__init__(self)        
        self.host = host

    def run(self):
        p = Popen('ping -n 1 ' + self.host, stdout=PIPE)
        m = re.search('Average = (.*)ms', p.stdout.read())
        if m: print 'Round Trip Time: %s ms -' % m.group(1), self.host
        else: print 'Error: Invalid Response -', self.host


if __name__ == '__main__':
    hosts = [
        'www.pylot.org',
        'www.goldb.org',
        'www.google.com',
        'www.yahoo.com',
        'www.techcrunch.com',
        'www.this_one_wont_work.com'
       ]
    Pinger(hosts)

【讨论】:

我要注册 www.this_one_wont_work.com 只是为了好玩和咯咯笑。 p = Popen('ping -n 1 ' + self.host, stdout=PIPE) 应该是p = Popen(['ping','-n','1','self.host'], stdout=PIPE)【参考方案14】:

使用 subprocess ping 命令 ping 解码它,因为响应是二进制的:

import subprocess
ping_response = subprocess.Popen(["ping", "-a", "google.com"], stdout=subprocess.PIPE).stdout.read()
result = ping_response.decode('utf-8')
print(result)

【讨论】:

【参考方案15】:

你可以尝试使用 socket 获取站点的 ip 并使用 scrapy 执行 icmp ping 到该 ip。

import gevent
from gevent import monkey
# monkey.patch_all() should be executed before any library that will
# standard library
monkey.patch_all()

import socket
from scapy.all import IP, ICMP, sr1


def ping_site(fqdn):
    ip = socket.gethostbyaddr(fqdn)[-1][0]
    print(fqdn, ip, '\n')
    icmp = IP(dst=ip)/ICMP()
    resp = sr1(icmp, timeout=10)
    if resp:
        return (fqdn, False)
    else:
        return (fqdn, True)


sites = ['www.google.com', 'www.baidu.com', 'www.bing.com']
jobs = [gevent.spawn(ping_site, fqdn) for fqdn in sites]
gevent.joinall(jobs)
print([job.value for job in jobs])

【讨论】:

【参考方案16】:

使用它在 python 2.7 上测试并且工作正常,如果成功则返回 ping 时间(以毫秒为单位),失败时返回 False。

import platform,subproccess,re
def Ping(hostname,timeout):
    if platform.system() == "Windows":
        command="ping "+hostname+" -n 1 -w "+str(timeout*1000)
    else:
        command="ping -i "+str(timeout)+" -c 1 " + hostname
    proccess = subprocess.Popen(command, stdout=subprocess.PIPE)
    matches=re.match('.*time=([0-9]+)ms.*', proccess.stdout.read(),re.DOTALL)
    if matches:
        return matches.group(1)
    else: 
        return False

【讨论】:

在 Python 3.6 上失败。 ModuleNotFoundError: 没有名为“子进程”的模块 也失败了,因为command 是一个包含所有参数的字符串,而不是一个列表,因此在 Linux 上触发command not found 以获得完整的字符串。

以上是关于用 Python ping 一个站点?的主要内容,如果未能解决你的问题,请参考以下文章

python2写ping监控,自动发现ip

瓶 Python ping 检查 5 ping

python新手代码是啥?

用python批量添加保护站点

如何用Python3来实现ping功能

python 批量ping服务器