tag:www.stefanwienert.net,2008:/htw Htw - Stefan Wienert's Blog 2009-11-01T15:00:44Z Enki Stefan Wienert stwienert@gmail.com tag:www.stefanwienert.net,2008:Post/10 2009-11-01T14:00:00Z 2009-11-01T15:00:44Z Greasemonkey Useraddon: Notenviewer für die HIS-QIS der HTW Dresden <p>Wer an der <span class="caps">HTW</span> Dresden ein paar Semester studiert, kenn es vielleicht: Die Notenübersicht des <span class="caps">HIS</span> <span class="caps">QIS</span> wird nach einiger Zeit extrem unübersichtlich, und neue Noten zu finden wird zunehmend schwerer.<br /> Was als Idee von mir in einer extrem simplen Variante mal gestartet wurde, hat mein Kommilitone <a href="http://blog.burnred.de/">Thomas Rothe</a> inzwischen zu einer halben <span class="caps">IDE</span> ausgeweitet =):</p> <p>Eine übersichtlichere Anordnung der Noten, aufgetrennt nach Semester, farblich unterlegt für das <a href="https://wwwqis.htw-dresden.de/qisserver/rds?state=user&amp;type=0"><span class="caps">HIS</span>-<span class="caps">QIS</span> Notenabrufsystem</a> unserer Hochschule.</p> <p>Das Skript und die Installationsanweisungen findet ihr auf seiner <a href="http://www.informatik.htw-dresden.de/~s59561/#content/tools.xml">Hochschulseite</a>.</p> <p>Wie man sich selbst einen <span class="caps">RSS</span>-Feed aus dem <span class="caps">HISQIS</span> bastelt, hab ich ja <a href="http://site.stefanwienert.net/2009/08/14/noten-bersichts-bot-in-php">schonmal erklärt</a></p> tag:www.stefanwienert.net,2008:Post/6 2009-08-14T08:49:00Z 2009-10-18T10:49:01Z Notenübersichts-Bot in PHP <p>Vor zwei Wochen kam mir beim Überprüfen der aktuellen Notenergebnisse die Idee in den Sinn, das Ganze zu automatisieren und als Feed zur Verfügung zu stellen, um es in meinen Feedreader mit einzubinden und so immer auf dem aktuellen Stand sein zu können ;).</p> <p>Der Einfachheit halber hab ich <span class="caps">PHP</span>/Curl genommen, da ich kurz mal in Ruby reingeschaut hatte, mir die <span class="caps">HTTP</span>-Bibliothek aber nicht zweckdienlich erschien.</p> <h3>Teil 1: Den Quelltext der Webseite holen</h3> <p>Dazu mal mit Firefox und LiveHTTP-Headers-Addon schauen, was man beim Login zu alles schickt. In unserem Fall muss man danach noch einen Klick auf “Notenübersicht” machen.</p> <p>Das ganze dann in cURL gießen und eine cookies.txt schreibbar bereitstellen:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt>12<tt> </tt>13<tt> </tt>14<tt> </tt>15<tt> </tt>16<tt> </tt>17<tt> </tt>18<tt> </tt>19<tt> </tt><strong>20</strong><tt> </tt>21<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"> <span class="lv">$username</span>=<span class="s"><span class="dl">&quot;</span><span class="k">Meine Matrikelnummer</span><span class="dl">&quot;</span></span><tt> </tt> <span class="lv">$passwort</span>=<span class="s"><span class="dl">&quot;</span><span class="k">Mein Passwort ;)</span><span class="dl">&quot;</span></span><tt> </tt> <span class="lv">$ch</span> = curl_init();<tt> </tt> <span class="c">//Variablen setzen</span><tt> </tt> <span class="lv">$url</span>=<span class="s"><span class="dl">&quot;</span><span class="k">https://wwwqis.htw-dresden.de/qisserver/rds?state=user&amp;type=1&amp;category=auth.login&amp;startpage=portal.vm</span><span class="dl">&quot;</span></span>;<tt> </tt> <span class="c">//$url=&quot;https://wwwqis.htw-dresden.de/qisserver/rds?state=user&amp;amp;type=1&amp;amp;category=auth.login&amp;amp;startpage=portal.vm&quot;;</span><tt> </tt> <span class="lv">$arrSubmit</span>=<span class="s"><span class="dl">&quot;</span><span class="k">username=</span><span class="lv">$username</span><span class="k">&amp;submit=%C2%A0Ok%C2%A0&amp;password=</span><span class="lv">$password</span><span class="dl">&quot;</span></span>;<tt> </tt> <span class="lv">$cookies</span>=<span class="s"><span class="dl">&quot;</span><span class="k">cookie.txt</span><span class="dl">&quot;</span></span>;<tt> </tt><span class="c">//Session Optionen setzen</span><tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_URL</span>,<span class="lv">$url</span>);<tt> </tt> curl_setopt (<span class="lv">$ch</span>, <span class="co">CURLOPT_POST</span>, <span class="i">1</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_POSTFIELDS</span>, <span class="lv">$arrSubmit</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_HEADER</span>, <span class="i">0</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_COOKIEJAR</span>, <span class="lv">$cookies</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_COOKIEFILE</span>, <span class="lv">$cookies</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_FOLLOWLOCATION</span>, <span class="pc">true</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_RETURNTRANSFER</span>, <span class="pc">true</span>);<tt> </tt><span class="c">//Ausf?hren der Aktionen</span><tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_SSL_VERIFYPEER</span>, <span class="pc">FALSE</span>);<tt> </tt> <span class="lv">$result</span>=curl_exec(<span class="lv">$ch</span>);<tt> </tt> curl_close(<span class="lv">$ch</span>);<tt> </tt></pre></td> </tr></table> <p>In unserem Beispiel des <span class="caps">HIS</span>-<span class="caps">QIS</span> gibt es noch eine Art zweiter Session-ID, die ausgelesen werden, und mit übergeben werden muss:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"> <span class="pd">preg_match</span>(<span class="s"><span class="dl">&quot;</span><span class="k">/asi=([^</span><span class="ch">\&quot;</span><span class="k">]*)</span><span class="ch">\&quot;</span><span class="k">/</span><span class="dl">&quot;</span></span>,<span class="lv">$result</span>,<span class="lv">$treffer</span>);<tt> </tt> <span class="lv">$asi</span>=<span class="lv">$treffer</span>[<span class="i">1</span>];<tt> </tt></pre></td> </tr></table> <p>Dann der Zweite durchlauf mit der asi:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt>12<tt> </tt>13<tt> </tt>14<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"> <span class="lv">$url</span>=<span class="s"><span class="dl">&quot;</span><span class="k">https://wwwqis.htw-dresden.de/qisserver/rds?state=htmlbesch&amp;moduleParameter=Student&amp;menuid=notenspiegel&amp;asi=</span><span class="lv">$asi</span><span class="dl">&quot;</span></span>;<tt> </tt> <span class="lv">$ch</span> = curl_init();<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_URL</span>,<span class="lv">$url</span>);<tt> </tt> curl_setopt (<span class="lv">$ch</span>, <span class="co">CURLOPT_POST</span>, <span class="i">0</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_HEADER</span>, <span class="i">0</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_COOKIEJAR</span>, <span class="lv">$cookies</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_COOKIEFILE</span>, <span class="lv">$cookies</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_FOLLOWLOCATION</span>, <span class="pc">true</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_RETURNTRANSFER</span>, <span class="pc">true</span>);<tt> </tt> curl_setopt(<span class="lv">$ch</span>, <span class="co">CURLOPT_SSL_VERIFYPEER</span>, <span class="pc">FALSE</span>);<tt> </tt> <span class="lv">$result</span>=curl_exec(<span class="lv">$ch</span>);<tt> </tt> <span class="c">//echo curl_error($ch);</span><tt> </tt> <span class="c">//Session beenden</span><tt> </tt> curl_close(<span class="lv">$ch</span>);<tt> </tt></pre></td> </tr></table> <p>Damit ist der Text in der Variablen $result<br /> Extraktion der wichtigen Zeilen mit XPath</p> <p>Mittels Firebug schauen, wo die Prüfungsergebnisse drinstehen und die XPaths kopieren bzw. analysieren. Damit erhalten wir eine NodeList die wir ausgeben/speichern können:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="lv">$Doc</span> = <span class="r">new</span> <span class="co">DOMDocument</span>();<tt> </tt><span class="lv">$Doc</span>-&gt;loadHTML(<span class="lv">$result</span>);<tt> </tt><span class="lv">$Doc</span>-&gt;preserveWhiteSpace = <span class="pc">false</span>;<tt> </tt><span class="lv">$Doc</span>-&gt;normalizeDocument();<tt> </tt><span class="lv">$XPath</span> = <span class="r">new</span> <span class="co">DOMXPath</span>(<span class="lv">$Doc</span>);<tt> </tt><span class="lv">$NodeList</span> = <span class="lv">$XPath</span>-&gt;query(<span class="s"><span class="dl">&quot;</span><span class="k">//tr[@bgcolor='#EFEFEF']</span><span class="dl">&quot;</span></span>);<tt> </tt><span class="r">foreach</span> (<span class="lv">$NodeList</span> <span class="r">as</span> <span class="lv">$node</span>)<tt> </tt>{ <tt> </tt> <span class="pd">echo</span> <span class="lv">$node</span>-&gt;nodeValue;<tt> </tt> ...<tt> </tt>}<tt> </tt></pre></td> </tr></table> <p>Schon fast fertig, was fehlt noch?</p> <ul> <li>Die Datumswerte auslesen, nach Sekunden umwandeln um danach die Noten danach zu sortieren.</li> </ul> <ul> <li>Einfacher Caching Algorithmus à la “Wenn unsere cache-datei älter als 30 minuten ist, dann erstelle sie neu [durchlaufe den Algorithmus] und schreibe das Ergebnis in die Cache-Datei; andernfalls gib nur die cache-Datei aus”</li> </ul> <ul> <li>Ausgabe als <span class="caps">RSS</span>-Feed, einfach mal die Spezifikation googlen ;)</li> </ul>