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: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Das heißt ich kann den gar nicht formatieren?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Doch, aber der Formatstring muss unicode sein.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@egon11: Doch, aber Du musst halt sicherstellen das entweder Unicodezeichenketten in Unicodezeichenketten oder Bytezeichenketten in Bytezeichenketten formatiert werden. Am saubersten ist es für Text `unicode` zu nehmen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK, es kommt aber nur 'None' als Ausgabe.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Wo kommt nur None als Ausgabe? Du hast ein print mit einer Liste.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup

url = "http://www.sportal.de/fussball/bundesliga/tabelle/tabelle-saison-2019-2020"
response = requests.get(url)
html = BeautifulSoup(response.content, 'lxml')

tabelle = html.find(class_="table_content")
liste = []
beschreibung = "{0:<4} {1:<22} {2:>4} {3:>4} {4:>4} {5:>4} {6:>7} {7:>4} {8:>4} ".format("Pl", "Verein", "Sp", "G", "UE", "V", "Tore", "Diff", "P") + "\n\n"

liste.append(beschreibung)    
for row in tabelle.find_all("ul"):
    meintext = [d.unicode for d in row.find_all("li")]
    text_fertig = "{0:<4} {1:<22} {2:>4} {3:>4} {4:>4} {5:>4} {6:>7} {7:>4} {8:>4} ".format(meintext[0],meintext[2],meintext[3],meintext[4],meintext[5],meintext[6],\
                                                                                meintext[7],meintext[8],meintext[9]) + "\n"
    liste.append(text_fertig.encode('utf8'))

print("".join(liste))
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Sirius3 hat geschrieben: Sonntag 5. Januar 2020, 11:55 Wo kommt nur None als Ausgabe? Du hast ein print mit einer Liste.
Ja bei print kommt immer "None".
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Das kann nicht sein, denn eine Liste wird niemals "None" als Ausgabe geben.
Und einfach irgendwo an zufälligen Stellen `encode` einzustreuen, wird nicht zu einer nachhaltigen Lösung führen.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Das encode habe ich wieder raus genommen. so sieht meine print Ausgabe aus:

Code: Alles auswählen

Pl   Verein                   Sp    G   UE    V    Tore Diff    P 

None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
None None                   None None None None    None None None 
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Jetzt sehe ich erst, was Du gemacht hast. Du hast d.text durch d.unicode ersetzt. Wie kommst Du nur auf die Idee, dass das was sinnvolles sein könnte. Mit Raten kommst Du nicht weiter. Also entweder Du liest die Dokumentation oder befolgst das, was Dir hier empfohlen wird.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wie schon gesagt wurde: response.content liefert Bytes, aber in so einem Fall will man Unicode. Also muss man "text" statt "content" benutzen. Teilt man es außerdem zur Übersicht und Testbarkeit in Funktionen auf und zieht die konfigurierbaren Teile an den Anfang, dann kann das so aussehen:

Code: Alles auswählen

#!/usr/bin/env python3
from bs4 import BeautifulSoup
import requests

URL = "http://www.sportal.de/fussball/bundesliga/tabelle/tabelle-saison-2019-2020"

TABLE_CONFIG = {
    "Pl": "<4",
    "Verein": "<22",
    "Sp": ">4",
    "G": ">4",
    "UE": ">4",
    "V": ">4",
    "Tore": ">7",
    "Diff": ">4",
    "P": ">4",
}

def get_table_soup(url):
    response = requests.get(url)
    response.raise_for_status()
    soup = BeautifulSoup(response.text, "lxml")
    return soup.find(class_="table_content")

def parse_table_rows(soup):
    for row in soup.find_all("ul"):
        yield [elem.text.strip() for elem in row.find_all("li")
               if not elem.text.isspace()]

def print_table(rows, config):
    template = " ".join(f"{{:{spec}}}" for spec in config.values())
    print(template.format(*config.keys()))
    for row in rows:
        print(template.format(*row))

def main():
    rows = parse_table_rows(get_table_soup(URL))
    print_table(rows, TABLE_CONFIG)


if __name__ == '__main__':
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Ob man `text` oder `content` nimmt ist eigentlich egal denn das geht ja in jedem Fall durch den HTML-Parser und danach ist es `unicode`, egal was man da rein gefüttert hat. Das war ja das Problem, das versucht wurde die `unicode`-Objekte die BeautifulSoup liefert in ein `str`-Objekt zu formatieren. Und das Problem hat Dein Code auch, wenn er denn überhaupt unter Python 2 laufen würde.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@snafu: das ist nicht das Problem. Denn wenn BeautifulSoup ein Bytes-Objekt bekommt, dann ermittelt es das Encoding wenn möglich am meta-Tag. Außerdem geht es gerade darum, das mit Python2 zum Laufen zu bringen. Da kann man sich nicht auf die Reihenfolge von Wörterbüchern verlassen oder f-Strings benutzen.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

response.content führt in der cmd.exe unter Windows jedenfalls zu Darstellungsproblemen mit Umlauten. Bei response.text besteht das Problem nicht. Für Python 2.7 habe ich es jetzt nicht getestet. Die neuen Features gehen da natürlich nicht. Fragt sich dann aber eher, warum jemand noch Python 2.x nutzt und ob er kein Upgrade machen kann...
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: *Die* Frage wurde auch schon gestellt und beantwortet: Das soll ein Plugin für Enigma2 sein, und da gibt's halt nur Python 2. Das zu ändern dürfte den Rahmen sprengen. ;-)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Als ob ich hier mehr als drei Beiträge im Thread lese... :lol: ;)
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich habe mir gerade gelesen dass das Modul "lxml" schneller als bs4 arbeiten soll.
Kann man daraus etwas basteln was ich vor hab?
Wenn ja ich finde dazu kein richtiges howto im Netz, eventuell jemand einen Tipp?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

lxml ist bestimmt schneller, aber der Grund dafuer ist, dass es ein wrapper um die C-Bibliotheken libxml und libxslt ist. Sind die auf deiner enigma vorhanden? Sonst ist das alles vergebliche Liebesmueh.

Und so oder so frage ich mich, warum du hier rumoptimieren willst. Es fallen ja keine Tore im Mikrosekunden-Takt. Wenn es ein paar Sekunden dauert, das zu updaten - wo liegt genau das Problem?
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Das Problem ist, es gab mal das "kicker" plugin. Somit konnte man aktuelle Ergebnisse etc. abrufen.
Wenn man da auf eine Seite ging dauerte es nicht lang und die wurde geladen.
Wenn ich jetzt mein Plugin öffne, dauert es knapp 7 Sekunden, bis die Seite geladen hat. Und das auf einer 1,6GHZ schnellen Box.
Es gibt aber auch Boxen mit 750 MHZ...
Deswegen frage ich nach einer schnelleren alternative.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@egon11: Das ist erst einmal keine Frage von `lxml` *oder*` BeautifulSoup, denn letzteres würde ich auf jeden Fall verwenden, und das kann `lxml` als Parser verwenden. Bei Python 2 würde ich auch dringend vom 'html.parser' aus der Standardbibliothek abraten, denn das war bei Python 2 nur bei fehlerfreiem HTML wirklich verwendbar. Das Modul ist erst in Python 3 robuster geworden.

Bevor Du irgendetwas optimierst solltest Du erst einmal schauen *wo* die Zeit verbraucht wird. Es gibt ja mindestens die drei Teilbereiche laden der Daten über das Netz, parsen des HTML, und dann das suchen und extrahieren der Werte.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten