Ping a site in Python?
Asked Answered
R

18

94

How do I ping a website or IP address with Python?

Rallentando answered 25/11, 2008 at 9:58 Comment(3)
Please define "ping". Do you mean to use the ICMP ping protocol, or see if a web server is running? Or something else?Respond
this proved more helpful for a problem I was solving:https://mcmap.net/q/111981/-how-can-i-see-if-there-39-s-an-available-and-active-network-connection-in-pythonKippy
here is the implement of pure python: falatic.com/index.php/39/pinging-with-pythonEatables
Q
85

See this pure Python ping by Matthew Dixon Cowles and Jens Diemer. Also, remember that Python requires root to spawn ICMP (i.e. ping) sockets in linux.

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

The source code itself is easy to read, see the implementations of verbose_ping and of Ping.do for inspiration.

Quiz answered 25/11, 2008 at 12:39 Comment(11)
ping uses time.clock that doesn't yield anything useful on my Linux box. timeit.default_timer (it is equal to time.time on my machine) works. time.clock -> timeit.default_timer gist.github.com/255009Bhopal
@Vinicius - thanks! Updated with the new location on github. Seems like it's constantly maintained, too!Quiz
ping has no method called do_one. I couldn't find a simple way to get the ping time.Alterant
@JosephTurian, you're right. I updated the example to match current version of the source.Quiz
this is no longer working - kwarg 'run' is gone , and i get the error: Operation not permitted - Note that ICMP messages can only be sent from processes running as root.Bugger
'run' has been renamed to 'count'Unremitting
Why does this library require root, yet the ping binary in linux can be run as any user?Jus
@ChrisWithers the 'ping' binary runs as root via the 'setuid' bit. superuser.com/a/1035983/4706Quiz
I get AttributeError: 'module' object has no attribute 'verbose_ping'. How can I fix this?Fidelity
@AlperenGörmez I'm not sure what ping module you're importing - can try to print ping to double-check. Installing the package from PyPI only installs ping.py as a binary script. You can import it, though, e.g by copying it somewhere else. I just verified again that it has a verbose_ping functionQuiz
The python-ping GitHub page no longer exists and the PyPI project has not been updated since 2011. I do not recommend using it.Ala
A
48

Depending on what you want to achive, you are probably easiest calling the system ping command..

Using the subprocess module is the best way of doing this, although you have to remember the ping command is different on different operating systems!

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

You don't need to worry about shell-escape characters. For example..

host = "google.com; `echo test`

..will not execute the echo command.

Now, to actually get the ping results, you could parse the out variable. Example output:

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

Example regex:

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')

Again, remember the output will vary depending on operating system (and even the version of ping). This isn't ideal, but it will work fine in many situations (where you know the machines the script will be running on)

Almeta answered 25/11, 2008 at 10:49 Comment(3)
I found I had to tweak your regex match expression as the out contains encoded \n which seem to interfere with the matching: matcher = re.compile("\nround-trip min/avg/max/stddev = (\d+.\d+)/(\d+.\d+)/(\d+.\d+)/(\d+.\d+)")Piotrowski
@Pierz: just use matcher.search instead without changing the regex.Bhopal
On Windows, you should use -n instead of -c. (See ePi272314's answer)Ala
E
40

You may find Noah Gift's presentation Creating Agile Commandline Tools With Python. In it he combines subprocess, Queue and threading to develop solution that is capable of pinging hosts concurrently and speeding up the process. Below is a basic version before he adds command line parsing and some other features. The code to this version and others can be found 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()

He is also author of: Python for Unix and Linux System Administration

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

Ethanol answered 25/11, 2008 at 12:28 Comment(2)
Don't know that this actually answers the question, but it's very useful information!Mcatee
I know it comes from PyCon... but it's pretty bad. Performing system calls is a waste of time & resource, while also being incredibly system-dependent, and hard to parse. You should rather opt in for a method using Python to send/receive ICMP requests, as there are others on this thread.Assent
R
10

It's hard to say what your question is, but there are some alternatives.

If you mean to literally execute a request using the ICMP ping protocol, you can get an ICMP library and execute the ping request directly. Google "Python ICMP" to find things like this icmplib. You might want to look at scapy, also.

This will be much faster than using os.system("ping " + ip ).

If you mean to generically "ping" a box to see if it's up, you can use the echo protocol on port 7.

For echo, you use the socket library to open the IP address and port 7. You write something on that port, send a carriage return ("\r\n") and then read the reply.

If you mean to "ping" a web site to see if the site is running, you have to use the http protocol on port 80.

For or properly checking a web server, you use urllib2 to open a specific URL. (/index.html is always popular) and read the response.

There are still more potential meaning of "ping" including "traceroute" and "finger".

Respond answered 25/11, 2008 at 11:12 Comment(1)
echo was once widespread but it now disabled by default on most systems. So, it is not a practical way to test if the machine runs fine.Zibeline
S
9

Most simple answer is:

import os
os.system("ping google.com") 
Schuss answered 19/5, 2020 at 18:12 Comment(0)
M
8

I did something similar this way, as an inspiration:

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()
Mamba answered 22/7, 2009 at 12:59 Comment(5)
glad you stayed away from external libraries and subprocessAmen
What if there's no index.html?Kodiak
More importantly, what if there's no web server?Havoc
Indeed, there is no need to concatenate that /index.html; in any site where there'd actually be a document called index.html, it would be right there, in the server root. Instead you'd prepend http:// or https:// to the hostSoloman
While this isn't really a ICMP ping so much as a TCP port 80 "ping" + HTTP test, it would probably be better to do a HEAD (or OPTIONS) request as you won't actually receive any content, so bandwidth will affect it less. If you want something more spare, you could just try to open a TCP 80 socket to the host and immediately close it.Caseose
I
6

Here's a short snippet using subprocess. The check_call method either returns 0 for success, or raises an exception. This way, I don't have to parse the output of ping. I'm using shlex to split the command line arguments.

  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."
Inland answered 19/9, 2012 at 7:35 Comment(1)
Warning: doesn't work on windows (-c is -n there, and the logic about the return code is different)Bugger
M
6

I develop a library that I think could help you. It is called icmplib (unrelated to any other code of the same name that can be found on the Internet) and is a pure implementation of the ICMP protocol in Python.

It is completely object oriented and has simple functions such as the classic ping, multiping and traceroute, as well as low level classes and sockets for those who want to develop applications based on the ICMP protocol.

Here are some other highlights:

  • Can be run without root privileges.
  • You can customize many parameters such as the payload of ICMP packets and the traffic class (QoS).
  • Cross-platform: tested on Linux, macOS and Windows.
  • Fast and requires few CPU / RAM resources unlike calls made with subprocess.
  • Lightweight and does not rely on any additional dependencies.

To install it (Python 3.6+ required):

pip3 install icmplib

Here is a simple example of the ping function:

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')

Set the "privileged" parameter to False if you want to use the library without root privileges.

You can find the complete documentation on the project page: https://github.com/ValentinBELYN/icmplib

Hope you will find this library useful.

Miasma answered 21/11, 2020 at 20:5 Comment(2)
Moderator note: this answer follows our requirements for self-promotion, is not unsolicited (the question asks for a Python solution for using ping) and so is not spam by our definition of the term.Georgianngeorgianna
if you want to ping a website URL instead of an IP address, remove http from the beginning and slash at the end.Kimmie
C
2

read a file name, the file contain the one url per line, like this:

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

use command:

python url.py urls.txt

get the result:

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

source code(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)
Comehither answered 1/12, 2012 at 13:14 Comment(0)
A
2
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"
Abdicate answered 6/3, 2015 at 10:29 Comment(0)
A
2

If you want something actually in Python, that you can play with, have a look at Scapy:

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

That's in my opinion much better (and fully cross-platform), than some funky subprocess calls. Also you can have as much information about the answer (sequence ID.....) as you want, as you have the packet itself.

Assent answered 28/6, 2019 at 12:17 Comment(0)
P
2

On python 3 you can use ping3.

from ping3 import ping, verbose_ping
ip-host = '8.8.8.8'
if not ping(ip-host):
    raise ValueError('{} is not available.'.format(ip-host))
Pantia answered 7/2, 2022 at 14:30 Comment(0)
J
0

using system ping command to ping a list of hosts:

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)
Josiah answered 25/11, 2008 at 17:12 Comment(2)
I'm going to register www.this_one_wont_work.com just for kicks and giggles.Cree
p = Popen('ping -n 1 ' + self.host, stdout=PIPE) Should be p = Popen(['ping','-n','1','self.host'], stdout=PIPE)Arelus
T
0

You can find an updated version of the mentioned script that works on both Windows and Linux here

Tinner answered 16/11, 2009 at 12:10 Comment(1)
The linked code fails on Python 3.8. "SyntaxError: invalid syntax"Ala
L
0

using subprocess ping command to ping decode it because the response is binary:

import subprocess
ping_response = subprocess.Popen(["ping", "-a", "google.com"], stdout=subprocess.PIPE).stdout.read()
result = ping_response.decode('utf-8')
print(result)
Longsome answered 6/8, 2020 at 20:9 Comment(0)
G
0

you might try socket to get ip of the site and use scrapy to excute icmp ping to the 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])
Gilly answered 17/12, 2020 at 3:28 Comment(0)
B
0

If you only want to check whether a machine on an IP is active or not, you can just use python sockets.

import socket
s = socket.socket()
try:
    s.connect(("192.168.1.123", 1234)) # You can use any port number here
except Exception as e:
    print(e.errno, e)

Now, according to the error message displayed (or the error number), you can determine whether the machine is active or not.

Beers answered 16/6, 2022 at 15:22 Comment(0)
D
-1

Use this it's tested on python 2.7 and works fine it returns ping time in milliseconds if success and return False on fail.

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
Dichroite answered 11/4, 2015 at 17:10 Comment(2)
Fails on Python 3.6. ModuleNotFoundError: No module named 'subproccess'Ala
Also fails because command is a string including all arguments instead of a list so triggers command not found for the full string on Linux.Purlin

© 2022 - 2024 — McMap. All rights reserved.