Neue Items in RSS-Feeds auslesen

Django, Flask, Bottle, WSGI, CGI…
Antworten
seemarc
User
Beiträge: 10
Registriert: Donnerstag 26. Dezember 2019, 18:52

Hallo,
ich möchte aus einem RSS-Feed, in dem Links zu neuen Beiträgen auf einer Website gepostet werden, neue Links auslesen und den Titel sowie den Artikeltext an mich per E-Mail senden lassen.
Mein Problem ist, das ich nicht weiß, wie ich "neue" Links erkennen lassen kann.

Mein Code bis jetzt:

Code: Alles auswählen

#
###
#
import feedparser
import requests
import time
from bs4 import BeautifulSoup
from urllib.parse import urljoin
#
###
# 

##RSS
# d 
d = feedparser.parse('rsslink') 
# laf = first-article-link
fal_rss_sl = d.entries[0]['link'] #1. Link auf der Website zu Artikel
sal_rss_sl = d.entries[1]['link']
tal_rss_sl = d.entries[2]['link']
#
###
#
def query_fal():
    URL = fal_rss_sl
    headers = {"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'}
    page = requests.get(URL, headers=headers)
    soup = BeautifulSoup(page.content, 'html.parser')
    #
    diva = soup.find ('div', attrs={'class':'card'})
    #
    title = soup.find('h1')
    text = diva.div.next_sibling.next_sibling.next_sibling

query_fal()
Nun möchte ich aber überprüfen lassen, ob es neue Artikellinks gibt und diese dann entsprechend parsen. Hat da jemand eine Idee?
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@seemarc: Rein am RSS-Feed kannst Du das gar nicht erkennen. Man wird sich dafür noch etwas zwischen den Aufrufen merken müssen. Entweder wann man das letzte mal abgefragt hat und dann nur Sachen liefern die neuer sind. Oder man merkt sich Datum und Link und vergleicht dann ob neuere vorhanden sind. Letzteres ist robuster, weil es auch RSS-Feeds gibt, bei denen auch mal ältere Einträge hinzu kommen, also welche die einen Zeitstempel vor dem letzten Abfragen haben, die aber vorher noch nie dabei waren.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@seemarc: Anmerkungen zum Quelltext: Kommmentarzeichen sind nicht dazu lustige Muster zu machen. Das bringt dem Leser keinen Mehrwert.

`time` und `urljoin` werden importiert, aber nirgends verwendet.

Auf Modulebene gehört nur Code der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Komplett gross geschriebene Namen sind für Konstanten, nicht für Variablen. Es macht auch nicht wirklich Sinn `fal_rss_sl` in `URL` umzubenennen.

`d`, `fal_rss_sl`, `sal_rss_sl`, und `tal_rss_sl` sind sehr schlechte Namen. Namen sollen dem Leser vermitteln was der Wert dahinter bedeutet, und nicht zum rätselraten zwingen. Also weder einbuchstabige Namen noch welche die kryptische Abkürzungen enthalten oder gar nur daraus bestehen. Man nummeriert auch keine Namen durch, und schon gar nicht mit `f`, `s` und `t` als Abkürzung für `first`, `second`, und `third`. Falls ich hier jetzt das Namensschema richtig geraten habe, trotz des fehlerhaften Kommentars beim ersten Namen. Was ich nicht erraten konnte war warum ausgerechnet `d` für den geparsten Feed steht.

Wenn man Namen durchnummeriert, egal wie man versucht das zu verschleiern, will man sich in der Regel entweder bessere Namen ausdenken, oder gar keine einzelnen Namen sondern eine Datenstruktur. Oft ist das dann eine Liste.

Das Ergebnis von `requests.get()` ist keine Seite sondern eine Antwort. Ob da dann eine (HTML-)Seite dabei ist hängt davon ab was der Server als Body schickt. Und ich würde da auch immer `raise_for_status()`-Aufrufen oder anderweitig sicherstellen das man nicht versucht eine Fehlermeldung im Body als normale, erwartete Daten weiter zu verarbeiten.

CSS-Klassen werden von `BeautifulSoup` besonders behandelt, so dass man da nicht unbedingt ein Wörterbuch draus machen muss. Man kann einen CSS-Klassennamen in der Regel einfach als zweites Argument an die Suchmethoden übergeben.

Warum das Element eine Diva sein soll, erschliesst sich mir nicht so ganz. Zickt das immer rum und ist launisch? 😜

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import feedparser
import requests
from bs4 import BeautifulSoup

RSS_URL = "rsslink"
USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
    " AppleWebKit/537.36 (KHTML, like Gecko)"
    " Chrome/79.0.3945.88"
    " Safari/537.36"
)


def query_article(url):
    response = requests.get(url, headers={"User-Agent": USER_AGENT})
    response.raise_for_status()
    
    soup = BeautifulSoup(response.content, "html.parser")
    title_node = soup.h1
    card_div = soup.find("div", "card")
    text_node = card_div.div.next_sibling.next_sibling.next_sibling
    ...


def main():
    feed = feedparser.parse(RSS_URL)
    article_links = [entry["link"] for entry in feed.entries[:3]]
    query_article(article_links[0])


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
seemarc
User
Beiträge: 10
Registriert: Donnerstag 26. Dezember 2019, 18:52

@__blackjack__: Habe auf die Namenskonvention nicht wirklich geachtet, war erstmal nur zur Testzwecken.

'time' und 'urljoin' werden beide später noch verwendet, jedoch bevor ich weitergemacht habe ist mir das Problem aufgefallen. Die Kommentarzeichen habe ich zur Strukturierung für mich verwendet.

diva kommt von div_a ;D


Ich werde mir dein Script jetzt mal anschauen, bin immer noch nicht wirklich auf die Lösung meines Problems gestoßen.
Idee: Link1; in Datei speichern; sleep 5 min; link1 mit oberstem link im rss feed vergleichen und dann sollte das Ergebnis ungleich sein muss ich noch schauen wie ich alle neuen Links herausfinden kann und diese dann einzeln parsen kann. Ich brauche nämlich jeden Title+Text später in einer eigenen E-Mail. Ebenfalls kann es ja sein das während den 5 min sleep anstatt einem 20 neue Links ankommen, die müsste ich alle 20 als neu erkennen können.
Antworten