C'est un tutoriel complet que je souhaitez vous partager ici, il n'est pas de moi, il est de David Meyer et vous pouvez le trouver en suivant l'URL https://www.gettraction.de/blog/screaming-frog-r-websiteaenderungen-ermitteln/. La raison pour laquelle je souhaitez le partager, c'est qu'il est en Allemand et je ne trouve pas d'équivalent en français ; je précise que mon Allemand est beaucoup trop rouillé, donc s'il y a des erreurs, je corrigerai. ... et puis l'article est top quand même, du R et du SEO, moi ça me botte grave !

L'article se fait de la manières suivante:

  1. La sortie - qu'est-ce qui en sort?
  2. Vue d'ensemble des étapes de travail
  3. Explorer le site Web
  4. Comparer des sites Web
  5. Le script en détail

Comme on le sait, il est judicieux de garder un œil attentif sur un site web lors de la mise en œuvre du concept SEO et dans le cadre du support. L'un des outils les plus puissants pour être toujours à jour est l'exploration et la mise en correspondance différées du site Web en fonction de l'URL. Afin de réduire au minimum le temps nécessaire pour cela, nous automatiserons tout, de l'exploration à la sortie d'Excel dans cet article ! En d'autres termes, la seule chose à faire en plus de la configuration initiale est de l'analyse des données de sortie Excel.

De mon côté je préfère largement Google Sheets à Excel, pour le Cloud, pour les formules et puis l'intégration du SQL est pratique

Les données de sorties

Afin de clarifier si la comparaison d'exploration est quelque chose pour vous, il est logique de jeter un coup d'œil à la sortie en premier:

Le résultat final est toujours un fichier Excel, qui enregistre les différences par rapport à l'analyse précédente pour chaque métrique dans un onglet. Les points suivants sont traités:

  • Nouvelles URL
  • Les URL ne sont plus liées
  • Modifications apportées aux URL

Pour la partie Modifications apportées aux URL, deécouvrons en détails les points ci-dessous:

  • Codes d'état
  • Instructions canoniques
  • Méta robots
  • H1
  • Titres
  • Descriptions
  • Types de contenu
  • Profondeur de clic
  • Taille du fichier

Sortie Excel pour des données

Vue d'ensemble des étapes de travail

Fondamentalement, nous avons 3 étapes pendant tout le processus:

  • Nous explorons le site Web à intervalles réguliers avec Screaming Frog
  • Nous comparons les crawls les uns avec les autres grâce à R (possible aussi en Python, mais c'est un autre tutoriel)
  • Nous analysons le résultat final via un tableur (Note: je préfère Google Sheets ici, mais lui utilise Excel qui fonctionne aussi bien)

Processus de travail avec Screaming Frog et R

Exploration du site

Pour cette étape, nous avons besoin du Screaming-Frog SEO Spider. Et c'est tout, bien pratique, vous pouvez utiliser un autre crawler, dans ce cas, il faudra adapter le script.

Création de la structure de dossiers et configuration des tâches d'analyse dans le planificateur de tâches

Afin d'automatiser notre exportation à tout intervalle de temps et ainsi gagner régulièrement beaucoup de temps, nous créons une structure de dossiers standardisée et créons des tâches à explorer dans le planificateur de tâches Windows .

Structure des dossiers

Au départ, nous avons besoin de 4 dossiers, qui doivent tous être stockés dans le même répertoire. La structure ressemble à ceci:

01_crawl_adjustments /[Client] C'est là qu'intervient le XLSX généré par le script R. 02_sf_exports /[Client] /[aaaa.mm.dd.hh.mm.ss] La grenouille hurlante stocke automatiquement ses exportations ici. D'une part, le "internal_all.csv". D'autre part - pour pouvoir regarder en détail par la suite - l'intégralité du crawl en tant que ".seospider". 03_sf_configs Les fichiers de configuration Screaming-Frog sont stockés ici (si disponibles). 04_R / [Projet R] Voici le projet ".R", qui construit la comparaison des deux dernières explorations d'un site Web et la stocke dans "01_crawlabgleiche / [client] /". Tous les dossiers en gras de l'illustration ci-dessus doivent être créés initialement. Le reste est généré automatiquement par notre script et le SF.

Tâche Windows pour les analyses

  1. Créez les 4 dossiers initiaux.
  2. Créez un dossier pour chaque client sous 02_sf_exports.
  3. S'il existe des fichiers de configuration Screaming-Frog pour les analyses prévues, stockez-les dans le dossier "03_sf_configs".
  4. Ouvrez le "Planificateur de tâches" via la recherche Windows.
  5. Il est recommandé de créer un nouveau dossier pour les analyses et les travaux R dans la planification des tâches
  6. Accédez au dossier nouvellement créé
  7. Clic droit -> "Créer une nouvelle tâche" pour créer une nouvelle tâche
  8. Dans la boîte de dialogue, vous devez donner un nom au travail (ici, il est conseillé de normaliser la dénomination et d'inclure l'intervalle, par exemple "1month_kunde". Sous l' onglet "Trigger", vous pouvez spécifier l'intervalle souhaité et les jours d'exécution. Nous rampons chaque semaine, par exemple Cela ressemblerait à ceci: Accédez au dossier nouvellement créé
  9. Clic droit -> "Créer une nouvelle tâche" pour créer une nouvelle tâche
  10. Dans la boîte de dialogue, vous devez donner un nom au travail (ici, il est recommandé de normaliser la dénomination et d'inclure l'intervalle, par exemple "1month_kunde". Sous l' onglet "Trigger", vous pouvez spécifier l'intervalle souhaité et les jours d'exécution. Nous explorons chaque semaine, par exemple

Faites correspondre les sites Web Nous avons besoin de R Studio pour cette étape. Voici un bref guide et une explication de l'installation .

Création du script R et création de jobs Windows

Note: cela peut être adapté pour Mac aussi ;-)

Création du script R

  1. Téléchargez le dossier ici depuis notre hub Git .
  2. Il y a 2 fichiers ("website_change_monitor.R" et "FUNS.R")
  3. Ouvre R Studio et crée un nouveau R-Project dans le dossier / 04_R /.
  4. Copiez maintenant les deux fichiers du téléchargement dans votre dossier de projet ("/ 04_R / [nom du projet] /")

Il ne nous reste plus qu'à adapter 2 chemins dans le script R et nous avons déjà tout préparé pour notre travail Windows!

Accédez au fichier "website_change_monitor.R" dans R Studio dans votre projet et ajustez les variables suivantes: Deux variables Excel

PATH_TO_XLSX_EXPORTS est le chemin dans votre dossier / 01_crawl_abgleiche

PATH_TO_SF_EXPORTS est le chemin dans votre dossier / 02_sf_exports

(Astuce: pour être sûr, vous pouvez entrer "C: /" puis naviguer vers le dossier respectif avec TAB et les touches fléchées)

Maintenant, enregistrez le script avec "CTRL & S" / "CMD + S".

Pour le script au travail, vous devez installer deux packages R . Vous pouvez le faire simplement en cliquant sur les conseils «installer» en haut de R Studio. Si les messages n'apparaissent pas, vous pouvez installer tous les packages comme suit:

```  install.packages ("[package]")


Par exemple:

install.packages("tidyverse")


Les noms de tous les packages requis peuvent être trouvés dans les  bibliothèques n ° 1  (toutes chargées avec `library ()`) dans le script. Les noms de tous les packages requis se trouvent dans les  bibliothèques n ° 1  (toutes chargées avec `library ()`) dans Scénario.

### Créer le travail Windows pour le script R

Créez à nouveau un nouveau dossier pour R dans le planificateur de tâches.
1. Ici crée une nouvelle tâche avec le nom et le déclencheur. Le déclencheur doit bien sûr être défini  après l'  exécution des travaux d'analyse.
2. Entrez le chemin de votre installation R dans le champ "Programme / Script", quelque chose comme ceci: "C: \ Program Files \ R \ R-3.6.1 \ bin \ Rscript.exe"
3. Dans le champ "Ajouter des arguments", nous entrons maintenant le nom de fichier du script R: "website_change_monitor.R"
4. Dans le champ "Démarrer dans", nous saisissons le chemin du dossier dans lequel se trouve le script: "/ 04_R / [nom du projet] /"
5. Maintenant, nous pouvons sauver le travail!

C'est tout! Nous avons maintenant une comparaison d'exploration entièrement automatisée. Pour configurer une autre comparaison, il vous suffit de créer un dossier pour le nouveau client dans `02_sf_exports` et de créer une tâche d'analyse dans le planificateur de tâches Windows. Le script enregistre automatiquement le nouveau client. Vous pouvez maintenant trouver vos excels de sortie dans le `dossier / 01_Crawl_Abgleiche /`.

## Le script dans chaque détail
### Bibliothèques
Les packages R requis pour exécuter le script sont chargés ici. Afin de pouvoir l'utiliser lors de l'exécution du script, vous devez l'installer au préalable (décrit dans la section  Créer le script R ).

Libraries -------------------------------------------

options(java.parameters = "-Xmx8g") library(tidyverse) library(xlsx) library(slackr) library(lubridate) source("FUNS.R") Vars


### Obtenir des fichiers et trouver tous les CSV
Ici, tous les fichiers avec une extension .csv sont listés récursivement à partir du chemin contenu dans la variable PATH_TO_SF_EXPORTS.

Get-files -------------------------------------------

Find all CSVs

files <- list.files(PATH_TO_SF_EXPORTS, full.names = TRUE, recursive = TRUE, pattern = "\.csv")


### Diviser les chemins
Maintenant, nous divisons les chemins des fichiers répertoriés dans le bloc de données "df_file_paths" en colonnes individuelles.

Split paths

df_file_paths <- tibble(path = files) %>% splitstackshape::cSplit(splitCols = "path", drop = FALSE, sep = "/", direction = "wide", type.convert = FALSE) %>% as_tibble()


### Extraire le site Web, datetime
Ici, nous déterminons quelles parties des chemins contenus dans "df_file_paths" sont quels éléments et donnons les noms aux colonnes correspondantes.

Extract website, datetime

select_cols <- c(1, ncol(df_file_paths) - 2, ncol(df_file_paths) - 1)

df_file_paths <- df_file_paths[ , select_cols]

names(df_file_paths) <- c("path", "website", "datetime")


### Convertir en date
Ici, nous convertissons la date à comprendre comme un caractère dans la colonne "datetime" en un format de données de date correct. Pour cela, j'utilise la très utile Library Lubridate.

Convert to date

df_file_paths <- df_file_paths %>% mutate(datetime = ymd_hms(datetime), date = date(datetime))


### Vérifiez s'il existe deux explorations
Nous regroupons par la colonne «site Web» et comptons si le nombre d'éléments par groupe est supérieur à 1. Ensuite, nous divisons à nouveau le groupe.

Check if two crawls exist

df_file_paths <- df_file_paths %>% group_by(website) %>% filter(n() > 1) %>% ungroup()


### Obtenez les deux dernières analyses

Nous regroupons à nouveau par "site Web" et ajoutons la colonne "date_rank" au bloc de données. Ceci est calculé en utilisant la fonction rank () dans l'ordre décroissant à travers la colonne "datetime". Enfin, nous filtrons les entrées avec "date_rank" 1 & 2 et interrompons à nouveau le regroupement.

Get last two crawls

df_file_paths <- df_file_paths %>% group_by(website) %>% mutate(date_rank = rank(desc(date))) %>% filter(date_rank %in% c(1, 2)) %>% ungroup()


### Obtenir le site Web pour l'itération

Afin de pouvoir créer une seule comparaison d'exploration pour chaque site Web, nous devons considérer chaque site Web comme un objet individuel dans une liste et effectuer de manière itérative les mêmes actions pour chaque objet de cette liste. Pour cela, nous utilisons une simple boucle for (). Nous préparons maintenant cette liste en utilisant la fonction unique. Après avoir alimenté la colonne "sites Web" à partir de "df_file_paths", cela renvoie un vecteur sans valeurs doubles. Dites - nous avons une liste de tous nos sites Web qui peuvent être utilisés comme objet d'itération.

Get websites for iteration

websites <- unique(df_file_paths$website)


### Filtre pour les tests
Avant de commencer la comparaison proprement dite, nous vérifions ici si la variable "TESTING_WEBSITE" mentionnée précédemment existe et, si c'est le cas, filtrons uniquement sur le site Web qui y est contenu.

Filter for testing

if (exists("TESTING_WEBSITE")) websites <- TESTING_WEBSITE


### Comparer les analyses

Nous parcourons notre vecteur "sites Web" et effectuons les actions suivantes pour chaque site Web:

Au début de la boucle, nous réduisons l'ensemble de données couvert dans cette itération aux données d'un seul site Web et définissons des variables temporaires pour la nouvelle et l'ancienne date d'exploration. Nous sortons un message dans la console et lisons dans les deux crawls en utilisant la fonction "read_crawl" définie dans "FUNS.R". Pour cela, nous ajoutons une colonne avec la nouvelle / ancienne date.

for (WEBSITE in websites) {

try_res <- tryCatch({

df_website_file_paths <- df_file_paths %>% 
  filter(website == WEBSITE)

CRAWL_NEW_DATE <- max(df_website_file_paths$date)
CRAWL_OLD_DATE <- min(df_website_file_paths$date)

message("\n\n[", WEBSITE, "] ", strrep("*", 40), "\n\n~ Read crawls\n")

crawl_new <- read_crawl(df_website_file_paths[df_website_file_paths$date == CRAWL_NEW_DATE, "path"][[1,1]]) %>% 
  mutate(date = CRAWL_NEW_DATE)
crawl_old <-read_crawl(df_website_file_paths[df_website_file_paths$date == CRAWL_OLD_DATE, "path"][[1,1]]) %>% 
  mutate(date = CRAWL_OLD_DATE)

### Créer un répertoire-site Web s'il n'existe pas
Le commentaire est tout à fait approprié - nous créons (s'il n'est pas disponible) un répertoire en utilisant l' objet d' itération et le chemin de  PATH_TO_XLSX_EXPORTS .

Create website-dir if not exists

dir.create(file.path(PATH_TO_XLSX_EXPORTS, WEBSITE),
           showWarnings = FALSE)

### Obtenir de nouvelles URL (liées)
Un autre message dans la console. Ici, nous filtrons dans une anti-jointure du nouveau à l'ancien crawl, vers les URL dans la colonne «contenu» «html» ou la colonne «status» correspond à la chaîne «Connection Timeout».

Cela ne laisse que les URL contenues dans la nouvelle analyse qui n'existent plus dans l'ancienne. Nous utilisons "select" pour sélectionner les colonnes que nous voulons et convertir le tout en un bloc de données, car la bibliothèque XLSX ne comprend pas un tibble.
## Get new (linked) URLs ---------------------------
message("~ Get new (linked) URLs\n")

new_urls <- crawl_new %>%
  filter(str_detect(content, "html") | status == "Connection Timeout") %>%
  anti_join(crawl_old %>%
              filter(str_detect(content, "html") | status == "Connection Timeout"), 
            by = "address") %>%
  mutate(is_canonical = (address == canonical_link_element_1 | canonical_link_element_1 == "")) %>%
  select(date,
         address,
         status_code,
         status,
         indexability_status,
         meta_robots_1,
         canonical_link_element_1,
         title_1,
         meta_description_1,
         is_canonical) %>%
  mutate(date = as.character(date)) %>%
  as.data.frame() 

convert to DataFrame as xlsx:: cannot handle tibble()


### Ne plus obtenir d'URL liées / supprimées

Message dans la console. La même procédure qu'au point 4.5.2, seulement ici nous anti-jointure de l'ancien vers le nouveau crawl.

Get not longer / deleted URLs -------------------

message("~ Get not longer / deleted URLs\n")

no_longer_linked_urls <- crawl_old %>%
  filter(str_detect(content, "html") | status == "Connection Timeout") %>%
  anti_join(crawl_new %>%
              filter(str_detect(content, "html") | status == "Connection Timeout"),
            by = "address")

### Obtenir le code d'état des URL non liées / supprimées

Ici, nous vérifions le code de statut des pages qui ne sont plus liées, car nous ne le connaissons pas via le crawl. La raison en est que nous voulons vérifier si une page n'est plus correctement liée. Si l'URL répond par "404 Not Found", il est parfaitement logique de ne plus la lier. Cependant, si la page répond par "200 OK", la question se pose de savoir pourquoi elle n'est plus liée si elle peut encore être atteinte. Un récupérateur de code d'état parallélisé s'exécute en arrière-plan. Selon le nombre d'URL qui ne sont plus liées, la requête peut prendre plus de temps. Sur la console, cependant, vous pouvez voir les URL qui viennent d'être interrogées, de sorte que vous ayez au moins une vue d'ensemble approximative du fait que quelque chose se passe toujours et que le script n'est pas bloqué. (Ce point montre, entre autres, qu'il est logiqueeffectuer les analyses avec la même configuration).
## get Status Code of not linked / deleted URLs
message("~ Get Status Code of not linked / deleted URLs\n")

urls <- no_longer_linked_urls$address

if (length(urls) > 0) {

  r <- fetch_multi_urls(urls)

  r_df <- tibble(
    address = unlist(lapply(r, `[[`, "url")),
    status_code_current = unlist(lapply(r, `[[`, "status_code"))
  )

  no_longer_linked_urls <- no_longer_linked_urls %>%
    left_join(r_df, by = "address") %>%
    select(date,
           address,
           status_code,
           status,
           indexability_status,
           status_code_current,
           meta_robots_1,
           canonical_link_element_1,
           title_1,
           meta_description_1) %>%
    rename(status_code_old = status_code) %>%
    mutate(date = as.character(date)) %>%
    as.data.frame()

}

### Obtenez des URL identiques

Ce qui est probablement 😉. Nous filtrons sur les URL HTML des deux explorations et mettons la main sur une jointure interne pour obtenir les URL identiques de la comparaison. Pour ce faire, nous ajoutons des colonnes pour chaque détail d'une URL dans l'ensemble de données, qui indiquent si la valeur correspondante a changé.
message("~ Get identical URLs\n")

identical_urls <- crawl_new %>%
  filter(str_detect(content, "html")) %>%
  inner_join(crawl_old %>%
               filter(str_detect(content, "html")),
             by = "address",
             suffix = c("_new", "_old")) %>%
  mutate(change_status_code = status_code_new != status_code_old,
         change_canonical = canonical_link_element_1_new != canonical_link_element_1_old,
         change_index = meta_robots_1_new != meta_robots_1_old,
         change_title = title_1_new != title_1_old,
         change_description = meta_description_1_new != meta_description_1_old,
         change_content_type = content_new != content_old,
         change_crawl_depth = crawl_depth_new != crawl_depth_old,
         change_h1 = h1_1_new != h1_1_old,
         change_word_count = word_count_new != word_count_old,
         change_indexability = indexability_new != indexability_old,
         change_indexability_status = indexability_status_old != indexability_status_new,
         change_orphan_pages = (is.na(crawl_depth_old) & !is.na(crawl_depth_new)) | (!is.na(crawl_depth_old) & is.na(crawl_depth_new)))
### Obtenir une URL identique avec les modifications

Maintenant que nous avons défini l'ensemble de données au niveau des URL, qui est inclus dans les deux analyses, nous pouvons maintenant examiner et comparer les composants individuels de cet ensemble de données.

### Pages orphelines:

Ici, nous définissons, en fonction de ce qui est dans notre colonne change_orphan_pages, que nous avons créée au point 4.5.5, s'il s'agit d'une page qui n'est plus ou nouvellement orpheline. Nous enregistrons cela en tant que bloc de données afin de pouvoir l'afficher plus tard dans Excel.

Cette procédure reste la même pour chaque métrique. Par conséquent, je n'entrerai pas dans tous les sous-éléments ici.

Get identical URLs with changes -----------------

message("~ Get identical URLs with changes\n")

## orphane pages
message("\tOrphan pages")

change_orphan_pages <- identical_urls %>%
  filter(change_orphan_pages == TRUE) %>% 
  mutate(change = case_when(!is.na(crawl_depth_old) & is.na(crawl_depth_new) ~ "neu verwaist",
                            is.na(crawl_depth_old) & !is.na(crawl_depth_new) ~ "nicht mehr verwaist")) %>% 
  select(change,
         address,
         status_code_old,
         status_code_new,
         status_old,
         status_new,
         title_1_old,
         title_1_new) %>% 
  as.data.frame()

### Obtenez les plus grandes ressources

Ici, nous trions les images, JavaScript et CSS, par taille décroissante (size_bytes) et les enregistrons sous DataFrame.
## Get biggest ressources --------------------------
message("~ Get biggest ressources\n")

## images
message("\tImages")

top_image <- crawl_new  %>%
  filter(str_detect(content, "image")) %>%
  select(address, size_bytes) %>%
  arrange(desc(size_bytes)) %>%
  as.data.frame()

## JavaScript
message("\tJavaScript")

top_js <- crawl_new  %>%
  filter(str_detect(content, "javascript")) %>%
  select(address, size_bytes) %>%
  arrange(desc(size_bytes)) %>% 
  as.data.frame()

## CSS
message("\tCSS\n")

top_css <- crawl_new  %>%
  filter(str_detect(content, "css")) %>%
  select(address, size_bytes) %>%
  arrange(desc(size_bytes)) %>%
  as.data.frame()

### Créer Excel

Ici, nous utilisons la bibliothèque XLSX pour créer un classeur et le remplir avec nos feuilles dans la variable "sheet_order" et les blocs de données créés dans la boucle. Avec saveWorkbook (), le chemin d'accès est donné à l'exportation et la comparaison d'exploration, avec la nouvelle et l'ancienne date dans le nom, est enregistrée dans le dossier correspondant du site Web.
## Create Excel ------------------------------------
message("~ Write Excel for: [ ", WEBSITE, " ] ", strrep("*", 40), "\n")

## set order of sheets here
sheet_order <- c("new_urls",
                 "no_longer_linked_urls",
                 "change_orphan_pages",
                 "change_status_code",
                 "change_index",
                 "change_canonical",
                 # "change_indexability",
                 # "change_indexability_status",
                 "change_title",
                 "change_description",
                 "change_h1",
                 "change_word_count",
                 "change_content_type",
                 "change_crawl_depth",
                 "top_image",
                 "top_js",
                 "top_css")

wb <- createWorkbook()

for (sheet in sheet_order) {

  if (nrow(eval(parse(text = sheet))) > 0)

    add_sheets(wb, sheet)

}

saveWorkbook(wb, file.path(PATH_TO_XLSX_EXPORTS,
                           WEBSITE,
                           paste0(CRAWL_NEW_DATE,
                                  "__",
                                  CRAWL_OLD_DATE,
                                  "__",
                                  WEBSITE,
                                  ".xlsx")))


Cela termine la boucle for et le script crée les comparaisons d'exploration de tous les sites Web existants.

Article précédent