automatisierte crawl-abgleiche in r blogbeitragsbild

SEO-Monitoring mit Crawlabgleichen in R – 2020 Version

Bekanntlich ist es sinnvoll eine Website während der Umsetzung des SEO-Konzepts sowie im Rahmen der Betreuung genaustens im Auge zu behalten. Eine der mächtigsten Instrumente um immer auf dem neusten Stand zu sein, ist das zeitversetzte Crawlen und Abgleichen der Website basierend auf der URL Basis. Um den regelmäßigen Zeitaufwand dafür auf ein Minimum zu reduzieren, werden wir in diesem Beitrag alles vom Crawling bis zum Output-Excel automatisieren! Anders ausgedrückt, das Einzige was zu tun ist neben der initialen Einrichtung, ist die intellektuelle Analyse des Ausgabe-Excel.

Da unser letzter Blog-Beitrag zu diesem Thema schon einige Zeit her ist und wir uns bei [Get:Traction] natürlich auch ständig weiterentwickeln, ist es an der Zeit, mal wieder ein Update zu lancieren! Optimierung ist schließlich der Inbegriff unserer Kernkompetenz.

Der Output – Was kommt dabei raus?

Um abzuklären, ob der Crawlabgleich etwas für Dich ist, ist es sinnvoll zuerst einmal einen Blick auf den Output zu werfen:

Das Endergebnis ist nach wie vor eine Excel Datei, welche in einem Reiter für jede Metrik die Unterschiede zum vorherigen Crawl aufzeichnet. Dabei sind folgende Punkte abgedeckt:

  • Neue URLs
  • Nicht mehr verlinkte URLs
  • Änderungen bei URLs, die in beiden Crawls vorhanden sind:
    • Status Codes
    • Canonical-Anweisungen
    • Meta Robots
    • H1
    • Titles
    • Descriptions
    • Content Types
    • Klicktiefe
    • Dateigröße
SEO-Monitoring: Excel Datei mit Reitern für jede Metrik

Übersicht der Arbeitsschritte

Grundsätzlich haben wir 3 Schritte während des gesamten Prozesses:

– Wir crawlen die Website in Zeitabständen

– Wir vergleichen die Crawls miteinander

– Wir analysieren das Endergebnis

SEO Monitoring mit Screaming Frog, R und Excel

Crawlen der Website

Für diesen Arbeitsschritt benötigen wir die Screaming-Frog SEO Spider.

Erstellen der Ordnerstruktur und Einrichtung der Crawl-Jobs im Aufgabenplaner

Um unseren Export nach beliebigen Zeitabständen zu automatisieren und damit regelmäßig viel Zeit zu sparen, legen wir eine standardisierte Ordnerstruktur an und erstellen im Windows Aufgabenplaner Jobs für das Crawling.

Ordnerstruktur

Initial benötigen wir 4 Ordner, die alle im gleichen Verzeichnis abzulegen sind:

Ordnerstruktur

Die Struktur sieht folgendermaßen aus:

  • 01_crawl_abgleiche
    • /[Kunde]
      • Hier kommen die vom R-Skript generierten XLSX rein.
  • 02_sf_exports
    • /[Kunde]
      • /[yyyy.mm.dd.hh.mm.ss]
        • Hier legt der Screaming Frog automatisch seine Exporte ab. Zum einen den „internal_all.csv“. Zum anderen – um im Nachhinein im Detail nachsehen zu können – den gesamten Crawl als „.seospider“.
  • 03_sf_configs
    • Hier liegen die Screaming-Frog Konfigurationsdateien ab (sofern vorhanden).
  • 04_R
    • /[R-Projekt]
      • Hier liegt das „.R“-Projekt, welches aus den letzten beiden Crawls für eine Website den Abgleich bastelt und diesen in „01_crawlabgleiche/[Kunde]/“ abglegt.

Alle fett geschriebenen Ordner in der obigen Darstellung müssen einmal initial angelegt werden. Der Rest wird automatisch von unserem Skript und dem SF generiert.

Windows Job für Crawls

  1. Erstellen der 4 initialen Ordner.
  2. Erstellen eines Ordners für jeden Kunden unter 02_sf_exports.
  3. Wenn Screaming-Frog Konfigurationsdateien für die vorgesehenen Crawls vorhanden sind, diese im Ordner „03_sf_configs“ ablegen.
  4. Öffne die „Aufgabenplanung“ über die Windows-Suche.
  5. Es ist empfehlenswert einen neuen Ordner für die Crawlings sowie die R-Jobs in der Aufgabenplanung zu erstellen:
