¿Hacer ping a un sitio en Python?

Respuestas:

82

Vea este ping Python puro de Matthew Dixon Cowles y Jens Diemer . Además, recuerde que Python requiere root para generar sockets ICMP (es decir, ping) en 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

El código fuente en sí es fácil de leer, vea las implementaciones de verbose_pingy Ping.dopara inspiración.

orip
fuente
4
pingusos time.clockque no producen nada útil en mi caja de Linux. timeit.default_timer(es igual a time.timeen mi máquina) funciona. time.clock-> timeit.default_timer gist.github.com/255009
jfs
@Vinicius - ¡gracias! Actualizado con la nueva ubicación en github. ¡Parece que también se mantiene constantemente!
orip
3
ping no tiene un método llamado do_one. No pude encontrar una forma sencilla de obtener el tiempo de ping.
Joseph Turian
1
'Run' ha sido renombrado a 'count'
pferate
1
@ChrisWithers el binario 'ping' se ejecuta como root a través del bit 'setuid'. superuser.com/a/1035983/4706
oriP
42

Dependiendo de lo que desee lograr, probablemente sea más fácil llamar al comando ping del sistema.

Usar el módulo de subproceso es la mejor manera de hacer esto, aunque debe recordar que el comando ping es diferente en diferentes sistemas operativos.

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

No necesita preocuparse por los caracteres de escape de shell. Por ejemplo..

host = "google.com; `echo test`

..will no ejecute el comando echo.

Ahora, para obtener los resultados del ping, puede analizar la outvariable. Salida de ejemplo:

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

Ejemplo de expresión regular:

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

Nuevamente, recuerde que la salida variará según el sistema operativo (e incluso la versión de ping). Esto no es ideal, pero funcionará bien en muchas situaciones (en las que conoce las máquinas en las que se ejecutará el script)

dbr
fuente
Descubrí que tenía que modificar su expresión de coincidencia de expresiones regulares ya que outcontiene codificado \ n que parece interferir con la coincidencia:matcher = re.compile("\nround-trip min/avg/max/stddev = (\d+.\d+)/(\d+.\d+)/(\d+.\d+)/(\d+.\d+)")
Pierz
En Windows, debería usar en -nlugar de -c. ( Vea la respuesta de ePi272314 )
Stevoisiak
39

Puede encontrar la presentación de Noah Gift Creando herramientas ágiles de línea de comandos con Python . En él, combina subprocesos, colas y subprocesos para desarrollar una solución que sea capaz de hacer ping a los hosts al mismo tiempo y acelerar el proceso. A continuación se muestra una versión básica antes de que agregue el análisis de la línea de comandos y algunas otras características. El código de esta versión y otras se puede encontrar aquí.

#!/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()

También es autor de: Python para la administración de sistemas Unix y Linux.

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

Ryan Cox
fuente
4
No sé si esto realmente responde a la pregunta, ¡pero es información muy útil!
ig0774
Sé que proviene de PyCon ... pero es bastante malo. Realizar llamadas al sistema es una pérdida de tiempo y recursos, además de ser increíblemente dependiente del sistema y difícil de analizar. Debería optar por un método que utilice Python para enviar / recibir solicitudes ICMP, ya que hay otros en este hilo.
Cukic0d
9

Es difícil decir cuál es su pregunta, pero existen algunas alternativas.

Si quiere ejecutar literalmente una solicitud utilizando el protocolo de ping ICMP, puede obtener una biblioteca ICMP y ejecutar la solicitud de ping directamente. Google "Python ICMP" para encontrar cosas como este icmplib . Es posible que también desee mirar scapy .

Esto será mucho más rápido que usarlo os.system("ping " + ip ).

Si quiere "hacer ping" genéricamente a un cuadro para ver si está activo, puede usar el protocolo de eco en el puerto 7.

Para el eco, usa la biblioteca de socket para abrir la dirección IP y el puerto 7. Escribe algo en ese puerto, envía un retorno de carro ( "\r\n") y luego lee la respuesta.

Si quiere hacer "ping" a un sitio web para ver si el sitio se está ejecutando, debe usar el protocolo http en el puerto 80.

Para verificar correctamente un servidor web, usa urllib2 para abrir una URL específica. ( /index.htmlsiempre es popular) y lee la respuesta.

Todavía hay más significados potenciales de "ping", incluidos "traceroute" y "finger".

S. Lot
fuente
5
El eco fue una vez generalizado, pero ahora está deshabilitado de forma predeterminada en la mayoría de los sistemas. Por lo tanto, no es una forma práctica de probar si la máquina funciona bien.
bortzmeyer
8

Hice algo similar de esta manera, como inspiración:

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()
Harald Schilly
fuente
1
me alegro de que se haya mantenido alejado de las bibliotecas externas ysubprocess
tshepang
¿Qué pasa si no hay index.html?
sbose
4
Más importante aún, ¿qué pasa si no hay un servidor web?
Kim Gräsman
De hecho, no es necesario concatenar eso /index.html; en cualquier sitio donde realmente hubiera un documento llamado index.html, estaría allí mismo, en la raíz del servidor. En su lugar, anteponer http:// o https://al anfitrión
Antti Haapala
Si bien esto no es realmente un ping ICMP sino un "ping" del puerto TCP 80 + prueba HTTP, probablemente sería mejor hacer una solicitud HEAD (u OPTIONS) ya que en realidad no recibirá ningún contenido, por lo que el ancho de banda afectarlo menos. Si desea algo más de repuesto, puede intentar abrir un socket TCP 80 al host y cerrarlo inmediatamente.
Nick T
6

Aquí hay un breve fragmento de uso subprocess. El check_callmétodo devuelve 0 para el éxito o genera una excepción. De esta manera, no tengo que analizar la salida de ping. Estoy usando shlexpara dividir los argumentos de la línea de comando.

  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."
Moondoggy
fuente
3
Advertencia: No funciona en Windows ( -ces -nallí, y la lógica sobre el código de retorno es diferente)
WIM
3

leer un nombre de archivo, el archivo contiene una URL por línea, así:

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

comando de uso:

python url.py urls.txt

obtener el resultado:

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

código fuente (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)
hustljian
fuente
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"
Ibrahim Kasim
fuente
2

Si quieres algo realmente en Python, con lo que puedas jugar, echa un vistazo a Scapy:

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

Eso, en mi opinión, es mucho mejor (y completamente multiplataforma) que algunas llamadas de subprocesos funky. También puede tener tanta información sobre la respuesta (ID de secuencia .....) como desee, ya que tiene el paquete en sí.

Cukic0d
fuente
2

La respuesta más simple es:

import os
os.system("ping google.com") 
Loto
fuente
1

Puede encontrar una versión actualizada del script mencionado que funciona tanto en Windows como en Linux aquí

Nacido para montar
fuente
El código vinculado falla en Python 3.8. "SyntaxError: sintaxis no válida"
Stevoisiak
0

usando el comando system ping para hacer ping a una lista de 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)
Corey Goldberg
fuente
6
Me voy a registrar en www.this_one_wont_work.com solo por diversión y risas.
Matthew Scouten
p = Popen('ping -n 1 ' + self.host, stdout=PIPE)Debería ser p = Popen(['ping','-n','1','self.host'], stdout=PIPE)
toc777
0

usando el comando ping del subproceso para decodificarlo porque la respuesta es binaria:

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

puede probar socket para obtener la ip del sitio y usar scrapy para ejecutar un ping icmp a la 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])
xiaojueguan
fuente
0

Desarrollo una biblioteca que creo que podría ayudarte. Se llama icmplib (no está relacionado con ningún otro código del mismo nombre que se pueda encontrar en Internet) y es una implementación pura del protocolo ICMP en Python.

Está completamente orientado a objetos y cuenta con funciones sencillas como el clásico ping, multiplicación y traceroute, así como clases de bajo nivel y sockets para quienes quieran desarrollar aplicaciones basadas en el protocolo ICMP.

Aquí hay algunos otros aspectos destacados:

  • Se puede ejecutar sin privilegios de root.
  • Puede personalizar muchos parámetros, como la carga útil de los paquetes ICMP y la clase de tráfico (QoS).
  • Multiplataforma: probado en Linux, macOS y Windows.
  • Rápido y requiere pocos recursos de CPU / RAM a diferencia de las llamadas realizadas con subprocesos.
  • Ligero y no depende de dependencias adicionales.

Para instalarlo (se requiere Python 3.6+):

pip3 install icmplib

Aquí hay un ejemplo simple de la función 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')

Establezca el parámetro "privilegiado" en False si desea utilizar la biblioteca sin privilegios de root.

Puede encontrar la documentación completa en la página del proyecto: https://github.com/ValentinBELYN/icmplib

Espero que encuentre útil esta biblioteca.

Valentin
fuente
2
Nota del moderador : esta respuesta sigue nuestros requisitos de autopromoción , no es solicitada (la pregunta solicita una solución de Python para usar ping) y, por lo tanto, no es spam según nuestra definición del término.
Martijn Pieters
-1

Use esto, está probado en Python 2.7 y funciona bien, devuelve el tiempo de ping en milisegundos si tiene éxito y devuelve False si falla.

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
MSS
fuente
1
Falla en Python 3.6. ModuleNotFoundError: Ningún módulo llamado 'subproceso'
Stevoisiak
También falla porque commandes una cadena que incluye todos los argumentos en lugar de una lista, por lo que se activa command not foundla cadena completa en Linux.
arielf