SEO-Monitoring mit Screaming Frog & R: Websiteveränderungen ermitteln

Der Kollege Stefan Keil ist in seinem Blogpost bereits auf SEO-Alerting mittels Testomato eingegangen. Während es sich beim Alerting um ein proaktives Warnsystem handelt, das sofort anschlägt, wenn ein Fehler an meiner Website auftritt, geht es beim SEO-Monitoring darum, wöchentlich über den Status des Systems informiert zu werden.

SEO-Reporting im dreistufigen System

Neben den wöchentlichen Reports aus der GSC, Sistrix und Google Analytics schauen wir uns bei [get:traction] auch die Veränderungen einer Website auf URL-Basis an. Dazu crawlen wir wöchentlich die Seiten unserer Kunden und vergleichen den aktuellen Crawl mit dem der Vorwoche.

Die wichtigsten Websiteänderungen auf einen Blick

Als Ergebnis erhält man einen Excel-Report, in dem folgende Veränderungen (wenn sie denn stattgefunden haben) aufgeführt werden:

  • Neue gefundene URLs
  • Nicht mehr verlinkte URLs
  • geänderte Status-Codes
  • geänderte Canonical-Anweisungen
  • geänderte Meta-Robots
  • geänderte H1
  • geänderte Title
  • geänderte Description
  • geänderte Content-Type
  • geänderte Klicktiefe
  • geänderte Dateigröße

Excel-Report mit den Websiteänderungen

Durch den Report besteht dann die Möglichkeit, bspw. die Umsetzungen von Maßnahmen (Optimierung der Titles & Descriptions, Index- / Weiterleitungsmanagement) zu kontrollieren oder auch einfach nur auf dem Laufenden zu bleiben, welche URLs neu hinzugekommen sind.

Das R-Script zur Emittlung der Websiteänderungen

Wie bereits bei meinem letzten Blogpost zur automatischen Behebung von GSC-Crawling Fehlern stellen wir Euch an dieser Stelle wieder das Script zur Verfügung. Das Script könnt Ihr hier von GitHub herunterladen. Für die Datenerhebung, sprich: das Crawling Eurer Website, braucht Ihr den Screaming Frog.

Ausführen des Scripts: Die tl;dr-Variante

  1. Ladet das Script herunter und speichert es in einem neuen R-Projekt.
  2. Crawlt mit dem Screaming Frog die gewünschte(n) Website(s).
  3. Exportiert die Crawls (internal_all.csv) aus dem Screaming Frog und speichert sie in einem beliebigen Verzeichnis. Wichtig ist, dass ihr die Exporte nach folgendem Schema benennt: {Kunde}_{YYYY-MM-DD}_internal_all.csv. Für unsere Website sieht die Benennung bspw. so aus: gt_2017-11-13_internal_all.csv.
  4. Ändert im Script die Variablen path_to_crawls und path_to_export, sodass erstere den Pfad zu den Crawls und letztere den Pfad zum Verzeichnis enthält, in das die Excel-Reports geschrieben werden sollen.
  5. Führt nun das gesamte Script aus.

Das Script in allen Einzelheiten

Crawling der Website

Beim Crawlen der Website müsst Ihr nicht viel beachten. Wichtig ist nur, dass Ihr die aktuellste Version des Screaming Frog verwendet, da bei älteren Versionen die Überschriften des Exports etwas anders heißen, wodurch das Script einige Spalten nicht finden kann.

Den Crawler könnt ihr beliebig einstellen (also bspw., dass er nofollow-Links nicht folgt). Da das Script nur die HTML-Seiten auswerten wird, könnt Ihr hier schon das Crawling von Bildern, CSS etc. ausschließen; müsst es aber nicht, da das Script automatisch auf HTML-Seiten filtert.

Wichtig ist, dass Ihr die internall_all.csv-Exporte nach dem bereits genannten Schema KUNDE_YYYY-MM-DD_internal_all.csv benennt, da anhand der Dateinamen die aktuellsten Crawls je Kunde ermittelt werden (dazu gleich mehr). Auch den Kommentar am Anfang der Exportdatei braucht Ihr nicht entfernen – macht alles das Script. Sprich: einfach auf Export drücken, Speicherort auswählen, Datei benennen, fertig.

Speichert die Crawls in einem Verzeichnis Eurer Wahl. Dabei müsst Ihr nicht darauf achten, dass Ihr ältere Crawls löscht oder die Crawls verschiedener Kunden in separaten Verzeichnisse ablegt. Wie bereits geschrieben, ermittelt das Script anhand aller, im angegebenen Verzeichnis gespeicherten Crawls die beiden aktuellsten je Kunde.

Eintragen der Pfad-Variablen im R-Script

Zum Ausführen des Scripts braucht Ihr natürlich R und idealerweise RStudio. Eine Anleitung zur Installation findet Ihr in meinem vorherigen Blogpost.

Habt Ihr das Script in ein neues Projekt importiert, müsst Ihr noch zwei kleine Anpassungen vornehmen. Relativ am Anfang findet Ihr die Variable path_to_crawls in die Ihr den Pfad zu den Crawl-Exporten angebt (bspw. C:/Users/Patrick/Documents/Websiteaenderungen/Crawls/) sowie die Variable path_to_export in die Ihr den Pfad für die zu generierenden Excel-Reporte eintragt (bspw. C:/Users/Patrick/Documents/Websiteaenderungen/Exports/).

Ermittlung der aktuellsten Screaming Frog Crawls je Kunde und Einlesen der Crawls

Ab hier müsst Ihr am Script nichts mehr ändern. Damit Ihr aber nachvollziehen könnt, wie das Script aufgebaut ist, führe ich Euch durch die einzelnen Bestandteile.

Direkt nach dem # Setup folgt die Definition einer eigenen Funktion. Auf die gehe ich aber später ein, wenn sie verwendet wird.

Der nächste Script-Abschnitt ermittelt nun erst einmal alle Crawl-Dateien (file_list), die im von Euch angegebenen Verzeichnis liegen.

Der for-loop splittet die Dateinamen nach Kunde, Datum, Typ und Pfad auf und schreibt sie in den Dataframe file_parts, der wie folgt aussieht:

customer date type path
Kunde 1 2017-10-24 internal_all kunde1_2017-10-24_internal_all.csv
Kunde 1 2017-11-01 internal_all kunde1_2017-11-01_internal_all.csv
Kunde 1 2017-11-07 internal_all kunde1_2017-11-07_internal_all.csv
Kunde 2 2017-11-01 internal_all kunde2_2017-11-01_internal_all.csv
Kunde 2 2017-11-07 internal_all kunde2_2017-11-07_internal_all.csv
Kunde 3 2017-09-17 internal_all kunde3_2017-09-17_internal_all.csv
Dass hier auch der Type des Crawls ermittelt wird, liegt daran, dass ich zukünftig auch den all_inlinks.csv-Export integrieren möchte, um bspw. bei neuen URLs die verlinkenden Seiten im Report angeben zu können. Aktuell hat diese Spalte also keine Funktion. Ignoriert sie einfach.

Wie Ihr sehen könnt, liegen für Kunde 1 drei, für den zweiten Kunden zwei und für den dritten Kunden ein Crawl im Verzeichnis. Für Kunde 3 kann also kein Ableich der Crawls erfolgen. Deshalb überprüft der folgende Abschnitt, ob für jeden Kunden mindestens zwei Crawls vorhanden sind.

Wie bereits erwähnt, braucht Ihr ältere Crawls nicht aus dem Verzeichnis löschen. Stattdessen ermittelt das Script die beiden aktuellsten Crawls je Kunde automatisch.

Dazu wird die obige Tabelle mit den Crawl-Data nach Kunden gruppiert, innerhalb der Gruppe die Data absteigend sortiert und gerankt, sodass sich folgende Tabelle ergibt, aus der für jede Gruppe die Zeilen mit dem Rank 1 oder 2, also den beiden aktuellsten Crawls je Kunde, in einen neuen Dataframe geschrieben werden.

customer date type path date_rank
Kunde 1 2017-11-07 internal_all kunde1_2017-11-07_internal_all.csv 1
Kunde 1 2017-11-01 internal_all kunde1_2017-11-01_internal_all.csv 2
Kunde 1 2017-10-24 internal_all kunde1_2017-10-24_internal_all.csv 3
Kunde 2 2017-11-07 internal_all kunde2_2017-11-07_internal_all.csv 1
Kunde 2 2017-11-01 internal_all kunde2_2017-11-01_internal_all.csv 2

Für jeden Kunden liegen nun die Dateipfade (path) der letzten beiden Crawls vor, die an den nachfolgenden for-loop gegeben werden, um die Crawls einzulesen und in einen Dataframe zu schreiben.

Zusätzlich zu den Spalten, die aus dem Screaming Frog kommen, werden beim Einlesen noch die Spalten customer und date hinzugefügt, anhand derer später der Dataframe gefiltert wird.

