Seite 1 von 1

Webuntis API

Verfasst: Samstag 23. März 2024, 19:44
von fcutim07
Moin, ich bin gerade dabei etwas herumzuspieln mit der Untis API, bei der man mit den einloggdaten, informationen von einem webuntis acc bekommen kann.

Nun habe ich diesen code bisher, der den timetable von einem bestimmten datum bis zu einem bestimmten datum zeigen soll, aber dies tut er leider nicht. Ich er soll mit dort alle stunden ansagen, die man in diesem zeitraum hat, aber ich weiß leider nicht wie ich das ausgeben kann...

Das ist bisher mein code:

Code: Alles auswählen

import webuntis

s = webuntis.Session(
    server='chios.webuntis.com',
    username='User,
    password='Password',
    school='School',
    useragent='WebUntis Test'
)

s.login()

monday=20240304
friday=20240308

klasse = s.klassen().filter(name='class')[0]

table = s.timetable(klasse=klasse, start=monday, end=friday).to_table()


s.logout()
Die einnlogdaten habe ich natürlich weg gemacht :D

Re: Webuntis API

Verfasst: Samstag 23. März 2024, 20:22
von noisefloor
Hallo,

naheliegend wäre, die Variablen mit ˋprintˋ ausgeben zu lassen.

Gruß, noisefloor

Re: Webuntis API

Verfasst: Samstag 23. März 2024, 20:30
von sparrow
Es gibt ein Beispie.
Und ich denke, dass Inteeger als Datum falsch sind.

Re: Webuntis API

Verfasst: Montag 25. März 2024, 15:09
von fcutim
noisefloor hat geschrieben: Samstag 23. März 2024, 20:22 Hallo,

naheliegend wäre, die Variablen mit ˋprintˋ ausgeben zu lassen.

Gruß, noisefloor
Leider funktioniert das nicht, da dort dann ein Haufen Müll ausgespuckt wird…

Re: Webuntis API

Verfasst: Montag 25. März 2024, 15:19
von Dennis89
Hallo,

wie sieht der Müll denn aus?


Grüße
Dennis

Re: Webuntis API

Verfasst: Montag 25. März 2024, 15:55
von fcutim
[(datetime.time(8, 0), [(datetime.date(2024, 3, 4), {PeriodObject({'id': 499297, 'date': 20240304, 'startTime': 800, 'endTime': 845, 'kl': [{'id': 340}], 'te': [{'id': 408}], 'su': [{'id': 288}], 'ro': [{'id': 32}], 'activityType': 'Unterricht'})}), (datetime.date(2024, 3, 5), {PeriodObject({'id': 285336, 'date': 20240305, 'startTime': 800, 'endTime': 845, 'kl': [{'id': 337}, {'id': 340}, {'id': 343}, {'id': 346}], 'te': [{'id': 68}], 'su': [{'id': 428}], 'ro': [{'id': 156}], 'activityType': 'Unterricht'}), PeriodObject({'id': 286458, 'date': 20240305, 'startTime': 800, 'endTime': 845, 'kl': [{'id': 337}, {'id': 340}, {'id': 343}, {'id': 346}], 'te': [{'id': 412}], 'su': [{'id': 452}], 'ro': [{'id': 168}], 'activityType': 'Unterricht'}), PeriodObject({'id': 285054, 'date': 20240305, 'startTime': 800, 'endTime': 845, 'kl': [{'id': 337}, {'id': 340}, {'id': 343}, {'id': 346}], 'te': [{'id': 484}], 'su': [{'id': 424}], 'ro': [{'id': 160}], 'activityType': 'Unterricht'}), PeriodObject({'id': 288126, 'date': 20240305, 'startTime': 800, 'endTime': 845, 'kl': [{'id': 337}, {'id': 340}, {'id': 343}, {'id': 346}], 'te': [{'id': 376}], 'su': [{'id': 496}], 'ro'
Sowas kommt hier nur... Das geht so weiter, unendlich viel text. Mit "Müll" habe ich mich wahrscheinlich falsch ausgedrückt, da das kein Müll ist, aber lesen kann ich da leider nix.

Re: Webuntis API

Verfasst: Montag 25. März 2024, 16:00
von fcutim
sparrow hat geschrieben: Samstag 23. März 2024, 20:30 Es gibt ein Beispie.
Und ich denke, dass Inteeger als Datum falsch sind.
Das Beispiel zeigt mir genau das gleiche an, was ich bisher mit meinem code auch schon habe...

Re: Webuntis API

Verfasst: Montag 25. März 2024, 16:10
von Sirius3
Du bekommst halt eine tabellenartige Struktur, geh du jetzt nach den von dir gewünschten Daten durchsuchen musst.
Das von sparrow verlinkte Beispiel zeigt, wie Du über die Tabelle iterieren kannst. Deine Aufgabe ist jetzt, zu verstehen, dass das kein Müll ist. Dazu hilft es, dir per type den Typ ausgeben zu lassen.

Re: Webuntis API

Verfasst: Montag 25. März 2024, 17:02
von fcutim07
Alles klar, jetzt bin ich so weit und habe es geschafft das in einer html datei in einer tabelle darzustellen, nun das problem, dass ich gerne haben wollen würde, dass der nur den stundenplan von meinem benutzer anzeigt, und nicht gleich, von meiner ganzen klasse. Wie würde das gehen?

Das ist bisher mein erweiterter code:

Code: Alles auswählen


import webuntis

s = webuntis.Session(
    server='chios.webuntis.com',
    username='user',
    password='password',
    school='schule',
    useragent='WebUntis Test'
)

s.login()

monday = 20240226
friday = 20240301

klasse = s.klassen().filter(name='class')[0]

table = s.timetable(klasse=klasse, start=monday, end=friday).to_table()

with open('test.html', 'w') as f:
    f.write('<!DOCTYPE html>\n')
    f.write('<html>\n<head>\n')
    f.write('<title>Stundenplan</title>\n')
    f.write('<link rel="stylesheet" type="text/css" href="style.css">\n')
    f.write('</head>\n<body>\n')

    f.write('<table border="1"><thead><th>Time</th>')
    for weekday in ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']:
        f.write('<th>' + str(weekday) + '</th>')
    f.write('</thead><tbody>')
    for time, row in table:
        f.write('<tr>')
        f.write('<td>{}</td>'.format(time.strftime('%H:%M')))
        for date, cell in row:
            f.write('<td>')
            if cell:
                for period in cell:
                    subjects = ", ".join(su.name for su in period.subjects)
                    f.write(subjects)
            else:
                f.write('-')  
            f.write('</td>')
        f.write('</tr>')
    f.write('</tbody></table>\n')

    f.write('</body>\n</html>\n')

s.logout()


Re: Webuntis API

Verfasst: Dienstag 26. März 2024, 16:34
von __blackjack__
@fcutim07: Namen sollte man nicht kryptisch abkürzen. Also nicht `s` wenn man `session` meint, oder `f` wenn `file` gemeint ist, oder `su` für `subject`.

Die `Session`-Objekte sind Kontextmanager, die sollte man mit ``with`` zusammen verwenden.

Beim öffnen von Textdateien sollte man immer explizit die Kodierung angeben. Und bei HTML im Header auch welche Kodierung das ist, sonst läuft das auf diverse Heuristiken hinaus mit denen die Kodierung geraten wird, und das muss nicht korrekt sein.

Die Wochentage stehen auf Englisch in der HTML, alles andere ist Deutsch‽

`weekday` ist bereits eine Zeichenkette. `str()` macht da keinen Sinn.

Das zusammenstückeln von Zeichenketten und Werten mittels ``+`` und `str()` ist eher BASIC als Python. Dafür gibt es die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.

Wenn es mehrere `period` in einer `cell` gibt, dann werden die Fächerlisten ohne irgendein Trennzeichen aneinandergeklebt, das ist sicher so nicht gewollt.

Wenn man irgendwelche Daten in HTML schreibt von denen man nicht weiss ob die vielleicht Sonderzeichen enthalten die in HTML eine besondere Bedeutung haben, muss man sicherstellen das diese Zeichen „escaped“ werden. Bei Datum/Zeit und den Wochentagen kann man ja recht sicher sein, aber was die Fächer enthalten, ist unsicher. Wobei man natürlich auch auf nummer sicher gehen kann, und einfach alles was man da an Werten einsetzt, escapen kann.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import html
from datetime import datetime as DateTime

from webuntis import Session

ENCODING = "UTF-8"


def is_given_weekday(date_number, weekday):
    return DateTime.strptime(str(date_number), "%Y%m%d").weekday() == weekday


def main():
    monday = 20240226
    friday = 20240301
    assert is_given_weekday(monday, 0), f"{monday} is no monday"
    assert is_given_weekday(friday, 4), f"{friday} is no friday"

    with Session(
        server="chios.webuntis.com",
        username="user",
        password="password",
        school="schule",
        useragent="WebUntis Test",
    ) as session:
        session.login()
        table = session.timetable(
            klasse=session.klassen().filter(name="class")[0],
            start=monday,
            end=friday,
        ).to_table()
        
        with open("test.html", "w", encoding=ENCODING) as file:
            file.write(
                "<!DOCTYPE html>\n"
                "<html>\n"
                "<head>\n"
                f'<meta charset="{html.escape(ENCODING, True)}">\n'
                "<title>Stundenplan</title>\n"
                '<link rel="stylesheet" type="text/css" href="style.css">\n'
                "</head>\n"
                "<body>\n"
                '<table border="1"><thead><th>Time</th>'
            )
            for weekday in [
                "Montag",
                "Dienstag",
                "Mittwoch",
                "Donnerstag",
                "Freitag",
            ]:
                file.write(f"<th>{html.escape(weekday)}</th>")
            
            file.write("</thead><tbody>")
            for time, row in table:
                file.write(f"<tr><td>{time:%H:%M}</td>")
                for _date, cell in row:
                    file.write("<td>")
                    if cell:
                        #
                        # BUG If there is more than one `period` then the
                        #     subject lists are concatenated without any
                        #     separator! Either separate them or make sure
                        #     there's only one such list per `cell` written.
                        #
                        for period in cell:
                            file.write(
                                html.escape(
                                    ", ".join(
                                        subject.name
                                        for subject in period.subjects
                                    )
                                )
                            )
                    else:
                        file.write("—")
                    file.write("</td>")
                file.write("</tr>")
            file.write("</tbody></table>\n</body>\n</html>\n")


if __name__ == "__main__":
    main()
Falls `table` komplett ist, also keine Daten beim Zugriff mehr dynamisch aus dem Web abfragt, könnte man das schreiben der HTML-Datei aus dem ``with``-Block heraus nehmen und sich schneller wieder vom Server abmelden.

Ich persönlich finde das zusammestückeln/stückchenweise schreiben von HTML ja ein bisschen unübersichtlich und damit auch fehleranfällig. Ich würde da eher zu einer Template-Engine wie Jinja2 greifen.

Re: Webuntis API

Verfasst: Donnerstag 28. März 2024, 15:21
von grubenfox
__blackjack__ hat geschrieben: Dienstag 26. März 2024, 16:34
Ich persönlich finde das zusammestückeln/stückchenweise schreiben von HTML ja ein bisschen unübersichtlich und damit auch fehleranfällig. Ich würde da eher zu einer Template-Engine wie Jinja2 greifen.
Dem ersten Satz stimme ich hier mal zu....
Dem zweiten auch irgendwie, nur das ich von Jinja2 nun gar keinen Plan habe und irgendwo hier mal einen Hinweis auf dominate gelesen hatte. Ich habe bis jetzt leider nur einmal zum Testen mit dominate herum gespielt. Daher bin ich noch nicht so firm darin und deshalb ebenfalls ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import dominate
from dominate.tags import *

from datetime import datetime as DateTime

from webuntis import Session

ENCODING = "UTF-8"


def is_given_weekday(date_number, weekday):
    return DateTime.strptime(str(date_number), "%Y%m%d").weekday() == weekday


def main():
    monday = 20240226
    friday = 20240301
    assert is_given_weekday(monday, 0), f"{monday} is no monday"
    assert is_given_weekday(friday, 4), f"{friday} is no friday"

    with Session(
        server="chios.webuntis.com",
        username="user",
        password="password",
        school="schule",
        useragent="WebUntis Test",
    ) as session:
        session.login()
        webuntis_table = session.timetable(
            klasse=session.klassen().filter(name="class")[0],
            start=monday,
            end=friday,
        ).to_table()
        

        doc = dominate.document(title='Stundenplan')

        with doc.head:
            link(rel='stylesheet', href='style.css', type='text/css')
            meta(charset=ENCODING)

        with doc:
            with table(border=1):
                with thead():
                    th('Time')
                    for weekday in [
                        "Montag",
                        "Dienstag",
                        "Mittwoch",
                        "Donnerstag",
                        "Freitag",
                    ]:
                        th(weekday)
                with tbody():
                    for time, row in webuntis_table:
                        with tr():
                            td(f'{time:%H:%M}')
                            for _date, cell in row:
                                if cell:
                                    #
                                    # BUG If there is more than one `period` then the
                                    #     subject lists are concatenated without any
                                    #     separator! Either separate them or make sure
                                    #     there's only one such list per `cell` written.
                                    #
                                    td_inhalt = for period in cell:
                                            ", ".join(
                                                subject.name
                                                for subject in period.subjects
                                                )
                                    td(td_inhalt)
                                else:
                                    td('—')

        with open("test.html", "w", encoding=ENCODING) as file:
            file.write(doc)


if __name__ == "__main__":
    main()

Re: Webuntis API

Verfasst: Samstag 30. März 2024, 14:07
von __blackjack__
Mit Jinja2, ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
from datetime import datetime as DateTime
from pathlib import Path

from jinja2 import Template
from webuntis import Session

ENCODING = "UTF-8"
TEMPLATE = """\
<!DOCTYPE html>
<html lang="de">
  <head>
    <meta charset="{{ encoding }}">
    <title>Stundenplan</title>
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>
  <body>
    <table>
      <thead>
        <th>Zeit</th>
        <th>Montag</th>
        <th>Dienstag</th>
        <th>Mittwoch</th>
        <th>Donnerstag</th>
        <th>Freitag</th>
      </thead>
      <tbody>
        {% for time, row in table %}
          <tr>
            <td>{{ "{:%H:%M}".format(time) }}</td>
            {% for _date, cell in row %}
              <td>
                {% if cell %}
                  {# BUG If there is more than one `period` then the subject
                         lists are concatenated without any separator! Either
                         separate them or make sure there's only one such list
                         per `cell` written. #}
                  {% for period in cell %}
                      {{ period.subjects|join(", ", "name") }}
                  {% endfor %}
                {% else %}
                  —
                {% endif %}
              </td>
            {% endfor %}
          </tr>
        {% endfor %}
      </tbody>
    </table>
  </body>
</html>
"""


def is_given_weekday(date_number, weekday):
    return DateTime.strptime(str(date_number), "%Y%m%d").weekday() == weekday


def main():
    monday = 20240226
    friday = 20240301
    assert is_given_weekday(monday, 0), f"{monday} is no monday"
    assert is_given_weekday(friday, 4), f"{friday} is no friday"

    with Session(
        server="chios.webuntis.com",
        username="user",
        password="password",
        school="schule",
        useragent="WebUntis Test",
    ) as session:
        session.login()
        table = session.timetable(
            klasse=session.klassen().filter(name="class")[0],
            start=monday,
            end=friday,
        ).to_table()

        Path("test.html").write_text(
            Template(TEMPLATE, autoescape=True).render(
                encoding=ENCODING, table=table
            ),
            encoding=ENCODING,
        )


if __name__ == "__main__":
    main()
Man kann die Vorlage natürlich auch in einer eigenen Datei speichern, mit dem Vorteil, dass man dort Syntaxhervorhebung und Editor-/IDE-Unterstützung für HTML/Jinja haben könnte.