Pingować witrynę w Pythonie?

80

Jak pingować witrynę lub adres IP za pomocą Pythona?

user40572
źródło
2
Zdefiniuj „ping”. Czy masz na myśli użycie protokołu ICMP ping lub sprawdzenie, czy działa serwer sieciowy? Albo coś innego?
S.Lott,
okazało się to bardziej pomocne w przypadku problemu, który rozwiązałem: stackoverflow.com/questions/3764291/checking-network-connection
jedierikb
1
oto implementacja czystego Pythona: falatic.com/index.php/39/pinging-with-python
thinker007

Odpowiedzi:

82

Zobacz ten ping w czystym Pythonie autorstwa Matthew Dixona Cowlesa i Jensa Diemera . Pamiętaj też, że Python wymaga roota do tworzenia gniazd ICMP (tj. Pingowania) w Linuksie.

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

Sam kod źródłowy jest łatwy do odczytania, zobacz implementacje verbose_pingi Ping.dodla inspiracji.

orip
źródło
4
pingużywa, time.clockktóre nie dają niczego użytecznego na moim Linuksie. timeit.default_timer(to jest równe time.timena moim komputerze) działa. time.clock-> timeit.default_timer gist.github.com/255009
jfs
@Vinicius - dzięki! Zaktualizowano o nową lokalizację na githubie. Wygląda na to, że jest stale utrzymywany!
orip
3
ping nie ma metody o nazwie do_one. Nie mogłem znaleźć prostego sposobu na uzyskanie czasu pingowania.
Joseph Turian,
1
„run” został przemianowany na „count”
pferate
1
@ChrisWithers plik binarny „ping” działa jako root poprzez bit „setuid”. superuser.com/a/1035983/4706
orip
42

W zależności od tego, co chcesz osiągnąć, prawdopodobnie najłatwiej jest wywołać systemowe polecenie ping.

Najlepszym sposobem na to jest użycie modułu podprocesu, chociaż musisz pamiętać, że polecenie ping jest różne w różnych systemach operacyjnych!

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

Nie musisz martwić się o znaki ucieczki pociskiem. Na przykład..

host = "google.com; `echo test`

..will nie wykonać polecenia echo.

Teraz, aby faktycznie uzyskać wyniki pingowania, możesz przeanalizować outzmienną. Przykładowe dane wyjściowe:

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

Przykładowe wyrażenie regularne:

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

Ponownie pamiętaj, że dane wyjściowe będą się różnić w zależności od systemu operacyjnego (a nawet wersji ping). To nie jest idealne rozwiązanie, ale będzie działać dobrze w wielu sytuacjach (jeśli znasz maszyny, na których będzie działać skrypt)

dbr
źródło
Okazało się, że muszę poprawić Twoje wyrażenie dopasowania wyrażenia regularnego, ponieważ outzawiera zakodowane \ n, co wydaje się przeszkadzać w dopasowywaniu:matcher = re.compile("\nround-trip min/avg/max/stddev = (\d+.\d+)/(\d+.\d+)/(\d+.\d+)/(\d+.\d+)")
Pierz
W systemie Windows należy używać -nzamiast -c. ( Zobacz odpowiedź ePi272314 )
Stevoisiak
39

Możesz znaleźć prezentację Noah Gift Tworzenie narzędzi wiersza poleceń Agile w Pythonie . Łączy w nim podproces, kolejkę i wątki, aby opracować rozwiązanie, które jest w stanie jednocześnie pingować hosty i przyspieszyć proces. Poniżej znajduje się podstawowa wersja, zanim doda parsowanie wiersza poleceń i kilka innych funkcji. Kod do tej wersji i innych można znaleźć tutaj

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

Jest także autorem: Python for Unix and Linux System Administration

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

Ryan Cox
źródło
4
Nie wiem, czy to faktycznie odpowiada na pytanie, ale jest to bardzo przydatna informacja!
ig0774
Wiem, że pochodzi z PyCon ... ale jest dość zły. Wykonywanie wywołań systemowych jest stratą czasu i zasobów, a jednocześnie jest niezwykle zależne od systemu i trudne do przeanalizowania. Powinieneś raczej wybrać metodę używającą Pythona do wysyłania / odbierania żądań ICMP, ponieważ są inne w tym wątku.
Cukic0d
9

Trudno powiedzieć, jakie jest twoje pytanie, ale jest kilka alternatyw.

Jeśli masz na myśli dosłowne wykonanie żądania przy użyciu protokołu ICMP ping, możesz pobrać bibliotekę ICMP i bezpośrednio wykonać żądanie ping. Google „Python ICMP”, aby znaleźć takie rzeczy, jak ten icmplib . Możesz spojrzeć na scapy .

Będzie to znacznie szybsze niż użycie os.system("ping " + ip ).

Jeśli masz zamiar generalnie „pingować” urządzenie, aby sprawdzić, czy jest włączone, możesz użyć protokołu echa na porcie 7.

W przypadku echo używasz biblioteki gniazd do otwierania adresu IP i portu 7. Piszesz coś na tym porcie, wysyłasz znak powrotu karetki ( "\r\n"), a następnie czytasz odpowiedź.

Jeśli chcesz „pingować” witrynę sieci Web, aby sprawdzić, czy jest ona uruchomiona, musisz użyć protokołu http na porcie 80.

W przypadku lub prawidłowego sprawdzania serwera WWW używasz urllib2 do otwierania określonego adresu URL. (/index.html jest zawsze popularne) i przeczytaj odpowiedź.

Nadal istnieje więcej potencjalnych znaczeń „ping”, w tym „traceroute” i „finger”.

S.Lott
źródło
5
echo było kiedyś powszechne, ale teraz jest domyślnie wyłączone w większości systemów. Dlatego nie jest to praktyczny sposób sprawdzenia, czy maszyna działa poprawnie.
bortzmeyer
8

Coś podobnego zrobiłem w ten sposób, jako inspirację:

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
źródło
1
cieszę się, że subprocess
trzymałeś
A jeśli nie ma pliku index.html?
sbose
4
Co ważniejsze, co się stanie, jeśli nie ma serwera WWW?
Kim Gräsman
Rzeczywiście, nie ma potrzeby konkatenacji tego /index.html; w każdej witrynie, w której faktycznie byłby wywołany dokument index.html, znajdowałby się on właśnie tam, w katalogu głównym serwera. Zamiast tego, jako prepend http:// lub https://do gospodarza
Antti Haapala
Chociaż nie jest to tak naprawdę ping ICMP, a raczej "ping" na porcie TCP 80 + test HTTP, prawdopodobnie lepiej byłoby wykonać żądanie HEAD (lub OPTIONS), ponieważ w rzeczywistości nie otrzymasz żadnej zawartości, więc przepustowość wpływają na to mniej. Jeśli potrzebujesz czegoś bardziej oszczędnego, możesz po prostu spróbować otworzyć gniazdo TCP 80 na hoście i natychmiast je zamknąć.
Nick T
6

Oto krótki fragment używający subprocess. check_callMetoda albo zwraca 0 w przypadku powodzenia lub zgłasza wyjątek. W ten sposób nie muszę analizować danych wyjściowych polecenia ping. Używam shlexdo dzielenia argumentów wiersza poleceń.

  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
źródło
3
Ostrzeżenie: nie działa w systemie Windows ( -cjest -n, a logika dotycząca kodu zwrotnego jest inna)
wim
3

czytaj nazwę pliku, plik zawiera jeden adres URL w każdym wierszu, na przykład:

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

użyj polecenia:

python url.py urls.txt

uzyskać wynik:

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

