Lerne Coding
Den RSS-Feed mittels Python automatisiert tweeten
25.07.2021

RSS-Feed parsen und automatisiert twittern

Inhaltsverzeichnis
[[TABLE OF CONTENTS]]
access_timeGeschätzte Lesezeit ca. Minuten

Mein Twitter-Account war bisher sehr inkonsequent geführt. Mal habe ich über neue Artikel getweetet und mal nicht. Das soll sich nun ändern. Ich möchte, dass ein Bot alle meine Artikel automatisch tweetet. Inspiriert wurde ich durch Kalle Hallden, der so etwas bereits mit seinen YouTube Videos gemacht hat. Das Video dazu findest du hier. Das fertige Endergebnis meines Bots, findest du auf meinem Twitter-Account.

Automating My Workflow With Python

Schritt 1: Den RSS-Feed parsen

Bevor ich über meine Artikel tweeten kann, muss ich erstmal wissen, ob etwas Neues hochgeladen wurde und was. Das erkenne ich anhand des RSS-Feeds. Dieser befindet sich bei HelloCoding hier: https://hellocoding.de/feed.xml. Falls du alle interessanten Blogs in einem Interface haben möchtest, könntest du diesen in einen RSS-Reader importieren, um keinen Artikel mehr zu verpassen. (Geheimtipp 😄)

Um den Feed zu parsen habe ich mich dazu entschieden, den Feedparser zu verwenden. Ein ganz normaler XML-Parser hätte es aber vermutlich auch getan. Da bei mir das Datum nicht automatisch geparst werden konnte, habe ich zum Einlesen des Datums noch eine weitere Bibliothek hinzugefügt: Dateparser. Diese kümmert sich um das reibungslose Parsen des Datums. Alternativ könnte man auch das feste Datumsformat zum Parsen nutzen, ich baue meinen Bot aber in diesem Fall lieber etwas resistenter, damit ich den Code bei anderen RSS Feeds mit anderem Datumsformat wiederverwenden kann.

Hier noch mal die essenziellen Bibliotheken für das Auslesen des RSS Feeds im Überblick:

# Feedparser
pip install feedparser

# Dateparser
pip install dateparser

Wie ist der Feed aufgebaut?

Der Feed bzw. XML ist ein verschachteltes Informationskonstrukt, ähnlich wie HTML. Es können Informations-Tags geöffnet und geschlossen werden, es können Tags in Tags verschachtelt werden, es können aber auch unterschiedliche Tags verwendet werden. In den jeweiligen Tags sind dann die entsprechenden Informationen enthalten.

Feed parsen

Das Herunterladen des Feeds könnte zwar via Sockets abgearbeitet werden, der Feedparser hat diese Funktion jedoch selbst integriert, was mir den entsprechenden Handlungsschritt erspart hat. Der Vorteil, es aber dennoch mit Socket selbst zu implementieren, wäre unter anderem eine bessere mögliche Fehlerabwickelung.

all_articles = feedparser.parse("https://hellocoding.de/feed.xml")

In der Variable all_articles befindet sich nun ein Array mit allen Informationen. Neben den Head-Informationen, welche hier nicht gebraucht werden, befinden sich die Artikel im Reiter entries. Diese können ganz normal mit einer Schleife durchgeloopt werden.

for article in all_articles["entries"]:

Artikeldaten ermitteln

Nun habe ich auch Zugriff auf die verschiedenen Parameter des Artikels. Ich schreibe diese in Variablen, um sie besser lesen zu können:

for article in all_articles["entries"]:
    article_name = article["title"]
    article_link = article["link"]
    article_author = article["author"]
    article_timestamp = article["published"]

Jetzt möchte ich noch das Datum zu einem Unix-Timestamp einlesen, um das Datum vergleichen zu können. Der Dateparser gibt mir den Timestamp anschließend als Float zurück. Da ein Integer aber reicht, schneide ich die Nachkommastellen einfach ab, indem ich das Ergebnis zu einem Integer konvertiere.

article_timestamp = int(dateparser.parse(article["published"]).timestamp())

Autor validieren

Nachdem der Autor als Variable verfügbar ist, kann geprüft werden, ob der Artikel überhaupt von mir ist. Artikel von Felix möchte ich auf meinem Twitteraccount nicht teilen. Deshalb frage ich nun ab, ob der Autor meinen Namen enthält. Jeder String hat in Python Zugriff auf magische Methoden, u.a. contains, welche nach einem Wort oder einem Teil des Satzes sucht;

if not article_author.__contains__("Riedl"):
    continue