Neuen Ordner erstellen
  1. Navigiere in den neu erstellten Ordner
  2. Erstelle mit Rechtsklick -> „Neue Aufgabe erstellen“ eine neue Aufgabe
  3. Im Dialogfeld müsst ihr dem Job nun einen Namen geben (Hier empfiehlt es sich die Namensgebung zu standardisieren und das Intervall mit einzubeziehen z.B. „1month_kunde“. Unter dem Reiter „Trigger“ könnt ihr das gewünschte Intervall und die Ausführungstage festlegen. Wir crawlen bspw. wöchentlich. Das sähe dann so aus:Navigiere in den neu erstellten Ordner
  4. Erstelle mit Rechtsklick -> „Neue Aufgabe erstellen“ eine neue Aufgabe
  5. Im Dialogfeld müsst ihr dem Job nun einen Namen geben (Hier empfiehlt es sich die Namensgebung zu standardisieren und das Intervall mit einzubeziehen z.B. „1month_kunde“. Unter dem Reiter „Trigger“ könnt ihr das gewünschte Intervall und die Ausführungstage festlegen. Wir crawlen bspw. wöchentlich. Das sähe dann so aus:
SEO Monitoring: Trigger bearbeiten
  1. Im Reiter Aktion legen wir nun den Job folgendermaßen an:
  • Kopiert euch den Pfad der „ScreamingFrog CLI“ mittels „Shift-Rechtsklick“ -> „Als Pfad kopieren“
  • („C:\Program Files (x86)\Screaming Frog SEO Spider\ScreamingFrogSEOSpiderCli.exe“)
  • Klickt auf „Neu“ und tragt den Kopierten Pfad im Feld „Programm/Skript“ ein
  • Kopiert nun in das Feld „Argumente hinzufügen“ folgenden Text:

–project-name Kunden_Crawlabgleiche –task-name 1month_tue_1200_kunde –crawl „https://www.beispiel.de/“ –config „C:\03_sf_configs\kunde.seospiderconfig“ –headless –output-folder „C:\02_sf_exports\kunde“ –timestamped-output –save-crawl –export-tabs Internal%3AAll –export-format csv

  • Ersetzt nun alle fett markierten Stellen im Text durch eure eigenen Angaben.
    • Kunden_Crawlabgleiche ist der Projektname im Screaming-Frog. Kann dort angelegt werden. (Optionaler Parameter)
    • 1_month_tue_1200_[kunde] ist der Name des Tasks im Screaming-Frog.
    • Die URL ist die zu crawlende website
    • Die beiden Pfade geben einmal den Ort der zu nutzenden SF-Config für den Crawl an und den Output Folder. Hier muss der Pfad in den jeweiligen Kunden Ordner unter /02_sf_exports rein.
  • Eine Dokumentation zu den genutzten Parametern findet sich hier.

Das Endergebnis sieht dann so aus:

Endergebnis

Jetzt könnt Ihr auf OK klicken und den Job speichern. Damit haben wir unseren automatisierten Crawl!

Abgleichen der Websites

Für diesen Arbeitsschritt benötigen wir R Studio. Hier eine kurze Anleitung und Erklärung zur Installation.

Anlegen des R-Skripts und Erstellen von Windows-Jobs

Anlegen des R-Skripts

  • Ladet euch den Ordner hier von unserem Git-Hub herunter.
  • Hier befinden sich 2 Dateien („website_change_monitor.R“ und „FUNS.R“)
  • Öffnet R Studio und legt ein neues R-Project im Ordner /04_R/ an.
  • Kopiert jetzt die beiden Dateien aus dem Download in euren Projektordner („/04_R/[Projektname]/“)

Jetzt müssen wir nur noch 2 Pfade im R Skript anpassen und schon haben wir alles für unseren Windows Job vorbereitet!

Navigiert hierzu in R Studio in eurem Projekt in die Datei „website_change_monitor.R“ und passt folgende Variablen an:

Variablen anpassen

PATH_TO_XLSX_EXPORTS ist der Pfad in euren /01_crawl_abgleiche Ordner.

PATH_TO_SF_EXPORTS ist der Pfad in euren /02_sf_exports Ordner.

(Tipp: Um auf der sicheren Seite zu sein könnt ihr „C:/“ eingeben und dann mit TAB und den Pfeiltasten bis in den jeweiligen Ordner navigieren)

Speichert das Skript jetzt mit „STRG & S“.

Damit das Skript funktioniert müsst ihr ein paar R Packages installieren. Das geht ganz einfach indem ihr am oberen Rand in R Studio auf den hints „install“ durchklickt. Sollten die Meldungen nicht aufpoppen, könnt ihr alle Packages folgendermaßen installieren:

Als Beispiel einmal:

Die Namen aller benötigten Packages findet ihr unter #1 Libraries (alle die mit „library()“ geladen werden) im Skript.Die Namen aller benötigten Packages findet ihr unter #1 Libraries (alle die mit „library()“ geladen werden) im Skript.

Anlegen des Windows-Jobs für das R-Skript

  1. Legt euch wieder im Aufgabenplaner einen neuen Ordner für R an.
  2. Erstellt hier eine neue Aufgabe mit Namen und Trigger. Der Trigger sollte natürlich nach dem ausführen der Crawl Jobs gesetzt werden.
  3. Gebt im Feld „Programm/Skript“ den Pfad zu eurer R-Installation ein, ungefähr so: „C:\Program Files\R\R-3.6.1\bin\Rscript.exe“
  4. Im Feld „Argumente hinzufügen“ geben wir nun den Dateinamen des R-Skripts an: „website_change_monitor.R“
  5. Im Feld „Starten in“ geben wir den Pfad des Ordners an, in dem sich das Skript befindet: „/04_R/[Projektname]/“
  6. Jetzt können wir den Job speichern!
Job speichern

Das wars! Jetzt haben wir einen völlig automatisierten Crawlabgleich. Zur Einrichtung eines weiteren Abgleichs, müsst ihr nur einen Ordner für den neuen Kunden in 02_sf_exports erstellen und einen Crawl-Job im Windows Aufgabenplaner erstellen. Das Skript registriert den neuen Kunden von alleine. Eure Output-Excels findet ihr nun im Ordner /01_Crawl_Abgleiche/.

Das Skript in allen Einzelheiten

Libraries

Hier werden die zum Ausführen des Skripts benötigten R-Packages geladen. Um diese beim Ausführen des Skripts nutzen zu können, müsst ihr diese vorher installieren (Beschrieben in Punkt Anlegen des R-Skripts).

Vars

Hier werden die Pfade für die Imports und Exports festgelegt. Zusätzlich legen wir hier unseren Slack API Key als Variable (Auskommentiert da nicht essenziell) an, um erfolgreich ausgeführte Scripts sowie Fehlermeldungen in unseren Scripts- Slack Channel automatisiert zu pushen! Damit hat man also auch ein Warnsystem implementiert. Die Variable „#TESTING_WEBSITE“ ist standardmäßig auskommentiert mit einem #. Sollte man Adhoc nur eine einzige Website vergleichen wollen, kann man hier das # entfernen und in die Gänsefüßchen die Website schreiben. Dabei einfach den Namen des Ordners verwenden, wie ihr ihn im sf_exports Verzeichnis erstellt habt.

Slack

Hier wird dem „slackR“ Package die nötige Information mitgegeben. Den API Key, in welchen Channel soll gepusht werden? Unter welchem Namen sollen die Nachrichten dort auftauchen?

Die Sektion ist im download-Skript ebenfalls auskommentiert, da die Nutzung von SlackR natürlich nicht obligatorisch ist.

Get Files

Find all CSV’s

Hier werden alle Dateien mit .csv-Endung rekursiv aus dem in der Variable PATH_TO_SF_EXPORTS enthaltenen Pfad aufgelistet.

Split paths

Nun splitten wir die Pfade der aufgelisteten Dateien in dem Dataframe „df_file_paths“ in einzelne Spalten auf.

Extract website, datetime

Hier determinieren wir, welche Teile der in „df_file_paths“ enthaltenen Pfade welches Element sind und geben den entsprechenden Spalten die Namen.

Convert to date

Hier konvertieren wir das bisher als Character zu verstehende Datum in der Spalte „datetime“ in ein richtiges Datums-Datenformat. Dazu nutze ich die äußerst nutzvolle Library Lubridate.

Check if two Crawls exist

Wir gruppieren nach der Spalte „website“ und zählen, ob die Anzahl an Elementen pro Gruppe mehr als 1 beträgt. Anschließend lösen wir die Gruppierung wieder auf.

Get last two crawls

Wir gruppieren abermals nach „website“ und fügen dem Dataframe die Spalte „date_rank“ hinzu. Dieser wird mithilfe der rank() Funktion absteigend durch die Spalte „datetime“ berechnet. Abschliessend filtern wir auf Einträge mit „date_rank“ 1 & 2 und lösen die Gruppierung wieder auf.

Get Website for iteration

Um für jede Website einen einzelnen Crawl Abgleich bauen zu können, müssen wir jede Website als einzelnes Objekt einer Liste betrachten und die gleichen Aktionen für jedes Objekt in dieser Liste iterativ durchführen. Hierzu bedienen wir uns eines einfachen for()-loops. Diese Liste bereiten wir nun mithilfe der unique-Funktion vor. Diese gibt uns, nach Einspeisung der Spalte „websites“ aus „df_file_paths“, einen Vector ohne doppelte Werte zurück. Sprich – wir haben eine Liste aller unserer Websites, die als Iterationsobjekt benutzt werden können.

Filter for testing

Bevor wir mit dem eigentlichen Abgleich loslegen, gucken wir hier nach, ob die vorher angesprochene Variable „TESTING_WEBSITE“ besteht und wenn ja, filtern nur auf die dort enthaltene Website.

Compare Crawls

Wir iterieren über unseren „websites“ vector und führen für jede enthaltene Website folgende Aktionen aus:

Am Anfang des Loops reduzieren wir das in dieser Iteration behandelte Datenset auf die Daten einer einzigen Website und setzen temporäre Variablen für das neue und alte Crawldatum. Wir geben eine Message in der Console aus und lesen beide Crawls, mithilfe der in „FUNS.R“ definierten Funktion „read_crawl“, ein. Dazu fügen wir eine Spalte mit neuem/altem Datum an.

Create website-dir if not exists

Der Kommentar ist ziemlich treffend – wir kreieren (wenn nicht vorhanden) ein Verzeichnis mithilfe des Iterationsobjektes sowie des Pfads aus PATH_TO_XLSX_EXPORTS.

Get new (linked) URLs

Abermals eine Message in die Console. Hier filtern wir innerhalb eines Anti-Joins vom neuen auf den alten Crawl, auf URLs, in dessen „content“ Spalte „html“ vorkommt oder die „status“ Spalte dem String „Connection Timeout“ entspricht.

Dabei bleiben nur noch die im neuen Crawl enthaltenen URLs zurück, die im alten nicht mehr existieren. Wir wählen per „select“ aus, welche Spalten wir haben wollen und konvertieren das ganze in ein Dataframe, da die XLSX Library kein Tibble versteht.

Get no longer linked/ deleted URLs

Message in die Console. Gleiches Vorgehen wie bei Punkt 4.5.2 Nur hier Anti-joinen wir vom alten auf den Neuen Crawl.

Get Status Code of not linked/deleted URLs

Message. Hier prüfen wir den Status Code der nicht mehr verlinkten Seiten, da wir ihn ja über den Crawl nicht kennen. Der Grund ist, dass wir prüfen wollen, ob eine Seite korrekterweise nicht mehr verlinkt ist. Antwortet die URL mit „404 Not Found“, ergibt es vollkommen Sinn, sie nicht mehr zu verlinken. Antwortet die Seite hingegen mit „200 OK“, stellt sich die Frage, warum sie nicht mehr verlinkt ist, wenn sie doch erreichbar ist. Im Hintergrund rennt hier ein parallelisierter Status-Code-Fetcher los. Je nachdem, wie viele URLs nicht mehr verlinkt sind, kann die Abfrage durchaus länger dauern. Auf der Console seht ihr aber die gerade abgefragten URLs, sodass ihr zumindest einen groben Überblick habt, dass sich noch etwas tut und dass das Skript nicht hängen geblieben ist. (Anhand dieses Punktes ist unter anderem erkennbar, dass es sinnvoll ist, die Crawls jeweils mit gleicher Konfiguration durchzuführen).

Get identical URLs

Was wohl 😉. Wir filtern auf HTML URLs beider Crawls und machen uns eines inner-Joins habhaft, um die identischen URLs des Abgleichs zu erhalten. Dazu fügen wir im Datenset Spalten für jedes Detail einer URL an, welche angeben, ob sich der entsprechende Wert geändert hat.

Get identical URL with changes

Da wir nun das Datenset an URLs definiert haben, welches in beiden Crawls enthalten ist, können wir nun die einzelnen Bestandteile dieses Datensets betrachten und vergleichen.

Verwaiste Seiten:

Hier definieren wir, je nach dem, was in unserer Spalte change_orphan_pages, die wir in Punkt 4.5.5 gebildet haben, steht, ob es sich um eine nicht mehr oder neu verwaiste Seite handelt. Dies speichern wir als Dataframe, um es später in der Excel abbilden zu können.

Dieses Vorgehen bleibt für jede Metrik das gleiche. Darum werde ich hier nicht auf jeden Unterpunkt eingehen.

Get biggest resources

Hier sortieren wir bei Images, JavaScript und CSS, absteigend nach der Größe (size_bytes) und speichern diese als DataFrame.

Create Excel

Hier nutzen wir die Library XLSX, um eine Arbeitsmappe zu erstellen und diese mit unseren sheets in der „sheet_order“ variable und den im Loop erstellten Data-Frames zu befüllen. Mit saveWorkbook() wird dem Export der Pfad übergeben und der Crawlabgleich, mit neuem und altem Datum im Namen, im entsprechenden Ordner der Website abgespeichert.

Send Slack notification (Fail, Success)

Zu guter Letzt unsere Slack-Notification. Hier wird eine Message aus dem momentanen Iterationsobjekt und einer vorgefertigten Nachricht zusammengebaut und mithilfe der vorher erstellten Variablen und des Packages SlackR in den Channel gepostet. Alle Slack-Inhalte sind im download-Skript auskommentiert, da die Nutzung von „SlackR“ rein optional ist.

Damit ist der For-Loop abgeschlossen und das Skript erstellt die Crawlabgleiche aller vorhandenen Websites.

Viel Spaß beim Abgleichen! Wenn ihr Fragen oder Anregungen habt, gerne kommentieren oder mir direkt eine Mail schreiben 🙂

ScreamingFrog, Knime, Google Big Query

SEOkomm 2019: ScreamingFrog, KNIME und Google BigQuery

Es war wieder einmal SEOkomm. Im Jahr 2019 war ich nicht nur Gast, sondern durfte, zusammen mit Sabine Langmann, auf die große Bühne. Leider hat in 30 Minuten Vortrag bei weitem nicht alles hineingepasst. Für alle die im Vortrag waren, oder auf anderem Wege hierher gefunden haben, gibt’s in diesem Blogbeitrag noch einmal alle Infos! Den Teil von Sabine Langmann zu unserem SEOkomm 2019 Vortrag findest du in ihrem Blog unter https://www.sabine-langmann.com/.


Den ScreamingFrog automatisch für mehrere Projekte starten und einen Export generieren… die Exporte des ScreamingFrog einlesen, säubern und im Anschluss in Google BigQuery speichern – Vor diese Herausforderung habe ich mich für die diesjährige SEOkomm gestellt. Eine zusätzliche Bedingung war jedoch: Kein Programmcode! Normalerweise wäre schließlich Python das Werkzeug meiner Wahl. Da Quellcode aber häufig abschreckt und mir wichtig war, dass es jeder nachbauen kann, habe ich mich entschieden den ETL Prozess in KNIME zu realisieren.

Neben den Standard-Daten die der ScreamingFrog liefert, wurden zusätzlich weitere Werte per „Custom Extraction“ durch den Crawler erfasst. In Sabines Blogartikel zur Custom Extraction, Xpath und allem was dazugehört bekommt ihr alle Infos zum ersten Teil des Talks.

Was lerne ich hier & was brauche ich dafür?

Im Grunde benötigt ihr nicht viel. Ganz wichtig ist neben ein paar Tools jedoch, dass ihr Lust habt etwas zu basteln und keine Angst habt etwas kaputt zu machen. Und wenn es Fragen gibt: Schreibt mir gerne einen Kommentar oder kontaktiert mich direkt.

Benötigte Tools: ScreamingFrog (v12+), KNIME (v4+), BigQuery, BigQuery-Befehlszeilentool, Simba-Treiber für BigQuery (4.2)

Hinweis: BigQuery ist nicht kostenlos. Es gibt Jedoch für alle die mit der Google Cloud experimentieren wollen einen „Free Tier“ von 300$. Außerdem bietet jedes der Google Cloud Produkte ein monatlich erneuertes freies Kontingent.

Wenn ihr es euch nun zur Aufgabe macht, meinen Prozess nachzubauen, werdet ihr auf dem Weg die folgenden Dinge lernen:

  • Steuere den ScreamingFrog per Kommandozeile oder Batch-Datei.
  • Nutze KNIME, um die generierten Exporte einzulesen und zu säubern, sodass mit den Daten gearbeitet werden kann.
  • Spiele die Daten – ebenfalls mit KNIME – in Google BigQuery.
  • Starte die Abläufe automatisch mittels Windows Aufgabenplaner.
  • Frage Google BigQuery mit KNIME ab und beantworte deine Fragen.

Wenn ihr das Projekt SEOkomm2019 von Github herunterladet, befinden sich darin folgende Dateien, bzw. diese Struktur (von oben nach unten):

Ordnerstruktur des Projekts
  • bq_logs: Log-Dateien des BigQuery Uploads
  • knime_cleaned: Temporäre Dateien zum Upload und JSON-Schemas für BigQuery Tabellen
  • knime_loaded: „Archiv“ für Crawls die in BigQuery geladen sind
  • sf_configs: ScreamingFrog Konfigurationsdateien
  • sf_exports: Export-Ordner der Crawls
  • sf_logs: Log-Dateien der Crawls
  • crawl_fahrrad.bat: Beispiel Batch Datei zum Crawl der Fahrrad.de E-Bike Kategorie
  • etl_fahrrad.bat: Beispiel Batch Datei zum Ausführen des KNIME Workflows

Zur Vorbereitung des Vortrags auf der SEOkomm2019 wurden drei Seiten regelmäßig gecrawlt. Diese waren gourmondo.de, geschenke24.de und fahrrad.de. Im weiteren Verlauf zeige ich euch alles am Beispiel von fahrrad.de.

ScreamingFrog per Batch-Datei steuern

Seit der Version 10 des ScreamingFrog gibt es die Möglichkeit, diesen per Kommandozeile zu steuern. Das bedeutet, ihr müsst ScreamingFrog nicht komplett mit Interface und allem Drum und Dran starten. Vielmehr könnt ihr durch einfache Befehle im Terminal einen Crawl starten, kontrollieren was exportiert und wohin der Export am Ende gespeichert wird. Hier findet ihr eine Übersicht aller Befehle für den ScreamingFrog.

Hinweis: In der Anleitung auf ScreamingFrog.co.uk wird im Terminal zunächst der Pfad gewechselt, sodass man sich im Verzeichnis des Froschs befindet. Hier liegt nämlich die ScreamingFrogSEOSpiderCli.exe, die man benötigt. Damit man dies nicht jedes Mal machen muss, könnt ihr den Pfad einfach in euren „PATH“ eintragen. Dann kennt Windows den Befehl ohne den Pfad zu wechseln.
Geht dazu wie folgt vor:
1. „Windowstaste + R“ drücken um „Ausführen“ zu öffnen.
2. „Systemumgebungsvariablen bearbeiten“ eingeben und aufrufen.
3. „Umgebungsvariablen“ anklicken
4. Im oberen Feld „Benutzervariablen für [Nutzername]“ die Variable „Path“ suchen und „Bearbeiten“.
5. „Neu“ anwählen und den Frosch-Pfad eintragen. Bei mir z.B.: „C:\Program Files (x86)\Screaming Frog SEO Spider“

Wenn wir die Befehle in eine Batch-Datei schreiben, können wir den ScreamingFrog nicht nur per Kommandozeile steuern, wir können die erstellte Datei auch einfach per Doppelklick ausführen. Außerdem, wie in unserem Fall, ist es nun auch ganz einfach, die Datei in den Windows Aufgabenplaner zu hängen und automatisch zu starten.

Warum nicht das Scheduling in ScreamingFrog nutzen?
Der ScreamingFrog bringt ebenfalls eine eigene Funktion zum „Scheduling“ mit. Da wir jedoch im Windows Aufgabenplaner mehrere Tasks hintereinander ausführen, wurde der Weg per Batch-Datei gewählt.

So eine Batch-Datei, oder auch Bat-Datei ist dabei relativ simpel zu erstellen. Es handelt sich dabei um eine simpele Text-Datei die auf „.bat“ endet. Der Inhalt unserer Batch-Datei „crawl_fahrrad.bat“ sieht nun wie folgt aus:

Die einzelnen Angaben sind relativ selbsterklärend. Auf die weniger klaren gehe ich kurz ein:

  • –timestamped-output
    • Wenn vorhanden, werden alle Exporte in eigene Ordner geschrieben deren Name aus Datum und Zeitpunkt besteht.
  • –project-name / –task-name
    • Seit Version 12 können Crawls die in der ScreamingFrog Datenbank gespeichert werden in Projekte aufgeteilt werden. Jeder Crawl in diesem Projekt ist ein Task. Dies kann man hiermit angeben.
  • –headless
    • Das ScreamingFrog Interface startet nicht.
  • >> „sf_logs/fahrrad_%DATE%.log“
    • Kein Frosch-Befehl. Dies bewirkt, das die Ausgabe des Terminals in eine Datei geschrieben wird. Da „%DATE% im Dateinamen steht, gibt es jeden Tag eine neue Datei.
    • Warum? Damit wir, wenn einmal etwas nicht klappt, nachlesen können was schief gelaufen ist.

Habt ihr nun den Pfad zur ScreamingFrogSEOSpiderCli.exe in euren Windows-Path eingefügt und eine Batch-Datei erstellt (oder die vorhandene verwendet), solltet ihr euren Crawl einfach per Doppelklick auf die Datei ausführen können.

ScreamingFrog per Windows Aufgabenplaner starten

Damit unsere Batch-Datei automatisch ausgeführt wird, hängen wir diese in den Windows Aufgabenplaner. Diesen startet ihr zum Beispiel in dem ihr die Windows-Taste drückt und dort „Aufgabenplaner“ eingebt.

Hier könnt ihr nun ganz einfach unter „Aktion“ → „Aufgabe erstellen“ eine neue Aufgabe erstellen. Ich empfehle euch jedoch dringend: legt Ordner an, um eure Aufgaben zu sortieren! Euer Zukunfts-Ich wird es euch danken.

Den Task anzulegen ist recht simpel. Ihr müsst der Aufgabe nur einen Namen geben, entscheiden wann der Task ausgeführt wird und natürlich festlegen was ausgeführt werden soll. Ich habe euch die wichtigsten Einstellungen hier als Screenshots eingefügt.

Aktion bearbeiten: Hier wird die Aktion konfiguriert

Im Punkt „Aktion bearbeiten“ gebt ihr bei „Programm/Script“ einfach den vollständigen Pfad zu der Batch-Datei an.
„E:\…\seokomm2019\website_spy\crawl_fahrrad.bat“
Im Feld „Starten in“ den Ordner zu dem Projekt. Das ist wichtig, da wir relative Pfade verwendet haben, die sonst nicht funktionieren.
„E:\…\seokomm2019\website_spy“


Du bist hier angekommen und dein Crawl läuft automatisch, von selbst, exportiert Daten als CSV… du musst nichts mehr dafür tun? Fantastisch! 😀🤜🤛😁 Aber wir sind ja noch nicht fertig. Also hol dir einen ☕ und ab in die nächste Runde 🔔. Den Crawl mit KNIME bearbeiten und in BigQuery speichern. 😎👍

ScreamingFrog Crawl in KNIME einlesen, bearbeiten und in BigQuery laden

Eins muss ich vorweg sagen: Ich kann euch im Rahmen dieses Artikels KNIME leider nicht erklären. Wir steigen also direkt voll ein.
Aber es gibt auch gute Nachrichten: KNIME ist nicht kompliziert! Im Grunde ist es ein riesiges Puzzle an Funktionen die ihr richtig zusammensetzen müsst.

Und noch mehr gute News: Auf unserem Blog findet ihr KNIME Artikel und wir bieten KNIME-Schulungen an!

KNIME Artikel & Downloads
KNIME für Anfänger
KNIME Knoten Cheat Sheet
Infos zur get:traction KNIME Schulung
KNIME Schulung für SEO
→ Oder direkt Kontakt aufnahmen unter KNIME@gettraction.de

Hier seht ihr nun den Workflow, der die ganze Arbeit macht. In den folgenden Abschnitten zeige ich euch kurz, wofür die einzelnen Teile des Workflows zuständig sind.

KNIME Worfklow: SreamingFrog → BigQuery

Hinweis: Wenn ihr den Workflow wirklich ausführen wollt und nicht das Beispiel von fahrrad.de nutzt, müsst ihr die Projekt-Unterordner (Ordner „fahrrad“ in „sf_exports“, „knime_cleand“ und „knime_loaded“) per Hand anlegen. Das gleiche gilt für den Datensatz in Google BigQuery.

Konfiguration

Ich habe es mir angewöhnt KNIME Workflows über eine Konfig-Komponente zu steuern. Das sind mehrere Knoten (wie hier im Bild zu sehen), die zu einer Komponente zusammengefügt wurden (Rechtsklick + „Create Component“).

Wenn in der Komponente Eingabe-Knoten vorhanden sind, kann der neu entstandene Knoten mit Rechtsklick + „Configure“ (F6) konfiguriert werden. Falls du einen KNIME Server hast, erscheinen diese Eingabemöglichkeiten im Webportal (aber das führt jetzt etwas zu weit 😉).

Tipp: Beschäftigt euch mit den Komponenten!
Man kann hiermit verdammt viel anstellen.
→ Eigenständige Knoten die eine komplette Beschreibung der Funktion, sowie der Eingabe- und Ausgabeports mit sich tragen.
→ Ausgabe von mehreren Diagrammen, die sich über einen Editor einfach anordnen lassen.
→ Teilen der Komponenten mit Kollegen und vieles mehr!

Crawls in KNIME einlesen

Der zweite Part listet alle CSV-Dateien auf die im angegebenen Ordner vorhanden sind. Der Pfad hierfür kommt aus der vorherigen Komponente (SF Exports).

Diese Liste an CSV-Dateien wird im nun startenden Loop abgearbeitet. Dabei wird jeweils eine Datei vom File Reader eingelesen. Der Loop „verrät“ dem File Reader dabei welche Datei an der Reihe ist.

Crawls in KNIME bereinigen

Nun folgen drei Meta-Knoten. Diese fassen ebenfalls mehrere Knoten in sich zusammen. Im Gegensatz zu den Komponenten machen sie aber auch nicht mehr. Auf zwei der Knoten gehe ich kurz ein.

„append datetime“

Da wir mehrere Crawls abspeichern und diese natürlich auf ihren Zeitstempel filtern werden, benötigt jeder Datensatz einen Zeitstempel. Erinnert ihr euch an das SF Kommando „timestamped-output“? Genau diesen Zeitstempel, also den Namen des Ordners indem der Export liegt, verwenden wir nun als neue Spalte in unseren Daten.

„clean extractions“

Hier passiert nun die Bereinigung der Informationen aus den ScreamingFrog „Custom extractions“. In den Beispielen der SEOkomm2019 haben wir vor allem Preisinformationen extrahiert. Diese beinhalten natürlich Zeichen wie „€“ und „%“ und werden somit nur als Strings eingelesen, nicht als Zahlen.

Mittels einfachen RegExp Befehlen im „Column Expresseion“ Knoten lassen sich die Zahlen extrahieren. Diese werden im Anschluss einfach von Strings in „echte“ Zahlen umgewandelt, damit man mit ihnen arbeiten und rechnen kann.

ScreamingFrog Crawl mit KNIME in BigQuery laden

Habt ihr bereits das BigQuery-Befehlszeilentool (bq) installiert und konfiguriert? Wir benutzen es jetzt!

Hier passiert nun die ganze Magie. Wir laden die Daten in BigQuery! Mit dem „External Tool“ Knoten führen wir den Befehl bq load mit dem bq-Tool aus. Dieser lädt eine CSV-Datei in eine Tabelle.

Was passiert hier genau? Der Knoten speichert die Daten der Tabelle in eine temporäre Datei, die bei jedem Vorgang überschrieben wird. Ausgeführt wird was im Bereich „External Tool“ angegeben wird. In unserem Fall die Windows Kommandozeile. Diese führt dann einfach das bq-Kommando aus, das in „Commandline Arguments“ angegeben ist.

So sieht der bq-Befehl im Ganzen aus. Dabei gibt man mit load an das Daten geladen werden. Natürlich muss man per Parameter mitteilen, um welchen Dateityp es sich handelt (CSV, JSON, etc) und wie die Datei aufgebaut ist. Wichtig ist, dass ihr den korrekten Datensatz angebt. Hier ist es seokomm2019.fahrrad.products, wobei seokomm2019 das Projekt ist, fahrrad der Datensatz und products die Tabelle (Projekt und Datensatz müsst ihr leider händisch anlegen).

Dateien mit KNIME verschieben

KNIME bietet viele Möglichkeiten mit Dateien zu arbeiten. Diese können verschoben, kopiert, gelöscht oder umbenannt werden. Dabei funktioniert das sowohl lokal, als auch auf FTP Servern oder zum Beispiel Amazon S3 Buckets.

Wir verschieben im Workflow lokal die Exporte des ScreamingFrog in den Ordner „knime_loaded“. Dieses dient als ein Archiv aller importierten Daten.

Solltet ihr eure BigQuery Tabelle neu erstellen müssen, da ihr z.B. den KNIME Workflow angepasst habt, kopiert ihr einfach alle CSV Dateien aus „knime_loaded“ zurück in „sf_exports“ und lasst KNIME einfach für euch arbeiten.

Slack Nachricht mit KNIME schicken

Für den Slack Knoten in KNIME benötigst du einen OAuth Token. Hier findest du alle Infos zu den Tokens. Wenn du den Token hast, kannst du ganz einfach Nachrichten an einen Slack Channel schicken. In diesem Workflow gebe ich mir selbst Bescheid, dass der Workflow gelaufen ist.

KNIME per Batch-Datei steuern

KNIME bietet, so wie ScreamingFrog, die Möglichkeit per Kommandozeile ausgeführt zu werden. Daher können wir auch wieder eine simple BAT-Datei schreiben, die unseren ETL-Prozess ausführt. Wichtig ist dabei -reset, damit der Workflow jedes mal zurückgesetzt wird und -nosave, da der Workflow nicht gespeichert werden muss.

KNIME per Windows Aufgabenplaner starten

Da wir ja bereits einen Task im Aufgabenplaner für den ScreamingFrog Crawl angelegt haben, muss nun nur noch ein weiterer Task in den bereits bestehenden Ablauf eingefügt werden. Die KNIME Batch-Datei also einfach nach der Frosch Batch-Datei einhängen. So eingestellt läuft nach Abschluss des Crawls direkt der KNIME Workflow ab, liest den Crawl Export ein, bereinigt ihn und schreibt ihn in Google BigQuery.

Windows Aufgabenplaner mit zwei Tasks

Das war es auch schon mit dem KNIME Workflow 😎. Klasse, dass du noch hier bist! Ich hoffe es gab nicht allzu viele Momente bei denen du dir die Haare gerauft hast (╯°□°)╯︵ ┻━┻…
Wenn du weiter dran bleibst, zeige ich dir wie du mit KNIME Daten aus Google BigQuery abfragst.

Google BigQuery mit KNIME abfragen

Bevor wir mit KNIME Daten aus BigQuery abfragen können, müssen wir etwas Vorarbeit leisten. Es gibt leider noch keinen nativen Knoten, um mit Google BigQuery zu kommunizieren. Aber im KNIME Forum liest man zumindest, dass das KNIME-Team bereits an so etwas arbeitet.

Eben noch habe ich geschrieben, dass es keine nativen Knoten gibt und schon kann ich meine Aussage wieder revidieren. Die neue Version KNIME 4.1 ist veröffentlicht worden. Dort gibt es nun Knoten für Google Big Query.

We plan to have a dedicated Big Query Connector for the new DB framework in once of the next releases which will fix this issue and will make working with BigQuery within KNIME Analytics Platform easier.

https://forum.knime.com/t/knime-labs-db-nodes-bigquery-db-query-readers-dont-work/15482/4

Wie zu Beginn beschrieben, benötigen wir den Simba-Treiber für BigQuery. Google stellt ihn direkt zur Verfügung. Ich habe Version 4.2 benutzt. Ihr ladet ein Zip-Archiv herunter. Dieses muss im nächsten Schritt entpackt werden, wohin ist dabei eigentlich egal. Ich habe mir angewöhnt solche Treiber die ich in KNIME benutze an einem Ort zu sammeln.

Nun müsst ihr in den KNIME Einstellungen die Datenbankverbindung samt Treiber hinterlegen. Zu den Einstellungen findet ihr unter „File“→“Preferences“→“KNIME“→“Databases“.

Google BigQuery Datenbankverbindung in KNIME erstellen

  1. Punkt Datenbanken auswählen.
  2. „Add“ auswählen, um neue Verbindung zu erstellen
  3. „Add directory“ auswählen und den entpackten Ordner angeben.
  4. „Find driver classes“ auswählen. Nun sollte der Treiber automatisch ausgewählt sein.

Ist das geschafft, müssen die restlichen Felder einfach ausgefüllt werden. Das „URL template“ ist bei mir wie folgt vergeben:

jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443/;ProjectId=seokomm2019;OAuthType=1

Im Anschluss alles mit „OK“ bestätigen und die Einstellungen speichern.

SEO Monitoring: Veränderte Title aus Google BigQuery mit KNIME abfragen

Da KNIME nun mit Google BigQuery kommunizieren kann, sind die KNIME Datenbank-Knoten wie gewohnt einsetzbar. Aber was tun wir nun damit?

Ein nützlicher und sehr simpler Fall im SEO Monitoring besteht darin, Crawls miteinander zu vergleichen. Da wir ScreamingFrog Crawls mit Zeitstempeln in Google BigQuery gespeichert haben, ist es ein leichtes zwei dieser Datensätze aufeinanderzulegen. In diesem simplen Beispiel interessiert uns, welche Title sich zwischen den beiden Crawls geändert haben. Die Antwort ist nur einen SQL entfernt!

Veränderte Title in KNIME aus BigQuery abfragen

In KNIME sieht ein simpler Workflow für eine Abfrage aus wie im Screenshot zu sehen (auch als Export im Download auf Github).

  1. Verbindung zu BigQuery herstellen (DBConnector)
  2. Tabelle in der Datenbank auswählen (DB Table Selector)
  3. Datenbank Query eingeben (DB Query)
  4. Datenbank Query ausführen (DB Reader)
  5. Das Ergebnis in eine Excel Datei schreiben

Achtung: Wenn ihr die Verbindung zu Google BigQuery herstellt, erscheint ein Pop-up mit einer URL. Diese müsst ihr in eurem Browser aufrufen mit dem ihr in BigQuery eingeloggt seid. Führt dort den üblichen Authentifizierungsprozess durch. Den Bestätigungscode kopiert ihr in das Pop-up Fenster und bestätigt mit OK.


Puuuuuh ヽ(✿゚▽゚)ノ 🎉 geschafft! Wir sind am Ende angekommen 🏆🏆🏆
Wir können nun:
– ScreamingFrog per Batch-Datei steuern und automatisch ausführen.
– ScreamingFrog Crawls mittels KNIME bearbeiten und in Google BigQuery laden.
– Daten aus Google BigQuery mit KNIME abfragen und auswerten.

Was kommt als nächstes?

Als kleines Projekt für die SEOkomm hat dieses Setup wunderbar funktioniert. Natürlich gibt es einige Next-Steps, die möglich sind um alles zu professionalisieren. Vor der SEOkomm2019 war dafür leider keine Zeit mehr.

  1. ScreamingFrog Crawls in der Cloud
    • Lokale Crawls sind stets fehleranfällig. Ein denkbares Setup ist den Frosch auf eine Amazon Ec2 zu installieren und die Crawls in ein angeschlossenes S3 Bucket zu speichern.
  2. KNIME Prozesse auf dem KNIME Server
    • Die bestehenden Worfklows können direkt auf einem KNIME Server ausgeführt werden.
    • Sowohl ETL Prozesse als auch Analysen lassen sich somit von allen Anwendern nutzen.

Noch ein kleines ToDo für dich…

Du hast Lust noch etwas zu experimentieren? Nun… du hast deine Crawl-Daten in Google BigQuery. Nichts leichter als jetzt ein Google Data Studio Dashboard anzuschließen und deine Daten auszuwerten!

Hier ein Beispiel der fahrrad.de E-Bike Daten: Google Data Studio für Fahrrad.de

Ich hoffe dir hat der Artikel gefallen und du konntest etwas mitnehmen. Ob du nun im SEOkomm2019 Vortrag warst, oder einfach nur so interessiert an KNIME, ScreamingFrog und BigQuery bist. Wenn dir gefallen hat was du gelesen hast oder Fragen aufgekommen sind, freue ich mich über einen Kommentar. Gerne auch einen Screenshot deines Data Studio Dashboards mit Crawl-Daten ✌😎

r4seo: Dokumentation und Reproduktion von SEO-Anasylen mit R

R4SEO – Dokumentation, Reproduktion und Kommunikation von SEO-Analysen mit R

Ich muss leider mit einem Problem beginnen, das wohl viele von uns kennen. Stell Dir dazu kurz vor, dass Dein Kunde Deine Analyse nach einem halben Jahr in der Schublade wiedergefunden hat und jetzt gerne mit der Umsetzung Deiner Maßnahmen beginnen möchte. Oder Du bist Angestellter in einem Unterneh-men und das Management hat Dir endlich die Ressourcen zur Verwirklichung bereitgestellt. So oder so, es ist einige Zeit vergangen, Du hast Dich anderen Dingen gewidmet und um ehrlich zu sein, weißt Du nicht mehr so genau, was und wie Du damals im Detail analysiert hast.
Alles kein Problem, schnell das Analysedokument wieder hervorgekramt, reingeschaut – sieht alles echt gut aus, hast Dir damals wirklich etwas dabei gedacht. Beispielsweise das Diagramm hier gefiel Deinem Kunden / Vorgesetzten wirklich gut:

R4SEO Diagramm Eigen-vs Fremdwahrnehmung

Abbildung 1: Eigen- vs. Fremdwahrnehmung der eigenen Webpages anhand von Page Views und Internal Link Score

Damals wusstest Du natürlich ungefähr, für welche Seiten die unbeschrifteten Punkte stehen. Heute…  – natürlich nicht mehr. Also gut, auch kein Problem: Excel-Datei mit den Daten suchen. Excel-Datei in einem anderen Ordner als dem Ordner mit der Analyse-Datei finden. Vergangenheits-Ich verfluchen, weil es mal wieder nichts dokumentiert hat. Das richtige Tabellenblatt suchen (Tabelle 34, ist doch logisch, hättest Du auch direkt drauf kommen können). Formeln suchen. Formeln verstehen. Excel-Datei suchen, die in der Formel referenziert wird, suchen. Sich für das nächste Mal wirklich, wirklich, wirklich vornehmen, alle Dateien besser zu strukturieren und alle Arbeitsschritte zu dokumentieren.

Oder anders herum. Da jetzt ein halbes Jahr vergangen ist, haben sich natürlich die Page Views geändert. Außerdem hast Du ein bisschen an der internen Verlinkung herumgeschraubt. Auch kein Problem: Excel auf, neuen Crawl importieren. Ach ja, Du hast die URLs ja vorher segmentiert. Wo liegen noch mal die Segment-Muster? Gut, passt wieder. Aktuelle Google Analytics-Daten an die URLs schreiben. Damals natürlich nicht mit Analytics Edge abgefragt, also doch wieder manuell Hand anlegen.

Ok, ich höre ja schon auf. Ich denke, Du fühlst den Schmerz und weißt, was ich meine.

Wir haben hier also ein massives Problem, was sehr viel Zeit, Geld und vor allem Nerven kostet. Denn im Grunde darf keiner dieser Arbeitsschritte nötig sein. Jede Analyse sollte zu jedem Zeitpunkt nachvollziehbar und reproduzierbar sein. Warum stehen wir dennoch immer wieder vor dem gleichen Problem? Dazu ein kleiner Abstecher in die Theorie.

Prozessschritte einer Datenanalyse

Jeder Analyseprozess besteht aus vier bzw. fünf Teilschritten. Als Erstes müssen die Daten aus den jeweiligen Quellen (Datenbanken, APIs, CSVs, usw.) in das Analyse-Tool – meistens Excel – importiert werden. Im nächsten Schritt werden die Daten aufgeräumt, um sie für den nachfolgenden Prozessschritt handhabbar zu machen. Aufräumen meint unter anderem das Normalisieren von Werten, weite in lange Tabellen überführen, Daten im JSON-Format in tabellarische Form bringen et cetera.

Nun folgt die eigentlich spannende Tätigkeit: das Verstehen. Das Verstehen ist dabei ein iterativer Prozess aus Datentransformation und -visualisierung. Du formulierst Fragen, die Du an die Daten stellst. Um sie zu beantworten, musst Du die Daten in den meisten Fällen in eine aggregierte Form bringen. Konkret möchtest Du beispielsweise wissen, wie häufig welcher Status Code in einem Crawl vorkommt. Oder Du reduzierst die täglichen Rohdaten aus der Google Search Console (GSC) respektive Google Analytics (GA) auf eine höhere Zeitebene, sprich: Monate, Quartale, Jahre. Transformation heißt auch, dass Du die Rohdaten um zusätzliche Dimensionen anreicherst, indem Du beispielsweise URL- oder Phrasensegmente bildest. Die Transformation wechselt sich mit der Visualisierung ab. Denn Auffälligkeiten in den Daten sind in Diagrammen zumeist einfacher zu erkennen als in den zugrundeliegenden Tabellen.

Anwendungsbrüche bei einer Datenanalyse

Abbildung 2: Anwendungsbrüche bei einer Datenanalyse mit Excel und Word / Power Point

Während dieser explorativen Datenanalyse überführst Du Deine Einsichten in ein Dokument, mit dessen Hilfe die Insights an den jeweiligen Empfänger kommuniziert werden sollen. Das ist zumeist Word oder Power Point. Und an dieser Stelle tritt der Bruch ein, der das oben beschriebene Problem bedingt. Analyse und Kommunikation finden in unterschiedlichen Anwendungen statt. Möchten Du oder der Empfänger auf die zugrundeliegenden Daten zugreifen, ist das nicht mehr ohne weiteres möglich, denn sie sind nicht aneinandergekoppelt. Natürlich kannst Du im Word immer wieder auf die entsprechende Excel(-Tabelle) hinweisen, aber das ist unglaublich mühsam und fehleranfällig. Meistens lässt man es dann doch … wird schon keiner nachfragen.

Und von der anderen Richtung kann das finale Dokument nicht unmittelbar – beispielsweise mit aktualisierten Daten –  neu generiert werden. Im Grunde musst Du jedes Diagramm und jede Beschreibung noch einmal anfassen.

Und dann bleibt noch der Punkt mit der Dokumentation. Selbst wenn Du Dir in Excel eine Power Query-Abfrage gebaut hast, die das Importieren und Transformieren der Daten weitestgehend automatisiert und somit reproduzierbar macht, ist Excel einfach nicht dafür ausgelegt, eine umfassende Dokumentation der einzelnen Schritte zu erstellen. Und sind wir ehrlich, niemand mag seine Arbeit dokumentieren, und wenn es einem das Tool dann auch noch extra schwer macht, nehmen wir das doch gerne als Vorwand, um es dann ganz sein zu lassen. Ist dann ja nicht mein Problem, sondern das des Zukunft-Ichs.

So, ich denke, das waren genug Probleme. Wie sieht die Lösung aus? – Mit einem Buchstaben gesagt: R.

Datenanalyse mit RStudio und RMarkdown

Abbildung 3: Reproduzierbare und Nachvollziehbare Datenanalyse mit RStudio und RMarkdown

Mit etwas mehr Buchstaben: R + RStudio + RMarkdown. R ist eine statistische Programmiersprache. Kernmerkmale sind, dass sie sich sehr gut auf Daten in tabellarischem Format versteht und ein umfangreiches Spektrum an Funktionen zur Datentransformation, -aggregation und -visualisierung bietet. Also all das, was wir brauchen. RStudio ist eine IDE, eine graphische Oberfläche, die auf R, das standardmäßig auf der Kommandozeile ausgeführt wird, aufsattelt und somit die Handhabung deutlich vereinfacht und komfortabler macht. RMarkdown schließlich ist eine Library, die es ermöglicht, R-Skripte und Markdown in einer Datei zu verwenden, um daraus direkt Dokumente zu erzeugen.

Aber genug der theoretischen Hinführung. Die Vorteile werden am konkreten Beispiel am deutlichsten.

RStudio & RMarkdown: Eine schnelle Einführung


Zwei Hinweise noch vorweg: Ich kann an dieser Stelle natürlich keine Einführung in R bieten. Ich denke aber, dass die Syntax und die verwendeten Funktionen weitestgehend selbsterklärend sind. Ich beschreibe daher nur grob, was die einzelnen Code-Abschnitte tun. Solltet Ihr durch diesen Beitrag Lust bekommen haben, Euch mit R zu befassen, findet Ihr im Internet eine Vielzahl an Tutorials zur Installation und ersten Schritten in R und RStudio. Wenn Ihr Euch tiefergehend mit der Thematik beschäftigen wollt, kann ich Euch die Online-Lern-Plattform https://www.datacamp.com wärmstens ans Herz legen. Einige Kurse sind dort kostenlos, sodass Ihr euch einen ersten Eindruck verschaffen könnt. Ein Buch, das nicht nur R, sondern vor allem auch die zugrundeliegenden Konzepte der Daten Analyse sehr gut vorstellt, ist R for Data Science von Hadley Wickham. Dem Autor der Library tidyverse, die ich im Folgenden ausgiebig verwenden werde. Das Buch könnt Ihr auch online unter https://r4ds.had.co.nz/ kostenlos lesen.

🎁 Um Euch das Abtippen / Kopieren zu ersparen, findet Ihr den Code hier zum Downloaden:
https://github.com/netzstreuner/r4seo_reproduzierbare_analysen


Legen wir los!

Damit Ihr eine grobe Vorstellung davon bekommt, wovon ich überhaupt rede, hier ein Screenshot von RStudio. (1) ist der File Explorer. Hier seht Ihr Eure Skripte, Ordner, CSVs et cetera. (2) ist der Code Editor, in dem Ihr Skripte schreibt. (3) ist das Environment. Wenn Ihr Variablen oder Funktionen definiert, werden sie Euch hier angezeigt. (4) ist die Console, auf der Nachrichten vom Code ausgegeben werden. Oder Ihr nutzt sie, um ad hoc Code auszuführen, der nicht Bestandteil des Skripts sein soll.

Einführung in das RStudio Interface

Abbildung 4: Das RStudio-Interface

Im linken, unteren Panel (2) habe ich bereits ein sogenanntes R-Notebook erzeugt, das standardmäßig eine Beispiel-Befüllung enthält. Im Detail sieht es wie folgt aus:

R Notebook Beispiel

Abbildung 5: R Notebook mit Beispiel-Befüllung

Durch einen Mausklick kann das Notebook gerendert werden, sodass ein HTML-Dokument erzeugt wird.

Ausführung Code-Chunk

Im GIF seht Ihr, wie ich zuerst einen sogenannten Code-Chunk ausführe, der einen Plot generiert. Dazu gleich im Detail mehr. Anschließend rendere ich den Output. Da das Format ein HTML-Dokument ist, bietet es eine gewisse Interaktivität. Zu sehen ist, wie ich den Code, der den Plot generiert, ein- und ausklappe. Für eine Zeile Code ist das recht müßig, aber Ihr seht hier das Key-Feature, welches die Dokumentation der Analyse ermöglicht. Da jederzeit der zugrundeliegende Code des Notebooks angezeigt werden kann, dokumentiert sich die Analyse quasi selbst. In Kombination mit Kommentaren im Code ist dadurch jederzeit nachvollziehbar, wie Daten transformiert oder aggregiert wurden, um die Tabellen oder Plots im Output-Dokument zu erstellen.

Im folgenden Screenshot seht Ihr das Notebook und den Output noch einmal gegenübergestellt, damit Ihr im Detail nachvollziehen könnt, welche Elemente wie gerendert werden.

Vergleiche R Notebook-Skript und gerenderter Output

Abbildung 6: R Notebook-Skript und gerenderter Output im Vergleich

Am Anfang des Notebooks seht Ihr ein YAML, über das Meta-Angaben wie der Titel und das Output-Format definiert werden können. Anschließend folgt ganz normaler Text in Markdown-Syntax. Das Besondere an den Notebooks sind die in Backticks eingefassten Code-Chunks. In diesen kann R-Code geschrieben werden, der beim Rendering des Notebooks ausgeführt wird. Analyse-Code und Beschreibung der Insights stehen somit in einem Dokument und bilden eine Einheit, die jederzeit erneut ausgeführt werden kann.

Konfiguration des Notebooks

Nachdem Ihr gesehen habt, wie R-Notebooks grundsätzlich funktionieren, möchte ich Euch exemplarisch durch die einzelnen Analyse-Schritte führen. Dazu lösche ich den gesamten Beispielinhalt und beginne, meinen eigenen zu schreiben.

Zunächst gilt es, das Notebook resp. das daraus resultierende Analyse-Dokument zu konfigurieren. Wie bereits erwähnt, könnt ihr mittels YAML bestimmte Meta-Angaben und Einstellungen definieren. Meine sehen so aus:

Außerdem kann ohne Weiteres auch noch ein Logo eingehängt werden.


Hinweis: Immer, wenn ich wie gerade Code-Snippets angebe, müsst Ihr Euch die einfach als Code-Chunk denken. Der Übersichtlichkeit halber verzichte ich auf die Einfassung.


Das Resultat sieht dann wie folgt aus.

Beispiel-Output

Abbildung 7: Beispiel-Output mit benutzerdefinierter Formatierung, TOC und Überschriften

Wie Ihr im YAML seht, können über eine normale CSS-Datei Formatierungen vorgenommen werden. Hier ändere ich exemplarisch Font und unterstreiche Überschriften. Außerdem lasse ich automatisch ein Inhaltsverzeichnis basierend auf den nummerierten Überschriften generieren. Je nach Empfänger der Analyse macht es Sinn, den Code immer in eingeklappter Form einzubinden, um den Textfluss nicht unnötig zu stören.

Daten importieren und aufbereiten

Gut, beginnen wir mit der eigentlichen Arbeit. Als Erstes müsst Ihr natürlich die benötigten Daten importieren. Als Beispiel verwende ich hier zwei Screaming-Frog-Crawls – einen aktuellen und einen älteren. Letzteres dient später dazu, zu prüfen, welche Veränderungen es zwischen zwei Zeitpunkten auf der Website gab.

Ach ja, eins noch vorweg:  Für die nachfolgenden Arbeiten benötigen wir zwei Packages, die den Funktionsumfang von R erweitern. Das ist zum einen tidyverse, eine sehr mächtige Sammlung verschiedenen Sub-Packages zum Einlesen, Aufbereiten und Visualisieren von Daten, zum anderen janitor. Letzteres stellt einige komfortable Hilfsfunktionen bereit, um Daten ad hoc zu aggregieren. Eine sehr gute Einführung in die Syntax und die wichtigsten Funktionen von tidyverse findet Ihr in dieser Präsentation. Die beiden Packages ladet Ihr, indem Ihr den nachfolgenden Code direkt unterhalb des YAML einfügt.

Einige Libraries geben beim Laden eine Nachricht aus. Die wollt Ihr natürlich nicht im Analyse-Dokument haben. Auch der Code an sich macht im Output-Dokument keinen Sinn. Dem Empfänger dürfe egal sein, welche Packages Ihr verwendet. Daher kann auf Ebene der einzelnen Code-Chunks sehr genau definiert werden, wie diese sich beim Rendern verhalten sollen. Hier unterdrücke ich mit message=FALSE die Lade-Nachricht und mit include=FALSE die Darstellung des Codes.

So, jetzt aber wirklich an die Arbeit. Daten laden. Wie gesagt, wir brauchen zwei Crawls. Diese habe ich in einem Unterverzeichnis _data abgelegt. Dadurch schaffe ich Ordnung in meinem Workspace, indem ich Skript-Dateien, Daten und – später – Exporte voneinander trenne.

Das Laden geht denkbar einfach mit einer Zeile Code von der Hand.

Die Funktion read_csv liest die Datei des angegebenen Pfades ein. Der Screaming Frog schreibt immer einen Kommentar in die erste Zeile der CSV, die wir hier mit skip = 1 direkt überspringen. Die Daten werden eingelesen und in einen sogenannten DataFrame, sprich: eine Tabelle, in der Variable crawl gespeichert. So sieht sie aus.

Crawlimport Dataframe

Abbildung 8: DataFrame des importierten Crawls

Die Spaltennamen sind für ein programmatisches Umfeld recht unschön. Sie enthalten Groß- und Kleinschreibung sowie Leer- und Sonderzeichen. Wollt Ihr die Spalten in der jetzigen Form ansprechen, müsstet Ihr sie jedes Mal in Backticks einfassen, da andernfalls das Leerzeichen die Ausführung unterbricht. Also schnell eine kleine Hilfsfunktion hinzugenommen. clean_names() normalisiert die Benennung automatisch.

Normalisierte Spaltenüberschriften

Abbildung 9: Normalisierte Spaltenüberschriften

Genauso wie die Spaltenüberschriften liegen einige der Spaltenwerte in Groß- und Kleinschreibung vor. Das ist problematisch, wenn Ihr bspw. wissen wollt, wie häufig welcher Content Type vorkommt.


Hinweis: Wenn Ihr im Folgenden Code seht, der mit > eingeleitet wird, sind das Eingaben, die ich auf der Konsole durchgeführt habe. Sie sind also kein Bestandteil des Analyseskripts, sondern dienen nur dazu, schnell einen Blick auf die Daten zu werfen.


Hier dürfte Euch erst einmal egal sein, ob UTF nun groß- oder kleingeschrieben ist. Entsprechend definiert Ihr Euch eine eigene Funktion, die die Werte der angegebenen Spalten zu Kleinbuchstaben ändert.

Diese wendet Ihr dann ebenfalls auf den Crawl an.

Wie Ihr im obigen Screenshot gesehen habt, gibt es nach der Normalisierung immer noch zwei Ausprägungen für HTML-Seiten – mit und ohne Angabe des Character-Encodings. Euch interessiert aber nur, ob es eine HTML-Seite ist. Genauso ist die Angabe des Bildformats zu spezifisch – Image allein reicht vollkommen aus. Daher definiert Ihr eine weitere Funktion, die die Werte der Spalte content auf weniger Ausprägungen reduziert und in die neue Spalte content_type schreibt.

Bei Analyse ist es immer sinnvoll, einzelne Website-Bereiche getrennt voneinander zu betrachten. Klassisch kann hier nach Seiten-Templates (Startseite, Produktübersichtsseite, Produktdetailseite usw.) differenziert werden. Insbesondere bei Verlagswebsites bietet sich zusätzlich eine inhaltliche Segmentierung nach Ressorts (Politik, Wirtschaft, Feuilleton etc.) an. Auch hierfür definiert Ihr eine Funktion und wendet sie auf den Crawl an.

Schließlich gebt Ihr noch an, bei welchen Spalten es sich um kategoriale Daten handelt. Das heißt, die Werte in der jeweiligen Spalte können nur eine bestimmte Anzahl an vorgegebenen Ausprägungen annehmen. In der Spalte indexibility kann bspw. nur indexable oder non-indexable stehen. Wichtig ist dies insbesondere bei Spalten wie dem Status Code, deren Werte zunächst Zahlen sind (200, 301, 404 etc.). Auf den konkreten Grund gehe ich später im Detail ein.

In Summe sehen das Einlesen und Aufbereiten wie folgt aus. Da Ihr die Aufbereitung als Funktionen definiert habt, könnt ihr Sie natürlich ohne Weiteres sowohl auf den aktuellen als auch auf den alten Crawl anwenden.

Ad-hoc-Betrachtung der Daten

Oben habt Ihr das Package janitor geladen. Janitor macht das Betrachten von Daten on the fly wunderbar einfach.

Wollt Ihr wissen, wie häufig die einzelnen Content Types vorkommen, könnt Ihr den crawl an die Funktion tabyl() geben. Neben dem Aufkommen erhaltet Ihr damit auch direkt die Anteile.

adorn_totals() (adorn = schmücken) fügt eine Zeile mit der Summe hinzu.

Die Prozent-Formatierung ist recht unleserlich. adorn_pct_formatting() schafft Abhilfe.

In gleicher Weise könnt Ihr bspw. überprüfen, wie häufig jeder Status Code bei jedem Content Type vorkommt.

Visualisierung der Crawl-Daten mittels ggplot

Mit den oben gezeigten Funktionen könnt Ihr Euch einen schnellen Überblick verschaffen. Wesentlich intuitiver für das Verständnis von Mengengerüsten sind allerdings Diagramme – insbesondere bei der Kommunikation der Analyse.

Im Folgenden zeige ich Euch daher, wie Ihr ein Barchart der Status Codes plotten könnt. Hier zunächst einmal der Code, den wir gleich Schritt für Schritt durchgehen.

Ihr gebt den aktuellen Crawl an die count()-Funktion, die das Aufkommen der einzelnen status_codes zählt. Das kennt Ihr im Prinzip schon von den obigen Screenshots. Das Ergebnis ist eine Aggregationstabelle. Diese leitet Ihr wiederum an die Plotting-Funktion ggplot(). Innerhalb dieser definiert Ihr, dass der Status Code auf der x-Achse, die Anzahl (n) auf der y-Achse dargestellt werden soll. Außerdem gebt Ihr noch an, dass die Balken entsprechend der Status Codes eingefärbt werden sollen (fill). Dazu gleich mehr. Führt Ihr den Code bis hierhin – also bis zur und einschließlich der dritten Zeile – aus, erhaltet Ihr zunächst nur folgenden Plot.

Beispiel Plotleinwand

Abbildung 10: Leinwand des Plots mit Achsen-Beschriftung

ggplot() zieht zunächst einmal nur eine Leinwand und das Koordinatensystem auf, auf der die Daten dargestellt werden sollen. Ihr habt allerdings noch nicht angegeben, welche Art von Diagramm verwendet werden soll. Das macht Ihr mit geom_bar(). Der Code bis dort ausgeführt, plottet das nachfolgende Diagramm.

R Plot Statuscodes

Abbildung 11: Barchart der Status Codes

An dieser Stelle wird nun auch ersichtlich, warum wir bei der Aufbereitung der Crawl-Daten die Spalte status_code als kategorial definiert haben. Derartige Daten werden von ggplot() automatisch mit möglichst unterschiedlichen Farbwerten geplottet. Hättet Ihr dies nicht getan, würde ggplot() den Status Code, der ja aus Zahlenwerten besteht, als kontinuierlichen Datentyp auffassen und entsprechend ein kontinuierliches Farbspektrum verwenden. An der Legende könnt Ihr den Unterschied sehr gut erkennen.

R Plot Beispiel Füllfarbe

Abbildung 12: Darstellung der Füllfarbe bei Kontinuierlichen Werten

Mittels geom_text() gebt Ihr an, dass die Anzahl der Status Codes noch einmal als Label über die Balken geschrieben werden soll. Ich hoffe, langsam wird deutlich, wie Plotting mittels ggplot() funktioniert. Ihr tragt Schicht für Schicht auf die Leinwand auf, bis Ihr das gewünschte Aussehen konfiguriert habt. Eigentlich auch nicht wesentlich anders im Vergleich zu Excel, nur dass Ihr tippt statt in Dropdowns zu klicken.

R Plot Beispiel Balkenbeschriftung

Abbildung 13: Beschriftung der Balken

Die Legende ist redundant, denn die farblichen Balken dienen allein der schnellen visuellen Unterscheidbarkeit. Sie encodieren hier nicht unbedingt eine zusätzliche Information. Also unterdrückt Ihr die Generierung der Legende via guides(fill = FALSE).

R Plot Beispiel entfernte Legende

Abbildung 14: Entfernte Legende

Der graue Hintergrund ist meiner Meinung nach sehr aufdringlich. Also verwende ich hier ein helleres Theme (theme_light()).

R Plot Beispiel helles Theme

Abbildung 15: Anwendung eines hellen Themes auf den Plot

Bisher habt Ihr nur die Darstellung der Daten beeinflusst. Natürlich können auch die Textelemente des Plots verändert werden. Mittels labs() gebt Ihr die Beschriftung an. theme() dient dazu, ihre Darstellung genauer zu formatieren. Der Titel soll fett geplottet werden, Untertitel und Caption in Grau.

R Plot Beschriftung mit Untertitel

Abbildung 16: Beschriftung des Plot mit (Sub-)Titel, Caption und Achsen-Labels

Zu guter Letzt könnt Ihr natürlich noch die Farben der Balken bestimmen, um beispielsweise Eure Unternehmensfarben zu verwenden. Oder weil Ihr – wie ich – die Standardfarben einfach nicht so großartig findet. Ich gebe die Farbcodes hier als Variable COLOR_SCHEMA an, sodass ich sie nur einmal am Anfang des Skripts definieren und jederzeit schnell ändern kann.

Hier sind Input und Output im Detail gegenübergestellt. Wie Ihr sehen könnt, habe ich noch ein bisschen Text um den Plot gesetzt. Die Besonderheit ist, dass ihr in RMarkdown Code nicht nur innerhalb der Code-Chunks ausführen könnt, sondern kleine Code-Snippets auch innerhalb des Fließtextes. r nrow(crawl) zählt zum Beispiel die Zeilen des Crawls. Dadurch könnt ihr prinzipiell Text-Templates verwenden, innerhalb derer sich die Zahlen entsprechend der zugrundeliegenden Daten dynamisch ändern.

R plot notebook und output Gegenüberstellung

Abbildung 17: Gegenüberstellung des Plots im Notebook und im Output-Dokument

Interne Verlinkung in eine SQLite-Datenbank schreiben

Im obigen Plot sind nur acht URLs zu sehen, die mit 404 antworten. Trotzdem ist es natürlich immer von Interesse nachzusehen, woher diese URLs verlinkt werden – und vor allem mit welchem Ankertext. Denn ist dieser immer gleichlautend, kann man davon ausgehen, dass es sich um Template-Links handelt. Sie können also sehr schnell an einer Stelle behoben werden. Im Gegensatz zu Content-Links, die zumeist einzeln angepackt werden müssen. Ich möchte nun also die URLs des Crawls, die nicht erreichbar sind, mit den Link-gebenden Seiten aus dem all_inliks-Export des Screaming Frog zusammenführen.


Hinweis: Mir ist bewusst, dass Ihr auch einfach im all_inlinks-Export auf die 404er filtern könntet. Ich brauche hier aber ein Beispiel, um Euch einen Join aus einer Datenbank zu veranschaulichen. Bitte entschuldigt also den kleinen Umweg.


Als erstes müsst ihr natürlich die all_inlinks.csv importieren. Das Verfahren kennt Ihr bereits.

Der Report ist im vorliegenden Fall sehr klein.

Je nach Größe der Website kann der Report aber sehr schnell mehrere Millionen Zeilen und somit mehrere GigaByte groß sein. Da ich in meinen Analysen nur ad hoc auf ihn zurückgreife, möchte ich Ihn nicht die ganze Zeit im RAM vorhalten. Aus diesem Grund habe ich mir angewöhnt, ihn direkt in eine SQLite-Datenbank zu schreiben. Der große Komfortfaktor einer SQLite-Datenbank ist, dass Ihr – wie Ihr sofort sehen werdet – sie mit einer Zeile Code direkt auf Eurem Rechner initialisieren könnt. Ihr braucht also keinen Server, auf dem Ihr erst einmal eine Datenbank installieren müsst. Mit folgendem Code erstellt Ihr die Datenbank, wenn sie noch nicht vorhanden ist. Andernfalls verbindet Ihr Euch mit einer bestehenden.

Als nächstes schreibt Ihr den DataFrame all_inlinks in die Datenbank. Auch das ist erneut denkbar einfach. Gibt es die Tabelle inlinks noch nicht in der Datenbank, wird sie automatisch erzeugt. Außerdem definiert Ihr, auf welchen Spalten in der Datenbank ein Index gebildet werden soll. Mit rm() löscht Ihr den DataFrame wieder aus dem RAM.

Anschließend muss die gerade in der Datenbank erstellte Tabelle natürlich referenziert werden, um Anfragen gegen sie zu fahren. Auch das ist ganz einfach und erfolgt durch dir folgende Code-Zeile.

inlinks ist jetzt die Referenz. Referenz meint hier, dass hier wirklich nur eine Verbindung besteht. Es werden keine Daten nach R geladen. Das seht Ihr, wenn ihr die Referenz aufruft.

Source und Database zeigen an, dass es sich hier tatsächlich um eine reine Datenbank-Tabelle handelt. Dass keine Daten nach R geladen werden, seht Ihr auch am [?? x 9]. Die Datenbank teilt Euch zwar mit, dass die Tabelle 9 Spalten hat. Allerdings ist zum jetzigen Zeitpunkt – da keine explizite Anfrage gegen die Datenbank besteht – nicht ermittelbar, wie viele Zeilen (??) in der Tabelle vorliegen.

Dieses Verhalten geht sogar so weit, dass selbst die Formulierung einer Anfrage nicht ausgeführt wird, solange dies nicht explizit von Euch gewünscht ist.


Bitte entschuldigt, wenn das gerade etwas nerdig ist. Aber das ist wirklich ein wahnsinnig komfortables Verhalten, wenn Ihr mit sehr großen Datenmengen bei begrenzten RAM-Ressourcen arbeiten müsst.


Wie müsst Ihr euch dieses Verhalten konkret vorstellen? Im Folgenden definiere ich eine Abfrage gegen die Datenbank. Es soll durchgezählt werden, wie häufig eine Seite intern verlinkt wird. Anschließend wird die Tabelle absteigend nach der Link-Zahl sortiert und dann nur die URLs geladen, die mehr als 200 Inlinks haben. Die Abfrage an sich wird in die Variable top_linked_pages geschrieben. Ruft Ihr die Abfrage auf, seht Ihr im Kopf der Antwort, dass es sich um eine lazy query handelt. Die Abfrage ist also faul, sie gibt nur ein paar Beispiel-Zeilen zurück, kennt aber nicht die Gesamtmenge ([?? x 2]), solange Ihr nicht explizit angebt (collect()), dass die Abfrage ausgeführt werden soll.

Apropos Abfrage, Ihr seht kein SQL. Simple Abfragen können gänzlich mit R-Funktionen beschrieben werden, die dann automatisch in SQL übersetzt werden. Um Euch das SQL anzeigen zu lassen, könnt Ihr show_query() verwenden. Die SQL-Abfrage ist vielleicht nicht gerade elegant, erfüllt aber ihren Zweck.

Jetzt aber zurück zur Ermittlung der Verlinkung der 404er. Ihr habt jetzt alle internen Links in der Datenbank vorliegen und könnt Sie nun mit Eurem Crawl zusammenführen.

Die resultierende Tabelle könnt Ihr Euch direkt im Analyse-Dokument ausgeben lassen. Sie bietet einige interaktive Elemente, indem sie bspw. eine Pagination darstellt, die Ihr klicken könnt. Um hier eine Handlung für die IT zu generieren, könnt Ihr die Tabelle natürlich direkt als CSV exportieren. Es gibt auch Packages, um eine Excel zu erzeugen. Der Einfachheit halber belasse ich es an dieser Stelle aber bei einer CSV.

R Gegenüberstellung Notebook und Output

Abbildung 18: Gegenüberstellung der Tabelle im Notebook und im Output-Dokument

Delta-Betrachtung eines alten und des aktuellen Crawls

Aufschlussreich ist es auch immer, zu sehen, welche Änderungen sich im zeitlichen Verlauf an einer Website ergeben haben. Hier wollen wir exemplarisch betrachten, welche Ressourcen nicht mehr, weiterhin oder neu verlinkt werden. Weitere denkbare Betrachtungsobjekte sind Title- und Description-Änderungen sowie Status-Code-Wechsel. Der Einfachheit halber gehe ich an dieser Stelle aber nur auf die Ressourcen ein. Das zugrundeliegende Verfahren könnt Ihr aber adaptieren.

Zunächst brauchen wir eine Funktion, die uns einen Indikator bereitstellt, ob eine Ressource nur im alten, nur im aktuellen oder in beiden Crawls vorkommt. R bietet von Haus aus keine solche Funktion, daher müssen wir eine eigene schreiben. Sie ist nicht sonderlich komplex, aber lang. Daher erspare ich Euch die Definition.

Hinweis: Die Funktion habe ich übrigens nicht selbst geschrieben, sondern von Stack Overflow übernommen. Ein weiterer großer Vorteil von R resp. programmatischer Analyse im Allgemeinen. Man muss nicht ständig das Rad neu erfinden. Deutlich klügere / erfahrenere Menschen als wir es sind, standen mit Sicherheit schon einmal vor den gleichen Problemen und haben sich Rat im Internet gesucht. Stack Overflow ist damit die reinste Fundgrube, an der Ihr Euch scharmlos bedienen könnt und solltet.

Mit folgendem Code legt ihr die beiden Crawls übereinander und erhaltet als Resultat eine Tabelle mit Flag-Spalte.

R Delta Tabelle

Abbildung 19: Delta-Tabelle mit Flagspalten

Diese Tabelle gebt Ihr wiederum an eine Plotting-Funktion.

Anhand des resultierenden Plots können wir sehr leicht Veränderungen an den Mengengerüsten der Ressourcen erkennen. Hier sind offensichtlich verhältnismäßig viele HTML-, Bilder- und JS-Ressourcen entfallen. Ein genauer Blick in die Daten würde uns zeigen, dass die AMP-Variante der Website deaktiviert wurde.

R Beispiel Plot Crawlvergleich

Abbildung 20: Plot der Delta-Betrachtung zweier Crawls

Daten aus Google Analytics mittels API-Abfragen beschaffen

Fast geschafft! Zu guter Letzte möchte ich Euch noch zeigen, wie Ihr auch externe Datenquellen in Eure Analyse integrieren könnt. Exemplarisch möchte ich dies für Google-Analytics-Daten (GA) machen. Im Grunde kann aber jede Quelle, die eine API bereitstellt, hinzugezogen werden. Denkbar sind bspw. auch die Google Search Console oder Sistrix.


Hinweis: Und Ihr seid nicht einmal auf Datenquellen mit API beschränkt. Selbst Web Scraping könnt Ihr mit R verwirklichen. Allerdings muss ich zugeben, dass dazu Python deutlich komfortabler ist.


Für GA gibt es dankbarerweise ein Package – googleAnalyticsR. Vom gleichen Autor, Mark Edmondson, gibt es auch noch Packages für die Authentifizierung (googleAuthR), welches wir auch verwenden werden, und die Google Search Console (searchConsoleR).

Zunächst müsst Ihr natürlich die benötigten Packages laden.

Anschließend müsst Ihr über options() Eure API-Credentials angeben, die Ihr in der Google Cloud Platform generieren könnt, und dem Skript die Berechtigung für Euren Google-Account erteilen.

gar_auth() wird beim ersten Ausführen Euren Browser öffnen, in dem Ihr den Skript-Zugriff bestätigt. Dadurch wird eine Authentifizierungsdatei erzeugt. Fortan müsst Ihr diesen manuellen Schritt also nicht mehr durchführen.

Hinweis: Damit steht im Übrigen einer automatischen Report-Erstellung auch nichts mehr im Wege! Holt Euch wöchentlich die aktuellen Daten, schreibt sie in einer Datenbank und generiert einmal in der Woche mittels RMarkdown einen automatischen Report, den Ihr Euch per Mail zuschicken lasst.

Nachdem die Authentifizierung durchgeführt wurde, könnt Ihr Euch die GA-Properties anzeigen lassen, um die benötigte viewID der anzufragenden Datensicht zu ermitteln.

Die Abfrage gegen die API sieht dann wie folgt aus.

Ihr definiert den abzufragenden Berichtszeitraum sowie die Kombination aus Metriken und Dimensionen. Großer Vorteil des Packages ist, dass es, wenn Ihr anti_sample auf TRUE gesetzt habt, überprüft, ob in der API-Antwort ein Sampling vorhanden ist. Sollte dies der Fall sein, bricht das Package die Anfrage automatisch in möglichst granulare Anfragen herunter, um das Sampling zu umgehen.

Die GA-Daten liegen nun in R vor. Um sie mit den Crawl-Daten zusammenführen zu können, muss noch kurz die Domain an den pagePath geschrieben werden.

Wir wollen uns nun im Detail angucken, ob Seiten unserer Website, die viele Page Views erhalten – also aus Nutzersicht stark nachgefragt werden – intern auch stark verlinkt sind – wir sie somit ebenfalls als bedeutsam erachten. Das ist ein klassischer Abgleich der Eigen- und Außenwahrnehmung unserer Webpages. Dazu joint Ihr die beiden DataFrames crawl und ga_data.

Anschließend plotten wir wieder den DataFrame.

R Beispiel Plot interne Verlinkung

Abbildung 21: Eigen- vs. Fremdwahrnehmung

Fazit

Und damit sind wir wieder beim Plot, der diesen Beitrag eingeleitet hat. Ich hoffe, ich konnte Euch einen ersten „kleinen“ Einblick in die Potenziale der Daten-Analyse mittels R bieten. Wenn Ihr es bis hierin geschafft habt, habt Ihr bereits viel gesehen und gelernt. Ich habe Euch gezeigt, wie Ihr mittels RMarkdown reproduzierbare Analyse-Dokumente erstellen könnt, die jederzeit nachvollziehbar sind, da der Code erhalten bleibt und sich somit selbst dokumentiert. Wir sind die verschiedenen Phasen eines Analyse-Prozesses durchlaufen, vom Import der Daten, über die Aufbereitung und Anreicherung der Daten, hin zur Transformation und Visualisierung. Ihr habt mit janitor ein Package kennengelernt, mit dem Ihr Euch on-the-fly einen Einblick in die Datenbasis verschaffen könnt. Darüber hinaus habt Ihr das grundlegende Konzept der Datenvisualisierung in R mittels ggplot() gesehen. Ihr habt eine SQLite-Datenbank initialisiert, um darin die interne Verlinkung zu speichern, sodass Ihr sie nicht im RAM vorhalten müsst. Um der zeitlichen Dimension Rechnung zu tragen, haben wir zwei Crawls übereinandergelegt, um Unterschiede zu ermitteln. Zum Schluss habt Ihr erfahren, wie Ihr Externe Datenquellen wie die Google-Analytics-API anzapfen könnt, um Eure Crawl-Daten anzureichern.

Wenn Ihr Lust auf R bekommen habt, möchte ich Euch noch einmal das Buch R for Data Science von Hadley Wickham wärmstens ans Herz legen – und ja, ich habe schamlos, nein, in ehrfürchtiger Devoation den Titels seines Buches adaptiert. Mir ist bewusst, dass der Einstieg in R nicht gerade einfach ist. Insbesondere wenn man bisher keine Erfahrung mit Programmierung hat. Aber lasst Euch gesagt sein, die hatte ich am Anfang auch nicht. Und ich habe es nicht bereut, Zeit ins Erlernen zu investieren. Auf lange Sicht lohnt es sich wirklich. Das folgende Diagramm veranschaulicht das sehr schön. Am Anfang ist die Lernkurve für R sehr steil. Da seid Ihr mit Excel deutlich schneller. Je komplexer die Aufgaben jedoch werden, desto weniger schwierig wird ihre Lösung mit R, während bei Excel die Schwierigkeit signifikant zunimmt.

R4SEO Vergleich Excel und R

Abbildung 22: Schwierigkeit und Komplexität von Excel und R. https://blog.revolutionanalytics.com/2017/02/the-difference-between-r-and-excel.html

Um Euch bei Euren ersten Schritten nicht allein zu lassen, möchte ich Euch ermuntern, der Gruppe OmPyR auf Facebook beizutreten, die mein Kollege Johannes Kunze und ich gegründet haben. Wir möchten Daten-Analysen mittels R, Python, KNIME aber auch Excel stärker in der Online-Marketing-Community verankern. Dazu wollen wir eine Plattform für den Austausch etablieren – denn aller Anfang ist schwer! Wir hätten uns in unserer Anfangszeit eine solche Gruppe sehr gewünscht und möchten Euch jetzt die Möglichkeit bieten, von unseren – aber auch den Erfahrungen der Community – zu profitieren, um den Einstieg so einfach wie möglich zu gestalten.

Also, ich hoffe, man liest sich. Bis dahin, happy R! 👋

Patrick Lürwer: Javascript SEO: Pre- vs. Post-Rendering-Abgleich von Screaming-Frog-Crawls mit R

JavaScript SEO: Pre- vs. Post-Rendering-Abgleich von Screaming-Frog-Crawls mit R

tl;dr

  • Der Blogbeitrag beschreibt ein Framework in Form eines R-Skripts, das ich zum Analysieren von Screaming-Frog-Crawls verwende.
  • Dazu wird die entsprechende Website mit aktiviertem und deaktiviertem JavaScript-Rendering gecrawlt.
  • Die Crawls werden dann in R eingelesen und um einige Metriken angereichert:
      • Indexierbarkeit von Seiten
      • Segmentierung der URLs
    • Google-Analytics-Daten (hier: PageViews)
    • Google-Search-Appearance-Daten (hier: Impressions, Clicks)
    • Interner PageRank der URLs
  • Interne Links werden in eine SQLite-Datenbank geschrieben.
  • Der gerenderte und der nicht gerenderte Crawl werden verglichen:
    • Welche URLs kommen nur in einem der beiden Crawls vor?
    • Für URLs, die in beiden Crawls vorkommen, wird überprüft, ob sich bspw. die Titles & Descriptions, die Wortzahl und die Crawl-Tiefe ändern.
  • Im Rahmen der anschließenden Analyse werden Diagramme generiert, die einen ersten Überblick zur Beantwortung der folgenden Fragen geben:
    • Wie ist der Anteil der (nicht) indexierbaren Seiten?
    • Liegen meine wichtigen Seiten hinsichtlich der Klicktiefe auf einer der vorderen Ebenen?
    • Welche Unterschiede bestehen auf meiner Website, wenn JavaScript aktiviert resp. deaktiviert ist?
    • Welche Verzeichnisse weisen die meisten URLs auf?
    • Welche Segmente weisen die meisten URLs auf?
    • Sind meine wichtigsten Seiten auch aus Nutzersicht die wichtigsten?

Kontaktieren Sie uns & profitieren Sie von mehr Traktion durch SEO!

SEO Berlin – [sichtbar & erfolgreich]
Wielandstraße 9, 12159 Berlin
030 / 296 73 998
berlin@gettraction.de

SEO Darmstadt- [sichtbar & erfolgreich]
Heinrich-Hertz-Straße 6, 64295 Darmstadt
06151 / 860 69 85
darmstadt@gettraction.de

5 Gründe für get:traction:

  • individuelle SEO-Beratung & -Betreuung
  • keine Abnahmeverpflichtung
  • zertifizierte SEO-Experten
  • transparente & faire Arbeitsweise
  • nachhaltige SEO-Strategien