Dann wird der Dataframe noch ein bisschen aufgeräumt.

  • Die Spaltennamen werden normalisiert (Kleinschreibung und Leerzeichen durch Unterstriche ersetzen), damit ich beim Schreiben des Scripts die Spaltennamen nicht ständig in Backticks ` einfassen muss.
  • NAs werden durch leere Zellen ersetzt, um sie vergleichbar zu machen. Ansonsten würde bspw. eine Überprüfung der der address-URL mit dem canonical_link_element_1 (s. weiter unten) immer NA ergeben, wenn der Canonical-Link nicht vorhanden ist. ("url" == NA evaluiert korrekterweise zu NA statt zu FALSE)
  • Als letztes wird nur auf HTML-Seiten gefiltert.

Abgleich der Screaming Frog Crawls

Sooo, jetzt können wir endlich mit dem eigentlich Abgleich der Crawls beginnen. Bzw. fast, denn zunächst muss noch schnell eine Hilfstabelle erstellt werden, über die der nachfolgende for-loop interieren kann, um sich den jeweiligen Kunden sowie die Data des aktuellen und des vorherigen Crawls zu holen.

Der Dataframe sieht dann so aus:

customer crawl_new crawl_old
Kunde 1 2017-11-07 2017-11-01
Kunde 2 2017-11-07 2017-11-01

Ermittlung der neuen URLs

Für jede Zeile, sprich: Kunden, werden dann die folgenden Aktionen ausgeführt:

Aus dem Dataframe internal_all_html, der die Crawls aller Kunden enthält, werden für den ersten Kunden der alte und der neue Crawl in separate Dataframes geschrieben.

Mittels Anti-Join werden alle URLs ermittelt, die im neuen, aber nicht im alten Crawl vorhanden sind. Diese URLs werden in einen weiteren Dataframe new_urls geschrieben, welcher später dann als Tabellenblatt in den Excel-Report gespeichert wird. Für neue URLs wird überprüft, ob es sich bei diesen um kanonische URLs handelt (mutate(is_canonical = (address == canonical_link_element_1 | canonical_link_element_1 == ""))). Außerdem werden einige wichtige URL-Metriken ausgewählt und ebenfalls in den Dataframe geschrieben.

Das Datum wandle ich hier in einen String um (mutate(date = as.character(date))), damit es als Text in die Excel geschrieben wird. Ansonsten kann es vorkommen, dass Excel das Datum falsch formatiert. Außerdem wird der Dataframe von einem tibble in einen data.frame formatiert, da das Package xlsx::, das ich zum Erstellen der Excel verwende, nicht mit Tibbles umgehen kann.

Ermittlung der nicht mehr verlinkten URLs

Das Gleiche erfolgt nun für die nicht mehr verlinkten URLs, also jene URLs, die zwar im alten, aber nicht mehr im neuen Crawl vorhanden sind.

Der Unterschied ist hier, dass ich überprüfe, welchen Status Code die nicht mehr verlinkten URLs haben. Grundsätzlich muss es sich bei diesen nicht um gelöschte URLs handeln, sondern sie können bspw. fälschlicherweise einfach nicht mehr verlinkt sein. Wenn hier also URLs mit 200 OK antworten, sollte ich mir das genauer anschauen, warum sie nicht mehr verlinkt werden. Zur Ermittlung des Status Codes wird die anfangs übersprungene, eigene Funktion verwendet.

Aktuell werden die Status Codes nicht parallel abgefragt, sodass die Funktion die Ausführungszeit des Skripts deutlich verlängern kann. Sind also viele URLs zu prüfen und/oder antwortet die Website langsam, wundert euch nicht, dass das Skript einige Minuten benötigt. Bei mir dauert die Abfrage für ca. 200 URLs ungefähr 2 – 3 Minuten.

Erneut werden die ermittelten URLs in einen eigenen Dataframe geschrieben, der später ein Tabellenblatt in der Excel darstellt. Dasselbe gilt im Übrigen für alle weiteren Dataframes, die jetzt folgen.

Ermittlung der identischen URLs

Über einen Inner-Join werden nun alle URLs ermittelt, die in beiden Crawls vorhanden sind.

Dabei erfolgt auch der Abgleich der wichtigsten URL-Merkmale.

  • Da die Meta-Robots- / Content-Type-Angaben in verschiedenen Schreibweisen möglich sind (bspw. index, follow vs. INDEX,FOLLOW) werden sie in Kleinschreibung umgewandelt und Leerzeichen entfernt. Dadurch ist sichergestellt, dass die Anweisung an sich und nicht ihre Schreibweise geprüft wird.
  • Für den Abgleich der Dateigröße (size_change) und der Antwortzeit (response_time_change) definiere ich hier einen Schwellwert von 10%, sodass nicht jede kleine Abweichung direkt im Report erscheint.

Ich spare mir jetzt, die Generierung der Tabellenblätter für jedes URL-Merkmal zu beschreiben, da sie alle nach dem selben Prinzip funktionieren.

  1. Filtern des Dataframes mit den identischen URLs entsprechend des jeweiligen Merkmals (bspw.filter(status_code_change == TRUE)), für das in der Excel ein eigenes Tabellenblatt erstellt werden soll.
  2. Auswahl der URL-Merkmale, die im Tabellenblatt aufgeführt werden sollen. Bspw. für URLs, bei denen sich der Status Code geändert hat, werden die URL sowie der alte und der neue Statuscode ins Tabellenblatt übernommen (select(address, status_code_new, status_code_old)).
  3. Schreiben des gefilterten Dataframes in einen neuen Dataframe, der später das Tabellenblatt darstellt.
Bei der Generierung der Tabellenblätter für URLs bei denen sich der Canonical Link, die Meta Robots, der Title, die Description, der Content Type, die Klicktiefe, die H1, die Dateigröße oder die Antwortzeit geändert haben, werden URLs, bei denen sich der Status Code geändert hat, herausgefiltert, da letzteres häufig mit einer Änderung an den restlichen Merkmalen einhergeht. Wenn also eine URL jetzt mit 301 Redirect antwortet, weist sie natürlich keinen Canonical Link mehr auf. Um hier Doppelungen in den Reports zu vermeiden, werden sie entsprechend herausgefiltert (.[!.$address %in% status_code_change$address, ]).

Schreiben der Dataframes in eine Excel-Datei

Sind alle Schritte durchlaufen, haben wir eine Reihe von Dataframes (new_urls, deleted_urls, status_code_change usw.), die als Tabellenblätter in eine Excel geschrieben werden.

Dazu wird zunächst ein neues Workbook (createWorkbook()) erzeugt, die einzelnen Tabellenblätter angelegt (createSheet()) und in diese die jeweiligen Dataframes geschrieben (addDataFrame()). Schließlich wird das Workbook gespeichert (saveWorkbook) wobei die Benennung anhand des Kunden und der Crawl-Data erfolgt.

Das war’s!

 

Für Anregungen und Probleme, über die Ihr gestolpert seid, oder sogar Verbesserungsvorschläge bin ich immer offen. Entweder direkt hier in den Kommentaren, per Mail oder Twitter.

 

Bis dahin: Happy R! 👋

Hier noch einmal der Link auf’s GitHub-Repro.

Und hier auch noch einmal der Link auf meinen letzten Blogpost zur automatischen Behebung von GSC-Crawling-Fehlern.

Artikel teilen

SEO-Monitoring mit Screaming Frog & R: Websiteveränderungen ermitteln
4.9 (98.33%) 12 votes

The following two tabs change content below.

Patrick Lürwer

Senior Analyst & Partner
Schon in meinem Studium des Bibliotheksmanagements habe ich mich weniger für die Bücher als vielmehr für ihre Metadaten interessiert. Meine Leidenschaft für Daten — das Erfassen, Aufbereiten und Analysen — habe ich dann durch mein Master-Studium der Informationswissenschaft weiter ausleben und vertiefen können. Bei get:traction kombiniere ich meine Data-Hacking-Skills und meine Online-Marketing-Expertise, um datengestützte Empfehlungen für Kunden zu formulieren und umgesetzte Maßnahmen zu messen. Mein Hauptaufgabenbereich liegt dabei in der Analyse von Crawls, Logfiles und Tracking-Daten, der Konzeption von Informationsarchitekturen und der Anreicherung von Webinhalten mittels semantischer Auszeichnungen.

5 Comments on “SEO-Monitoring mit Screaming Frog & R: Websiteveränderungen ermitteln”

  1. Hi,

    I’m running in an error called:
    NA does not exist in the current working directory.

    I assume, that the path contains a mistake? Is that right?

    1. Hi Mike,

      that’s right. You have a backslash in your second path (C:\Users/). If you change it, it should work.

      Best regards,
      Patrick

  2. Thanks for your answer. Sorry that was a short mistake from my site. The error also exists with the right backslash.

    1. Hi Mike,

      that may be a stupid question, but are there two crawls in the folder? I.e., in your first comment you specified the path_to_crawls with "C:/Users/customerweb/Documents/Websiteaenderungen/Crawls/KUNDE_2017-12-01_internal_all". I did not notice the first time, but it seems to me that you are providing a file name instead of a folder.

      Suppose the two crawls KUNDE_2017-12-01_internal_all.csv and KUNDE_2017-12-08_internal_all.csv you would like to compare are located in your folder "C:/Users/customerweb/Documents/Websiteaenderungen/Crawls/ you have to assign the path_to_crawls-variable as follows: path_to_crawls < - "C:/Users/customerweb/Documents/Websiteaenderungen/Crawls/.

      If that is not the case let me know.

Schreibe einen Kommentar

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