kleines XML-ParserScript

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Earl3000
User
Beiträge: 9
Registriert: Dienstag 1. Juli 2008, 10:47
Wohnort: DD

Hallo,

ich habe vor kurzen begonnen mir Pyhton zu Gemuete zu fuehren. Das klappt auch relativ gut...(':cry:')

Nun habe ich fuer ein Skript fuer NAGIOS ein Network Monitoring System (NMS) geschrieben, welches aus einer XML-Datei eines Temp-Sensors die aktuelle Temperatur ausliest und diese entsprechend verarbeitet.
Jedoch kam ich nun zu folgendem Problem:

das Skript 'check_temperature.py' kann ich in meinem Home-Verzeichnis ausfuehren.
Aber ich kann es nicht in einem anderen Verzeichnis unter einem anderen User (der Nagios user) ausfuehren.

Ausgabe (in meinem Verzeichnis): 'Temp OK: 23.0'
ist die gewuenschte Ausgabe und der Returnwert stimmt auch

Ausgabe (anderer Ort/ anderer User):
--> keinen Rueckgabewert vom Skript oder Fehler wie diesen:

Code: Alles auswählen

File "check_temperature2.py", line 57, in <module>
CurrentTemp = float(Temp)/10
TypeError: float() argument must be a string or a number
UND nun mein Script:

Code: Alles auswählen

#!/usr/bin/python

# -*- coding: utf-8 -*-
import sys
import os
import urllib

from optparse import OptionParser

parser = OptionParser("check_temperature -H http://... -w WarningTemp -c CriticalTemp")

##########################################################################

#PARAMETER # check_temperature -H http://... -w 25 -c 30

parser.add_option("-H", "--URL", dest="url")

parser.add_option("-w", "--Warning", dest="warning")

parser.add_option("-c", "--Critical", dest="critical")

(optionen, args) = parser.parse_args()

########################################

#Aus DATEI alles auslesen
#datei = open("tme.xml", "r")

#DateiInhalt = datei.readlines()

#datei.close()
########################################

# Aus INTERNET(URL) lesen

url="http://theta0/tme.xml"

Content = urllib.urlopen(url)


########################################

def ReadXML (Content, StartsWith, EndsWith):
    for Line in Content:
          if Line.count(StartsWith) > 0:
                   Temp = Line[Line.index(StartsWith) + len(StartsWith) :Line.index(EndsWith)]
                    return Temp


########################################

Temp = ReadXML(Content, "", "")
CurrentTemp = float(Temp)/10
WarningTemp = 26.0
CriticalTemp = 28.5

#AUSWERTUNG
if CurrentTemp ==None:
      print "ERROR - could not receive temperature from sensor or could not connect to sensor"
      print "Please be sure you have installed and connected your device to the network"
      exit (3)

if CurrentTemp >= WarningTemp:

    if CurrentTemp >= CriticalTemp:

          print "Temp Critical: ",CurrentTemp
          exit (2)
    print "Temp Warning: ",CurrentTemp
    exit (1)
else:
   print "Temp OK: ",CurrentTemp;
   exit (0)
Da ich unter Linux arbeite und darin noch nicht allzu viel Erfahrungen habe, koennte ich mir folgendes vorstellen:

1. die Berechtigungen fuer die Datei der jeweiligen User... schon geprueft --> kein Erfolg
2. der Pfad fuer das zu verwendende Python stimmt nicht mehr ueberein
3. sonstiges: ich bin zu dumm/ ein anderes Problem

Koennt ihr mir vielleicht helfen?
Ich verstehe das nicht, warumes an einem Ort laeuft und dort wo's soll nicht :?:

Danke


P.S hat jemand Ahnung von Nagios oder Bock Erfahrungen darueber auszutauschen?
Benutzeravatar
dennda
User
Beiträge: 17
Registriert: Montag 19. November 2007, 22:07

Hi.

Also generell erst mal: Wenn du XML parsen willst empfehle ich dir dringend einen XML-Parser zu nehmen und das nicht händisch zu tun.
Dazu kannst du z.B. folgendes zuhilfe nehmen:
  • * lxml (nicht in der stdlib)
    * ElementTree (stdlib)
    * xml.dom (stdlib)
Wenn du das wider meinen Ratschlag doch selbst zerwursten willst würd ich da mal ein paar Debug-Statements einbauen. Ich habe mir deinen Code nicht genauer angeschaut, aber ich könnte mir beispielsweise vorstellen, dass die Bedingung des if-Statements in Zeile 46 nicht zu True evaluiert wird. Dementsprechend würde das da nicht weiterlaufen und die Funktion würde None zurückliefern.

Das nur mal als kurzen Ratschlag.

Es gibt noch einiges was man zu deinem Snippet sagen könnte, vielleicht fühlt sich ja jemand mit mehr Zeit berufen das zu tun. :)
BlackJack

@Earl3000: Also so wie `ReadXML()` aufgerufen wird, kommt da immer eine leere Zeichenkette zurück wenn die Datei minestens eine Zeile enthält. Selbst wenn die leer sein sollte. Denn der "slice" ist letztendlich immer ``Line[0:0]``:

Code: Alles auswählen

In [1]: ''.count('')
Out[1]: 1

In [2]: line = 'hallo'

In [3]: line.count('')
Out[3]: 6

In [4]: line.index('')
Out[4]: 0

In [5]: len('')
Out[5]: 0
Das Skript kann also bei Dir gar nicht so funktionieren wie Du behauptest.
Earl3000
User
Beiträge: 9
Registriert: Dienstag 1. Juli 2008, 10:47
Wohnort: DD

Hi dennda,

danke erstmal dass du etwas Zeit fuer mein Problem gefunden hast :)
dennda hat geschrieben:
  • * lxml (nicht in der stdlib)
    * ElementTree (stdlib)
    * xml.dom (stdlib)
in meiner ersten Version habe ich mit dem xml.dom.minidom geparst.
Letztendlich hatte ich mich aber gegen einen solchen Parser entschieden, weil er fuer meine Zwecke aber zu viel Arbeit macht...
ich denke er braucht nicht erst alles komplett zu parsen, wenn ich doch nur einen einzigen Wert benoetige


Wuerde mich aber feuen, wenn sich jemand finden wuerde, der noch einiges zu meinem Codesnippet sagen koennte, da ich gerne Erfahrungen,Kritik und Anmerkungen entgegennehme, denn ich will ja noch etwas lernen...

Die Funktion 'ReadXML' liest mir aber genau den Wert der XML-Datei aus, denn ich brauche, auch mit den if-Bedingungen.
Jedoch halt nur in meinem Verzeichnis, was ja fuer mich halt so komisch ist.
Warum geht das nur dort und wo anders nicht.

Was meinst du mit Debug-Statements?
Man hat's nicht leicht, aber leicht hat's einen. :wink:
Earl3000
User
Beiträge: 9
Registriert: Dienstag 1. Juli 2008, 10:47
Wohnort: DD

Okay,

ich habe aber trotzdem die moeglichkeit, komischerweise meinen Wert zu erhalten.
Weiss jemand warum. Gibt es irgendwelche anderen Einstellungen in meinem home???
Aber okay, wie sehe denn die Alternative aus? Muss ich wieder zu einem solchen Parser zurueckgreifen? Ich hatte den doch seit der letzten erfolgreich verabschiedet...:cry:
Man hat's nicht leicht, aber leicht hat's einen. :wink:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Earl3000 hat geschrieben:in meiner ersten Version habe ich mit dem xml.dom.minidom geparst.
Letztendlich hatte ich mich aber gegen einen solchen Parser entschieden, weil er fuer meine Zwecke aber zu viel Arbeit macht...
ich denke er braucht nicht erst alles komplett zu parsen, wenn ich doch nur einen einzigen Wert benoetige
Das nimm eben SAX. Das Problem mit XML ist, dass immer irgendwelche Leute denken sie könnten halbfunktionierende Parser nutzen und das wäre schon in Ordnung so. Ich würde trotzdem lxml nehmen, außer es gibt spezielle Gründe die dagegen sprechen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
dor_neue
User
Beiträge: 74
Registriert: Montag 16. Juni 2008, 18:51

kannst Du vielleicht mal den Inhalt der XML posten?
Dann kann man sich nen Überblick verschaffen ob ein parser wirklich notwendig ist...

// Edit \\

@Audax & Leonidas:
Is zwar richtig das man immer versuchen sollte, das richtige Werkzeug zu nehmen um zu arbeiten, allerdings im Verhältniss...
Ich weiß wie sehr ich zu kämpfen hab mit XML und Python und kann mir vorstellen um nur eine einzige Zeile, bzw. einen einzigen Wert auszulesen is das nen bissel viel...
Oder hab ich da nen großen Denkfehler dabei?!?
Zuletzt geändert von dor_neue am Dienstag 1. Juli 2008, 12:35, insgesamt 1-mal geändert.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Earl3000
User
Beiträge: 9
Registriert: Dienstag 1. Juli 2008, 10:47
Wohnort: DD

das hier ist meine XML-Datei:

Code: Alles auswählen

<thermometer>
<title>
Ethernet thermometer TME designed by Papouch s.r.o. - www.papouch.com
</title>
<description>INDOOR</description>
<temperature>251</temperature>
<mintemperature>"N"</mintemperature>
<maxtemperature>"N"</maxtemperature>
</thermometer>
mir ging es darum 'nur' die aktuelle Temp auszulesen.
Was ratet ihr? Gleich einen kompletten Parser dazu anzuwerfen?
Man hat's nicht leicht, aber leicht hat's einen. :wink:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

dor_neue hat geschrieben:Is zwar richtig das man immer versuchen sollte, das richtige Werkzeug zu nehmen um zu arbeiten, allerdings im Verhältniss...
Es gibt bei der Verarbeitung von XML zwei Möglichkeiten: Parser oder ohne Parser. Letztere ist eigentlich immer falsch.
Von wegen Verhältnis: ein funktionierender Parser ist definitiv problemloser als ein selbstgeschriebener, denn jemand der XML versteht hat ihn geschrieben, optimiert und getestet. Also warum selbst einen schreiben, wenn es doch schon welche gibt die besser sind? Selberschreiben ist in diesem Kontext Eindeutig unverhältnismäßig kompliziert.
dor_neue hat geschrieben:Ich weiß wie sehr ich zu kämpfen hab mit XML und Python und kann mir vorstellen um nur eine einzige Zeile, bzw. einen einzigen Wert auszulesen is das nen bissel viel...
Mit lxml sind das vielleicht 2 Zeilen. Mit ET warscheinlich ganz ähnlich. Mit DOM etwas mehr und mit SAX noch viel mehr. Du siehst: je besser/mächtiger der Parser, desto einfacher wird es.

Edit: Eine einfache Implementierung die davon ausgeht dass Temperatur immer an der gleichen Stelle steht:

Code: Alles auswählen

from xml.etree import ElementTree as ET
tree = ET.fromstring("""<thermometer>
<title>
Ethernet thermometer TME designed by Papouch s.r.o. - www.papouch.com
</title>
<description>INDOOR</description>
<temperature>251</temperature>
<mintemperature>"N"</mintemperature>
<maxtemperature>"N"</maxtemperature>
</thermometer>""")
print ET.getchildren()[2].text
Edit: Letzte Zeile geht noch anders, die findet jetzt den Temperatur-Node egal wo er steht.

Code: Alles auswählen

print [e for e in tree.getchildren() if e.tag == 'temperature'][0].text
Zuletzt geändert von Leonidas am Dienstag 1. Juli 2008, 12:55, insgesamt 4-mal geändert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Earl3000 hat geschrieben:mir ging es darum 'nur' die aktuelle Temp auszulesen.
Was ratet ihr? Gleich einen kompletten Parser dazu anzuwerfen?
Natürlich. XML darfst du auch nicht anders parsen, weil sich das Dokument nach den XML Regeln ändern kann und du es trotzdem noch laden können musst.

Korrekte Lösung:

Code: Alles auswählen

>>> from lxml import etree
>>> etree.fromstring("""<thermometer>
... <title>
... Ethernet thermometer TME designed by Papouch s.r.o. - www.papouch.com
... </title>
... <description>INDOOR</description>
... <temperature>251</temperature>
... <mintemperature>"N"</mintemperature>
... <maxtemperature>"N"</maxtemperature>
... </thermometer>""")
<Element thermometer at 73cc90>
>>> _.findtext('temperature')
'251'
Wahlweise statt lxml halt einen anderen ElementTree nehmen.
TUFKAB – the user formerly known as blackbird
dor_neue
User
Beiträge: 74
Registriert: Montag 16. Juni 2008, 18:51

Mkay, ich nehm alles zurück und behaupte das Gegenteil...
Ich hatte es mit SAX versucht und bin daran im 1. Versuch kläglich gescheitert...
Aber auf meiner ToDo-Liste steht lxml jetzt mit ganz oben...
Jetzt aber wieder zurück zum Thema von Earl3000, damit dem guten Mann auch geholfen werden kann...
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

dor_neue hat geschrieben:Ich hatte es mit SAX versucht und bin daran im 1. Versuch kläglich gescheitert...
SAX ist für sowas auch nicht gedacht. SAX kann man nutzen, wenn man auf eine Stream aus Events was tun will. zB basiert Genshi auf einem SAX Stream.
TUFKAB – the user formerly known as blackbird
Earl3000
User
Beiträge: 9
Registriert: Dienstag 1. Juli 2008, 10:47
Wohnort: DD

Danke an alle, insbesondere an mitsuhiko & leonidas

Habe mich dazu ueberreden lassen wieder einen PArser zu benutzen.
Habe ihn jetzt eingebaut und werde nun sehen ob mein bestehendes Problem bei den versch. Verzeichnissen und Usern damit behoben ist...
Man hat's nicht leicht, aber leicht hat's einen. :wink:
Earl3000
User
Beiträge: 9
Registriert: Dienstag 1. Juli 2008, 10:47
Wohnort: DD

Also nochmal:

ich habe den mein Code jetz umgeaendert.
weil's mittlerweile etwas mehr geworden ist :http://paste.pocoo.org/show/78253/

Das Problem besteht aber nach wie vor:
in meinem home-Verzeichnis ( /home/meinVerzeichnis/... ) kann ich das Skript 'check_temperature.py' ausfuehren und ein der andere Nutzer auch.
--> Ausgabe: Temp OK: 25.3
genauso soll es sein. ( mittlerweile ist's hier auch waermer geworden :lol: )

Wenn ich dieses Skript aber unter einem anderen Verzeichnis ( /usr/local/nagios/libexec ) ausfuehre geht dies nicht mehr !!!
Weder ich noch der andere USer koennen es erfolgreich ausfuehren.
--> Ausgabe:

Code: Alles auswählen

Traceback (most recent call last):
  File "./check_temperature2.py", line 61, in <module>
    url = urllib2.urlopen(url)                  # opens url (XML-file)
  File "/usr/lib/python2.5/urllib2.py", line 121, in urlopen
    return _opener.open(url, data)
  File "/usr/lib/python2.5/urllib2.py", line 380, in open
    response = meth(req, response)
  File "/usr/lib/python2.5/urllib2.py", line 491, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib/python2.5/urllib2.py", line 418, in error
    return self._call_chain(*args)
  File "/usr/lib/python2.5/urllib2.py", line 353, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.5/urllib2.py", line 499, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
urllib2.HTTPError: HTTP Error 503: Service Unavailable

Woran kann das also liegen?

Ich bitte nochmal um so eine tolle und schnelle Antwortrunde.
Danke


P.S.: fuer das andere Skript von vorhin trifft genau dasselbe zu...
Man hat's nicht leicht, aber leicht hat's einen. :wink:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ist doch ganz einfach: http://www.theta0.com/tme.xml ist schlichtweg nicht verfügbar.

PS: Inline-Kommentare stinken. Ersetze sie bitte durch welche die über der betreffenden Zeile sind.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Earl3000
User
Beiträge: 9
Registriert: Dienstag 1. Juli 2008, 10:47
Wohnort: DD

Hmmm... :? das dachte ich auch...

Aber das ist ziemlich doof, denn ich kann die Skripts gleichzeitig abschicken/aufrufen und das eine antwortet mit Erfolg un ddas andere nicht...:?:
Man hat's nicht leicht, aber leicht hat's einen. :wink:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Earl3000 hat geschrieben:Aber das ist ziemlich doof, denn ich kann die Skripts gleichzeitig abschicken/aufrufen und das eine antwortet mit Erfolg un ddas andere nicht...:?:
Und wie erklärst du dir dass die Webseite bei einem Down ist und beim anderen nicht?

PS: Man vergleich auch nicht ``None`` mit ``==`` sondern prüft mittels ``is``.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Earl3000
User
Beiträge: 9
Registriert: Dienstag 1. Juli 2008, 10:47
Wohnort: DD

ja das ist ja das was mir so Kopfzerbrechen bereitet ...
Ich verstehe es nicht und bin noch immer auf der Suche nach der Loesung.
Dacht nur Ihr haettet vielleicht gleich eine passende parat.
Man hat's nicht leicht, aber leicht hat's einen. :wink:
Earl3000
User
Beiträge: 9
Registriert: Dienstag 1. Juli 2008, 10:47
Wohnort: DD

Ich habe erfolgreich das Problem beheben koennen.
Ich kann nun an beiden Orten und unter verschiedenen User das Skript ausfuehren.
:!: :!: :!:

Loesung des Problems:
bei der url musste der komplette Hostname mit Domaene verwendet werden.

K.A. warum aber jetzt geht's
Man hat's nicht leicht, aber leicht hat's einen. :wink:
Antworten