kod źródłowy (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
źródło
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
źródło
2

Jeśli chcesz czegoś faktycznie w Pythonie, czym możesz się bawić, spójrz na Scapy:

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

To moim zdaniem znacznie lepsze (iw pełni wieloplatformowe) niż niektóre funky wywołania podprocesu. Możesz także mieć tyle informacji o odpowiedzi (identyfikator sekwencji .....), ile chcesz, ile masz samego pakietu.

Cukic0d
źródło
2

Najprostsza odpowiedź brzmi:

import os
os.system("ping google.com") 
Lotos
źródło
1

Zaktualizowaną wersję wspomnianego skryptu, który działa zarówno w systemie Windows, jak i Linux, można znaleźć tutaj

Urodzony by jeździć
źródło
Połączony kod nie działa w Pythonie 3.8. „
Błąd
1

Rozwijam bibliotekę, która moim zdaniem może ci pomóc. Nazywa się icmplib (niezwiązany z żadnym innym kodem o tej samej nazwie, który można znaleźć w Internecie) i jest czystą implementacją protokołu ICMP w Pythonie.

Jest całkowicie zorientowany obiektowo i ma proste funkcje, takie jak klasyczny ping, multiping i traceroute, a także niskopoziomowe klasy i gniazda dla tych, którzy chcą tworzyć aplikacje w oparciu o protokół ICMP.

Oto kilka innych najważniejszych informacji:

  • Można uruchomić bez uprawnień roota.
  • Można dostosować wiele parametrów, takich jak ładunek pakietów ICMP i klasa ruchu (QoS).
  • Wieloplatformowe: testowane w systemach Linux, macOS i Windows.
  • Szybki i wymaga kilku zasobów procesora / pamięci RAM w przeciwieństwie do wywołań wykonywanych za pomocą podprocesu.
  • Lekki i nie wymaga żadnych dodatkowych zależności.

Aby go zainstalować (wymagany Python 3.6+):

pip3 install icmplib

Oto prosty przykład funkcji 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')

Ustaw parametr „uprzywilejowany” na Fałsz, jeśli chcesz używać biblioteki bez uprawnień administratora.

Pełną dokumentację można znaleźć na stronie projektu: https://github.com/ValentinBELYN/icmplib

Mam nadzieję, że ta biblioteka okaże się przydatna.

Valentin
źródło
2
Uwaga moderatora : ta odpowiedź jest zgodna z naszymi wymaganiami dotyczącymi autopromocji , nie jest niezamawiana (pytanie dotyczy rozwiązania w Pythonie do używania pingów), a więc nie jest spamem w naszej definicji tego terminu.
Martijn Pieters
0

użycie systemowego polecenia ping do pingowania listy hostów:

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
źródło
6
Zamierzam zarejestrować www.this_one_wont_work.com tylko dla kopnięć i chichotów.
Matthew Scouten
p = Popen('ping -n 1 ' + self.host, stdout=PIPE)Powinno być p = Popen(['ping','-n','1','self.host'], stdout=PIPE)
toc777
0

użycie polecenia ping podprocesu, aby zdekodować ping, ponieważ odpowiedź jest binarna:

import subprocess
ping_response = subprocess.Popen(["ping", "-a", "google.com"], stdout=subprocess.PIPE).stdout.read()
result = ping_response.decode('utf-8')
print(result)
user14062446
źródło
0

możesz spróbować z gniazda, aby uzyskać ip strony i użyć scrapy do wykonania polecenia ping icmp na 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
źródło
-1

Użyj tego, co zostało przetestowane w Pythonie 2.7 i działa dobrze, zwraca czas ping w milisekundach, jeśli się powiedzie, i zwróci False w przypadku niepowodzenia.

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
źródło
1
Niepowodzenie w Pythonie 3.6. ModuleNotFoundError: Brak modułu o nazwie „subproccess”
Stevoisiak
Również kończy się niepowodzeniem, ponieważ commandjest to ciąg zawierający wszystkie argumenty zamiast listy, więc wyzwala command not foundpełny ciąg w systemie Linux.
arielf