Website filtern

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
Newbie96
User
Beiträge: 10
Registriert: Samstag 4. April 2020, 23:29

Hallo erstmal,
ich bin relativ neu in Python.
Meine Aufgabe bestand darin, dass ich die Anne Wills Talkshow Website nach den Gästen filter.
ich habe einen Code erstellt, der eigentlich auch einwandfrei funktioniert. Ich habe die Gäste Liste nun als Ergebnis bekommen, aber mit teilen des html codes.
Könnte mir vielleicht jemand erklären wie ich nur die Namen raus bekomme ohne den rest?

Der Code:

Code: Alles auswählen

from bs4 import BeautifulSoup
import requests

html = 'https://daserste.ndr.de/annewill/index.html'
hauptlink = 'https://daserste.ndr.de/'
req_html = requests.get(html).content
soup_html = BeautifulSoup(req_html, 'html.parser')

sendung = hauptlink + soup_html.select_one('div[class="mod modA modStage"] a[class="imglink"]')['href']
req_sendung = requests.get(sendung).content
soup_sendung = BeautifulSoup(req_sendung, 'html.parser')

gaesteseite = hauptlink + soup_sendung.select_one('a[title*="Gäste"]')['href']
req_gaesteseite = requests.get(gaesteseite).content
soup_gaesteseite = BeautifulSoup(req_gaesteseite, 'html.parser')

gaesteliste = soup_gaesteseite.select('h3[class="subtitle small"]')
print(gaesteliste)
Das Ergebnis vom Code:
[<h3 class="subtitle small"><br/><br/>Olaf Scholz (SPD)</h3>, <h3 class="subtitle small"><br/><br/>Alexander Kekulé</h3>, <h3 class="subtitle small"><br/><br/>Martina Wenker</h3>, <h3 class="subtitle small"><br/><br/>Christel Bienstein</h3>, <h3 class="subtitle small"><br/><br/>Jens Südekum</h3>, <h3 class="subtitle small"><br/><br/>Christian Gerlitz (SPD)</h3>]

Falls jemand so gütig ist und mir helfen kann. Vielen dank.
Mfg
Benutzeravatar
__blackjack__
User
Beiträge: 13107
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Newbie96: Man kann mit CSS nur Elemente beschreiben, keine Textknoten. Da musst Du im letzten Schritt also eine Schleife über das Ergebnis laufen lassen und mit den entsprechenden BeautifulSoup-Mitteln den Text von den Elementen abfragen. Eine „list comprehension“ bietet sich hier an.

Man sollte übrigens keine kryptischen Abkürzungen in Namen verwenden. Und `req_*` ist auch inhaltlich falsch, denn das Ergebnis von einem „request“ ist kein „request“ sondern ein „response“.

Es wird auch einfach der Body der Antwort weiterverarbeitet ohne zu prüfen ob der Server überhaupt mit der Seite mit der Information antwortet, oder ob die Antwort eine Fehlermeldung ist. Es bietet sich an die `raise_for_status()`-Methode auf der Antwort aufzurufen oder das `ok`-Attribut auszuwerten.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Klasse selectiert man mit CSS per Punkt, dann ist auch der genaue Strings im class-Attribut nicht relevant. Urls sollte man nicht mit + zusammenstückeln, sondern benutzt urllib.parse.urljoin. Dann braucht man auch nicht extra `hauptlink`, was eh nicht funktioniert, wenn man mal auf relative Links stößt.

Code: Alles auswählen

from bs4 import BeautifulSoup
import requests
from urllib.parse import urljoin

url_index = 'https://daserste.ndr.de/annewill/index.html'
response = requests.get(url_index)
response.raise_for_status()
soup_index = BeautifulSoup(response.text, 'html.parser')
href_sendung = soup_index.select_one('div.modStage a.imglink')['href']
url_sendung = urljoin(url_index, href_sendung)

response = requests.get(url_sendung)
response.raise_for_status()
soup_sendung = BeautifulSoup(response.text, 'html.parser')
href_gaeste = soup_sendung.select_one('a[title*="Gäste"]')['href']
url_gaeste = urljoin(url_sendung, href_gaeste)

response = requests.get(url_gaeste)
response.raise_for_status()
soup_gaeste = BeautifulSoup(response.text, 'html.parser')
gaeste = [e.text for e in soup_gaeste.select('h3.subtitle')]
Jetzt sieht man da sehr viel kopierten Code, der besser in Funktionen gekapselt wird:

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

def receive_soup(url):
    """ loads a page from url and returns the parsed HTML """
    response = requests.get(url)
    response.raise_for_status()
    return BeautifulSoup(response.text, 'html.parser')

def receive_link(url, css_selector):
    """ loads a page and extract the url of the link given by css_selector """
    soup = receive_soup(url)
    href = soup.select_one(css_selector)['href']
    return urljoin(url, href)

def main():
    url_index = 'https://daserste.ndr.de/annewill/index.html'
    url_sendung = receive_link(url_index, 'div.modStage a.imglink')
    url_gaeste = receive_link(url_sendung, 'a[title*="Gäste"]')
    soup_gaeste = receive_soup(url_gaeste)
    gaeste = [e.text for e in soup_gaeste.select('h3.subtitle')]
    print(gaeste)

if __name__ == '__main__':
    main()
Newbie96
User
Beiträge: 10
Registriert: Samstag 4. April 2020, 23:29

Danke euch ! Hat mir geholfen.
Habe aber den Code jetzt komplett anders geschrieben, aber konnte es hier nicht mehr posten, weil der Beitrag noch nicht freigeschalten war.

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup

seite = requests.get('https://daserste.ndr.de/annewill/archiv/Unsere-Gaeste,gaesteliste1206.html')
soup = BeautifulSoup(seite.content, 'html.parser')
content = soup.find(id='content')
inhalt = content.find_all(class_='box')
liste = inhalt[0].find_all('h3')
print(liste[0].get_text())
print(liste[1].get_text())
print(liste[2].get_text())
print(liste[3].get_text())
print(liste[4].get_text())
print(liste[5].get_text())
das ist auf das simpelste runter gebrochen, aber ich verstehe es. Könnte mir aber vielleicht jemand schreiben, wie ich die print zeilen kombinieren könnte in eine. oder das er mit einem bestimmten befehl alle automatisch durchgeht ohne spezifisch zu werden. Falls die Aussagen absurd klingen, tut es mir leid, bin wie gesagt relativ neu in Python xd
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Das, was Du brauchst, ist eine for-Schleife.
Newbie96
User
Beiträge: 10
Registriert: Samstag 4. April 2020, 23:29

Sirius3 hat geschrieben: Sonntag 5. April 2020, 11:04 Das, was Du brauchst, ist eine for-Schleife.
Danke für den Tipp. Habe mich etwas rumprobiert, aber es klappt nicht ganz. Ich habe for x in range(...) print (x) als Basis genutzt, falls das überhaupt die richtige basis dafür ist. Es funktioniert nur zum teil mit einer Ausgabe wieder. Könntest du mir vielleicht einen Lösungsvorschlag geben?
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Was hast Du denn versucht? Code zeigen. `range` ist falsch, weil Du doch schon eine Liste hast und direkt über dessen Elemente iterieren kannst.
Newbie96
User
Beiträge: 10
Registriert: Samstag 4. April 2020, 23:29

Sirius3 hat geschrieben: Sonntag 5. April 2020, 11:33 Was hast Du denn versucht? Code zeigen. `range` ist falsch, weil Du doch schon eine Liste hast und direkt über dessen Elemente iterieren kannst.
So hab es geschafft mit

Code: Alles auswählen

for liste in liste:
  print (liste.get_text())
  
Der Code war nur Syntax halber. Aber das ist nun egal. Ich danke dir trotzdem für die ganzen Tipps!!! Meine Frage ist geklärt^^
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Ein `for liste in liste` überdeckt ja sofort die ursprüngliche Liste. Das funktioniert nur, weil am Anfang der Schleife ein Verweis auf die ursprüngliche Liste intern gespeichert wird.
Allein wenn man das liest, muß man sich doch wundern, was für Quatsch da steht.
Eingerückt wird immer mit 4 Leerzeichen und vor der öffnenden Klammer eines Funktionsaufrufst kommt kein Leerzeichen.
Benutzeravatar
__blackjack__
User
Beiträge: 13107
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Was auch noch komisch ist, ist ein `find_all()` um dann vom Ergebnis davon nur das erste Element zu verwenden. Dann willst Du doch offensichtlich nicht alles finden sondern nur das erste.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten