Erfahrungen über die Programmierung eines Text Spinners

5. Juli 2016 · Kategorien: CSS Stylesheets, Internet, JavaScript, PHP, SEO, Webentwicklung

TextGen

Die letzten Tage habe ich mir einmal die Zeit genommen, einen rein browserbasierten Text Spinner zu bauen. Ich kann mir vorstellen, dass der eine oder andere sich dafür interessiert. Deswegen möchte ich in diesem Artikel ein paar wenig darüber sprechen.

Was ist ein Text Spinner?

Ein Text- bzw. Artikel Spinner ist ein Tool, das es ermöglicht, an Hand eines Textes mit Hilfe einer Markup Sprache wie zum Beispiel Spintax Synonyme für bestimmte Wörter festzulegen. Hat man damit abgeschlossen und genügend Synonyme definiert, generiert der Text Spinner eine Vielzahl an Texten, die sich auf Grund der unterschiedlichen Wörter augenscheinlich unterscheiden, inhaltlich aber identisch sind.

Um das zu veranschaulichen, hier ein Beispiel-Satz aus Wikipedia:

Ein Tisch ist ein Möbelstück, das sich durch eine zugängliche, meist ebene und waagerechte Fläche charakterisieren lässt, die auf einem oder mehreren Beinen ruht, und dem Zweck der Ablage von Gegenständen dient.

Diesen Satz könnte man nun über den Artikel Spinner folgendermaßen bearbeiten:

Ein Tisch ist ein {Möbelstück|Mobiliar}, {das|welches} sich {anhand einer|mithilfe einer} {zugänglichen|erreichbaren}, {meist|häufig} {ebenen|flachen} und {waagerechten|horizontalen} Fläche {charakterisieren|beschreiben} lässt, {die|welche} auf einem oder {mehreren|einigen} Beinen {ruht|steht}, {und|sowie} dem {Zweck|Nutzen} der {Ablage|Lagerung} von {Gegenständen|Sachgegenständen} dient.

An Hand dieser Formatierung kann der Artikel Spinner nun unter anderem folgenden Satz erzeugen:

Ein Tisch ist ein Mobiliar, welches sich mithilfe einer erreichbaren, häufig flachen und horizontalen Fläche beschreiben lässt, welche auf einem oder einigen Beinen steht, sowie dem Nutzen der Lagerung von Sachgegenständen dient.

Wozu dient das Umschreiben von Texten?

Es gibt diverse Gründe, warum Texte umgeschrieben werden sollten.

Dahinter können natürlich fragwürdige Absichten stehen – wie zum Beispiel das Umschreiben von Texten, um diese dann als eigene auszugeben. Hierbei gab es ja schon einige Skandale von diversen Prominenten und Politikern, die im Nachhinein ihre Doktorarbeit aberkannt bekommen haben. Aber ja, ein Text Spinner kann auch hierbei helfen.

Ein weiterer Grund, der mich auch zur Entwicklung des Spinners bewogen hat, ist das Verfassen von Texten für meine Webseiten.
Google liebt guten – und vor allem einzigartigen – Content und ein Artikel Spinner hilft dabei, Texte aus diversen Quellen schnell und einfach entsprechend anzupassen. Wer selber Artikel im Netz verfasst, weiß, dass es nicht immer einfach ist, Texte so zu schreiben, dass sie nicht als duplicate content angesehen werden können. Da ist es hilfreich, wenn man die Texte noch einmal vor der Veröffentlichung durch einen Text Spinner bearbeitet.

Auch in dem Fall ist es möglich, einen fremden Text einfach zu kopieren und entsprechend mit Synonymen zu versehen. Es gibt aber Hinweise darauf, dass Google bereits Synonyme erkennen kann und solche Texte demzufolge dann trotzdem als duplicate content wertet. Um einen gut rankenden SEO-Text zu verfassen, reicht also ein schnelles Durchjagen durch den Spinner nicht aus – eigene Recherche ist weiterhin notwendig, der Spinner hilft nur dabei.

Worauf basiert TextGen?

TextGen läuft mit PHP und Laravel 5 im Backend sowie Angular JS und Websockets im Frontend.
Laravel ist aktuell mein liebstes PHP Framework, weil es einfach viele Sachen vereinfacht, eine gute Community hat und es erlaubt, relativ einfach sauberen Code zu schreiben.

Ich setze dabei immer auf Dependency Injections, während ich bis auf in den Views auf statische Facades verzichte. Auch ActiveRecords instanziiere ich nicht wahllos im Code, sondern greife auf ein Repository zurück. Wenn also an der Datenbank hantiert wird, wird immer ein Repository verwendet. Bis auf einer Ausnahme: Beim Auslesen der Synonyme werden raw Datenbank Queries verwendet. Das Auslesen muss schnell gehen und es sind hierbei viele Anfragen  zu erwarten. Da möchte mir einfach den Overhead sparen, der für das Initialisieren meiner Models notwendig ist. Immerhin möchte ich an dieser Stelle nur ein Array von Synonymen sortiert nach Priorität.

Da PHP immer noch mein Favorit ist und ich das Projekt auch nur in einer Backend-Sprache schreiben wollte, setze ich für die Websockets auf die Implementierung von Ratchet. Die erste Überlegung war, die Abfrage an Synonymen über AJAX zu lösen. Da aber Synonyme sofort beim Tippen bzw. durchgehen des Texts geladen werden sollten, wäre diese Lösung zu performancelastig.

Bei einer Implementierung via AJAX wird nämlich mit jeder Abfrage ein HTTP-Request durchgeführt, der einiges an Overhead mit sich führt. Jedes Mal mit eine Verbindung aufgebaut werden. Im Gegensatz zu Sockets. Hier wird die Verbindung aufgebaut, wenn die Seite geladen wird und erst wieder beendet, wenn der Besucher die Seite verlässt. Währenddessen kann man ziemlich einfach Messages, in meinem Fall JSON-kodierte Strings mit Synonymen, austauschen.

Als Datenbanksystem habe ich mich für MySQL entschieden. Anfangs wollte ich alles normalisieren (d.h. Wörter gehören zu Synonymsets). Das hat sich während der Entwicklung aber als unnötig kompliziert herauskristallisiert, sodass ich jetzt einen denormalisierten Weg fahre: Jedes Wort wird in einer Zeile mit all seinen Synonymen gespeichert.
Zugegeben, das ist nicht ganz sauber und schreit nach einer dokumentenbasierten Datenbank wie MongoDB.  Ein Wechsel des Datenbanksystems war mir aber zu dem Zeitpunkt zu aufwändig. Gegebenenfalls werde ich in der nächsten Zeit auf MongoDB wechseln.

TextArea mit Syntax Highlighting

Das war ein Herausforderung, vor der ich stand: Die in der Textarea hinzugefügten Synonyme wollte ich der Übersichtlichkeit halber gerne farblich markieren. Das ist in HTML bzw. CSS schlicht nicht möglich: Man kann einer Textarea lediglich eine einzige Textfarbe zuweisen.

Also habe ich mit dem contenteditable Attribut herumexperimentiert. Dieses Attribut erlaubt es, dass der Benutzer den Inhalt eines divs – ähnlich wie bei einer Textarea – bearbeiten kann. Da ein div HTML erlaubt, ist es auch ziemlich einfach, entsprechende Stellen zu färben.

Für das Ersetzen von Wörtern bzw. Hinzufügen von Synonymen ist die aktuelle Cursor Position allerdings wichtig. Diese lässt sich mit einem contenteditable div nicht so einfach ermitteln. Vor allem dann nicht, wenn der div entsprechende spans zur farblichen Markierung beinhaltet. Es gibt ein paar Libraries, die das mehr oder weniger lösen. Aber so richtig wollte bei mir keine funktionieren bzw. mein Code wurde weitaus komplexer.

Und nun?

Meine Lösung basiert nun darauf, dass ich dem Benutzer eine Textarea zur Bearbeitung des Texts stelle. Jetzt kommt aber der Clue: Die Textarea hat eine geringe Opacity, sodass ein absolut positionierter Div hinter der Textarea durchscheint. Beim Ändern des Inhalts der Textarea wird dieser Inhalt durch einen Parser gejagt und der dadurch entstandene HTML-Code mit Syntax Highlighting dem Div zugewiesen.

Wenn der Benutzer tippt, ist eine minimale Verzögerung von etwa 0,1 Sekunden feststellbar. Das sollte aber niemanden stören – es funktioniert!

Hier musste ich natürlich sicherstellen, dass der Text in der Textarea perfekt über dem Text des divs liegt. Hierbei muss der Parser teilweise helfen, indem er zum Beispiel  mehrfach vorkommende Leerzeichen mit einem   ersetzt. Ansonsten würden die Browser aufeinanderfolgende Leerzeichen lediglich als eines anzeigen.

Als ich das gebaut hatte, funktioniert es schon ganz gut. Lediglich im Firefox gab es Probleme. Obwohl beide Element, also div und Textarea, gleiche Schriftgröße und gleiches Padding hatten, brach der Text in seltenen Fällen im Firefox im div früher als in der Textarea.
Die Lösung liegt nahe: Ich habe das Padding mit Hilfe der CSS-Query @-moz-document url-prefix() lediglich für den Firefox etwas verringert. Gegebenfalls muss ich diese Query wieder entfernen, sofern Firefox diesen Bug fixt.

Design

Ich bin wahrlich kein Web Designer, trotzdem habe ich mich auch hier mal wieder am Design versucht.
Welche Elemente die primary color (aktuell türkis-blau) erhalten sollen, habe ich schon entschieden, bevor ich die eigentliche Farbe festgelegt hatte. Dazu setze ich auf SCSS und verwende für sämtliche Farben Variablen. Sobald ich mit einer Farbe nicht zufrieden bin, muss ich also nur an einer einzigen Stelle den Hex-Code ändern.

Um Chaos bei Margins und Paddings zu vermeiden, habe ich auch diese vordefiniert: Es sind nur Werte erlaubt, die den Fibonacci Zahlen angehören. Einen guten Artikel hierzu gibt es hier. The designer’s guide to the Golden Ratio.
Das heißt: in den SCSS-Dateien ist es nicht mehr “erlaubt”, fixe Zahlen für margin- und padding-Attribute zu verwenden. Stattdessen verwende ich nur Variablen ($spacing-1, $spacing-2, $spacing-3, $spacing-5, $spacing-8), die wiederum lediglich die Fibonacci Zahlen vermerken.

Das Hintergrundbild ist ein kostenloses Stock Photo von Stocksnap - farblich natürlich etwas angepasst. Stocksnap macht wirklich sehenswerte Fotos – ist auf jeden Fall eine Empfehlung von mir.

Ansonsten basiert das Design wie gesagt auf SCSS und Foundation 5. Gegebenfalls werde ich demnächst auf Foundation 6 updaten.
Kompiliert werden die SCSS- und JavaScript-Dateien mit gulp und Laravels elixir. Elixir nimmt ziemlich viel Arbeit ab. So setzt es zum Beispiel automatische Hashes in die Dateinamen, um den Browser Cache zu busten – und minimiert den JS- und CSS-Code auf der Produktionsumgebung (gulp –production).

Synonyme

Die Synonyme habe ich von OpenThesaurus. Anfangs habe ich mich deren API bedient. Als ich aber merkte, dass diese – vor allem in Verbindung mit dem gesetzen Request Limit – viel zu langsam ist, habe ich im Download-Bereich der Seite eine vollständige, textbasierte Synonymliste gefunden.

Import

Darauf habe ich einen Laravel artisan Command geschrieben, der mir die Textdatei importiert. Hierbei kann ich empfehlen, dass man selbst Sachen, bei denen man denkt, dass man sie einmalig ausführt, entsprechend wiederverwendbar implementiert. Oftmals – auch in diesem Fall – ist eine erneute Ausführung notwendig.

So habe ich zum Beispiel festgestellt, dass OpenThesaurus teilweise Ausrufezeichen und andere Sonderzeichen in den Synonymen hatte. Diese musste ich dann entsprechend mit regulären Ausdrücken entfernen und dann den Importer neu anstoßen.

Lernfähig

Den Vorteil, den ich in TextGen zu anderen Artikel Spinnern sehe ist, dass es online läuft und jeder Benutzer auf die gleiche Datenbank zugreift. So kann das Tool mit der Zeit neue Synonyme lernen:
Immer wenn ein Text generiert wurde, wird diese für einen bestimmten Zeitraum in der Datenbank festgehalten.

Ein Cronjob parst diese Texte dann, filtert die Synonyme und trägt sie entsprechend in die Datenbank ein. Bereits vorhandene Synonyme werden bei erneutem Auftreten hochpriorisiert, sodass sie in Zukunft an oberer Stelle auftauchen.

Gebeugte Wörter vs. Infinitiv

Beim Abrufen der Synonyme für ein Wort wird das Wort in den Infinitiv gesetzt – sofern in der gebeugten Form keine Synonyme gefunden wurden. Die mit Hilfe des Infinitivs gefunden Wörter werden dann wieder gebeugt.
Nun ja, deutsche Sprache – schwere Sprache. Das funktioniert natürlich nicht immer optimal und sorgt teilweise für etwas abstruse Synonyme. Trotzdem scheint mir dieses Verfahren gut genug zu sein, um es anzuwenden. Ich erhoffe mir aber natürlich, dass TextGen irgendwann so viele gebeugte Synonyme kennt, dass das nicht mehr notwendig ist.

Fazit – Text Spinner programmieren

Die Sache hat schon ein wenig Arbeit gemacht, weil das Tool relativ JavaScript-lastig ist und ich mit dem Syntax Highlighting in der Textarea ein Problem hatte, das mir nicht alltäglich passiert.
Trotzdem bin ich mit der Entwicklung ganz gut durchgekommen und es hat insgesamt doch viel Spaß gemacht.

Wenn ihr Rückfragen habt oder noch mehr wissen möchtet, wendet euch gerne in euren Kommentaren an mich.

Den fertigen Text Spinner findet hier: http://www.textgen.de

Autor: | Kategorien: CSS Stylesheets, Internet, JavaScript, PHP, SEO, Webentwicklung

1 Kommentar zu Erfahrungen über die Programmierung eines Text Spinners

  1. Sascha sagt:

    Sehr cooles Tool. Ob das Spinnen von Texten allerdings noch zeitgemäß ist, muss jeder selbst für sich entscheiden :) Würde mich über Erfahrungsberichte auf dieser Seite freuen ;)

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *