Html Seite einlesen

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.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Habe es jetzt abgeändert. trotzdem noch sehr unzufrieden.

Code: Alles auswählen

def begegnung():
    url = "https://sport.sky.de/bundesliga-spielplan-ergebnisse"
    response = requests.get(url)
    html = BeautifulSoup(response.text, 'lxml')
    liste  = []
    for spiel in html.find_all(class_="sdc-site-fixres__match"):
        print(spiel.text)
        for heimteam in spiel.find_all(class_="sdc-site-fixres__match-cell--hometeam"):
            print(heimteam.text)
        for team in heimteam.find_all(class_="sdc-site-fixres__match-cell--score"):
            print(team.text)
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn ›unzufrieden‹ bedeutet, dass es Quatsch ist, einen Score `team` zu nennen und den auch noch im `heimteam`-Zweig zu suchen, dann hast Du recht.
Eine for-Schleife, wenn es exakt ein Element gibt, ist auch ein Fehler.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK, ich werde es ändern. Mir fehlt jetzt noch das löschen von bestimmten tags, wie kann ich z.b. eine Klasse löschen?
Ich habe mir clear angeschaut. Aber so richtig nicht schlau geworden.
Ich möchte das "data-label-abandoned="X">0</span>" im Text entfernen.

Code: Alles auswählen

<div class="sdc-site-fixres__score"><span class="sdc-site-fixres__score-side sdc-site-fixres__score-side--home" data-update="score-home" data-label-postponed="X" data-label-cancelled="X" data-label-abandoned="X">0</span><span class="sdc-site-fixres__score-ko" data-update="start-time">20:30</span><span class="sdc-site-fixres__score-side sdc-site-fixres__score-side--away" data-update="score-away" data-label-postponed="X" data-label-cancelled="X" data-label-abandoned="X">0</span>
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

@egon11: nein, das willst Du nicht. Statt dessen willst Du die Unterstruktur auch noch lesen und in eine passendes Datenstruktur packen.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Jetzt habe ich die Spielpaarungen so wie ich es haben möchte, was mir noch fehlt sind die Tages Ansetzungen "<h4 class="sdc-site-fixres__header2">Freitag, 17. Januar</h4>".

Hat jemand eine Idee wie ich die Tages Ansetzungen an der richtigen Stelle mit einfügen kann?

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
import re
import itertools
def begegnung():
    url = "https://sport.sky.de/bundesliga-spielplan-ergebnisse"
    response = requests.get(url)
    html = BeautifulSoup(response.text, 'lxml')


    erst = html.find(class_="sdc-site-fixres-box")
    game_list = ([(hometeam.text.encode('utf8', 'replace').replace("ö", "oe").replace("ü", "ue").replace("ä", "ae").replace("ß", "ss").replace("\n", ""), \
            heading.text.encode('utf8', 'replace').replace("ö", "oe").replace("ü", "ue").replace("ä", "ae").replace("ß", "ss").replace("\n", ""),\
           awayteam.text.encode('utf8', 'replace').replace("ö", "oe").replace("ü", "ue").replace("ä", "ae").replace("ß", "ss").replace("\n", "") ) for hometeam,heading,awayteam in \
          itertools.izip_longest(erst.find_all(class_="sdc-site-fixres__match-cell--hometeam"),erst.find_all(class_="sdc-site-fixres__score-ko"),erst.find_all\
                (class_="sdc-site-fixres__match-cell sdc-site-fixres__match-cell--awayteam"))])
    for show in game_list:
        print(show)



if __name__=='__main__':
    begegnung()
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

Also, nochmal von vorne: nein. Jedes Spiel ist in einem Element mit Klasse sdc-site-fixres__match. Von dort aus kann man die Unterstruktur parsen. Was man nicht macht, ist die Unterstruktur als eigenständige Listen zusammenzusuchen. Das war doch schonmal richtiger.

Wo hast Du ein Problem, den header zusammen mit den match`s auch noch zu suchen, innerhalb von sdc-site-fixres-box?
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Sirius3 hat geschrieben: Montag 13. Januar 2020, 13:59 Wo hast Du ein Problem, den header zusammen mit den match`s auch noch zu suchen, innerhalb von sdc-site-fixres-box?
Ja genau. Ich habe schon Stunden versucht, das ganze zu Parsen, mit "for" und was weiß ich.
Letztendlich bekam ich es nicht hin.
Ziel sollte sein Die Tages Ansetzung, dann die jeweiligen Spiel(e), dann wieder Tages Ansetzung u.s.w.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Hat keiner ein Schema für mich? Ich komme absolut nicht weiter wie der "Suchbaum" aussehen muss.
Ich wäre dankbar.
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

Code: Alles auswählen

date = None
table = []
box = html.find(class_="sdc-site-fixres-box")
for row in box.find_all(class_=['sdc-site-fixres__match','sdc-site-fixres__header2']):
    if 'sdc-site-fixres__header2' in row.attrs['class']:
        date = row.text
    else:
        table.append(dict(
            hometeam=row.find(class_='sdc-site-fixres__match-cell--hometeam').text.strip(),
            awayteam=row.find(class_='sdc-site-fixres__match-cell--awayteam').text.strip(),
            score_home=row.find(class_='sdc-site-fixres__score-side--home').text.strip(),
            score_away=row.find(class_='sdc-site-fixres__score-side--away').text.strip(),
            date=date
        ))
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Vielen dank für die große Hilfe, jetzt kann ich damit weiter arbeiten.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Dank eurer Hilfe konnte ich mich weiter in die Sache einarbeiten was html betrifft.
Ich habe hier mal ein funktionierendes Script.
Mich interessiert es, ob ihr Fachleute den Code für ok haltet oder ob man da noch etwas verbessern könnte.
Aber wie gesagt, so wie es ist funktioniert es (Python2).

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup

def work():
    wahr = False
    url = "https://www.kicker.de/1-bundesliga/torjaeger"
    response = requests.get(url)
    html = BeautifulSoup(response.text, 'lxml')
    tabelle = html.find("table")  #tabellenkörper wird gesucht
    liste = []
    liste_end = []

    for end_score in tabelle.find_all("tr"):
        liste.append([table.text.strip().encode('utf8', 'replace').replace("ö", "oe").replace("ü", "ue").replace("ä", "ae").replace("ß", "ss") for table in end_score.find_all("td")])
    liste_end.append("\n {0:<2}   {1:<30}  {2:>6}    {3:>4}".format("Pl", "Spieler", "Spiele", "Tore"))
    for meineliste in liste:
        if len(meineliste) != 0:
            liste_end.append("\n {0:<2}   {1:<30}  {2:>6}    {3:>4}".format(meineliste[0],meineliste[1],meineliste[2],meineliste[6]))

    print("".join(liste_end))

if __name__ == '__main__':
    work()

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

@egon11: Die `replace()`-Aufrufe von Sonderzeichen *nach* dem kodieren als Bytestrings ist falsch.

Grunddatentypen haben in Namen nichts zu suchen. `liste` und `liste_end` verraten dem Leser ja auch überhaupt gar nicht was da enthalten ist, also was für eine Bedeutung die Werte haben. Man braucht auch nicht wirklich beide wenn man die Elemente die man am Ende nicht haben möchte gar nicht erst zu `liste` hinzufügt.

`end_score` passt IMHO nicht wirklich als Name für eine HTML-Tabellenzeile und `meineliste` ist wieder ein superschlechter generischer Name. `table` ist ebenfalls falsch und sehr irreführend weil es sich gar nicht um eine Tabelle handelt sondern um eine einzelne Zelle in einer Zeile einer Tabelle.

Die Vormatvorlage steht zweimal im Quelltext. Daten und Code sollte man aber nicht wiederholen. Das wäre ein Kandidat für eine Konstante.

Zeilen*ende*zeichen gehören ans *Ende* und nicht an den Anfang. In diesem Fall aber IMHO gar nicht in die Vorlage(n) sondern als Zeichenkette an der die Listenelemente dann verbunden werden.

Sich einfach die erste <table> zu greifen ist für meinen Geschmack nicht robust genug. Ich würde schauen ob man sich da nicht noch an IDs und/oder CSS-Klassen orientieren kann.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

@__blackjack__ danke.
Wie würdest du das lösen:
__blackjack__ hat geschrieben: Mittwoch 29. Januar 2020, 16:14 Die `replace()`-Aufrufe von Sonderzeichen *nach* dem kodieren als Bytestrings ist falsch.

Man braucht auch nicht wirklich beide wenn man die Elemente die man am Ende nicht haben möchte gar nicht erst zu `liste` hinzufügt.
Und was meinst du mit "Vormatvorlage steht zweimal im Quelltext".
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

Diese Formatvorlage: "\n {0:<2} {1:<30} {2:>6} {3:>4}"

Du encodierst den Text in UTF8, so dass "ö" zu zwei Bytes wird und diese zwei Bytes ersetzt Du dann durch "oe". UTF8 ist da zum Glück ein gutmütiges Encoding, aber generell sollte man das Encodieren erst dann machen, wenn man etwas ausgeben will, und die Datenverarbeitung komplett in Unicode machen.

Bei einer Zeile wie `wahr = False` kringeln sich mir die Zehennägel. url sollte als Konstante am Anfang der Datei stehen. Und wenn Du `meineliste` schreibst, wo ist dann `unsereliste`?
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Also soll ich zuerst ö durch oe ersetzen und dann später erst in UTF8 encoden?

Den Rest habe ich verstanden.
'wahr = False' ist wirklich bisschen lustig. Habe es abgeändert :D
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich habe jetzt eine variable erstellt, welche ich immer aufrufe:

Code: Alles auswählen

my_line = "\n" + " {0:<2}   {1:<30}  {2:>6}    {3:>4}"
dann aufrufen mit:

Code: Alles auswählen

my_line.format(....
Ist das jetzt so ok?
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

Auch hier gilt wieder, das my_-Präfix bietet keinen Mehrwert und line ist keine Name für ein FORMAT_TEMPLATE
Benutzeravatar
__blackjack__
User
Beiträge: 13970
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Warum da zwei Zeichenkettenliterale per ``+`` zusammengesetzt werden ist mir auch nicht so ganz klar. Zudem denke ich immer noch das Zeilenendezeichen ans Zeilenende gehören. Sonst hiessen sie ja Zeilenanfangszeichen. 😉
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Antworten