ubuntuusers.de

In Python durch Bäume navigieren

Status: Ungelöst | Ubuntu-Version: Ubuntu 18.04 (Bionic Beaver)
Antworten |

jAIk

Avatar von jAIk

Anmeldungsdatum:
7. Juni 2007

Beiträge: 254

Hallo zusammen,

ich würde gerne "guten" Programmcode schreiben und bin mir nicht sicher, wie ich das folgende Anwendungsszenario als Python-Anfänger sinnvoll abbilden kann. "Irgendwie" wäre problemlos möglich, aber das soll nicht Sinn und Zweck der Übung sein. Hier geht es primär darum, ein grundlegendes Verständnis der Methoden und Werkzeuge zu erlangen.

Szenario: Ich möchte einen Bot schreiben, der durch meine (eigene!) Website bei bekannter Struktur kreuz und quer navigiert. Für die tatsächliche Umsetzung der "Klicks" auf der Website nutze ich Selenium (für das Szenario allerdings nicht weiter relevant).

Meine Website sieht wie folgt aus. Die Struktur ist konstant.

Home
├── About Us
└── Members
    ├── Peter
    │   └── Publications
    ├── Paul
    └── Mary

Anforderung: Der Bot soll in der Lage sein, mit dem Parameter "wo_bin_ich" und "wo_soll_ich_hin" den kürzesten Weg durch den Baum zu gehen. Pro Knoten soll dann eine Funktion ausgeführt werden, die im Browser zu ebendiesem Knoten navigiert.

Beispiel: Ich möchte von Home-> Members-> Mary zu Home-> Members-> Peter → Publications wandern.

  1. Der kürzeste Pfad wird errechnet =⇒ Mary → Members → Peter → Publications

  1. Gehe von der Website Mary zur Website Members

  2. Gehe von der Website Members zur Website Peter

  3. Gehe von der Website Peter zur Website Publications

Umsetzungsidee:

Baumstruktur:

  • Für den Aufbau des Trees nutze ich eine Python Bibliothek wie z.B. anytree

  • Den Pfad von einer Node zur nächsten lasse ich mir Schritt für Schritt durch einen Walker ausgeben

"Execution" der Navigation im Webbrowser:

  • Für tatsächliche "execution" der Navigation schreibe ich eine Funktion, die über Selenium die "passende" Aktion auf der Website vornimmt. Hier würde ich über eine elif Abfrage erfragen, wo ich gerade bin und dann die Navigation ausführen (z.B.: if website == peter or website == paul or website == mary: \ =⇒ Selenium klickt auf den "Zürück" Hyperlink)

  • Es wird durch die Seitenüberschrift überprüft, ob ich tatsächlich auf der "Members" Website gelandet bin.

  • Wenn ja, nächster Schritt, wenn nein, starte von Home

Daher einfach die Fragen in die Runde:

  • Klingt das nach einer ordentlichen Struktur? Falls nein, was würdet ihr ändern?

  • Mit welchen Bordwerkzeugen / Libraries würdet ihr zur Umsetzung des "Walkers" arbeiten? Für mich sieht Anytree auf den ersten Blick sehr brauchbar aus. Wie seht ihr das?

Danke in jedem Fall, dass ihr bis hierhin gelesen habt 😉.

Gruß jaik

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11266

Wohnort: München

Ich frage mich da, ob es da überhaupt eine aufwendige Baumstruktur braucht, das ist doch eigentlich nichts anderes als einen relativen Pfad zu nutzen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
import os

def go_one_level_up(path):
    return os.path.dirname(path)

def go_to_sublevel(path, sublevel):
    return os.path.join(path, sublevel)

def change_path(from_path, to_path):
    p = from_path
    print(f"starting at {p}")
    for e in os.path.relpath(to_path, from_path).split('/'):
        if e == '..':
            p = go_one_level_up(p)
        else:
            p = go_to_sublevel(p, e)
        print(f"now in {p}")

if __name__ == '__main__':
    a = "/Home/Members/Mary"
    b = "/Home/Members/Peter/Publications"
    change_path(from_path=a, to_path=b)
$ ./test.py
starting in /Home/Members/Mary
now in /Home/Members
now in /Home/Members/Peter
now in /Home/Members/Peter/Publications 

jAIk

(Themenstarter)
Avatar von jAIk

Anmeldungsdatum:
7. Juni 2007

Beiträge: 254

Ich habe ein wenig gebraucht, um das zu verstehen, aber die Lösung sieht ebenso simpel wie richtig aus. Genial! Vielen Dank!

Die einzelnen Selenium Schritte würde ich dann in der change_path oder go_to_sublevel funktion implementieren, à la:

1
2
3
4
5
def go_to_sublevel(path, sublevel):
    if path == "/Home/Members" and sublevel == "Peter":
        # Klicke den Button "Peter" via Selenium.
        ...
    return os.path.join(path, sublevel)

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11266

Wohnort: München

jAIk schrieb:

Die einzelnen Selenium Schritte würde ich dann in der change_path oder go_to_sublevel funktion implementieren, à la:

1
2
3
4
5
def go_to_sublevel(path, sublevel):
    if path == "/Home/Members" and sublevel == "Peter":
        # Klicke den Button "Peter" via Selenium.
        ...
    return os.path.join(path, sublevel)

Die if-Abfrage ist soweit ich das verstehe überflüssig - es sollte da eigentlich genügen den Button zu klicken, der dem in der Variablen sublevel gespeicherten String entspricht. Und in go_one_level_up() lässt man selenium einen Klick auf "Zurück" (oder wie das auf deiner Webseite genannt wird) machen.

jAIk

(Themenstarter)
Avatar von jAIk

Anmeldungsdatum:
7. Juni 2007

Beiträge: 254

Die if-Abfrage ist soweit ich das verstehe überflüssig - es sollte da eigentlich genügen den Button zu klicken...

Wenn es immer der gleiche Button wäre, dann auf jeden Fall. Wenn sich der Button auf Seite a vom Button auf Seite b unterscheidet würde ich es für sinnvoll halten, hier jeweils für Fall 1 und Fall 2 eine kleine Funktion zu schreiben und diese dann in der entsprechenden if-Abfrage aufzurufen.

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11266

Wohnort: München

Sowas kann man auch prima in einem Dictionary unterbringen - also z.B. statt deinem Beispiel

1
2
3
4
5
6
7
8
9
name_aliases = {
    ("/Home/Members", "Peter"): "Peter",
}

def go_to_sublevel(path, sublevel):
    button_name = name_aliases[(path, sublevel)]
    # Klicke den Button "Peter" via Selenium.
    #    ...
    return os.path.join(path, sublevel)

Oder man fügt den Pfad vorher zu sammen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
name_aliases = {
    ("/Home/Members/Peter"): "Peter",
}

def go_to_sublevel(path, sublevel):
    new_path = os.path.join(path, sublevel)
    button_name = name_aliases[new_path]
    # Klicke den Button button_name via Selenium.
    #    ...
    return new_path

jAIk

(Themenstarter)
Avatar von jAIk

Anmeldungsdatum:
7. Juni 2007

Beiträge: 254

Cool, danke!

Antworten |