Пінгувати сайт на Python?


80

Як перевірити веб-сайт або IP-адресу за допомогою Python?


2
Будь ласка, визначте "ping". Ви маєте на увазі використовувати протокол пінгу ICMP або перевірити, чи працює веб-сервер? Або щось інше?
S.Lott,

це виявилося більш корисним для проблеми я вирішувала: stackoverflow.com/questions/3764291/checking-network-connection
jedierikb

1
ось реалізація чистого python: falatic.com/index.php/39/pinging-with-python
thinker007

Відповіді:


82

Дивіться цей чистий пінг-пітон від Метью Діксона Каулза та Єнса Дімера . Також пам’ятайте, що Python вимагає root для створення ICMP (тобто ping) сокетів у 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

Сам вихідний код легко читати, ознайомтесь із реалізаціями verbose_pingта Ping.doдля натхнення.


4
pingвикористовує, time.clockщо не дає нічого корисного на моєму Linux box. timeit.default_timer(це дорівнює time.timeна моїй машині) працює. time.clock-> timeit.default_timer gist.github.com/255009
jfs

@Vinicius - дякую! Оновлено новим розташуванням на github. Здається, це постійно підтримується!
орип

3
ping не має методу, який називається do_one. Я не міг знайти простий спосіб отримати час пінгу.
Джозеф Туріан

1
"run" перейменовано на "count"
пферат

1
@ChrisWithers бінарний файл "ping" запускається як корінь через біт "setuid". superuser.com/a/1035983/4706
orip

42

Залежно від того, що ви хочете отримати, вам, мабуть, найпростіше викликати системну команду ping ..

Використання модуля підпроцесу - найкращий спосіб зробити це, хоча ви повинні пам’ятати, що команда 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

Вам не потрібно турбуватися про символи втечі оболонки. Наприклад..

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


У Windows слід використовувати -nзамість -c. ( Див. Відповідь ePi272314 )
Стевойсяк,

39

Ви можете знайти презентацію Ноя Подарунка Створення гнучких інструментів командного рядка за допомогою Python . У ньому він поєднує підпроцес, чергу та потоки, щоб розробити рішення, здатне одночасно пінгувати хости та пришвидшити процес. Нижче наведено базову версію, перш ніж він додасть аналіз командного рядка та деякі інші функції. Код цієї та інших версій можна знайти тут

#!/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 для Unix та Linux System Administration

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


4
Не знаю, що це насправді відповідає на питання, але це дуже корисна інформація!
ig0774

Я знаю, що це походить від PyCon ... але це досить погано. Виконання системних дзвінків - це марна трата часу та ресурсів, при цьому вона неймовірно залежить від системи та важко аналізується. Вам краще скористатися методом, що використовує Python для надсилання / отримання запитів ICMP, оскільки в цьому потоці є інші.
Cukic0d

9

Важко сказати, у чому ваше питання, але є кілька альтернатив.

Якщо ви маєте на увазі буквальне виконання запиту за допомогою протоколу ICMP ping, ви можете отримати бібліотеку ICMP і виконати запит ping безпосередньо. Google "Python ICMP", щоб знайти такі речі, як цей icmplib . Можливо, ви також захочете поглянути на скапа .

Це буде набагато швидше, ніж використання os.system("ping " + ip ).

Якщо ви маєте на увазі загальний "пінг" ящика, щоб перевірити, чи він піднявся, ви можете використовувати протокол відлуння на порту 7.

Для відлуння ви використовуєте бібліотеку сокетів, щоб відкрити IP-адресу та порт 7. Ви пишете щось на цьому порту, надсилаєте каретку return ( "\r\n"), а потім читаєте відповідь.

Якщо ви маєте на увазі "перевірити" веб-сайт, щоб перевірити, чи він працює, вам доведеться використовувати протокол http на порту 80.

Для належної перевірки веб-сервера ви використовуєте urllib2, щоб відкрити певну URL-адресу. ( /index.htmlзавжди популярний) і прочитайте відповідь.

Є ще більше потенційних значень "ping", включаючи "traceroute" та "finger".


5
Колись ехо було широко поширеним, але тепер воно вимкнено за замовчуванням у більшості систем. Отже, це не практичний спосіб перевірити, чи працює машина нормально.
bortzmeyer

8

Я зробив щось подібне таким чином, як натхнення:

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

1
радий, що ти залишився подалі від зовнішніх бібліотек іsubprocess
tshepang

Що робити, якщо немає index.html?
sbose

4
Що ще важливіше, а що, якщо немає веб-сервера?
Кім Гресман,

Дійсно, немає потреби об'єднувати це /index.html; на будь-якому веб-сайті, де насправді був би документ, що називається index.html, він знаходився б там же, в корені сервера. Замість цього ви б випереджати http:// або https://до господаря
Антті Haapala

Хоча це насправді не пінг ICMP, а TCP-порт 80 "пінг" + тест HTTP, можливо, було б краще зробити запит HEAD (або OPTIONS), оскільки ви фактично не отримаєте жодного вмісту, тому пропускна здатність буде впливати на це менше. Якщо ви хочете щось більше запасного, ви можете просто спробувати відкрити сокет TCP 80 для хоста і негайно закрити його.
Nick T

6

Ось короткий фрагмент з використанням subprocess. 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."

3
Попередження: не працює на вікнах ( -cє -n, і логіка щодо коду повернення інша)
wim

3

прочитати ім'я файлу, файл містить одну 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)


2

Якщо ви хочете щось власне на Python, з чим ви можете грати, подивіться на Scapy:

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

На мою думку, це набагато краще (і повністю крос-платформне), ніж деякі фанкі дзвінки підпроцесу. Також ви можете мати стільки інформації про відповідь (ідентифікатор послідовності .....) скільки завгодно, як і сам пакет.




0

використання системної команди 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)

6
Я збираюся зареєструвати www.this_one_wont_work.com лише для ударів і хихикань.
Matthew Scouten

p = Popen('ping -n 1 ' + self.host, stdout=PIPE)Має бути p = Popen(['ping','-n','1','self.host'], stdout=PIPE)
toc777

0

за допомогою команди 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)

0

ви можете спробувати сокет, щоб отримати ip сайту, і скористатися scrap для виведення icmp-пінгу на 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])

0

Я розробляю бібліотеку, яка, на мою думку, може вам допомогти. Він називається icmplib (не пов'язаний з будь-яким іншим однойменним кодом, який можна знайти в Інтернеті) і є чистою реалізацією протоколу ICMP на Python.

Він повністю об'єктно-орієнтований і має прості функції, такі як класичний пінг, мультипінг та трасування, а також класи та сокети низького рівня для тих, хто хоче розробляти додатки на основі протоколу ICMP.

Ось деякі інші основні моменти:

  • Можна запускати без привілеїв root.
  • Ви можете налаштувати багато параметрів, таких як корисне навантаження пакетів ICMP та клас трафіку (QoS).
  • Крос-платформа: тестується на Linux, macOS та Windows.
  • Швидкий і вимагає небагато ресурсів ЦП / ОЗУ, на відміну від дзвінків, здійснених з підпроцесом.
  • Легкий і не покладається на додаткові залежності.

Щоб встановити його (потрібен 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')

Встановіть для параметра «привілейований» значення «False», якщо ви хочете використовувати бібліотеку без права root.

Ви можете знайти повну документацію на сторінці проекту: https://github.com/ValentinBELYN/icmplib

Сподіваюсь, ця бібліотека вам стане в нагоді.


2
Примітка модератора : ця відповідь відповідає нашим вимогам щодо самореклами , не є небажаною (питання вимагає рішення Python для використання ping) і тому не є спамом за нашим визначенням терміна.
Мартін Пітерс

-1

Використовуйте це, воно перевірено на python 2.7 і працює нормально; повертає час пінгу в мілісекундах, якщо успіх і повертає 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

1
Помилки на Python 3.6. ModuleNotFoundError: Немає модуля з назвою 'підпроцес'
Stevoisiak

Також не вдається, оскільки commandце рядок, що включає всі аргументи замість списку, тому запускає command not foundповний рядок у Linux.
arielf
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.