Webuntis API

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
fcutim07
User
Beiträge: 3
Registriert: Sonntag 13. August 2023, 22:10

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
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

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

Gruß, noisefloor
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Es gibt ein Beispie.
Und ich denke, dass Inteeger als Datum falsch sind.
fcutim
User
Beiträge: 12
Registriert: Dienstag 11. Oktober 2022, 16:03

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…
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

wie sieht der Müll denn aus?


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
fcutim
User
Beiträge: 12
Registriert: Dienstag 11. Oktober 2022, 16:03

[(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.
fcutim
User
Beiträge: 12
Registriert: Dienstag 11. Oktober 2022, 16:03

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...
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

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.
fcutim07
User
Beiträge: 3
Registriert: Sonntag 13. August 2023, 22:10

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()

Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@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.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
grubenfox
User
Beiträge: 432
Registriert: Freitag 2. Dezember 2022, 15:49

__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()
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

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.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten