IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Parser le résultat d'un ping ?


Sujet :

Python

  1. #1
    Membre extrêmement actif
    Avatar de kedare
    Homme Profil pro
    SRE
    Inscrit en
    Juillet 2005
    Messages
    1 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : SRE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 1 549
    Par défaut Parser le résultat d'un ping ?
    Hello,
    J'ai un probleme, j'ai une application qui parse le résultat d'un ping, cette ligne plus précisement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    5 packets transmitted, 5 received, 0% packet loss, time 3996ms
    Jusqu'a la tout va bien, seulement quelques fois j'ai une réponse comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    5 packets transmitted, 4 received, +2 duplicates, 20% packet loss, time 3998ms
    Et la... c'est la cata, le "+2 duplicates" se retrouve dans la colonne du packet_loss...
    Voila mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    ## Ping Logger
    ## The script ping an host and add an entry on the ping database (used with crontab each minutes)
    ##== MYSQL TABLE ==
    ## CREATE TABLE `ping` (
    ##   `when` datetime NOT NULL,
    ##   `full_result` text NOT NULL,
    ##   `packets_transmitted` varchar(255) default NULL,
    ##   `received` varchar(255) default NULL,
    ##   `packet_loss` varchar(255) default NULL,
    ##   `time` varchar(255) default NULL
    ## ) ENGINE=ARCHIVE DEFAULT CHARSET=utf8 
    ##
    import MySQLdb
    import subprocess
     
    HOME = "***"
    PING = ["/bin/ping","-c5", "-v", "-W2", "%s" % (HOME)]
     
     
    dbcon = MySQLdb.connect(
        host = "127.0.0.1",
        user = "kedare",
        passwd = "****",
        db = "kedare")
     
    output = subprocess.Popen(PING, stdout=subprocess.PIPE).communicate()
    result =  output[0].split("\n")[-3].split(", ")
     
    ptransmitted = result[0]
    preceived = result[1]
    ploss = result[2]
    ptime = result[3]
     
    dbcur = dbcon.cursor()
    dbcur.execute("""
    INSERT INTO ping VALUES 
    (
        NOW(),
        %s,
        %s,
        %s,
        %s,
        %s
    );""", (output[0], ptransmitted, preceived, ploss, ptime))
    dbcur.close()
    Savez vous comment régler ce problème ?
    Merci

  2. #2
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Si 'duplicates' se place toujours au même endroit, il suffit de faire un test sur len(output) et l'éliminer quand il est présent.
    Si sa position est aléatoire ou si il y a d'autres 'parasites' alors il faut faire une recherche par mots-clés et nettoyer avant d'abonder la table Mysql
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  3. #3
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Par défaut
    Bonjour,

    Avec un peu de regexp, ça marche pas mal:

    P.S : attention contient du code python 3.x

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    #! /usr/bin/env python3.0
     
    import re
     
    def main():
        test_case_1 = "5 packets transmitted, 5 received, 0% packet loss, time 3996ms"
        test_case_2 = "5 packets transmitted, 4 received, +2 duplicates, 20% packet loss, time 3998ms"
     
        print(parse_ping_output(test_case_1))
        print(parse_ping_output(test_case_2))
     
    def parse_ping_output(ping_output):
        reobj = re.compile(r"([0-9]+)\spackets\stransmitted,\s([0-9]+)\sreceived,\s(\+([0-9]+)\sduplicates,\s)*([0-9]+)%\spacket\sloss,\stime\s([0-9]+)ms")
        match = reobj.search(ping_output)
        result_list = list()
        if match:
            find_result = reobj.findall(ping_output)
            # si match.group(3) est vide (None), alors la chaine contenant "+ x duplicates" n'existe pas
            # donc match.group(4) est aussi vide. Dans les deux cas, on ne veut pas match.group(3) qui est donc situé à l'index 2
            for i in range(len(find_result[0])):
                if i != 2:
                    result_list.append(find_result[0][i])
     
        return result_list
     
    if __name__ == "__main__":
        main()

    Input:

    "5 packets transmitted, 5 received, 0% packet loss, time 3996ms"
    "5 packets transmitted, 4 received, +2 duplicates, 20% packet loss, time 3998ms"
    output:

    ['5', '5', '', '0', '3996']
    ['5', '4', '2', '20', '3998']
    Après cela, il est toujours possible de retourner une liste d'entiers plutôt que de chaînes de caractères. Ca n'est pas très compliqué.

  4. #4
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut
    Personnellement, dans la RE, je remplacerais [0-9] par \d
    et je préfère mettre ? au lieu de * après (?:\+\d+\sduplicates,\s)

    Je n’ai pas mis de parenthèses autour de \d+ ci-dessus parce que kedare ne semble pas utiliser le nombre de duplicates, on peut donc se passer d’en faire un groupe.

    Pour éviter aussi que les parenthèses nécessaires pour englober la chaîne aléatoirement présente \+\d+\sduplicates,\s définissent une groupe, il faut ajouter ?: juste après la première parenthèse.

    D’autre part, écrire match = reobj.search(ping_output) juste pour pouvoir tester if m:
    puis faire find_result = reobj.findall(ping_output)
    c’est du gaspillage.
    Si l’objet match = reobj.search(ping_output) n’est pas None, alors il suffit de l’interroger pour obtenir certaines données.

    Ainsi quand m est un “Match Object“, m.groups() renvoie la succession des groupes sous forme de tuple.

    En évitant de définir des groupes superflus, on peut donc obtenir directement un tuple qui fournit les données voulues.

    Soit dit en passant, mettre la compilation reobj = re.compile("(\d+)...etc dans la fonction, c’est annuler l’intérêt d’une telle compilation qui normalement est faite une seule fois pour donner un objet regex qui sera utilisé plusieurs fois.

    kedare, ton code me donne à croire que
    output[0].split("\n")[-3] correspond aux chaînes
    ’5 packets transmitted, 5 received, 0% packet loss, time 3996ms’ et
    ’5 packets transmitted, 4 received, +2 duplicates, 20% packet loss, time 3998ms’
    que tu donnes en exemple
    et que
    ptransmitted est ’5 packets transmitted’
    preceived est ’4 received’
    ploss est ’20% packet loss’
    ptime est ’time 3998ms’

    J’ai donc placé différemment les parenthèses dans la RE pour que les groupes attrapés soient ceux-ci.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #! /usr/bin/env python3.0
     
    import re
     
    def main():
        test_case = ("5 packets transmitted, 5 received, 0% packet loss, time 3996ms",\
                     "5 packets transmitted, 4 received, +2 duplicates, 20% packet loss, time 3998ms")
     
        reobj = re.compile("(\d+\spackets\stransmitted),\s"
                           "(\d+\sreceived),\s"
                           "(?:\+\d+\sduplicates,\s)?"
                           "(\d+%\spacket\sloss),\s"
                           "(time\s\d+ms)")
     
        for ping_output in test_case:
            print reobj.search(ping_output).groups()
     
     
    if __name__ == "__main__":
        main()
    En définitive, c’est très court et ça devrait donner ça si je ne me trompe pas dans la compréhension de output[0].split("\n")[-3]

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    reobj = re.compile("(\d+)\spackets\stransmitted,\s"
                       "(\d+)\sreceived,\s"
                       "(?:\+\d+\sduplicates,\s)?"
                       "(\d+)%\spacket\sloss,\s"
                       "time\s(\d+)ms")
     
    output = subprocess.Popen(PING, stdout=subprocess.PIPE).communicate()
    result =  (output[0],) + reobj.search(output[0].split("\n")[-3]).groups())
     
     
    dbcur = dbcon.cursor()
    dbcur.execute("""
    INSERT INTO ping VALUES 
    (
        NOW(),
        %s,
        %s,
        %s,
        %s,
        %s
    );""" , result)
    dbcur.close()
    Nota:
    il me semble que l’expression dans le execute( INSERT ...) doit être
    execute("""INSERT INTO ping VALUES( NOW(),?,?,?,?,?);""" , result)
    et non pas
    execute("""INSERT INTO ping VALUES( NOW(),%s,%s,%s,%s,%s);""" , result)




    ---------------


    Il y a une autre solution, que je préfère parce qu’il n’y a pas besoin de faire intervenir de regex et qu’elle est certainement plus rapide:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    output = subprocess.Popen(PING, stdout=subprocess.PIPE).communicate()
    result =  output[0].split("\n")[-3].split(", ")
    result[2:-2] = []
    result = (output[0],) + tuple(result)
     
     
    dbcur = dbcon.cursor()
    dbcur.execute("""
    INSERT INTO ping VALUES 
    (
        NOW(),
        %s,
        %s,
        %s,
        %s,
        %s
    );""" % result)
    dbcur.close()
    C’est l’idee de Zavonen, mais sans avoir à tester la longueur de output[0].split("\n")[-3]


    PS

    L’expression «Parser le résultat d’un ping» me choque un peu.

    De quelques lectures,
    dont celle-ci
    http://en.wikipedia.org/wiki/Parsing
    je retire que le parsing, ou analyse syntaxique, s’applique à un texte ayant une structure relevant d’une grammaire. Cette grammaire s’exprime dans le texte sous forme d’une syntaxe, c’est à dire d’une structuration autour de tokens particuliers jouant un rôle clé (rôle grammatical).
    Le résultat d’un parsing est un objet (texte, arbre, etc...) dans lequel on retrouve les données initiales hiérarchisées d’une certaine manière.

    - dans le cas du code source d’un programme, le parsing repère, parmi les tokens qui constituent le code-source, les mots-clés du langage de programmation utilisé, en déduit la structure du code, vérifie que sa syntaxe est correcte et produit une représentation interne qui est ensuite transformée en language-machine

    - dans le cas d’un texte HTML, XML etc, les tokens particuliers sont les balises, les données initiales sont réorganisées en un structure hiérarchisée de nœuds et élements

    - le parsing en linguistique suit plus ou moins le même processus, bien que plus compliqué

    Veuillez me corriger si je suis trop schématique ou dans l’erreur, je ne suis pas un spécialiste.

    Bon, bref, je ne vois pas où sont les tokens particuliers relevant d’une grammaire dans un résultat de ping,
    et je ne trouve pas qu’un tuple ('5 packets transmitted', '5 received', '0% packet loss', 'time 3996ms') soit une structure hiérarchisée extraordinaire.

    Donc «parser le résultat d’un ping» me paraît une de ces expressions abusives qui abondent dans tous les domaines et qui sont embêtantes parce qu’elles finissent par instaurer un brouillard d’imprécision autour des termes. Et ça me chiffone.

  5. #5
    Membre extrêmement actif
    Avatar de kedare
    Homme Profil pro
    SRE
    Inscrit en
    Juillet 2005
    Messages
    1 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : SRE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 1 549
    Par défaut
    Merci
    Voila le script final :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    # -*- coding: cp1252 -*-
    ## Ping Logger
    ## The script ping an host and add an entry on the ping database (used with crontab each minutes)
    ##== MYSQL TABLE ==
    ## CREATE TABLE `kedare`.`ping` (
    ##`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
    ##`when` DATETIME NOT NULL ,
    ##`result` TEXT NOT NULL ,
    ##`transmitted` TINYINT NOT NULL ,
    ##`received` TINYINT NOT NULL ,
    ##`duplicates` TINYINT NOT NULL ,
    ##`loss` TINYINT NOT NULL ,
    ##`time` INT NOT NULL ,
    ##PRIMARY KEY ( `id` ) ,
    ##INDEX ( `when` , `transmitted` , `received` , `duplicates` , `loss` , `time` ) ,
    ##FULLTEXT (
    ##`result`
    ##)
    ##) ENGINE = MYISAM 
    ##
    import MySQLdb
    import subprocess
    import re
     
    HOME = "***.***.***.***"
    PING = ["/bin/ping","-c5", "-v", "-W2", "%s" % (HOME)]
     
    def main():
        dbcon = MySQLdb.connect(
        host = "127.0.0.1",
        user = "kedare",
        passwd = "****",
        db = "kedare")
     
        output = subprocess.Popen(PING, stdout=subprocess.PIPE).communicate()
        result =  output[0].split("\n")[-3]
        parsed = parse_ping_output(result)
        if parsed[2] == "":
            parsed[2] = "0"
        (ptransmitted, preceived, pduplicates, ploss, ptime) = [int(e) for e in parsed]
        dbcur = dbcon.cursor()
        dbcur.execute("""
        INSERT INTO ping VALUES 
        (
        DEFAULT,
        NOW(),
        %s,
        %s,
        %s,
        %s,
        %s,
        %s
        );""", (output[0], ptransmitted, preceived, pduplicates, ploss, ptime))
        dbcur.close()
     
    def parse_ping_output(ping_output):
        reobj = re.compile(r"([0-9]+)\spackets\stransmitted,\s([0-9]+)\sreceived,\s(\+([0-9]+)\sduplicates,\s)*([0-9]+)%\spacket\sloss,\stime\s([0-9]+)ms")
        match = reobj.search(ping_output)
        result_list = list()
        if match:
            find_result = reobj.findall(ping_output)
            for i in range(len(find_result[0])):
                if i != 2:
                    result_list.append(find_result[0][i])
     
        return result_list
     
    if __name__ == "__main__":
        main()

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Récupération résultat d'un ping
    Par jmmaugis dans le forum API standards et tierces
    Réponses: 4
    Dernier message: 04/05/2011, 10h05
  2. Résultat d'un 'ping smtp.gmail.com' chez vous ?
    Par peter27x dans le forum Débuter
    Réponses: 10
    Dernier message: 25/06/2010, 12h57
  3. Résultat d'un ping
    Par El-Diablo- dans le forum C++Builder
    Réponses: 2
    Dernier message: 06/07/2009, 11h07
  4. Réponses: 18
    Dernier message: 06/02/2008, 11h51
  5. Exploiter les résultats d'un ping ??
    Par Auzee dans le forum C
    Réponses: 1
    Dernier message: 13/06/2006, 14h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo