Seite 1 von 1

Website filtern

Verfasst: Samstag 4. April 2020, 23:42
von Newbie96
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

Re: Website filtern

Verfasst: Sonntag 5. April 2020, 08:49
von __blackjack__
@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.

Re: Website filtern

Verfasst: Sonntag 5. April 2020, 09:53
von Sirius3
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()

Re: Website filtern

Verfasst: Sonntag 5. April 2020, 10:51
von Newbie96
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

Re: Website filtern

Verfasst: Sonntag 5. April 2020, 11:04
von Sirius3
Das, was Du brauchst, ist eine for-Schleife.

Re: Website filtern

Verfasst: Sonntag 5. April 2020, 11:28
von Newbie96
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?

Re: Website filtern

Verfasst: Sonntag 5. April 2020, 11:33
von Sirius3
Was hast Du denn versucht? Code zeigen. `range` ist falsch, weil Du doch schon eine Liste hast und direkt über dessen Elemente iterieren kannst.

Re: Website filtern

Verfasst: Sonntag 5. April 2020, 11:40
von Newbie96
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^^

Re: Website filtern

Verfasst: Sonntag 5. April 2020, 12:24
von Sirius3
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.

Re: Website filtern

Verfasst: Sonntag 5. April 2020, 12:45
von __blackjack__
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.