Hallo,
wie kann ich alle Hyperlinks extrahieren, die "title="" >Anzeigen (*)" enthalten.
Ergebnis soll sein:
'"https://trauer.mittelhessen.de/traueranzeige/eleonore-hain/anzeigen"'
"https://trauer.mittelhessen.de/traueranzeige/juergen-schaefer-1957/anzeigen"
<div class="c-blockitem-footer">
<div class="col-12 py-2 border-left-0 border-right-0 border-dotted text-center">
<div class="d-inline-block position-relative"><i class="c-icon-cross"></i><a class="stretched-link pr-2 text-nowrap " href="https://trauer.mittelhessen.de/traueranzeige/eleonore-hain/anzeigen" title="" >Anzeigen (1)</a></div>
<div class="d-inline-block position-relative"><i class="c-icon-book-open"></i><a class="stretched-link pr-2 text-nowrap " href="https://trauer.mittelhessen.de/traueranzeige/eleonore-hain/kondolenzbuch" title=""
</div>
<div class="c-blockitem-footer">
...
<div class="d-inline-block position-relative"><i class="c-icon-cross"></i><a class="stretched-link pr-2 text-nowrap " href="https://trauer.mittelhessen.de/traueranzeige/juergen-schaefer-1957/anzeigen" title="" >Anzeigen (2)</a></div>
Viele Grüße
biofunc
Beautifulsoup: Hyperlink mit Titel und Wildcard extrahieren
Hallo sarrow,
ich hatte schon einiges probiert, komme aber nun nicht mehr weiter (Anfänger).
Funktioniert hat z.B.
import requests
import re
from bs4 import BeautifulSoup
url="https://trauer.mittelhessen.de/traueranzeigen-suche/zeitraum-01-05-2022-bis-03-05-2022/seite-1"
page = requests.get(url)
soup=BeautifulSoup(page.content, "html.parser")
anzeigen=soup.find_all ("a", href=re.compile(r"^https://trauer.mittelhessen.de/traueranzeige/"))
print (anzeigen)
Aber ich benötige nur die Links mit
anzeigen=soup.find_all ("a", href=re.compile(r"^https://trauer.mittelhessen.de/traueranzeige/*/anzeigen"))
Das mit dem Platzhalter hat dann nicht mehr funktioniert.
Deshalb die Idee, nach dem Titel in der href zu suchen. Da hatte ich einiges gegooglet und probiert - leider erfolglos.
VG
ich hatte schon einiges probiert, komme aber nun nicht mehr weiter (Anfänger).
Funktioniert hat z.B.
import requests
import re
from bs4 import BeautifulSoup
url="https://trauer.mittelhessen.de/traueranzeigen-suche/zeitraum-01-05-2022-bis-03-05-2022/seite-1"
page = requests.get(url)
soup=BeautifulSoup(page.content, "html.parser")
anzeigen=soup.find_all ("a", href=re.compile(r"^https://trauer.mittelhessen.de/traueranzeige/"))
print (anzeigen)
Aber ich benötige nur die Links mit
anzeigen=soup.find_all ("a", href=re.compile(r"^https://trauer.mittelhessen.de/traueranzeige/*/anzeigen"))
Das mit dem Platzhalter hat dann nicht mehr funktioniert.
Deshalb die Idee, nach dem Titel in der href zu suchen. Da hatte ich einiges gegooglet und probiert - leider erfolglos.
VG
- __blackjack__
- User
- Beiträge: 13134
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@biofunc: Der "*" in regulären Ausdrücken bedeutet nicht das was Du offenbar denkst was er bedeutet.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Bei der regulär Expression ist nicht nur der Asterix ('*') Falsch.
Ein Request Aufruf sollte man als Kontextmanager implementieren und das Compilern der Regex bringt mehr, wenn man es nur 1-mal macht. Der folgende Code sollte ungefähr machen, was du willst.
Ein Request Aufruf sollte man als Kontextmanager implementieren und das Compilern der Regex bringt mehr, wenn man es nur 1-mal macht. Der folgende Code sollte ungefähr machen, was du willst.
Code: Alles auswählen
import re
import typing
import requests
import bs4
def obituaries(url: str) -> typing.List[str]:
result: typing.List[str] = []
regex = re.compile(r'\/anzeigen$')
with requests.Session() as session:
page = session.get(url)
soup = bs4.BeautifulSoup(page.content, "html.parser")
for link in soup.find_all("a", href=regex):
result.append(link['href'])
return result
//a[contains(@title,'Traueranzeige')]/@href
bzw.
links=driver.find_elements_by_xpath("//a[contains(@title,'Traueranzeige')]")
for link in links:
print(link.get_attribute("href")
als xpath
ich habe mich auch mit mehreren Webscraping Methoden auseinander gesetzt. Ich finde Selenium und xpath am einfachsten und bei Xpather.com kann man es immer testen.
insbesondere javascript usw. kommt man damit besser klar.
bzw.
links=driver.find_elements_by_xpath("//a[contains(@title,'Traueranzeige')]")
for link in links:
print(link.get_attribute("href")
als xpath
ich habe mich auch mit mehreren Webscraping Methoden auseinander gesetzt. Ich finde Selenium und xpath am einfachsten und bei Xpather.com kann man es immer testen.
insbesondere javascript usw. kommt man damit besser klar.
- __blackjack__
- User
- Beiträge: 13134
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@imonbln Das macht nicht wirklich Sinn mit dem ``with`` weil ein `Session`-Objekt das genau einmal benutzt wird, nicht wirklich Sinn macht. Und ob man den regulären Ausdruck vor dem Aufruf kompiliert oder den `re.compile()`-Aufruf direkt als Argument schreibt, ist auch egal wenn der jedes mal kompiliert wird.
Das ist Python und nicht Java. Typannotationen die sowohl dem Leser als auch der Typprüfung *klar* sind, kann und sollte man sich sparen. `result` hat als Rückgawert den Typ der schon bei der Funktion annotiert ist. Der Leser sieht das und die Typprüfung bekommt das auch hin. Zumal man das nicht so langatmig mit (zu weit entfernter) Initialisierung einer leeren Liste und Schleife schreiben muss.
"/" hat in regulären ausdrücken keine besondere Bedeutung, da braucht es keinen \ davor.
Die `get()`-Methode von `Session`-Objekten liefert ein `Response`-Objekt. Das würde ich nicht `page` nennen, denn das weiss man nicht wirklich. Dementsprechend sollte man auch prüfen ob da überhaupt eine sinnvolle Antwort kam und keine Fehlermeldung vom Server.
Das ist Python und nicht Java. Typannotationen die sowohl dem Leser als auch der Typprüfung *klar* sind, kann und sollte man sich sparen. `result` hat als Rückgawert den Typ der schon bei der Funktion annotiert ist. Der Leser sieht das und die Typprüfung bekommt das auch hin. Zumal man das nicht so langatmig mit (zu weit entfernter) Initialisierung einer leeren Liste und Schleife schreiben muss.
"/" hat in regulären ausdrücken keine besondere Bedeutung, da braucht es keinen \ davor.
Die `get()`-Methode von `Session`-Objekten liefert ein `Response`-Objekt. Das würde ich nicht `page` nennen, denn das weiss man nicht wirklich. Dementsprechend sollte man auch prüfen ob da überhaupt eine sinnvolle Antwort kam und keine Fehlermeldung vom Server.
Code: Alles auswählen
import re
import requests
import bs4
def get_obituary_links(url):
response = requests.get(url)
response.raise_for_status()
return [
link["href"]
for link in bs4.BeautifulSoup(
response.content, "html.parser"
).find_all("a", href=re.compile(r"/anzeigen$"))
]
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Hallo zusammen,
vielen Dank für Eure Hinweise. Ich habe nun einen funktionierenden Code (siehe unten).
An einer Stelle habe ich aber noch ein Problem:
Bei der Fehlermeldung
requests.exceptions.MissingSchema: Invalid URL '/MEDIASERVER/content/LH178/obi_new/2019_1/Harald-Graf-Traueranzeige-01e3ee46-45c1-4acb-97a6-e9a70a06d918.pdf': No scheme supplied. Perhaps you meant http:///MEDIASERVER/content/LH178/obi_new/2019_1/Harald-Graf-Traueranzeige-01e3ee46-45c1-4acb-97a6-e9a70a06d918.pdf?
kommt es zu einem Programmabbruch. Im Link fehlt jeweils das vorangestellt https://trauer.mittelhessen.de.
Korrekt lautet der Link: https://trauer.mittelhessen.de/MEDIASERVER/content/LH178/obi_new/2019_1/Harald-Graf-Traueranzeige-01e3ee46-45c1-4acb-97a6-e9a70a06d918.pdf
Hier wäre eine Prüfung hilfreich und eine Ergänzung des Links um "https://trauer.mittelhessen.de", wenn dieser Teil fehlt. Sollte der Download dann immer noch nicht funktionieren, sollte dieser Download abgebrochen und mit dem nächsten fortgefahren werden. Könnte man dann am Programmende eine Liste mit allen fehlerhaften Links anzeigen lassen?
Kann mir an dieser Stelle jemand weiterhelfen?
Vielen Dank.
Hier der komplette Code:
vielen Dank für Eure Hinweise. Ich habe nun einen funktionierenden Code (siehe unten).
An einer Stelle habe ich aber noch ein Problem:
Code: Alles auswählen
for i, link in enumerate(
soup.find_all("a", href=lambda url: url.endswith(".pdf")), 1
):
print("Downloading file: ", i)
response = requests.get(link.get("href"))
response.raise_for_status()
Path(
f"{nachname}#{geburtsname}#{vorname}#aus#{wohnort}#geb.#{geboren_am}#gest.#{gestorben_am}#in#{gestorben_in}#{zeitung}#veröffentlicht am#{veroeffentlicht_am}#{i}.pdf").write_bytes(
response.content)
print("File ", i, " downloaded")
requests.exceptions.MissingSchema: Invalid URL '/MEDIASERVER/content/LH178/obi_new/2019_1/Harald-Graf-Traueranzeige-01e3ee46-45c1-4acb-97a6-e9a70a06d918.pdf': No scheme supplied. Perhaps you meant http:///MEDIASERVER/content/LH178/obi_new/2019_1/Harald-Graf-Traueranzeige-01e3ee46-45c1-4acb-97a6-e9a70a06d918.pdf?
kommt es zu einem Programmabbruch. Im Link fehlt jeweils das vorangestellt https://trauer.mittelhessen.de.
Korrekt lautet der Link: https://trauer.mittelhessen.de/MEDIASERVER/content/LH178/obi_new/2019_1/Harald-Graf-Traueranzeige-01e3ee46-45c1-4acb-97a6-e9a70a06d918.pdf
Hier wäre eine Prüfung hilfreich und eine Ergänzung des Links um "https://trauer.mittelhessen.de", wenn dieser Teil fehlt. Sollte der Download dann immer noch nicht funktionieren, sollte dieser Download abgebrochen und mit dem nächsten fortgefahren werden. Könnte man dann am Programmende eine Liste mit allen fehlerhaften Links anzeigen lassen?
Kann mir an dieser Stelle jemand weiterhelfen?
Vielen Dank.
Hier der komplette Code:
Code: Alles auswählen
# !/usr/bin/env python3
from pathlib import Path
import requests
from bs4 import BeautifulSoup
def download_pdfs(url):
response = requests.get(url)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
leer=""
vorname = soup.find(itemprop="givenName").get("content")
nachname = soup.find(itemprop="familyName").get("content")
name= soup.find(itemprop="name").get("content")
geburtsname = soup.find('div', {'class': "text-center text-muted"}).text
wohnort = soup.find(itemprop="homeLocation").get("content")
geboren_am = soup.find(itemprop="birthDate").get("content")
gestorben_am = soup.find(itemprop="deathDate").get("content")
gestorben_in = soup.find(itemprop="deathPlace").get("content")
zeitung=soup.find('h3', {'class': "mb-0"}).text
veroeffentlicht_am=soup.find('div', {'class': "mb-1 text-muted"}).text
for i, link in enumerate(
soup.find_all("a", href=lambda url: url.endswith(".pdf")), 1
):
print("Downloading file: ", i)
response = requests.get(link.get("href"))
response.raise_for_status()
Path(
f"{nachname}#{geburtsname}#{vorname}#aus#{wohnort}#geb.#{geboren_am}#gest.#{gestorben_am}#in#{gestorben_in}#{zeitung}#veröffentlicht am#{veroeffentlicht_am}#{i}.pdf").write_bytes(
response.content)
print("File ", i, " downloaded")
print("All PDF files downloaded")
def get_Anzeigen(url):
response = requests.get(url)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
anzeigen = []
for i, result in enumerate(soup.find_all("a")):
if "Anzeigen " in str(result.string):
anzeigen.append(result.get("href"))
return anzeigen
def main():
alle_anzeigen_links = [] # Hier werden alle links hinzugefügt
site_num = 1
loadingerror = False
while not loadingerror: # solange die Seitennummer existiert
seitenlink = f"https://trauer.mittelhessen.de/traueranzeigen-suche/zeitraum-01-01-2022-bis-31-01-2022/seite-{site_num}" # fügt die seitennummer automatisch an den link an
print(f"Lade Seite [{seitenlink}]")
seite_anzeigen_links = get_Anzeigen(seitenlink) # extrahiert alle links auf anzeigen der aktuellen seite
# sollte keine Anzeige gefunden werden, breche Schleife ab
if len(seite_anzeigen_links) == 0:
print(f"Keine Anzeigen auf Seite {site_num}")
break
# füge anzeigen der seite auf gesammeltes array hinzu
for link in seite_anzeigen_links:
alle_anzeigen_links.append(link)
site_num += 1
print("")
print("Alle Anzeigen:")
for link in alle_anzeigen_links:
print(f"Lade alle PDFs der Seite {link} herunter...")
download_pdfs(link)
print()
if __name__ == "__main__":
main()
Um URLs richtig zusammenzusetzen gibt es `urllib.parse.urljoin`.
bzw.
Code: Alles auswählen
response = requests.get(urllib.parse.urljoin(url, link.get("href")))
Code: Alles auswählen
anzeigen.append(urllib.parse.urljoin(url, result.get("href")))
- __blackjack__
- User
- Beiträge: 13134
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@biofunc: Anmerkungen zum Quelltext: Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.
Listen sind keine Arrays, sollten deshalb auch nicht so genannt werden, denn es gibt auch Arrays und das führt nur unnötig zu Verwirrung beim Leser.
`loadingerror` wird gar nicht verwendet. Dafür könnte man aus der ``while``-Schleife eine ``for``-Schleife über die `site_num`-Werte machen.
Statt einer ``for``-Schleife über ein iterierbares Objekt im jedes Element an eine Liste zu hängen, würde man einfach die `extend()`-Methode verwenden.
Bei `anzeigen` in `get_anzeigen()` bietet sich eine „list comprehension“ an.
`result.string` ist dort bereits eine Zeichenkette, da braucht es keinen `str()`-Aufruf mehr.
Das `i` von der Schleife wird nirgends verwendet.
In `download_pdfs()` werden `leer` und `name` definiert, aber nicht verwendet.
Die `find()`-Aufrufe mit dem Wörterbuch wo "class" als Schlüssel enthalten ist, lassen sich vereinfachen, weil das zweite Argument von `find()` als "class"-Attributwert behandelt wird, wenn es eine Zeichenkette ist.
Die beiden Funktionen fangen gleich an, das könnte man in eine weitere Funktion herausziehen. `get_anzeigen()` ist dann nur noch ein ``return`` mit einer „list comprehension“.
Ungetestet:
Listen sind keine Arrays, sollten deshalb auch nicht so genannt werden, denn es gibt auch Arrays und das führt nur unnötig zu Verwirrung beim Leser.
`loadingerror` wird gar nicht verwendet. Dafür könnte man aus der ``while``-Schleife eine ``for``-Schleife über die `site_num`-Werte machen.
Statt einer ``for``-Schleife über ein iterierbares Objekt im jedes Element an eine Liste zu hängen, würde man einfach die `extend()`-Methode verwenden.
Bei `anzeigen` in `get_anzeigen()` bietet sich eine „list comprehension“ an.
`result.string` ist dort bereits eine Zeichenkette, da braucht es keinen `str()`-Aufruf mehr.
Das `i` von der Schleife wird nirgends verwendet.
In `download_pdfs()` werden `leer` und `name` definiert, aber nicht verwendet.
Die `find()`-Aufrufe mit dem Wörterbuch wo "class" als Schlüssel enthalten ist, lassen sich vereinfachen, weil das zweite Argument von `find()` als "class"-Attributwert behandelt wird, wenn es eine Zeichenkette ist.
Die beiden Funktionen fangen gleich an, das könnte man in eine weitere Funktion herausziehen. `get_anzeigen()` ist dann nur noch ein ``return`` mit einer „list comprehension“.
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
from itertools import count
from pathlib import Path
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
def get_soup(url):
response = requests.get(url)
response.raise_for_status()
return BeautifulSoup(response.text, "html.parser")
def get_anzeigen(url):
return [
urljoin(url, result.get("href"))
for result in get_soup(url).find_all("a")
if "Anzeigen " in result.string
]
def download_pdfs(url):
soup = get_soup(url)
vorname = soup.find(itemprop="givenName").get("content")
nachname = soup.find(itemprop="familyName").get("content")
geburtsname = soup.find("div", "text-center text-muted").text
wohnort = soup.find(itemprop="homeLocation").get("content")
geboren_am = soup.find(itemprop="birthDate").get("content")
gestorben_am = soup.find(itemprop="deathDate").get("content")
gestorben_in = soup.find(itemprop="deathPlace").get("content")
zeitung = soup.find("h3", "mb-0").text
veroeffentlicht_am = soup.find("div", "mb-1 text-muted").text
for i, link in enumerate(
soup.find_all("a", href=lambda url: url.endswith(".pdf")), 1
):
print("Downloading file: ", i)
response = requests.get(urljoin(url, link.get("href")))
response.raise_for_status()
Path(
f"{nachname}#{geburtsname}#{vorname}#aus#{wohnort}"
f"#geb.#{geboren_am}#gest.#{gestorben_am}#in#{gestorben_in}"
f"#{zeitung}#veröffentlicht am#{veroeffentlicht_am}#{i}.pdf"
).write_bytes(response.content)
print("File ", i, " downloaded")
print("All PDF files downloaded")
def main():
alle_anzeigen_links = []
for site_num in count(1):
seitenlink = (
f"https://trauer.mittelhessen.de/traueranzeigen-suche"
f"/zeitraum-01-01-2022-bis-31-01-2022/seite-{site_num}"
)
print(f"Lade Seite [{seitenlink}]")
seite_anzeigen_links = get_anzeigen(seitenlink)
if not seite_anzeigen_links:
print(f"Keine Anzeigen auf Seite {site_num}")
break
alle_anzeigen_links.extend(seite_anzeigen_links)
print("\nAlle Anzeigen:")
for link in alle_anzeigen_links:
print(f"Lade alle PDFs der Seite {link} herunter...")
download_pdfs(link)
print()
if __name__ == "__main__":
main()
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Hallo Blackjack,
vielen Dank für Deine Hinweise! Ein Freund hat mich unterstützt und nun habe ich einen Code, der macht, was er soll (mit zwei ergänzten Fehlerroutinen).
Die Kommentare hat mein Freund für mich so hinterlegt, dass ich den Code als Anfänger auch verstehen kann.
Hier das fertige Programm:
Mit einer kleinen Modifikation funktioniert das Programm auch auf einer zweiten Seite.
Auf einer weiteren Seite stoße ich aber an meine Grenzen:
https://rz-trauer.de/traueranzeigen-suc ... 03-05-2022
Hier wird das Suchergebnis für einen Zeitraum nicht in einzelen Seiten, die man über die URL aufrufen kann, dargestellt. Vielmehr gibt es am Ende einen Button "Weitere Trauerfälle laden". Dort ist aber kein Link hinterlegt, sondern folgender Code:
Gibt es eine Möglichkeit, über ein Schleife alle "Weitere Trauerfälle laden" so lange auszuführen, bis alle Ergebnisse auf einer Seite dargestellt sind, um dann mit der eigentlichen Auswertung zu beginnen?
Viele Grüße
vielen Dank für Deine Hinweise! Ein Freund hat mich unterstützt und nun habe ich einen Code, der macht, was er soll (mit zwei ergänzten Fehlerroutinen).
Die Kommentare hat mein Freund für mich so hinterlegt, dass ich den Code als Anfänger auch verstehen kann.
Hier das fertige Programm:
Code: Alles auswählen
# !/usr/bin/env python3
from pathlib import Path
import urllib
import requests
from bs4 import BeautifulSoup
import time
import sys
from datetime import datetime
# config variablen
errorfile = "webscrape_errors.txt"
zeitraum = "01-01-2016-bis-31-12-2016"
# wenn datei schon existiert, füge 1.pdf/2.pdf/3.pdf/... hinzu
def add_file_number(filename):
i = 1
# überprüfe asdghf#grfadsfg#gdasf#0.pdf, dann asdghf#grfadsfg#gdasf#1.pdf, ...
while Path(f"{filename}#({i}).pdf").exists():
i+=1
return f"{filename}#({i}).pdf"
def download_pdf(metadata, announcement_metadata):
#urllib.parse.urljoin("https://google.de", "https://google.de/index.html")
filename = f"{metadata['nachname']}#{metadata['name']}#{metadata['geburtsname']}#{metadata['vorname']}#aus#{metadata['wohnort']}#geb.#{metadata['geboren_am']}#gest.#{metadata['gestorben_am']}#in#{metadata['gestorben_in']}#{announcement_metadata['zeitung']}#veröffentlicht am#{announcement_metadata['veroeffentlicht_am']}"
if announcement_metadata["link"].startswith("/"):
print(f"Ergänze {announcement_metadata['link']} zu ", end="")
announcement_metadata["link"] = "https://trauer.mittelhessen.de" + announcement_metadata["link"]
print(announcement_metadata["link"])
response = requests.get(announcement_metadata["link"])
response.raise_for_status()
filename = add_file_number(filename)
Path(filename).write_bytes(response.content)
print(f"Saved as '{filename}'")
print()
def get_general_metadata(sectionsoup):
metadata = {}
#extrahiere daten von Person
metadata["name"] = sectionsoup.find(itemprop="name").get("content")
metadata["vorname"] = sectionsoup.find(itemprop="givenName").get("content")
metadata["nachname"] = sectionsoup.find(itemprop="familyName").get("content")
metadata["geburtsname"] = sectionsoup.find('div', {'class': "text-center text-muted"}).text
metadata["wohnort"] = sectionsoup.find(itemprop="homeLocation").get("content")
metadata["geboren_am"] = sectionsoup.find(itemprop="birthDate").get("content")
metadata["gestorben_am"] = sectionsoup.find(itemprop="deathDate").get("content")
metadata["gestorben_in"] = sectionsoup.find(itemprop="deathPlace").get("content")
# nicht sicher ob richtig, hoffe aber so:
print(f"'{metadata['vorname']}' '{metadata['nachname']}' '{metadata['geburtsname']}' '{metadata['name']}'")
if metadata["name"] == metadata["nachname"]:
print(f"name '{metadata['name']}' ist gleich dem Nachnamen '{metadata['nachname']}' -> ersetze name mit ''")
metadata["name"] = ""
return metadata
# extrahiere metadaten einer Section, bzw. einer Zeitung
def get_announcement_metadata(sectionsoup):
announcement_metadata = {}
announcement_metadata["zeitung"] = sectionsoup.find("h3").get_text()
announcement_metadata["veroeffentlicht_am"] = sectionsoup.find("div", class_="mb-1 text-muted").get_text()
try:
announcement_metadata["link"] = sectionsoup.find("a", href=lambda url: url.endswith(".pdf"), title=" Speichern").get("href")
except AttributeError: # wenn der link einer section nicht gefunden werden konnte
announcement_metadata["link"] = "Not found!"
# schneide "vom " am Anfang vom Veröffentlichungsdatum weg
announcement_metadata["veroeffentlicht_am"] = announcement_metadata["veroeffentlicht_am"][4:]
return announcement_metadata
# filtere <section> tags aus, sortiere nach typ und extrahiere mit hilfe von get_general_metadata() und get_announcement_metadata()
# infos zur person und einzeln zu den zeitungsannouncen
def get_metadata(url):
response = requests.get(url)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
sections = soup.find_all("section")
general_metadata = {}
announcements_metadata = {}
# suche alle html tags <section> .... </section>
sections = soup.find_all("section")
for i, sectionsoup in enumerate(sections):
# Filter "Überschrifts" section heraus
if sectionsoup.get("itemtype") == "http://schema.org/Person":
# extrahiere generelle metadaten zur Person
general_metadata = get_general_metadata(sectionsoup)
elif sectionsoup.has_attr("id"):# filter sections without an id
sectionid = sectionsoup.get("id")
if sectionid.startswith("announcement"):
print(f"Found announcement [{sectionid}]")
# extrahiere metadaten pro announcement
announcement_metadata = get_announcement_metadata(sectionsoup)
if announcement_metadata["link"] == "Not found!":
print(f"ERROR! COULD NOT FIND PDF FOR ANNOUNCEMENT [{sectionid}]")
with open(errorfile, "a") as f:
f.write(f"[{datetime.now()}] Could not find the link for section [{sectionid}] in [{url}]\n")
else:
announcements_metadata[sectionid] = announcement_metadata
elif sectionid.startswith("virtualgift"):# Ignore (kann gelöscht werden, nur zur übersicht)
pass
return general_metadata, announcements_metadata
def get_Anzeigen(url):
response = requests.get(url)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
anzeigen = []
for result in soup.find_all("a"):
if "Anzeigen " in str(result.string):
anzeigen.append(result.get("href"))
return anzeigen
def main():
with open(errorfile, "a") as f:
f.write(f"\n[{datetime.now()}] NEW EXECUTION\n")
# sammle alle links zu Personen in alle_personen_links
alle_personen_links = [] # Hier werden alle links hinzugefügt
site_num = 1
while True: # solange die Seitennummer existiert
seitenlink = f"https://trauer.mittelhessen.de/traueranzeigen-suche/zeitraum-{zeitraum}/seite-{site_num}" # fügt die seitennummer automatisch an den link an
print(f"Lade Seite [{seitenlink}]")
seite_anzeigen_links = get_Anzeigen(seitenlink) # extrahiert alle links auf anzeigen der aktuellen seite
# sollte keine Anzeige gefunden werden, breche Schleife ab
if len(seite_anzeigen_links) == 0:
print(f"Keine Anzeigen auf Seite {site_num}")
break # beendet die while Schleife
# füge anzeigen der seite auf gesammeltes array hinzu
alle_personen_links.extend(seite_anzeigen_links)
print("=====================")
time.sleep(0.5)
site_num += 1
print()
print("Alle Anzeigen:")
for link in alle_personen_links:
try:
print(f"Extrahiere Anzeigen der Seite {link} ...")
metadata, announcements_metadata = get_metadata(link)
for key in announcements_metadata.keys():
print(f"Downloading PDF from '{announcements_metadata[key]['zeitung']}' [{announcements_metadata[key]['link']}]")
download_pdf(metadata, announcements_metadata[key])
time.sleep(0.1) # warte eine Sekunde
# Fängt alle Fehler ab, wartet kurz und bearbeitet den nächsten Link
except Exception as err:
print(err)
print("UNKNOWN ERROR! skipping...")
with open(errorfile, "a") as f:
f.write(f"[{datetime.now()}] ERROR while processing url [{link}] Error: {err}\n")
print("Cooldown (1s) ")
time.sleep(1)
print()
time.sleep(0.2)
print("Done!")
if __name__ == "__main__":
main()
Auf einer weiteren Seite stoße ich aber an meine Grenzen:
https://rz-trauer.de/traueranzeigen-suc ... 03-05-2022
Hier wird das Suchergebnis für einen Zeitraum nicht in einzelen Seiten, die man über die URL aufrufen kann, dargestellt. Vielmehr gibt es am Ende einen Button "Weitere Trauerfälle laden". Dort ist aber kein Link hinterlegt, sondern folgender Code:
Code: Alles auswählen
</script>
<div class="c-blockitem" id="pageButton">
<div class="BlockHeightLg col-12 text-center">
<form method="POST"data-ajax-mode="after" data-ajax-update="#block_655" data-ajax-method="POST" data-ajax-complete="familyPortal.ResetPager(pageObj664)" data-ajax="true" action="/content/Search/Pagination/655"> <input type="hidden" id="664TotalCount" name="TotalCount" value="681" /><input type="hidden" id="664StartIndex" name="StartIndex" value="5" /><input type="hidden" id="664AmountPerPage" name="AmountPerPage" value="5" /><input type="hidden" id="PageKey" name="PageKey" value="traueranzeigen-suche/zeitraum-01-05-2022-bis-25-05-2022" /><input type="hidden" id="664Start" name="Start" value="1" /><input type="submit" id="pager-664" data_toggle="tooltip" class="btn btn-secondary m-auto" title="Weitere Trauerfälle laden" value="Weitere Trauerfälle laden" name="submit" onclick="familyPortal.SetScreenPosition(); $(this).hide();"></form>
</div>
<script type="text/javascript">
var pageObj664 = {
Page: 1,
TakeNo: 5,
startIndex: 5,
totalElements: 681,
ButtonLink: "content/Search/pagination/664",
paginationParentId: "655",
paginationUpdateId: "664"
};
</script>
Viele Grüße