Probleme beim Scrapen einer Webseite

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
Benutzeravatar
Perlchamp
User
Beiträge: 178
Registriert: Samstag 15. April 2017, 17:58

Moinsen,
ich möchte gerne die Termine der örtlichen Müllabfuhr in ein Dashboard von HA einbinden. DAS ist das Ziel. Momentan bin ich dabei, in VS Code zum Testen ein .py-Scrape-Script zu erstellen. Doch bereits dort gibt es ein massives Problem, das ich anscheinend nicht im Stande bin, alleine zu lösen:

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup
import json

r = requests.get('https://www.stadtwerke-speyer.de/speyerGips/Gips?SessionMandant=Speyer&Anwendung=CMSWEBPAGE&Methode=RefreshHTMLAusgabe&RessourceID=687740&Container.Children:2.BezirkId=9&Container.Children:2.Strasse=Allerheiligenstra%26szlig%3Be')
soup = BeautifulSoup(r.content, 'html.parser')

print(soup)             # just comment
Rückgabe:

Code: Alles auswählen

<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
</body></html>
demzufolge sind alle weiteren Aktionen erfolglos, da mit NONE als Wert hier nichts anzufangen ist, weswegen ich die weiteren Codezeilen nicht veröffentlicht habe.
Diese Seite bedarf keiner Anmeldung, etc. Sie ist für Jedermann zu erreichen.

Kann mir jemand einen Wink geben, was nun zu tun ist?
Besten Dank vorab.

So long
Pc
Irgendwas ist immer !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
einfachTobi
User
Beiträge: 510
Registriert: Mittwoch 13. November 2019, 08:38

Du musst deinem Request einen üblichen User-Agent mitgeben:

Code: Alles auswählen

