Seite 1 von 1

Notenspiegel vom Prüfungsamt abrufen (QIS)

Verfasst: Donnerstag 15. März 2007, 18:15
von nixdorf
Diese Klasse kann benutzt werden um von einem QiS Server den Notenspiegel abzurufen. Einige Hochschulen bieten dieses Selbstbedienungssystem an.
Die Klasse ist mit der FH Aachen getestet. Für andere Hochschulen sind evtl. einige Modifikationen nötig.

Code: Alles auswählen

#
# usage: import qis
#        qis = qis.Qis ('user', 'passwort')
#        print qis.get_notenspiegel ()
#

import httplib, urllib, re

def unescape (s):
   if '&' not in s:
      return s
   s = s.replace("<", "<")
   s = s.replace(">", ">")
   s = s.replace("&apos;", "'")
   s = s.replace(""", '"')
   s = s.replace(" ", " ")
   s = s.replace("&", "&")
   return s

class Qis:
   def __init__(self, qis_user, qis_password):
      conn = httplib.HTTPSConnection ('www.qis.fh-aachen.de')
      
      # Anmeldeseite aufrufen um die Sessionid rauszufinden 
      conn.request('GET', '/qisserver/rds?state=user&type=0&application=lsf')
      response = conn.getresponse()
      response.read ()
      
      params_anmeldung = urllib.urlencode ({'username':"%s" % qis_user, 'password': "%s" % qis_password,'submit':'Ok'})
      headers_anmeldung = {"Content-type": "application/x-www-form-urlencoded", "Cookie" : "JSESSIONID=%s" % re.search ('JSESSIONID=(.*?);', response.getheader ('Set-Cookie')).group (1)} 
         
      # Anmeldung durchfuehren 
      conn.request ('POST', "/qisserver/rds?state=user&type=1", params_anmeldung, headers_anmeldung)
      response = conn.getresponse ()
      # Sessionid aktualisieren
      header_cookie = {"Cookie" : "JSESSIONID=%s" % re.search ('JSESSIONID=(.*?);', response.getheader ('Set-Cookie')).group (1)} 
      response.read ()
               
      # Menue abrufen
      conn.request ('GET', "/qisserver/rds?state=user&type=0&category=menu.browse&startpage=portal.vm", None, header_cookie)
      response = conn.getresponse ()
      content = response.read ()
      asi = re.search (';asi=(.*?)\"', content).group (1)
      
      # Notenspiegel abrufen
      conn.request ('GET', "/qisserver/rds?state=htmlbesch&moduleParameter=Student&menuid=notenspiegel&asi=%s" % asi, None, header_cookie)
      response = conn.getresponse ()
      self.notenspiegel  = response.read ()
      
      # Abmeldung      
      conn.request ('GET', "/qisserver/rds?state=user&type=4&category=auth.logout&menuid=logout", None, header_cookie)
      response = conn.getresponse()
      response.read ()
            
      # Verbindung beenden
      conn.close ()

   def get_notenspiegel (self, output_codec = 'utf8'):
      if not self.notenspiegel:
         return None
      pruefungen = []
      a = re.findall ('class=\"posrecords\"(.*?)</tr>', self.notenspiegel, re.S)      
      for b in a:
         pruefung = {}
         c = re.findall ('class=\"posrecords\">(.*?)</td>', b, re.S)
         pruefung["Fach"]     = unicode (unescape (c[0]), "cp1252" ).encode (output_codec)
         pruefung["Semester"] = unicode (unescape (c[1]), "cp1252" ).encode (output_codec)
         pruefung["Datum"]    = unicode (unescape (c[2]), "cp1252" ).encode (output_codec)
         pruefung["Note"]     = unicode (unescape (c[3]), "cp1252" ).encode (output_codec)
         pruefung["Credits"]  = unicode (unescape (c[4]), "cp1252" ).encode (output_codec)
         pruefung["Status"]   = unicode (unescape (c[5]), "cp1252" ).encode (output_codec)
         pruefung["Versuch"]  = unicode (unescape (c[6]), "cp1252" ).encode (output_codec)
         pruefungen.append (pruefung)
      return pruefungen
Als Beispiel, was man mit der Klasse machen kann habe ich quick&dirty ein kleines Sckript geschrieben.
Wenn man das bei jedem Rechnerstart ausführt, wird man über neue Noten informiert.

Code: Alles auswählen

import sys, qis, gtk

check = False
if len (sys.argv) > 1 and sys.argv [1] == "check":
   check = True

qis = qis.Qis ('user', 'passwort')
pruefungen = qis.get_notenspiegel ()

anzahl = 0

if check:
   try:
      fo = file ('anzahl_noten.dat')
      anzahl = int (fo.read ()) 
      fo.close ()
   except:
      pass
   
if not check or len (pruefungen) > anzahl:
   if check:
      file ('anzahl_noten.dat', "w").write (str (len (pruefungen)))
   
   text = ""
   
   for pruefung in pruefungen:
      if float (pruefung["Note"]) <= 4.0:
         text = text + "<span size=\"large\"><i>%s</i></span>\nSemester: %s Datum: %s\nNote: <span foreground=\"green\"><b>%s</b></span> Credits: %s\nStatus: %s Versuch: %s \n\n" % (pruefung["Fach"],pruefung["Semester"],pruefung["Datum"],pruefung["Note"],pruefung["Credits"],pruefung["Status"],pruefung["Versuch"])
      else:
         text = text + "<span size=\"large\"><i>%s</i></span>\nSemester: %s Datum: %s\nNote: <span foreground=\"red\"><b>%s</b></span> Credits: %s\nStatus: %s Versuch: %s \n\n" % (pruefung["Fach"],pruefung["Semester"],pruefung["Datum"],pruefung["Note"],pruefung["Credits"],pruefung["Status"],pruefung["Versuch"])      
   
   mbox = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, text)
   mbox.set_markup (text)
   try:
      response = mbox.run()
   finally:
      mbox.hide()
      mbox.destroy()

Verfasst: Sonntag 18. März 2007, 20:52
von abgdf
Hast Du auch eins, um Noten auf dem QiS Server zu schreiben :mrgreen: ?

Verfasst: Mittwoch 21. März 2007, 16:00
von nixdorf
Leider noch nicht :twisted:

wxPython Anzeige

Verfasst: Freitag 23. März 2007, 19:09
von nixdorf
Ich habe mal just for fun ein kleines wx Fenster gemacht, das die Ergebnisse der Abfrage anzeigt. Das Abfragemodul musste ich leicht verändern.

qis.py

Code: Alles auswählen

#
# usage: import qis
#        qis = qis.Qis ('vorname.nachname', 'passwort')
#        print qis.get_notenspiegel ()
#

import httplib, urllib, re

def unescape (s):
   if '&' not in s:
      return s
   s = s.replace("<", "<")
   s = s.replace(">", ">")
   s = s.replace("&apos;", "'")
   s = s.replace(""", '"')
   s = s.replace(" ", " ")
   s = s.replace("&", "&")
   return s

class Qis:
   def __init__(self, qis_user, qis_password):
      conn = httplib.HTTPSConnection ('www.qis.fh-aachen.de')
      
      # Anmeldeseite aufrufen um die Sessionid rauszufinden 
      conn.request('GET', '/qisserver/rds?state=user&type=0&application=lsf')
      response = conn.getresponse()
      response.read ()
      
      params_anmeldung = urllib.urlencode ({'username':"%s" % qis_user, 'password': "%s" % qis_password,'submit':'Ok'})
      headers_anmeldung = {"Content-type": "application/x-www-form-urlencoded", "Cookie" : "JSESSIONID=%s" % re.search ('JSESSIONID=(.*?);', response.getheader ('Set-Cookie')).group (1)} 
         
      # Anmeldung durchfuehren 
      conn.request ('POST', "/qisserver/rds?state=user&type=1", params_anmeldung, headers_anmeldung)
      response = conn.getresponse ()
      # Sessionid aktualisieren
      header_cookie = {"Cookie" : "JSESSIONID=%s" % re.search ('JSESSIONID=(.*?);', response.getheader ('Set-Cookie')).group (1)} 
      response.read ()
               
      # Menue abrufen
      conn.request ('GET', "/qisserver/rds?state=user&type=0&category=menu.browse&startpage=portal.vm", None, header_cookie)
      response = conn.getresponse ()
      content = response.read ()
      asi = re.search (';asi=(.*?)\"', content).group (1)
      
      # Notenspiegel abrufen
      conn.request ('GET', "/qisserver/rds?state=htmlbesch&moduleParameter=Student&menuid=notenspiegel&asi=%s" % asi, None, header_cookie)
      response = conn.getresponse ()
      self.notenspiegel  = response.read ()
      
      # Abmeldung      
      conn.request ('GET', "/qisserver/rds?state=user&type=4&category=auth.logout&menuid=logout", None, header_cookie)
      response = conn.getresponse()
      response.read ()
            
      # Verbindung beenden
      conn.close ()

   def get_notenspiegel (self):
      if not self.notenspiegel:
         return None
      pruefungen = []
      a = re.findall ('class=\"posrecords\"(.*?)</tr>', self.notenspiegel, re.S)      
      for b in a:
         pruefung = []
         c = re.findall ('class=\"posrecords\">(.*?)</td>', b, re.S)
         pruefung.append (unicode (unescape (c[0]), "cp1252" ))
         pruefung.append (unicode (unescape (c[1]), "cp1252" ))
         pruefung.append (unicode (unescape (c[2]), "cp1252" ))
         pruefung.append (unicode (unescape (c[3]), "cp1252" ))
         pruefung.append (unicode (unescape (c[4]), "cp1252" ))
         pruefung.append (unicode (unescape (c[5]), "cp1252" ))
         pruefung.append (unicode (unescape (c[6]), "cp1252" ))
         pruefungen.append (pruefung)
      return pruefungen



wxnotenspiegel.py

Code: Alles auswählen

import sys, os, qis, wx

import wx.lib.mixins.listctrl as listmix
      
def get_pruefungen (user, password):
   pruefungen = []
      
   pruefung   = []
   pruefung.append ("ZZZTest 0")
   pruefung.append ("Test 1")
   pruefung.append ("Test 2")
   pruefung.append ("5.0")
   pruefung.append ("9")
   pruefung.append ("Test 5")
   pruefung.append ("Test 6")
   pruefungen.append (pruefung)
   
   pruefung   = []
   pruefung.append ("AAATest 0")
   pruefung.append ("Test 1")
   pruefung.append ("Test 2")
   pruefung.append ("4.0")
   pruefung.append ("4")
   pruefung.append ("Test 5")
   pruefung.append ("Test 6")
   pruefungen.append (pruefung)
   
   # zum testen auskommentieren
   #pruefungen = []
   #myqis = qis.Qis (sys.argv[1], sys.argv[2])
   #pruefungen = myqis.get_notenspiegel ()
   
   return pruefungen
   

class CustomTaskBarIcon (wx.TaskBarIcon):
    TBMENU_RESTORE = wx.NewId()
    TBMENU_CLOSE   = wx.NewId()
    
    def __init__(self, frame):
        wx.TaskBarIcon.__init__(self)
        self.frame = frame

        icon = wx.IconFromBitmap (wx.ArtProvider_GetBitmap (wx.ART_INFORMATION, wx.ART_CMN_DIALOG, (32,32))) 
        self.SetIcon (icon, "Notenspiegel")
        
        self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate)
        self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE)
        self.Bind(wx.EVT_MENU, self.OnTaskBarClose,    id=self.TBMENU_CLOSE)

    def CreatePopupMenu(self):
        menu = wx.Menu()
        
        item = wx.MenuItem (menu, self.TBMENU_RESTORE, "Notenspiegel anzeigen")
        item.SetBitmap (wx.ArtProvider_GetBitmap (wx.ART_REPORT_VIEW, wx.ART_OTHER, (16,16)))
        menu.AppendItem (item)
        
        item = wx.MenuItem (menu, self.TBMENU_CLOSE, "Programm beenden")
        item.SetBitmap (wx.ArtProvider_GetBitmap (wx.ART_QUIT, wx.ART_MENU, (16,16)))
        menu.AppendItem (item)
        
        return menu

    def OnTaskBarActivate(self, evt):
        if self.frame.IsIconized():
            self.frame.Iconize(False)
        if not self.frame.IsShown():
            self.frame.Show(True)
        self.frame.Raise()

    def OnTaskBarClose(self, evt):
        self.frame.Close()

    def OnTaskBarRemove(self, evt):
        self.RemoveIcon()
   
class CustomListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
   def __init__(self, parent, ID, pos=wx.DefaultPosition,size=wx.DefaultSize, style=0):
      wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
      listmix.ListCtrlAutoWidthMixin.__init__(self)

class ListFrame (wx.Frame, listmix.ColumnSorterMixin):
   def __init__ (self, parent, title, pruefungen):
      wx.Frame.__init__ (self, parent, -1, title, size = (650, 300), style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
                          
      icon = wx.IconFromBitmap (wx.ArtProvider_GetBitmap (wx.ART_REPORT_VIEW, wx.ART_OTHER, (16,16))) 
      self.SetIcon (icon)
                          
      self.tbicon = CustomTaskBarIcon (self)
                          
      tID = wx.NewId ()
      
      self.pruefungen = pruefungen
      
      self.il = wx.ImageList (16, 16)

      self.sm_up  = self.il.Add (wx.ArtProvider_GetBitmap (wx.ART_GO_UP, wx.ART_TOOLBAR, (16,16)))
      self.sm_dn  = self.il.Add (wx.ArtProvider_GetBitmap (wx.ART_GO_DOWN, wx.ART_TOOLBAR, (16,16)))
      self.ok     = self.il.Add (wx.ArtProvider_GetBitmap (wx.ART_TICK_MARK, wx.ART_FRAME_ICON, (16,16)))
      self.nok    = self.il.Add (wx.ArtProvider_GetBitmap (wx.ART_CROSS_MARK, wx.ART_FRAME_ICON, (16,16)))
                   
      self.list = CustomListCtrl (self, tID,
                                  style=wx.LC_REPORT 
                                  | wx.BORDER_NONE
                                  | wx.LC_SORT_ASCENDING
                                  | wx.LC_VRULES
                                  | wx.LC_HRULES
                                  )
                                  
      self.list.SetImageList (self.il, wx.IMAGE_LIST_SMALL)
                                  
      self.PopulateList ()
      
      self.itemDataMap = self.pruefungen
      listmix.ColumnSorterMixin.__init__(self, 7)
      
      self.Bind (wx.EVT_CLOSE, self.OnClose)
      
   def OnClick (self, event):
      self.Show (False)   
      
   def OnClose (self, event):
      self.tbicon.Destroy()
      self.Destroy ()

   def GetListCtrl(self):
      return self.list

   def GetSortImages(self):
      return (self.sm_dn, self.sm_up)
      
   def PopulateList(self):
      self.list.InsertColumn(0, "Fach")
      self.list.InsertColumn(1, "Semester")
      self.list.InsertColumn(2, "Datum")
      self.list.InsertColumn(3, "Note", wx.LIST_FORMAT_RIGHT)
      self.list.InsertColumn(4, "Credits", wx.LIST_FORMAT_RIGHT)
      self.list.InsertColumn(5, "Status")
      self.list.InsertColumn(6, "Versuch", wx.LIST_FORMAT_RIGHT)
         
      i = 0
      for pruefung in self.pruefungen:
         if not pruefung[5] == "bestanden":
            index = self.list.InsertImageStringItem (sys.maxint, pruefung[0], self.nok)
         else:
            index = self.list.InsertImageStringItem (sys.maxint, pruefung[0], self.ok)
         self.list.SetStringItem (index, 1, pruefung[1])
         self.list.SetStringItem (index, 2, pruefung[2])
         self.list.SetStringItem (index, 3, pruefung[3])
         self.list.SetStringItem (index, 4, pruefung[4])
         self.list.SetStringItem (index, 5, pruefung[5])
         self.list.SetStringItem (index, 6, pruefung[6])
         self.list.SetItemData   (index, i)
         
         if not pruefung[5] == "bestanden":
            item = self.list.GetItem (index)
            item.SetTextColour (wx.RED)
            self.list.SetItem(item)      
            
         i = i + 1

      self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
      self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
      self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)
      self.list.SetColumnWidth(3, 60)
      self.list.SetColumnWidth(4, 80)
      self.list.SetColumnWidth(5, wx.LIST_AUTOSIZE)
      self.list.SetColumnWidth(6, 60)
   
class MyApp (wx.App):
   def OnInit (self):
      
      if len (sys.argv) < 3:
         dlg = wx.MessageDialog (None, '1. Parameter: Benutzername\n2. Parameter: Passwort',
                                'Notenspiegel Benutzung',
                                wx.OK | wx.ICON_INFORMATION
                                )
         dlg.ShowModal()
         dlg.Destroy()
         return True
         
      user     = sys.argv[1]
      password = sys.argv[2]
      
      pruefungen = get_pruefungen (user, password) 

      anzahl = 0
       
      notenfile = os.path.join (os.path.expanduser ('~'), 'anzahl_noten.dat') 
      try:
         fo = file (notenfile)
         anzahl = int (fo.read ()) 
         fo.close ()
      except:
         pass
      
      frame = ListFrame (None, "Notenspiegel", pruefungen)
      
      if len (pruefungen) > anzahl:
         file (notenfile, "w").write (str (len (pruefungen)))
         frame.Show (True)
      else:
         frame.Show (False)
         
      return True
   
def main ():
   app = MyApp (False)
   app.MainLoop ()
    
if __name__ == '__main__':
   __name__ = 'Main'
   main ()

setup.py

Code: Alles auswählen

from distutils.core import setup
import py2exe
  
setup (windows=['wxnotenspiegel.py'], zipfile=None, options = {"py2exe": {"compressed": 1,"optimize": 2,"bundle_files": 1}})