Web-Scraping einer HTML-Tabelle, unklare div-/bzw class Tags

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
tomrause
User
Beiträge: 12
Registriert: Freitag 26. Februar 2021, 19:20

Guten Tag zusammen,
ich beschäftige mich zur Zeit mit Python und finde die Sprache sehr intuitiv.

Im Moment möchte ich eine Tabelle mit Erdbebendaten aus
https://en.vedur.is/earthquakes-and-vol ... view=table
scrapen, die ich als Trainingsdaten nutzen will, um andere Anwendungen (z.B. R) damit zu nutzen.

Ich komme mit requests und BeautifulSoup schon etwas weiter, habe aber im Moment keinen "Anpacker" um an Daten der auf o.g. Seite sichtbaren Datentabelle zugreifen zu können.
Die in den verschieden verschachtelten div-Tags sichtbaren Hinweise <div id="qtable" class="qtable"> bekomme ich nicht 'gefasst".

Ich bitte um Hinweise, welcher Tag hier der richtige "Anfasser" ist.

Anmerkung: in einem script-Tag auf der Seite steht die komplette Liste der Messwerte zwar unschön aber erkennbar drin. Wie könnte ich alternativ daran kommen?

Ich danke für Hinweise.
Tom

Mein bisheriges Script:
import requests
from bs4 import BeautifulSoup
#python C:\tmp\python\scripts\basicscrape.py

url = 'https://en.vedur.is/earthquakes-and-vol ... view=table'
res = requests.get(url)
html_page = res.content
soup = BeautifulSoup(html_page, 'html.parser')
text = soup.find_all(text=True)
output = ''
blacklist = [
'[document]',
'noscript',
'header',
'html',
'meta',
'head',
'body',
'input',
# there may be more elements you don't want, such as "style", etc.
]
for t in text:
if t.parent.name not in blacklist:
output += '{} '.format(t)
print(output)
Ich bitte um Hinweise
Danke
Tom
Benutzeravatar
__blackjack__
User
Beiträge: 14054
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@tomrause: Die Daten stehen nicht in der Tabelle sondern in einem <script>-Tag als JavaScript. Da kommt man beispielsweise heran in dem man das JavaScript ausführt. Es gibt einen (langsamen) Interpreter in Python mit dem das ginge:

Code: Alles auswählen

#!/usr/bin/env python3
import re

import bs4
import js2py
import requests
from glom import glom, T
from rich import print

URL = (
    "https://en.vedur.is/earthquakes-and-volcanism/earthquakes"
    "/reykjanespeninsula/"
)


def main():
    response = requests.get(URL)
    response.raise_for_status()
    soup = bs4.BeautifulSoup(response.content, "html.parser")
    js_source = soup.find(
        "script", src=False, text=re.compile(r"\s+var VI;")
    ).text
    context = js2py.EvalJs()
    context.execute(js_source)
    quake_info = glom(
        context.VI.quakeInfo,
        [
            {
                "timestamp": T["t"].toJSON(),
                "latitude": "lat",
                "longitude": "lon",
                "depth": "dep",
                "magnitude": "s",
                "quality": "q",
                "distance": "dL",
                "direction": "dD",
                "location_name": "dR",
            }
        ],
    )
    print(quake_info)


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
tomrause
User
Beiträge: 12
Registriert: Freitag 26. Februar 2021, 19:20

Guten Morgen __blackjack__ und erst einmal vielen Dank für deine Antwort.

Ich habe deinen Code übernommen und zuerst mittels pip install js2py ... /...glom und ... / ...rich nachinstalliert (Was diese Module genau mache lese ich mir im Anschluß durch)

Leider tritt ein Fehler beim Ausführen auf: VI sei nicht definiert.
  • Beim definieren von js_source setzt du re ein. Kann es sein, daß dort VI fälschlicherweise ausgeschlossen wird, so daß bei quake_info VI.quakeInfo nicht erkannt wird?
  • Habe ich mir möglicherweise eine nicht passende glom-Version installiert (wenn es die überhaupt gibt...)?
  • Ich benutze Python 3.9.1.
Ich bitte um Hinweise.

Noch was: du schriebst:
Die Daten stehen nicht in der Tabelle sondern in einem <script>-Tag als JavaScript
.
Dennoch tauchen im Quelltext der Seite sauber formatierte Tabellen-markups mit den Werten auf...., übersetzt der Browser zur Laufzeit aus dem Script in die Tabelle? Ich bin verwirrt und bitte um weitere Hinweise.

Vielen Dank
Tom

Code: Alles auswählen

C:\Users\TR>python c:\tmp\python\scripts\readjstopy.py
Traceback (most recent call last):
  File "c:\tmp\python\scripts\readjstopy.py", line 46, in <module>
    main()
  File "c:\tmp\python\scripts\readjstopy.py", line 27, in main
    context.VI.quakeInfo,
  File "C:\Users\TR\AppData\Roaming\Python\Python39\site-packages\js2py\evaljs.py", line 242, in __getattr__
    return getattr(self._var, var)
  File "C:\Users\TR\AppData\Roaming\Python\Python39\site-packages\js2py\base.py", line 1214, in __getattr__
    cand = to_python(self._obj.get(str(item)))
  File "C:\Users\TR\AppData\Roaming\Python\Python39\site-packages\js2py\base.py", line 1158, in get
    raise MakeError('ReferenceError', '%s is not defined' % prop)
js2py.internals.simplex.JsException: ReferenceError: VI is not defined
Ich bitte um Hinweise
Danke
Tom
Benutzeravatar
__blackjack__
User
Beiträge: 14054
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@tomrause: Meh, im aktuellen BeautifulSoup4 gibt es kein `Tag.text`-Attribut mehr, das heisst jetzt `string`. Diese Änderung steht nicht in der Dokumentation. ☹️

Also aus dem:

Code: Alles auswählen

    js_source = soup.find(
        "script", src=False, text=re.compile(r"\s+var VI;")
    ).text
wird:

Code: Alles auswählen

    js_source = soup.find(
        "script", src=False, string=re.compile(r"\s+var VI;")
    ).string
Dann sollte es auch mit der neuesten BS4-Version funktionieren.

Edit: Eine Tabelle mit den formatierten Werten taucht eben *nicht* im Quelltext der Seite auf. Im gesamten Quelltext der Seite kommt nicht ein einziges <table>-Element vor. Das wird alles zur Laufzeit im Browser per JavaScript erzeugt.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
tomrause
User
Beiträge: 12
Registriert: Freitag 26. Februar 2021, 19:20

Hallo _blackjack_

Merci.
Jetzt muss ich das nur noch zu einer flachen Tabelle umbauen.
Danke
Tom
Ich bitte um Hinweise
Danke
Tom
Antworten