Ich hatte schon immer ein Interesse für Zitate und andere Gedanken von wichtigen Persönlichkeiten und spätestens mit meinem Einstieg in die Welt der elektronischen Kommunikation mittels Newsgroups damals, gab es einen wachsenden Pool von Zitaten, der mich über die Jahre hinweg begleitete.

Alles begann damals mit einer Funktion des Newsreaders Blue Wave, den ich nutzte, um mich mit meinem 14.400er Modem in die lokale Newsgroup Irata einzuwählen. Dabei konnte man ein Textfile hinterlegen, aus dem beim Kommentieren eine zufällige Zeile zur Ergänzung der Signatur ausgewählt wurde.

Später übernahm ich die Liste der Zitate dann für ein einfaches JavaScript auf meinen ersten Websites, welches es dort auch noch heute als Zitate des Tages gibt.

Vor ein paar Jahren schließlich hatte ich dann die Idee eines täglichen Zufallszitats für meine Browser-Startseite, die ich seither täglich auf meinem Arbeitslaptop nutze.

Und jetzt also ein Twitter Bot für dieses Thema. Na dann mal los! :)

Ausgangssituation und Refactoring

Durch mein Projekt mit der Browser-Startseite gab es seit Herbst 2019 bereits eine funktionierende Lösung, um abhängig vom Datum ein zufälliges Zitat von einer externen Website abzuholen und als einfache Website anzuzeigen. Das notwendige PHP-Script dafür war relativ geradlinig programmiert und der Code entsprach nicht mehr ganz meinen Ansprüchen, weswegen ich mich zunächst für ein Refactoring entschied. Dabei entstanden drei Klassen, die sich 1) der allgemeinen Programmlogik, 2) der Bereitstellung von Zitaten und 3) dem Rendern des Zitats widmen.

Zu dem Zeitpunkt hatte ich bereits entschieden, das Ganze auch auf GitLab zu veröffentlichen, wo ich am 1.3.2022 dann diese neue Version bereitstellte: https://gitlab.com/gruniversal/random-quote

Zitate von Quote Fancy

Die Zitate stammen hierbei übrigens nicht von mir, sondern von der Website Quote Fancy, die eine Vielzahl von Zitaten als Wallpaper zum Download bereitstellt.

Gemäß der Fair Use Bedingungen dürfen die Zitate sowohl im privaten als auch im begrenzten gewerblichen Kontext genutzt werden, sofern ein klare Attribution erfolgt, die ich sowohl im Code als auch hiermit sehr gern leiste.

Um die Zitate nicht immer zur Laufzeit abzuholen, kommt hierbei übrigens ein Caching zum Einsatz, welches sowohl die Ausführungsgeschwindigkeit erhöht, als auch den Traffic auf die Seite reduziert.

Wie baut man einen Twitter Bot?

Soweit zu den wohlbekannten Vorbedingungen meines Projektes. Ab hier begann nun das Neuland. Was muss man eigentlich machen, um einen Twitter Bot zu erstellen? Darf man das überhaupt? Und wie funktioniert das Ganze technisch?

Twitter Developer Account erstellen

Nunja.. in allen Quellen, die ich so gefunden habe, ist der erste logische Schritt einen Twitter-Account zu erstellen, genauer einen Twitter Developer Account. Während der Einrichtung muss man dabei verschiedene Fragen beantworten, wozu man den Account nutzen möchte und welche Dienste automatisiert werden sollen bzw. welche Arten von Daten man verarbeitet. Es fiel mir nicht schwer hier alle Fragen wahrheitsgemäß zu beantworten und kurze Zeit später hatte ich einen entsprechenden Zugriff. Die einzige schwierige Entscheidung war einen passenden Accountnamen zu finden, da viele favorisierte Namen schon in Verwendung waren.

Im zweiten Schritt muss man nun sein Projekt anlegen und passende Zugangsdaten erstellen. Es wird hier im Portal zwischen Projects und Apps unterschieden und empfohlen ein Project anzulegen und den moderneren API-Endpunkt nach API-Version 2 zu nutzen. Da ich aber nur eine einfache Anwendung plante und Beispiele mit API-Version 1 gelesen hatte, die aus meiner Sicht ausreichen würden, entschied ich mich statt dessen eine Standalone-App zu erstellen.

Wichtig ist hierbei die Zugangsdaten gut zu sichern, da diese nur bei der initialen Einrichtung angezeigt werden. Insgesamt erhält man folgende Informationen:

  • APP ID – eine nummerische Angabe
  • App-Name – der Name der App
  • App-Key – vergleichbar mit dem Nutzernamen für die App
  • Secret – vergleichbar mit dem Passwort für die App
  • Bearer Token – nur für OAuth2 erforderlich
  • Access Token – vergleichbar mit dem Nutzernamen für den User
  • Access Token Secret – vergleichbar mit dem Passwort für den User

Für die Erstellung der Benutzerzugangsdaten muss OAuth1.0a aktiv sein und es ist zudem darauf zu achten, dass diese mit Lese- und Schreibrechten erzeugt werden, da im Standard nur Leseoperationen erlaubt sind:

Für Twitter API v1.1 muss OAuth1.0a aktiv sein
Zudem sind Schreibrechte zum Twittern notwendig

Verwendung der Twitter API

Hat man die Einrichtung des Accounts abgeschlossen, stellt sich als Nächstes die Frage, wie man auf die Twitter API zugreifen möchte. Grundsätzlich ist es eine Web-Schnittstelle, die über HTTP-Requests funktioniert, die man also z.B. über Curl direkt ansprechen kann.

Ich hatte das kurz erwogen, aber da man anhand der Versionsnummern sieht, ist die API einer ständigen Fortentwicklung unterworfen und es könnte recht aufwändig werden, wenn man bei Änderungen in der API immer vielen eigenen Code anpassen muss. Deswegen erschien es mir schnell sinnvoll, hier auf eine etablierte Library zu setzen, die die grundlegende Kommunikation abstrahiert und mir damit ein besseres Interface bietet.

Twitter pflegt hier selbst eine Liste von möglichen PHP-Libraries und auch über einen normale Websuche findet man hier ganze gute Ressourcen. Dabei verfolgen die Libraries verschiedene Ansätze, was sich vor allem in der Art der Verwendung zeigt. So gibt es Libraries die eher auf spezifische Methoden für einzelne Operationen setzen, während andere näher an der technischen Struktur der API sind und generische Methoden anbieten.

Letztlich habe ich mich hier für TwitterOAuth entschieden, weil ich die Beispiele auf der Website nachvollziehbar fand und die Library aktiv entwickelt wird. Es wäre aber sicherlich auch gut möglich, eine der anderen Libraries zu nutzen.

Die Einbindung in mein Projekt gelingt dabei problemlos über Composer:

> composer require abraham/twitteroauth

Abgesehen von Konfiguration und Fehlerbehandlung ergibt sich letztlich folgender überschaubarer Code:

$api = new TwitterOAuth( APP_KEY, APP_SECRET, ACCESS_TOKEN, ACCESS_SECRET );
$api->get( 'account/verify_credentials' );
$upload = $api->upload( 'media/upload', [ 'media' => $quote_image, 'media_type' => 'image/jpeg' ], true );
$api->post( 'statuses/update', [ 'status' => $quote_text, 'media_ids' => $upload->media_id ] );

Regelmäßige Ausführung ohne Cronjobs

Mit dem nun komplett entwickelten Bot bleibt noch eine wichtige Frage offen. Wie kann man den Aufruf regelmäßig triggern, damit er täglich ein Zitat in die Twitter Timeline postet? Die klassische Antwort wäre hier ein Cronjob auf CLI-Ebene.

Da mein Hosting nicht über diese Option verfügt (etwas, was ich zu gegebener Zeit nochmal überdenken sollte), behelfe ich mir hierbei mit einem Webaufruf.

Dafür gibt es verschiedene Anbieter. Ich bin letztlich bei cron-job.org fündig geworden, hauptsächlich weil dieser keine zusätzlichen Kosten verursacht, d.h. das Angebot ist vollständig kostenlos. Zudem handelt es sich um einen deutschen Anbieter und der Datenschutz unterliegt damit den üblichen Regelungen der EU-DSGVO. Interessant: der Entwickler hat auch den Code auf GitHub bereitgestellt.

Die Anlage des Accounts und die Konfiguration sind komplett selbsterklärend und in Minuten erledigt und bisher arbeitet der Dienst absolut tadellos. Großartiges Projekt! :)

Fazit

Ok, Zeit für eine kleine Zusammenfassung. Dank der guten Vorarbeit von Quote Fancy in der Bereitstellung der Zitate und Abraham Williams für die Abstraktion der Twitter API sowie meiner schon bestehenden eigenen Vorarbeiten, konnte ich meinen Twitter Bot für Zufallszitate relativ einfach umsetzen.

Ob die Welt so ein Projekt wirklich braucht? Wohl nicht unbedingt, aber es war eine interessante Fingerübung und verbindet meine schon lange existierende Leidenschaft für Zitate mit den facettenreichen Herausforderungen der Twitter API.

Hier sehe ich auch auf jeden Fall noch Raum für Verbesserungen, da meine Lösung auf Basis von API-Version 1 wahrscheinlich irgendwann deprecated sein wird. Aber für den Moment tut es, was es soll und wenn es erforderlich wird, findet ihr zukünftige Updates im entsprechenden GitLab-Repo.

Möglicherweise etwas spannender dürfte der Twitter-Kanal selbst sein, wo ihr ab sofort täglich ein zufälliges Zitat erhalten könnt: https://twitter.com/r4nd0m_quot3

Habt ihr noch Fragen oder Feedback? Schreibt gern in die Kommentare! :)