webcrawler = "td class="number" headers=" auslesen

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
alfer
User
Beiträge: 8
Registriert: Samstag 16. Oktober 2021, 16:54

Hallo,

Ich bin dabei mir einen Webcrawler zu bauen der Aktiendaten von Morningstar zieht und diese in eine csv Datei speichert. Soweit läuft es ganz gut, allerdings hänge ich an folgenden Problem:

Mit diesem Code lese ich eine Reihe von daten aus einer Tabelle (Ertrag):

Code: Alles auswählen

url = "https://tools.morningstar.de/de/stockreport/default.aspx?tab=10&vw=is&SecurityToken=0P0001DHJ2%5D3%5D0%5DE0WWE%24%24ALL&Id=0P0001DHJ2&ClientFund=0&CurrencyId=EUR"
seite = requests.get(url)
    
bs4_seite = None
if seite.status_code == 200:
    bs4_seite = bs4.BeautifulSoup(seite.content, 'html.parser')
else:
    print('Seite konnte nicht geladen werden.', url)
    
table_incomestatement = bs4_seite.find('div', {'id': 'FinancialsIncomeStatement'})
table_tbody = table_incomestatement.find('tbody')
table_tr = table_tbody.find('tr')
    
for stockreport in table_tr.select("td"):
    print(stockreport)
Es werde auch alle 5 Einträge wieder gegeben:

Code: Alles auswählen

<td class="number" headers="MsStockReportFisY1">659,36</td>
<td class="number" headers="MsStockReportFisY2">1.012,44</td>
<td class="number" headers="MsStockReportFisY3">1.652,95</td>
<td class="number" headers="MsStockReportFisY4">2.656,77</td>
<td class="number" headers="MsStockReportFisY5">3.641,39</td>
Allerdings will ich jedem Eintrag in eine variable packen, also y1, y2, y3 usw. Nach vielen Googlen und YouTube schauen, gelingt es mir leider immer noch nicht.

Wäre super, wenn mir jemand helfen könnte.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Deine Fehlerbehandlung ist fehlerhaft. Wenn status_code nicht 200 ist, ist bs4_seite None und hat keine Methode find, so dass das Programm mit einem Fehler abbricht, der an einer Stelle auftritt, wo das ursprüngliche Problem gar nicht mehr sichtbar ist.

Statt einzelner Variablen benutzt man eine passende Datenstruktur: Liste, Wörterbuch oder was auch immmer für die Weiterverrbeitung nötig ist.
Wie sehen die Daten genau aus, die Du brauchst? Nur die Zahlen, die Headers? Wie viele Zeilen gibt es?
alfer
User
Beiträge: 8
Registriert: Samstag 16. Oktober 2021, 16:54

Danke für die schnelle Antwort!
Sirius3 hat geschrieben: Sonntag 17. Oktober 2021, 10:22 Deine Fehlerbehandlung ist fehlerhaft. Wenn status_code nicht 200 ist, ist bs4_seite None und hat keine Methode find, so dass das Programm mit einem Fehler abbricht, der an einer Stelle auftritt, wo das ursprüngliche Problem gar nicht mehr sichtbar ist.
Ist das ein generelles Problem oder bezieht sich das direkt auf die daten des weiteren codes? Das Program läuft bei mir generell durch, von daher habe ich nicht so darauf geachtet.
Sirius3 hat geschrieben: Sonntag 17. Oktober 2021, 10:22Statt einzelner Variablen benutzt man eine passende Datenstruktur: Liste, Wörterbuch oder was auch immmer für die Weiterverrbeitung nötig ist.
Wie sehen die Daten genau aus, die Du brauchst? Nur die Zahlen, die Headers? Wie viele Zeilen gibt es?
Es geht um die Zahlen. Wenn ich

Code: Alles auswählen

print(stockreport.text)
benutze werden auch nur diese wiedergegeben.

Es sind immer fünf datensätze, wenn kein Eintrag vorhanden ist, wird ein - benutzt. Die daten will ich in ein Dictionarie packen und das dann in ein csv datei schreiben (kommt später noch).
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@alfer,

der Rückgabewert eines HTTP Requests wird im allgemeinen Response genannt und der Rückgabewert des bs4 html.parsers ist ein "soup" Objekt.
Wenn man sich an solche Namenskonventionen hält, macht es den Code für andere auch verständlicher.
Du kannst einfach das csv-paket von Python verwenden um die Daten zu schreiben:

Code: Alles auswählen

import requests
import bs4
import csv

url = "https://tools.morningstar.de/de/stockreport/default.aspx?tab=10&vw=is&SecurityToken=0P0001DHJ2%5D3%5D0%5DE0WWE%24%24ALL&Id=0P0001DHJ2&ClientFund=0&CurrencyId=EUR"
response = requests.get(url)

if response.status_code == 200:
    soup = bs4.BeautifulSoup(response.content, "html.parser")
else:
    print("Seite konnte nicht geladen werden.", url)

table_incomestatement = soup.find("div", {"id": "FinancialsIncomeStatement"})
table_tbody = table_incomestatement.find("tbody")
table_tr = table_tbody.find("tr")


with open("data.csv", "w", encoding="utf-8", newline="") as csv_file:
    writer = csv.writer(csv_file, delimiter=";")
    writer.writerow((stockreport.text for stockreport in table_tr.select("td")))
Leider enthalten die Eurobeträge Komma als Dezimalzeichen. Daher muss man die gegebenen Falls in "float" umwandeln und dann mit dem Dezimalpunkt speichern. Oder man nimmt als Trennzeichen in der CSV-Datei ein Semikolon.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@rogerb: Für Geldbeträge sollte man Decimals verwenden, nicht floats.
In specifications, Murphy's Law supersedes Ohm's.
alfer
User
Beiträge: 8
Registriert: Samstag 16. Oktober 2021, 16:54

rogerb hat geschrieben: Dienstag 19. Oktober 2021, 10:32 @alfer,

der Rückgabewert eines HTTP Requests wird im allgemeinen Response genannt und der Rückgabewert des bs4 html.parsers ist ein "soup" Objekt.
Wenn man sich an solche Namenskonventionen hält, macht es den Code für andere auch verständlicher.
Du kannst einfach das csv-paket von Python verwenden um die Daten zu schreiben:

Code: Alles auswählen

import requests
import bs4
import csv

url = "https://tools.morningstar.de/de/stockreport/default.aspx?tab=10&vw=is&SecurityToken=0P0001DHJ2%5D3%5D0%5DE0WWE%24%24ALL&Id=0P0001DHJ2&ClientFund=0&CurrencyId=EUR"
response = requests.get(url)

if response.status_code == 200:
    soup = bs4.BeautifulSoup(response.content, "html.parser")
else:
    print("Seite konnte nicht geladen werden.", url)

table_incomestatement = soup.find("div", {"id": "FinancialsIncomeStatement"})
table_tbody = table_incomestatement.find("tbody")
table_tr = table_tbody.find("tr")


with open("data.csv", "w", encoding="utf-8", newline="") as csv_file:
    writer = csv.writer(csv_file, delimiter=";")
    writer.writerow((stockreport.text for stockreport in table_tr.select("td")))
Leider enthalten die Eurobeträge Komma als Dezimalzeichen. Daher muss man die gegebenen Falls in "float" umwandeln und dann mit dem Dezimalpunkt speichern. Oder man nimmt als Trennzeichen in der CSV-Datei ein Semikolon.
Hat mir sehr geholfen! Vielen dank!!!

Semikolon ist kein Problem, bei meiner NL office Version ist das die standaart Einstellung!
Antworten