Hey ich bin relativ neu auf dem gebiet Python, hab aber auch einiges Drauf. Ich wollte die Homeschoolingphase dazu nutzen schonmal mehr zu lernen. Dann bin ich beim Thema Webscraping gelandet, welches wir komischer weise noch nie im Unterricht behandelt haben. Jetzt meine Frage ist es möglich eine von einer Internetseite gelesene Zahl in eine Rechnung einzubauen? (Ich wollte in meinem Beispiel die Relativzahl zu den Corona Infizierten Bayerns Ausrechnen:
Hier mein bisheriger Script:
from urllib.request import Request, urlopen
req = Request("https://www.rki.de/DE/Content/InfAZ/N/N ... ahlen.html")
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; 64x ;rv:75.0) Gecko/20100101 Firefox/75.0')
seite = urlopen( req)
text = seite.read().decode("utf 8")
print(text[36309:36315]/(13000000)) (die Zahlen zeigen die Position der Zahl der Infizierten an/ die ca 13 Mio sind die Einwohner Bayerns)
Ich wäre sehr dankbar wenn mir jemand helfen könnte, ich hab echt keine Ideen mehr was ich tun soll
Webscraping in Rechnungen einbeziehen
- __blackjack__
- User
- Beiträge: 14052
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Isa_Iso: Falls sich die Zahl aus der Webseite hinreichend leicht auslesen lässt, dann ja, die kann man dann in einer Rechnung verwenden. Warum auch nicht? Einer Rechnung ist es egal ob die Werte fest im Quelltext stehen, aus einer GUI kommen, aus einer Datei eingelesen wurden, über einen Sensor ermittelt wurden der am Rechner angeschlossen ist, aus einer Datenbank abgefragt wurden, … – eine Zahl ist eine Zahl und damit kann man alles machen was man mit Zahlen so machen kann.
Das Problem bei deinem Code, und da solltest Du in Zukunft am besten selbst gleich sagen was das konkrete Problem ist, dürfte sein, dass man *Zeichenketten* nicht durch Zahlen teilen kann. Auch wenn die Zeichenkette Ziffern enthält die ein Mensch als Zahl lesen/erkennen kann, für den Rechner ist das halt eine Zeichenkette, mit der man nur die Operationen durchführen kann, die für Zeichenketten definiert sind. So etwas in dieser Richtung passiert in Deinem Code:
Du musst also die Zeichenkette "43.905" in die Zahl 43905 umwandeln um damit rechnen zu können. Das wird mit `int()` alleine nicht gehen wegen dem Tausenderpunkt, mit dem die Funktion nichts anfangen kann. Den muss man vorher entfernen.
Was an dem Code nicht sehr robust ist, ist das „slicing” mit den festen magischen Werten 36309 und 36315. Da braucht sich nur ein kleines bisschen am Quelltext der Seite vor dem 36.309ten Zeichen ändern und schon stimmen diese Zahlen nicht mehr und Du liest einen falschen Bereich aus. Hier verwendet man besser einen HTML-Parser und orientiert sich dann an der Struktur des HTML-Dokuments um an den Wert zu gelangen. Zum Beispiel könnte man erst das recht eindeutige <div> mit der ID "main" ansteuern und da dann eine Tabellenzelle mit dem Inhalt "Bayern" suchen um dann von dort zur nächsten Zelle zu gehen und dort den Text auszulesen. Ein beliebtes Modul für das parsen von HTML und suchen von Elementen ist BeautifulSoup4.
Webseiten würde ich mit dem externen `requests`-Modul abfragen. Das nimmt einem mehr Arbeit ab. Zum Beispiel kann man dort auch gleich dekodierten Text von der Antwort des Servers abfragen und vorher prüfen lassen ob die Antwort eventuell eine Fehlermeldung ist, statt der Seite die man haben wollte.
Das Problem bei deinem Code, und da solltest Du in Zukunft am besten selbst gleich sagen was das konkrete Problem ist, dürfte sein, dass man *Zeichenketten* nicht durch Zahlen teilen kann. Auch wenn die Zeichenkette Ziffern enthält die ein Mensch als Zahl lesen/erkennen kann, für den Rechner ist das halt eine Zeichenkette, mit der man nur die Operationen durchführen kann, die für Zeichenketten definiert sind. So etwas in dieser Richtung passiert in Deinem Code:
Code: Alles auswählen
In [156]: "43.905" / 13_000_000
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-156-b91da3b0486e> in <module>
----> 1 "43.905" / 13_000_000
TypeError: unsupported operand type(s) for /: 'str' and 'int'
Was an dem Code nicht sehr robust ist, ist das „slicing” mit den festen magischen Werten 36309 und 36315. Da braucht sich nur ein kleines bisschen am Quelltext der Seite vor dem 36.309ten Zeichen ändern und schon stimmen diese Zahlen nicht mehr und Du liest einen falschen Bereich aus. Hier verwendet man besser einen HTML-Parser und orientiert sich dann an der Struktur des HTML-Dokuments um an den Wert zu gelangen. Zum Beispiel könnte man erst das recht eindeutige <div> mit der ID "main" ansteuern und da dann eine Tabellenzelle mit dem Inhalt "Bayern" suchen um dann von dort zur nächsten Zelle zu gehen und dort den Text auszulesen. Ein beliebtes Modul für das parsen von HTML und suchen von Elementen ist BeautifulSoup4.
Webseiten würde ich mit dem externen `requests`-Modul abfragen. Das nimmt einem mehr Arbeit ab. Zum Beispiel kann man dort auch gleich dekodierten Text von der Antwort des Servers abfragen und vorher prüfen lassen ob die Antwort eventuell eine Fehlermeldung ist, statt der Seite die man haben wollte.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Ich würde da auch BS4 für nutzen.
Das könnte dann so aussehen:
Das könnte dann so aussehen:
Code: Alles auswählen
from bs4 import BeautifulSoup
import requests
HEADERS = {"User-Agent":"Dein User Agent"}
URL = "https://www.rki.de/DE/Content/InfAZ/N/Neuartiges_Coronavirus/Fallzahlen.html"
page = requests.get(URL, headers=HEADERS)
soup = BeautifulSoup(page.content, "html.parser")
table_rows = soup.find('table').find('tbody').find_all('tr')
for table_row in table_rows:
data = table_row.find_all('td')
for table_data in data:
if "Bayern" in table_data.text:
print(data[data.index(table_data) + 1].text)
break
- __blackjack__
- User
- Beiträge: 14052
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Jankie: Das nutzt IMHO BeautifulSoup nicht richtig aus mit zwei verschachtelten Schleifen und einem ``if`` in Python die etwas machen was auch BeautifulSoup selbst schon erledigen kann: das erste <td>-Element mit dem Inhalt "Bayern" in einer Tabelle finden.
Ich schaue auch immer nach der nächstgelegenen ID, denn die müssen ja eindeutig sein im gesamten Dokument. Das wäre ein <div> mit der ID "main". Damit ist man sicher(er), dass die erste Tabelle die man findet, nicht irgend etwas im Kopf oder einem Seitenelement ist, sondern das man die im Hauptteil der Seite findet.
Wenn man die Tabelle hat, kann man gleich nach <td> mit Textinhalt "Bayern" suchen lassen, ohne sich um die <tr>-Element zu kümmern.
``data[data.index(table_data) + 1]`` ist umständlich und nicht so leicht lesbar und damit unverständlicher für `data.next_sibling`.
Mein Versuch:
@Isa_Iso: Wobei die Zahl die Du damit dann ausrechnest im Grunde schon fast ebenfalls in der Tabelle steht, nämlich in der Spalte „Fälle/100.000 Einw.“. Die braucht man ja nur durch 100.000 zu teilen und schon braucht man die Einwohnerzahl Bayerns nicht mehr aus einer zusätzlichen Quelle.
Ich schaue auch immer nach der nächstgelegenen ID, denn die müssen ja eindeutig sein im gesamten Dokument. Das wäre ein <div> mit der ID "main". Damit ist man sicher(er), dass die erste Tabelle die man findet, nicht irgend etwas im Kopf oder einem Seitenelement ist, sondern das man die im Hauptteil der Seite findet.
Wenn man die Tabelle hat, kann man gleich nach <td> mit Textinhalt "Bayern" suchen lassen, ohne sich um die <tr>-Element zu kümmern.
``data[data.index(table_data) + 1]`` ist umständlich und nicht so leicht lesbar und damit unverständlicher für `data.next_sibling`.
Mein Versuch:
Code: Alles auswählen
#!/usr/bin/env python3
import requests
from bs4 import BeautifulSoup
URL = (
"https://www.rki.de/DE/Content/InfAZ/N/Neuartiges_Coronavirus"
"/Fallzahlen.html"
)
POPULATION_OF_BAVARIA = 13_117_089
"""
Source: „Bayrisches Landesamt für Statistik“ as at 2019-Q3.
`https://www.statistikdaten.bayern.de/genesis/online/data?operation=ergebnistabelleUmfang&levelindex=2&levelid=1589020140175&downloadname=12411-009r`_
"""
def main():
response = requests.get(URL)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
number_of_cases = int(
soup.find("div", id="main")
.table.find("td", text="Bayern")
.next_sibling.text.replace(".", "")
)
print(number_of_cases / POPULATION_OF_BAVARIA)
if __name__ == "__main__":
main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari