Werte aus Homepage 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
tmessers
User
Beiträge: 28
Registriert: Dienstag 30. Oktober 2018, 21:08

Hallo liebe Python-Gemeinde,

ich habe ein Frage zu einem Projekt.

Unter
https://www.baden-wuerttemberg.de/de/se ... rttemberg/
liegt ein Karte. In dieser sind Zahlenwerte eingetragen. Ich möchte bestimmte Zahlenwerte täglich auslesen und in ein json-file schreiben. Mit Pandas erzeuge ich dann ein DataFrame und erzeuge mit matplotlib die grafische Darstellung.

Ich habe versucht mit BeautifulSoup die Zahlenwerte zu finden, komme da aber nicht weiter.
Weiß jemand Rat?

Danke im Voraus für Eure Unterstützung.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich sehe da keine Karte. Darum kann man nur raten.

Ein Klassiker ist die Verwendung von JavaScript zum nachladen. Wenn das der Fall ist, kannst du im Browser debugger versuchen die requests zu identifizieren. Und die dann direkt nutzen. Oder zur Not selenium einsetzen.
tmessers
User
Beiträge: 28
Registriert: Dienstag 30. Oktober 2018, 21:08

Der Link hatte einen Schreibfehler.
https://www.baden-wuerttemberg.de/de/service/aktuelle-infos-zu-corona/corona-karte-baden-wuerttemberg/
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das Bild ist ein JPEG und die Zahlen auf der Karte sind im Bild. Das wirst Du da nicht so wirklich einfach raus bekommen.

Nach ein bisschen unmotiviertem rumklicken auf den Seiten, habe ich auf dieser Seite: https://sozialministerium.baden-wuertte ... rttemberg/ eine Excel-Datei entdeckt. Vielleicht ist das ja was für Dich.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
tmessers
User
Beiträge: 28
Registriert: Dienstag 30. Oktober 2018, 21:08

Danke für den Tipp.
Der war sehr gut.
Ich habe den folgenden Code geschrieben,
der meinen Zwecke erfüllt.

Code: Alles auswählen

 import pandas as pd
import matplotlib.pyplot as plt
import time
from datetime import date
import dateutil

df =pd.read_excel('https://sozialministerium.baden-wuerttemberg.de/fileadmin/redaktion/m-sm/intern/downloads/Downloads_Gesundheitsschutz/Tabelle_Coronavirus-Faelle-BW.xlsx', sheet_name=0, header=6)
#print(df)
#Auswahl der Zeilen, die Berücksichtigt werden sollen
df_auswahl=df.loc[[10,5,1,26,29],:]
#Transponieren der Spalten
df_auswahl=df_auswahl.T
#Erste Zeile des DataFrame löschen
df_auswahl.drop(['Unnamed: 0'],inplace=True)
df_auswahl.columns = ['Freiburg','Breisg.-Hochschw.','Baden-Baden','Ortenau','Rastatt']
#print(df_auswahl)
#——-Dialog: Zeitraum auswählen über Datum
#Letzen Datumswert ermitteln
erst_datum=df_auswahl.index[-1]
Frage=input('Wollen Sie den Zeitraum eingrenzen? j/n: /n Erstes Datum ist %s' %erst_datum)
if Frage == 'j':
  monat=input('Geben Sie den Monat ein. Format XX: ')
  tag=input('Geben Sie einen Tag ein. Format XX: ')
  datum=('2020-%s-%s' %(monat,tag))
else:
  datum=str(erst_datum)
#DataFrame in Abhängigkeit von datum erstellen  
df_neu= df_auswahl[df_auswahl.index > dateutil.parser.parse(datum)]
#print(df_neu)
#——-Werte für annotate ermitteln
wert_fre=int(df_neu.at[df_neu.index[0],df_neu.columns[0]])
#print(wert_fre)
wert_brh=int(df_neu.at[df_neu.index[0],df_neu.columns[1]])
wert_bad=int(df_neu.at[df_neu.index[0],df_neu.columns[2]])
wert_ort=int(df_neu.at[df_neu.index[0],df_neu.columns[3]])
wert_ras=int(df_neu.at[df_neu.index[0],df_neu.columns[4]])
#aktuelles Datum im DataFrame-Index ermitteln
akt_datum=df_neu.index[0]
#print(akt_datum)

#———Erstellung des Diagramms mit matplotlib
#Festlegung des Standes
stand=date.today()
#Plot erstellen
df_neu.plot(marker='.')
plt.xticks(rotation=30)
plt.grid(True)
plt.title('Coronafälle Stand: %s' %stand)
plt.gcf().autofmt_xdate() 
plt.annotate(str(wert_fre),xy=(akt_datum,wert_fre),color='blue')
plt.annotate(str(wert_brh),xy=(akt_datum,wert_brh),color='orange')
plt.annotate(str(wert_bad),xy=(akt_datum,wert_bad),color='green')
plt.annotate(str(wert_ort),xy=(akt_datum,wert_ort),color='red')
plt.annotate(str(wert_ras),xy=(akt_datum,wert_ras),color='purple')
plt.xlabel('Datum')
plt.ylabel('Fälle')
plt.show()
dateiname= ('%s Corona-BW.pdf' %stand)
plt.savefig(dateiname)
Was lässt sich aus Eurer Sicht verbessern?
tmessers
User
Beiträge: 28
Registriert: Dienstag 30. Oktober 2018, 21:08

Danke für den Tipp.
Der war sehr gut.
Ich habe den folgenden Code geschrieben,
der meinen Zwecke erfüllt.

Code: Alles auswählen

 import pandas as pd
import matplotlib.pyplot as plt
import time
from datetime import date
import dateutil

df =pd.read_excel('https://sozialministerium.baden-wuerttemberg.de/fileadmin/redaktion/m-sm/intern/downloads/Downloads_Gesundheitsschutz/Tabelle_Coronavirus-Faelle-BW.xlsx', sheet_name=0, header=6)
#print(df)
#Auswahl der Zeilen, die Berücksichtigt werden sollen
df_auswahl=df.loc[[10,5,1,26,29],:]
#Transponieren der Spalten
df_auswahl=df_auswahl.T
#Erste Zeile des DataFrame löschen
df_auswahl.drop(['Unnamed: 0'],inplace=True)
df_auswahl.columns = ['Freiburg','Breisg.-Hochschw.','Baden-Baden','Ortenau','Rastatt']
#print(df_auswahl)
#——-Dialog: Zeitraum auswählen über Datum
#Letzen Datumswert ermitteln
erst_datum=df_auswahl.index[-1]
Frage=input('Wollen Sie den Zeitraum eingrenzen? j/n: /n Erstes Datum ist %s' %erst_datum)
if Frage == 'j':
  monat=input('Geben Sie den Monat ein. Format XX: ')
  tag=input('Geben Sie einen Tag ein. Format XX: ')
  datum=('2020-%s-%s' %(monat,tag))
else:
  datum=str(erst_datum)
#DataFrame in Abhängigkeit von datum erstellen  
df_neu= df_auswahl[df_auswahl.index > dateutil.parser.parse(datum)]
#print(df_neu)
#——-Werte für annotate ermitteln
wert_fre=int(df_neu.at[df_neu.index[0],df_neu.columns[0]])
#print(wert_fre)
wert_brh=int(df_neu.at[df_neu.index[0],df_neu.columns[1]])
wert_bad=int(df_neu.at[df_neu.index[0],df_neu.columns[2]])
wert_ort=int(df_neu.at[df_neu.index[0],df_neu.columns[3]])
wert_ras=int(df_neu.at[df_neu.index[0],df_neu.columns[4]])
#aktuelles Datum im DataFrame-Index ermitteln
akt_datum=df_neu.index[0]
#print(akt_datum)

#———Erstellung des Diagramms mit matplotlib
#Festlegung des Standes
stand=date.today()
#Plot erstellen
df_neu.plot(marker='.')
plt.xticks(rotation=30)
plt.grid(True)
plt.title('Coronafälle Stand: %s' %stand)
plt.gcf().autofmt_xdate() 
plt.annotate(str(wert_fre),xy=(akt_datum,wert_fre),color='blue')
plt.annotate(str(wert_brh),xy=(akt_datum,wert_brh),color='orange')
plt.annotate(str(wert_bad),xy=(akt_datum,wert_bad),color='green')
plt.annotate(str(wert_ort),xy=(akt_datum,wert_ort),color='red')
plt.annotate(str(wert_ras),xy=(akt_datum,wert_ras),color='purple')
plt.xlabel('Datum')
plt.ylabel('Fälle')
plt.show()
dateiname= ('%s Corona-BW.pdf' %stand)
plt.savefig(dateiname)
Was lässt sich aus Eurer Sicht verbessern?
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@tmessers: Anmerkungen zum Quelltext:

`time` wird importiert, aber nicht verwendet.

Eingerückt wird in Python vier Leerzeichen pro Ebene, nicht zwei.

Nach Kommas und um binäre Operatoren erhöhen Leerzeichen die Lesbarkeit. Den ``%``-Operator hast Du anscheinend immer an den zweiten Operanden gesetzt, und bei einfachen Zuweisungen immer unnötige Klammern um den Ausdruck gesetzt‽

``%`` würde ich in neuem Code auch nicht mehr zur Zeichenkettenformatierung verwenden wenn es dafür nicht einen guten Grund gibt. Es gibt die `format()`-Methode und ab Python 3.6 f-Zeichenkettenliterale.

Die Auswahl der Zeilen nach Nummern wäre mir nicht robust genug. Ich würde da die erste Spalte zum Index machen und über die Namen zugreifen.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). `Frage` würde also klein geschrieben. Aber es ist gar keine Frage sondern eine Antwort.

Das Datum erst in eine Zeichenkette zu wandeln nur um es danach zu parsen ist unsinnig. Stattdessen sollte man einfach aus der Benutzereingabe gleich ein `datetime.date`-Objekt oder ein `pandas.Timestamp`-Objekt erstellen.

Namen sollten keine kryptischen Abkürzungen enthalten. Die ganzen "wert_???"-Namen mit den dreibuchstabigen Stadt-/Landkreisabkürzungen sind schlecht. Das sollten auch gar keine einzelnen Namen sein, denn man kann die erste Zeile einfach an den Namen `aktuelle_fallzahlen` binden und auch Pandas gleich zum Umwandeln nach `int` verwenden:

Code: Alles auswählen

In [66]: df.iloc[0].astype(int)                                                 
Out[66]: 
Freiburg              921
Breisg.-Hochschw.    1019
Baden-Baden           164
Ortenau               936
Rastatt               473
Name: 2020-04-22 00:00:00, dtype: int64
Für die `annotate()`-Aufrufe kann man dann eine Schleife über dieser Werte und die dazugehörigen Farben schreiben.

Apropos Farben: Die sollten da nicht so fest kodiert im Quelltext stehen, denn die hängen vom Farbschema ab. Wenn man die aus dem Plot von den Linien abfragt, ist man vom Farbschema unabhängig und bekommt dort immer die passenden Farben. Und man ist dann auch von der Anzahl der ausgewählten Stadt-/Landkreise unabhängig und kann ganz einfach welche hinzufügen oder weglassen, ohne den restlichen Code ändern zu müssen.

Code: Alles auswählen

#!/usr/bin/env python3
from datetime import date as Date

import matplotlib.pyplot as plt
import pandas as pd

EXCEL_FILE_URL = (
    "https://sozialministerium.baden-wuerttemberg.de/"
    "fileadmin/redaktion/m-sm/intern/downloads/Downloads_Gesundheitsschutz/"
    "Tabelle_Coronavirus-Faelle-BW.xlsx"
)


def main():
    #
    # Paare: (Bezeichnung in Quelle, kürzere Bezeichnung für den Plot).
    #
    stadt_und_landkreise = [
        ("Freiburg im Breisgau (Stadtkreis)", "Freiburg"),
        ("Breisgau-Hochschwarzwald", "Breisg.-Hochschw."),
        ("Baden-Baden (Stadtkreis)", "Baden-Baden"),
        ("Ortenaukreis", "Ortenau"),
        ("Rastatt", "Rastatt"),
    ]
    df_auswahl = (
        pd.read_excel(EXCEL_FILE_URL, header=6, index_col=0)
        .loc[[bezeichnung for bezeichnung, _ in stadt_und_landkreise], :]
        .transpose()
    )
    df_auswahl.columns = [
        kurz_bezeichnung for _, kurz_bezeichnung in stadt_und_landkreise
    ]

    datum = df_auswahl.index[-1]
    antwort = input(
        f"Wollen Sie den Zeitraum eingrenzen? j/n: /n"
        f" Erstes Datum ist {datum}"
    )
    if antwort == "j":
        monat = int(input("Geben Sie den Monat ein: "))
        tag = int(input("Geben Sie einen Tag ein: "))
        datum = pd.Timestamp(year=2020, month=monat, day=tag)

    df_plot_auswahl = df_auswahl[df_auswahl.index > datum]
    aktuelle_fallzahlen = df_plot_auswahl.iloc[0].astype(int)
    aktuelles_datum = aktuelle_fallzahlen.name

    stand = Date.today()
    plot = df_plot_auswahl.plot(
        title=f"Coronafälle Stand: {stand}", grid=True, rot=30, marker="."
    )
    plt.gcf().autofmt_xdate()
    plt.xlabel("Datum")
    plt.ylabel("Fälle")
    for fallzahl, farbe in zip(
        aktuelle_fallzahlen, (line.get_color() for line in plot.get_lines())
    ):
        plt.annotate(
            str(fallzahl), xy=(aktuelles_datum, fallzahl), color=farbe
        )
    plt.show()
    plt.savefig(f"{stand} Corona-BW.pdf")


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten