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

OK, habe es gerade auch gemerkt, aber wenn ich es wie @Sirius3 vorgeschlagen hat mache

Code: Alles auswählen

html = BeautifulSoup(response.content, 'html.parser')
tabelle = html.find('table')
for row in tabelle.find_all('tr'):
    print([cell.text.strip() for cell in row.find_all('td')]
stehen die Vereinsnamen doppelt da.
Sonst wäre es ok.
Benutzeravatar
__blackjack__
User
Beiträge: 13970
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@egon11: Wenn dabei zu viel rum kommt, muss man halt etwas gezielter vorgehen als einfach aus jeder Zelle den gesamten Text zu extrahieren.
“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
nezzcarth
User
Beiträge: 1739
Registriert: Samstag 16. April 2011, 12:47

egon11 hat geschrieben: Freitag 27. Dezember 2019, 21:53 stehen die Vereinsnamen doppelt da.
Sonst wäre es ok.
Mein Eindruck ist, dass du vielleicht mit HTML noch nicht ganz warm geworden bist. :) Wenn das der Fall sein sollte, möchte ich meinen Vorschlag von oben noch mal präzisieren: Nimm dir ein paar Stunden Zeit und lies dich ein wenig in HTML und evtl. CSS ein (BeautifulSoup unterstützt CSS-Selektoren). Gute Infos gibt es zum Beispiel beim Mozilla Developer Network (früher war "SELFHTML" eine weitere übliche Empfehlung, aber das habe ich mir ewig nicht angesehen.) Anschließend kannst du dir mit den Funktionen deines Browsers mal den Quelltext und den Dom-Tree (strg+c in Firefox) ansehen. Aus meiner Sicht ist das jedenfalls eine Voraussetzung, um die Aufgabe, die du dir gestellt hast zu bewältigen.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ok mache ich, schon mal vielen Dank.

Ich bin bei linkedin, da gibt es auch lern video's, kann da jemand etwas empfehlen?
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich habe jetzt mehrere Stunden damit verbracht, und habe jetzt mal folgendes geschrieben was genau meine Ansprüche hat.
Hier der Code:

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, 'html.parser')
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")


liste.append(beschreibung)    
for row in tabelle.find_all("ul"):
    meintext = [d.text.strip() 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])
    liste.append(text_fertig)

for text in liste:
    print(text)
Es kann ja mal jemand drüber schauen ob das so ok ist, und was man eventuell noch verbessern/erweitern kann.
Vielen Dank
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich muss leider noch einmal fragen.
Der Code funktioniert ja recht gut in python3.
Jetzt möchte ich es mal mit urllib bzw urllib2 in python2 testen.
Wie muss der code dann aussehen?

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, 'html.parser')

__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Python zwei ist tot. Seit diesem Jahr. https://pythonclock.org/

Warum also etwas damit testen?
Sirius3
User
Beiträge: 18245
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum möchtest du das? Python2 ist veraltet. Im übrigen verwendest du kein urllib, sondern request. Der Code sieht also identisch aus.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich möchte es in enigma2 einbauen, und da läuft nur python2.
Ich habe es mit 'request' gemacht, das ganze läuft auch, ich wollte nur mal testen ob das mit 'urllib2' schneller läuft, weil 'request' ganz schön lange dauert.
nezzcarth
User
Beiträge: 1739
Registriert: Samstag 16. April 2011, 12:47

egon11 hat geschrieben: Samstag 4. Januar 2020, 18:57 Ich möchte es in enigma2 einbauen, und da läuft nur python2.
Ich habe es mit 'request' gemacht, das ganze läuft auch, ich wollte nur mal testen ob das mit 'urllib2' schneller läuft, weil 'request' ganz schön lange dauert.
Was meinst du mit "dauert ganz schön lange"? Die einzelnen Anfragen? Die Erfahrung habe ich nicht gemacht; requests ist zwar sicher nicht die schnellste HTTP-Bibliothek für Python, aber von denen, die ich kenne die, die am angenehmsten zu benutzen ist und normalerweise schnell genug. Bottlenecks sind eher außerhalb von requests zu verorten, entweder im Netzwerk (langsam antwortende Server etc.), oder im restlichen Code. Als Fallback für Fälle, in denen requests nicht genügt, verwende ich manchmal PyCurl/libcurl. Damit kann man sich dann maßgeschneiderte, effiziente Anfragen basteln. Allerdings ist das nur ein dünner (sehr unpythonischer) Wrapper um eine C-Bibliothek, entsprechend Low-Level und unhandlich in der Benutzung. Vielleicht hat jemand anderes noch einen zugänglicheren Vorschlag.

Soweit ich jetzt auf Schnelle herausfinden konnte, haben die Entwickler von diesem 'enigma2' den Wechsel zu Python3 sehenden Auges verschlafen und auch nur so mittelmäßiges Interesse, da nachzubessen. Super :/
Zuletzt geändert von nezzcarth am Samstag 4. Januar 2020, 19:28, insgesamt 1-mal geändert.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

nezzcarth hat geschrieben: Samstag 4. Januar 2020, 19:20
Soweit ich jetzt auf Schnelle herausfinden konnte, haben die Entwickler von diesem 'enigma2' den Wechsel zu Python3 sehenden Auges verschlafen und auch nur so mittelmäßiges Interesse, da nachzubessen. Super :/
Ja genau so ist es.

Genau genommen dauert der Teil lange:

Code: Alles auswählen

response = requests.get(url)
html = BeautifulSoup(response.content, 'html.parser')
Gibt es für 'bs4' eine Alternative?

Ich schaue mir gerade mal 'xml.etree' an.
nezzcarth
User
Beiträge: 1739
Registriert: Samstag 16. April 2011, 12:47

egon11 hat geschrieben: Samstag 4. Januar 2020, 19:27 Genau genommen dauert der Teil lange:

Code: Alles auswählen

response = requests.get(url)
html = BeautifulSoup(response.content, 'html.parser')
Gibt es für 'bs4' eine Alternative?
Hier kann man nicht sagen, ob der HTTP-Request oder das Einlesen der Daten lange dauert. Das solltest du eingrenzen, bevor du mit Optimierungen beginnst.

BeautifulSoup greift auf eine Parser-Bibliothek zurück. Du verwendest 'html.parser' aus der Standardbibliothek. Andere Optionen sind die externen, separat zu installierenden Bibliotheken 'lxml' und 'html5lib'. 'lxml' ist nach meiner Erfahrung die schnellste Option.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK, wenn ich jetzt 'lxml' einsetze, kann er

Code: Alles auswählen

html.find(class_="table_content")
nicht umsetzen, muss dann der ganze code geändert werden?
nezzcarth
User
Beiträge: 1739
Registriert: Samstag 16. April 2011, 12:47

Was meinst du damit? Wenn es die Klasse "table_content" gibt, erhält man auch mit lxml als Backend die entsprechenden Elemente als Resultat.

'class'-Attribute können übrigens von mehreren Elementen verwendet werden, mit 'find' bekommst aber immer nur das erste. Für den Fall, dass es mehr als ein Resultat geben kann, gibt es 'find_all'. Wenn das Element, das du suchst, ein 'id'-Attribut hat, wäre es meiner Meinung nach sauberer das zu verwenden, da id-Attribute einmalig sein sollen.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich habe jetzt so

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-xml').encode('utf-8')

tabelle = html.find(class_="table_content")
Dann kommt der Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/scrip.py", line 8, in <module>
    tabelle = html.find(class_="table_content")
TypeError: find() takes no keyword arguments
nezzcarth
User
Beiträge: 1739
Registriert: Samstag 16. April 2011, 12:47

Nimm 'lxml' statt 'lxml-xml'.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Genau das gleiche.
nezzcarth
User
Beiträge: 1739
Registriert: Samstag 16. April 2011, 12:47

Achso, lass ".encode('utf-8')" weg. Das macht nicht, was du vielleicht denkst und verursacht das Problem, da es dem BeautifulSoup-Objekt 'bytes' macht. Das kann man übrigens leicht mit 'type(html)' im interaktiven Interpreter ausprobieren.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ohne

Code: Alles auswählen

.encode('utf-8')
kommt der Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/scrip.py", line 16, in <module>
    meintext[7],meintext[8],meintext[9]) + "\n"
UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-2: ordinal not in range(128)
Mein code sieht aktuell so aus:

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

liste.append(beschreibung)    
for row in tabelle.find_all("ul"):
    meintext = [d.text.strip() 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)

print(liste)

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

@egon11: Bei Python 2 musst Du halt selbst besser zwischen Text und Bytes unterscheiden und expliziter damit sein was Du haben willst. Du versuchst hier Text (`unicode`) in Byteketten (`str`) zu formatieren. Mach aus dem Text in den Du da formatieren willst mit einem u ein `unicode`-Objekt.
“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