import requests
response = requests.get("https://www.stadtwerke-speyer.de/speyerGips/Gips?SessionMandant=Speyer&Anwendung=CMSWEBPAGE&Methode=RefreshHTMLAusgabe&RessourceID=687740&Container.Children:2.BezirkId=9&Container.Children:2.Strasse=Allerheiligenstra%26szlig%3Be", 
                         headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0"})
Benutzeravatar
Perlchamp
User
Beiträge: 178
Registriert: Samstag 15. April 2017, 17:58

Super, vielen lieben Dank. Jetzt werde ich mal schauen, ob/wie es weitergeht.

So long
Pc
Irgendwas ist immer !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
Perlchamp
User
Beiträge: 178
Registriert: Samstag 15. April 2017, 17:58

... und der Ärger geht weiter, wer kann mir weiterhelfen:

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup

response = requests.get("https://www.stadtwerke-speyer.de/speyerGips/Gips?SessionMandant=Speyer&Anwendung=CMSWEBPAGE&Methode=RefreshHTMLAusgabe&RessourceID=687740&Container.Children:2.BezirkId=9&Container.Children:2.Strasse=Allerheiligenstra%26szlig%3Be", 
                         headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0"})
soup = BeautifulSoup(response.content, 'html.parser')
#print(soup)             # just comment

target = soup.find("div.table-responsive-wrap:nth-child(1) > table:nth-child(1) > tbody:nth-child(1)")
print(target)             # just comment
Auch hier lautet das Ergebnis wieder none.
Ich habe die Entwicklertools meines Browsers geöffnet, den entsprechenden Tag markiert, Rechtklick, CSS-Selektor kopieren, und dann im Script eingefügt. WO ist hier jetzt der Wurm begraben?
Man liest und liest, freut sich aufs Coden, und nichts klappt. Irgendwas ist immer...

So long
Pc
Irgendwas ist immer !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
einfachTobi
User
Beiträge: 510
Registriert: Mittwoch 13. November 2019, 08:38

find ist die falsche Methode, wenn du das Element mittels CSS identifizieren willst. Schau dir mal select() an.
Benutzeravatar
Perlchamp
User
Beiträge: 178
Registriert: Samstag 15. April 2017, 17:58

danke !
Irgendwas ist immer !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
imonbln
User
Beiträge: 187
Registriert: Freitag 3. Dezember 2021, 17:07

Ich möchte mal den Elefanten im Raum Adressieren, warum willst du die Webseite Scrapen, wenn auf der Webseite ein Link zu einem iCalendar ist? Wäre es nicht bedeutend einfacher den Kalender, in einem standardisierten Format herunterzuladen? Entweder dein Dashboard kann das dann direkt anzeigen oder du installiert die der passende Python Module, um die Einträge in etwas zu verwandeln, das dein Dashboard kann.  Auf jeden Fall sollte das einfacher und robuster Sein als die Webseite zu scrapen.
Benutzeravatar
Perlchamp
User
Beiträge: 178
Registriert: Samstag 15. April 2017, 17:58

@imonbln:
danke für den Tipp. Icalender kenne ich nicht. Ich werde mich mal informieren. Mit dem Script habe ich aufgegeben:
Bitte dennoch einmal die Kommentare im Script lesen, ob die richtig sind, damit ich doch noch was lerne...

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup
from scrapy import Selector   # für CSS-Selector-Identifizierung
#import json

url = "https://www.stadtwerke-speyer.de/speyerGips/Gips?SessionMandant=Speyer&Anwendung=CMSWEBPAGE&Methode=RefreshHTMLAusgabe&RessourceID=687740&Container.Children:2.BezirkId=9&Container.Children:2.Strasse=Allerheiligenstra%26szlig%3Be"
browser = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0"}
css_selector = 'div.table-responsive-wrap:nth-child(1) > table:nth-child(1) > tbody:nth-child(1)'
webseite = requests.get(url, headers=browser)
html_inhalt = BeautifulSoup(webseite.content, "html.parser")

#### HTML-Tag-Indetifizierung --------------------------------------- ####
#### [HTML-Tag] beispielsweise span, td, div (OHNE Klammern !)
#### [Parameter] beispielsweise class, id
#### Debugging
#print(html_inhalt.prettify())             
#target = html_inhalt.find(["HTML-Tag"], attrs={["Parameter"]:["Wert"]}).get_text()

#### CSS-Selektor-Identifizierung ----------------------------------- ####
#### [CSS-Selektor]: F12 -> Inspektor -> betreffenden Selektor markieren 
####                     -> Rechtsklick -> kopieren -> Selektor kopieren 
target_soup = html_inhalt.select(css_selector)
#### Debugging   
print(target_soup)

html_inhalt_str = str(html_inhalt)
target_scrapy = Selector(text=html_inhalt_str)
#### Debugging
#print(target_scrapy)

target_scrapy = target_scrapy.css(css_selector).extract()
#### Debugging   
print(target_scrapy)
beide Rückgaben sind none. 3 Stunden für die Katz'. Nur Beispiele, die 'sauber' sind, mit Klassen- oder id-Angabe, oder den HTML-Content selbst im Doc-String in das Script geschrieben...
Ach ja: die kommentierten Debugging-Bereiche liefern ein (richtiges) Ergebnis.

Besten Dank vorab.
so long
Pc
Irgendwas ist immer !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
imonbln
User
Beiträge: 187
Registriert: Freitag 3. Dezember 2021, 17:07

Der iCalendar ist wirklich nicht schwer, ich habe mal spaßeshalber das folgende Script zusammen gehackt um die einzelnen Tage aus dem Kalender zu extrahieren und für die Events zusammenzufassen.

Code: Alles auswählen

import collections
import icalendar
import requests


URL = "https://www.stadtwerke-speyer.de/speyerGips/Gips?SessionMandant=Speyer&Anwendung=Abfuhrkalender&Methode=TermineAnzeigenICS&Mandant=Speyer&Abfuhrkalender=Speyer2024&Bezirk_ID=9&Jahr=2024"
AGENT = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0"}


def get_icalendar():
    response = requests.get(URL, headers=AGENT, allow_redirects=True)
    response.raise_for_status()
    return icalendar.Calendar.from_ical(response.content)


def events_at_date(calendar):
    dates = collections.defaultdict(list)
    for event in calendar.walk("VEVENT"):
        event_type = event.decoded("SUMMARY").decode()
        event_date = event.decoded('DTSTART')
        dates[event_date].append(event_type)
    return dates


def main():
    calendar = get_icalendar()
    dates = events_at_date(calendar)
    for when, what in dates.items():
        print(when, what)


if __name__ == '__main__':
    main()

Benutzeravatar
Perlchamp
User
Beiträge: 178
Registriert: Samstag 15. April 2017, 17:58

moinsen,
ja, suuper !
Für heute bist du definitiv mein Hero.
Vielen herzlichen Dank !

So long
Pc
Irgendwas ist immer !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Antworten