Das Autor-Tag enthält eine E-Mail-Adresse sowie den Namen. Da es sehr viel wahrscheinlicher ist, dass ein Autor ebenfalls Tim heißt statt Riedl, verwende ich hier meinen Nachnamen. Sollte mein Nachname nicht vorkommen, soll der Datensatz übersprungen werden und der nächste Datensatz überprüft werden.

Ich wurde inzwischen mehrfach darauf aufmerksam gemacht, man könne doch auch statt contains in verwenden. Ja, funktioniert genauso, aber ich finde in dem Fall 'contains' bei Textvergleichen ansprechender, was die Lesbarkeit betrifft, da man es eher wie einen englischen Satz lesen kann. 'In' verwende ich eher für Arrays. Aber das ist nur mein subjektives Empfinden; nutze einfach das, was dir lieber ist, funktionieren wird beides.

Schritt 2: Prüfen, ob der Artikel bereits gepostet wurde

Um nicht jedes Mal alle via RSS-Feed übergebene Artikel zu posten, muss ich herausfinden, über welche Artikel ich bereits getweetet habe, und welche nicht.

Konzept

Jedes Mal, wenn der Feedparser ausgeführt wird, wird das Datum mitgeloggt. Anhand des Timestamps kann bei der nächsten Ausführung geprüft werden, ob ein Artikel bereits gepostet wurde oder nicht. Da die Einträge nach Datum sortiert sind, kann ich nach dem Ersten bereits geposteten Artikel das Programm beenden.

Der Timestamp wird als Zahl gespeichert. Eine Datenbank für einen einzelnen Zahlenwert aufzusetzen, finde ich etwas sinnlos, ggf. muss sogar erst noch eine Datenbank installiert und gehostet werden, was mir für diesen Bot zu viel Aufwand war. Solltest du mehrere Feeds auslesen, dann ja, aber bei einem einzigen Feed reicht denke ich eine normale JSON-Datei.

Umsetzung

Zunächst ermittle ich den aktuellen Timestamp während der Ausführung. Die Variable last_post_update speichert den Unix-Timestamp der letzten Ausführung des Scripts, welcher in einer JSON-Datei steht. Für den Fall, dass die Datei noch nicht existiert, da das Script z.B. zum ersten Mal ausgeführt wurde, wird die Variable last_post_update zunächst mit dem aktuellen Datum beschrieben, kann die JSON-Datei dann erfolgreich gelesen und geparst werden, wird der Wert später einfach überschrieben.

def get_last_post_timestamp() -> int:
    current_timestamp = int(datetime.now().timestamp())
    last_post_update = current_timestamp

Bevor die Datei ausgelesen werden kann, muss zunächst der Dateipfad ermittelt werden, unabhängig davon, von wo das Script ausgeführt wird. Mit os.path.realpath(__file__) kann der absolute (komplette) Pfad zum Python-Script ermittelt werden. Anschließend wird aus dem Pfad mit os.path.dirname() der Dateiname main.py entfernt und mit data.json ersetzt. Die Ordnerstruktur reicht für dieses Projekt völlig aus, alternativ kannst du sie aber auch z.B. in ein Unterverzeichnis deiner Wahl schieben. Der Pfad könnte optional in einer DotEnv Datei angegeben werden.

current_dir = os.path.dirname(os.path.realpath(__file__)) + "/data.json"

Ist der Pfad zur JSON-Datei ermittelt, kann diese auch ausgelesen werden. Sollte das einlesen scheitern, kannst du dein Programm mit Try-Except vor einem Absturz bewahren. Wenn du möchtest, kannst du den Fehler mitloggen, ansonsten überspringe das Exception-Handling mit Wort pass. Bedenke, dass das Überspringen der Exception mit pass Quick & Dirty in privaten Projekten in Ordnung ist, im kommerziellen Umfeld aber nicht.

try:
    with open(current_dir, "r") as f:
        last_post_update = int(json.loads(f.read())["last_post"])
except Exception as e:
    pass

Nachdem der Wert ausgelesen wurde, wird anschließend der neue Timestamp geschrieben. Auch hier solltest du wieder das Schreiben der Datei gegen Fehler im professionellen Umfeld absichern, aber für meine interne Umgebung reicht das so aus.

with open(current_dir, "w") as f:
        f.write(json.dumps({"last_post": current_timestamp}))

Schritt 3: Den Artikel auf Twitter posten

Nachdem nun klar ist, welche Artikel bereits gepostet werden dürfen und welche nicht, kann ich mich mit der Twitter API auseinandersetzen.

Installation

Um auf Twitter Tweets erstellen zu können, bediene ich mich an der offiziellen Twitter API. Dazu benötige ich einen API-Account, um darauf zugreifen zu können, sowie ein weiteres Python-Paket, um alles komfortabel tweeten zu können. Das von mir hier verwendete Paket heißt Tweepy. Alternativ bietet Twitter aber auch die Möglichkeit an, alles RESTful abzuwickeln.

pip install tweepy

Neuen Twitter-Developer-Account anlegen

Um Zugriff auf die Twitter API zu bekommen, musst du dich im Entwicklerportal von Twitter anmelden und einen Zugang beantragen. Twitter wird dir Fragen zu deinem Projekt stellen und wie du die API nutzen möchtest. Hast du diese beantwortet, wird dir eine E-Mail zur Verifizierung geschickt. Bis die E-Mail bei dir ankommt, kann jedoch etwas Zeit vergehen. Stress dich nicht, sollte diese nicht sofort im Postfach liegen.

Ist die Bestätigung von dir bestätigt worden, hast du Zugriff zum Developer-Portal. Hier musst du ein neues Projekt angelegen:

Im Developer Portal von Twitter eine neue App Anlegen
Im Developer Portal von Twitter eine neue App Anlegen

Ist das Projekt erstellt, müssen noch die Berechtigungen der API-Keys von 'nur lesen' auf 'lesen + tweeten' geändert werden, andernfalls kann Python nicht tweeten und das Script wird mit einer Fehlermeldung beendet.

Sind die Berechtigungen gesetzt, müssen die API-Zugangsdaten neu generiert und anschließend in das Projekt integriert werden. Da es sich hierbei um höchst sensible Daten handelt, ist die Verwendung einer DotEnv-Datei ratsam. Was DotEnv-Files sind und wie man diese verwendet, habe ich dir hier erklärt.

Mit Zugangsdaten einloggen

Mit dem folgenden Code authentifiziere ich mich nun mit meinen API-Nutzerdaten bei Twitter:

# authentication of consumer key and secret
auth = tweepy.OAuthHandler("twitter_consumer_key", "twitter_consumer_secret")

# authentication of access token and secret
auth.set_access_token("twitter_access_token", "twitter_access_token_secret")
api = tweepy.API(auth)

Mit Python tweeten

Tweepy hat die Möglichkeit normale Text-Tweets zu erstellen, aber auch Tweets mit Anhängen, z.B. einem Bild. Ein normaler Tweet reicht mir aber völlig aus und kann so erstellt werden:

api.update_status(status="Neuer Blogartikel:\n"+article_link)
print("Neuer Blogartikel:\n"+article_link)

Cronjob setzen

Nachdem das Script auf dem Server liegt, muss es nur noch automatisch in einem zeitlichen Intervall ausgeführt werden. Hierfür werden Cronjobs unter Linux verwendet. Wenn du eine ausführlichere Anleitung zu Cronjobs benötigst, kannst du diese hier nachlesen.

Um den Cronjob zu registrieren, gib in deine Linux Kommandozeile crontab -e ein und füge folgende Zeile am Ende der Datei an. Du musst nur noch den Pfad zu deinem Script anpassen. Bitte gib den vollständigen Pfad an z.B. /home/userxyz/github/rssfeedparser/main.py

0 * * * * python3 /path/to/main.py

Fertig, Dein Python Script wird nun stündlich den RSS Feed abfragen und einen Tweet erstellen, sollte besagter Artikel zeitlich nach der letzten Ausführung veröffentlicht worden sein.

Mein Endergebnis

Beispiel Tweet anzeigen 

Datenschutz Modus
Service kann nicht Aktiviert werden, überprüfe Datenschutz Einstellungen ob der Service github Aktiv ist!Diese ist eine Interne Meldung eig. solltes du diese Meldung nicht sehen. Falls doch liegt zur Zeit ein Fehler vor.
 

Fazit

Das Projekt ist nur ein kleines nice-to-have Script, welches ich schnell für meine private Umgebung geschrieben habe. Es wurde mit Absicht einfach gehalten, damit alle Schritte für Hobby-ITler und Anfänger nachvollziehbar sind. Themen wie automatisierte Tests (z.B. Unit-Tests), CI, CD, CT, Git, Python Debugger,... sind Themen für andere Artikel 😉

Bildquelle - Vielen Dank an die Ersteller:innen für dieses Bild
Kommentare zum Artikel

Es sind noch keine Kommentare vorhanden? Sei der/die Erste und verfasse einen Kommentar zum Artikel "Den RSS-Feed mittels Python automatisiert tweeten"!

Kommentar schreiben

Vom Autor Empfohlen
close