| Your continued donations keep Swissjabber running! |
Python Bot
Aus Swissjabber
Es kann sehr praktisch sein, einen eigenen Bot zu haben. Dieser kann die unterschiedlichsten Anforderungen und Wünsche erfüllen. Mit python-jabberbot steht ein Framework zur Verfügung, welche die Erstellung von Jabber-Bots auch für weniger erfahrene Benutzer möglich macht.
Inhaltsverzeichnis |
Einrichtung
python-jabberbot muss installiert sein. Seine Abhängigkeit ist python-xmpp, dieses Paket ist wahrscheinlich auf allen gängigen Distributionen im Paketmanagement-System verfügbar. Unter Debian und Fedora sind fertige Pakete vorhanden. Auf allen anderen Linux-Plattformen muss es gemäss Dokumentation installiert werden.
Unter Debian
apt-get install python-jabberbot
Unter Fedora
yum -y install python-jabberbot
Erster Bot
Der erste Bot kann auf einen Befehl eine Antwort geben. Nichts weltbewegendes, aber ein nettes Beispiel zur Funktionsdemonstration. Der erste Schritt ist der Import der benötigten Module.
from jabberbot import JabberBot, botcmd
Im ersten Abschnitt wird der allgemeine Teil des Bot definiert. Der Klasse-Namen kann frei gewählt werden. Der Beschreibungsteil wird von python-jabberbot dazu benutzt, beim Aufrufen der Hilfe Informationen über den Bot preiszugeben. Die Funktion des Bot und auch einen Kontakt-Adresse sollte als Minimum definiert werden (siehe auch Bot).
class pyBot(JabberBot):
"""
This is a simple Jabber bot. It can give you an answer.
Contact: Du <du at irgendeinedomain.ch>
"""
Die Befehle werden nach der Zeile @botcmd, die als Dekorator dient, definiert. Mit @botcmd(hidden=True) können Befehle von der Anzeige durch help ausgeschlossen werden. Der Aufbau ist immer gleich: def einBefehl( self, mess, args): , ein Kommentar, welcher auch bei der Eingabe von help verarbeitet wird und danach, was zu tun ist. return gibt die Ausgabe dann an den Benutzer zurück.
@botcmd
def hello( self, mess, args):
"""Say hello"""
return 'Hello Fabian, I am your python jabber bot.'
Die Anmelde-Daten bestehen aus einem Jabber-Konto und den Passwort. Der Klasse-Name aus dem ersten Abschnitt muss hier benutzt werden.
bot = pyBot('fabian.a@swissjabber.ch','xxxx')
Zuletzt muss dem Bot gesagt werde, dass er immer laufen soll.
bot.serve_forever()
Der komplette Code kann unter pybot01.py gefunden werden. Ein weiteres Beispiel für einen ersten Bot ist das Erzeugen von Echos. Die eingegebene Nachricht wird wieder zurückgeschickt.
@botcmd
def echo( self, mess, args):
"""I am your echo"""
return args
Verwendung
Im entsprechenden Verzeichnis kann nun der Bot gestartet werden.
python pybot01.py
[fab@localhost Documents]$ python pybot01.py /usr/lib/python2.6/site-packages/xmpp/auth.py:24: DeprecationWarning: the sha module is deprecated; use the hashlib module instead import sha,base64,random,dispatcher,re /usr/lib/python2.6/site-packages/xmpp/auth.py:26: DeprecationWarning: the md5 module is deprecated; use hashlib instead import md5 /usr/lib/python2.6/site-packages/xmpp/transports.py:315: DeprecationWarning: socket.ssl() is deprecated. Use ssl.wrap_socket() instead. tcpsock._sslObj = socket.ssl(tcpsock._sock, None, None) pyBot : *** roster *** pyBot : admin-bot@swissjabber.ch pyBot : whois@swissjabber.ch pyBot : fabian.a@swissjabber.ch pyBot : *** roster *** pyBot : bot connected. serving forever.
Die Fehlermeldungen sind etwas unschön, stören den Betrieb aber nicht. Wenn der Roster angezeigt wird und der der Bot verbunden ist, ist er bereit und wartet auf Befehle. Falls sich der Bot nicht verbinden kann, sollte die Konto-Daten geprüft werden.
pyBot : unable to authorize with server. pyBot : could not connect to server - aborting.
Der Hilfe-Befehl gibt Bot-Daten und die vorhandenen Befehle aus.
help
Der einzige Befehl, der vorhanden ist, ist hello.
hello
Wird ein unbekannter Befehl eingegeben, verarbeitet das Jabberbot-Framework die Eingabe, respektive gibt eine entsprechende Meldung aus.
Beenden
Der Bot kann mit Ctrl + c beendet werden, wenn er nicht mehr gebraucht wird.
Nachrichten-Verarbeitung
Das Jabberbot-Framework kann Nachrichten-Teile, wie den Absender und den Nachrichttext, direkt ansprechen. Die Daten müssen nicht zuerst extraiert werden. get.Body() gibt den Nachrichtentext zurück
@botcmd
def messagebody( self, mess, args):
"""Displays the message body"""
return mess.getBody()
Der Absender kann mit get.From() identifiziert werden. In diesen Beispielen gibt dies den eigenen Benutzer-Namen zurück.
@botcmd
def sender( self, mess, args):
"""Displays the sender of the message"""
return mess.getFrom()
Zum Bestimmen des Nachrichten-Type kann get.Type() benutzt werden.
@botcmd
def messagetype( self, mess, args):
"""Displays the type of the message"""
return mess.getType()
Bestimmen der Eigenschaften kann mit getProperties() gemacht werden.
@botcmd
def properties( self, mess, args):
"""Displays the properties of the message"""
return mess.getProperties()
System-Befehle
Zitate
Mit fortune lassen sich auf der Kommandozeile Zitate anzeigen. Diese lassen sich auch an einen Klient schicken. Natürlich muss fortune installiert sein, eventuell ist der Pfad anzupassen.
Zusätzlich zu den oben angegebenen Daten muss das os-Modul importiert werden.
import os
Der Code setzt sich aus dem Aufruf von fortune als System-Befehl und dem Zitat als Rückgabewert zusammen.
@botcmd
def fortune( self, mess, args):
"""Get a random quote"""
fortune = os.popen('/usr/bin/fortune').read()
return fortune
Jeder Aufruf gibt ein neues Zitat zurück. Der komplette Source-Code befindet sich hier.
Eingeloggte Benutzer
Statt eine SSH-Verbindung zum Server herzustellen, kann auch Jabber benutzt werden, um zu sehen, wer eingelogt ist.
Der Code führt who als System-Befehl aus. Der Unterschied zu fortune ist minimal. Nach dieser Konstruktion lassen sich weitere Befehle integrieren.
@botcmd
def who(self, mess, args):
"""Display who's currently logged in"""
who = os.popen('/usr/bin/who').read().strip()
return who
Der Aufruf gibt eine Liste zurück.
fab tty1 2009-12-11 20:54 (:0) fab pts/0 2009-12-12 21:16 (:0.0) fab pts/1 2009-12-12 21:56 (:0.0) fab pts/2 2009-12-12 23:59 (:0.0) fab pts/3 2009-12-13 09:15 (:0.0)
Der komplette Source-Code dieses Beispiels kann hier gefunden werden.
Zeit
Durch das Senden von time an den Bot, wird die aktuelle Zeit der Maschine, auf welcher der Bot läuft, übertragen. Damit mit Zeitangaben gearbeitet werden kann, muss das datetime-Modul importiert werden.
import datetime
Je nach persönlichem Geschmack kann das Ausgabe-Format angepasst werden.
@botcmd
def time( self, mess, args):
"""Displays current server time"""
return datetime.datetime.today().strftime('%A, %d. %B %Y %H:%M:%S')
Die Antwort des Bot ist die formatierte Datum/Zeit-Angabe.
Sunday, 13. December 2009 00:52:29
Oder das Beispiel aus der Dokumentation von python-jabberbot.
@botcmd
def time( self, mess, args):
"""Displays current server time"""
return str(datetime.datetime.now())
Der Source-Code pytimebot.py dieses Beispiels.
Whois
Möchten nun Befehle ausgeführt werden, welche ein Argument erfordern, funktioniert es mit dem bisherigen Beispielen nicht. Das Argument ist args und muss analog dem Aufruf auf der Kommanozeile bei der Ausführung mitgegeben werden.
@botcmd
def whois( self, mess, args):
"""Displays details about a domain name or an IP address"""
whois = os.popen('/usr/bin/whois ' + args).read().strip()
return whois
Wird die Zeile
whois = os.popen('/usr/bin/whois ' + args).read().strip()
durch
whois = os.popen('/usr/bin/nslookup ' + args).read().strip()
ersetzt oder als separater Befehl eingefügt, lassen sich weitere Informationen gewinnen. Natürlich dann auch eine Kombination erfolgen.
@botcmd
def whois( self, mess, args):
"""Displays details about a domain name or an IP address"""
whois = os.popen('/usr/bin/whois ' + args).read().strip()
nslook = os.popen('/usr/bin/nslookup ' + args).read().strip()
return 'Whois\n--------\n%s\n\nNslookup\n--------------\n%s' % ( whois, nslook, )
Eine ähnliche Funktion stellt der Whois-Bot bereit. Der Source-Code zu diesem Beispiel befindet sich hier.
System-Informationen
Für Benutzer kann es interessant, mehr über das System zu erfahren, auf welchem der Bot läuft.Das os-Modul importiert sein.
@botcmd
def server(self, mess, args):
"""Displays server information"""
server = os.uname()
data = "System: \t" + server[0] + \
"\n" +"FQDN: \t" + server[1] + \
"\n" +"Kernel: \t" + server[2] + \
"\n" +"Data: \t" + server[3] + \
"\n" +"Arch: \t" + server[4]
return data
Die Ausgabe ist dann als Liste formatiert.
System: Linux FQDN: localhost.localdomain Kernel: 2.6.31.6-162.fc12.i686 Data: #1 SMP Fri Dec 4 01:09:09 EST 2009 Arch: i686
Der Source-Code zu diesem Beispiel befindet sich hier. Ein alternatives Beispiel kann im Beispiel-Code des Jabberbot-Framework gefunden werden.
Uptime
Interessiert, wie lange das System, auf welchem der Bot ausgeführt wird, schon läuft? Dann ist dieser Code-Block das Richtige. Grosse Teile dieses Codes sind an die Arbeit von Hubert Chathi und seinem System status bot angelehnt und abgeschaut.
@botcmd
def uptime(self, mess, args):
"""Displays the server uptime"""
uptime = open('/proc/uptime').read().split()[0]
# This is heavily based on the work of Hubert Chathi and his System status bot.
uptime = float(uptime)
(uptime,secs) = (int(uptime / 60), uptime % 60)
(uptime,mins) = divmod(uptime,60)
(days,hours) = divmod(uptime,24)
uptime = 'Uptime: %d day%s, %d hour%s %02d min%s' % (days, days != 1 and 's' or '', hours, hours != 1 and 's' or '', mins, mins != 1 and 's' or '')
return uptime
Die Ausgabe sieht dann wie folgt aus:
Uptime: 1 day, 19 hours 24 mins
Der Source-Code kann hier gefunden werden.
Umfangreichere Ausgabe
Bei der Eingabe von help wird, wie bereits erwähnt, eine Liste mit den verfügbaren Befehlen an den Client geschickt. Es stehen zwei Blöcke zur Verfügung, um die Ausgabe statisch zu erweitern.
def top_of_help_message(self):
"""Returns a string that forms the top of the help message"""
return "pyBot - just a simple Bot"
def bottom_of_help_message(self):
"""Returns a string that forms the bottom of the help message"""
return "Version: 0.0.1"
Die Ausgabe der neuen Kopf- und Fusszeile:
pyBot - just a simple Bot
This is a simple Jabber bot. It can give you an answer.
Contact: Fabian Affolter <fabian at bernewireless.net>
hello: Say hello
Version: 0.0.1
Trennen von Konfiguration und Code
Sobald der Bot auch anderen Benutzern zur Verfügung stehen soll, tritt ein Problem auf. Der Benutzername und das Passwort sind bis jetzt im Code integriert. Damit es die Benutzer einfacher haben, sollten die Anmeldedaten in eine separate Datei ausgelagert werden. Als erstes Beispiel heisst die Datei mein-pybot und befindet sich im gleichen Verzeichnis wie der Bot. Als Inhalt muss sie folgende Daten enthalten:
[pybot] username = fabian.a@swissjabber.ch password = xxxx
Für das Einlesen von Daten steht ein Python-Modul (ConfigParser) zur Verfügung.
import ConfigParser
In config.read wird der Dateiname angegeben.
config = ConfigParser.RawConfigParser() config.read(['mein-pybot','mein-pybot'])
Die Daten müssen dann anstelle der Anmeldedaten eingefügt werden. Zuerst wird der Abschnitt (pybot) definiert und danach der Wert (username oder password).
bot = pyBot(config.get('pybot','username'), config.get('pybot','password'))
Wollen nun mehrere Benutzer auf dem gleichen System den Bot benutzen, funktioniert es so nicht, da nur eine Konfigurationsdatei vorhanden ist. Jeder Benutzer sollte seine eigenen Konfigurationsdatei in seine Benutzerverzeichnis (~/.mein-pybot) besitzen.
Eine umfangreichere Version kann im Code von pySysBot gefunden werden.


