Protéger son site réalisé avec un CMS

Protéger son site réalisé avec un CMS

Les CMS sont venus révolutionner le monde de l’informatique et du web. Ces systèmes de gestion de contenu sont devenus incontournables dans la création de sites web, mais sont malheureusement de plus en plus sujets aux cyber attaques. WordPress, Joomla, Magento, Drupal…il est nécessaire de mettre en place des systèmes pour leur sécurité. Que doit-on réellement savoir sur la sécurité des CMS ?

  1. Qu’est-ce qu’un CMS ?
  2. Pourquoi la sécurité d’un CMS est-elle importante ?
  3. Comparatif de la sécurité des principaux CMS 
  4. Quelles sont les menaces autour d’un CMS ?
  5. Une sécurité adaptée à votre CMS

→ WordPress
→ Joomla
Prestashop
Drupal

→ Magento

 

Qu’est ce qu’un CMS ?

Le Content Management System est un terme anglais utilisé sous l’abréviation “CMS”. En français, cet énoncé désigne un Système de Gestion de Contenu ou SGC. Le CMS regroupe des logiciels mis en place pour concevoir et mettre à jour de façon dynamique des applications multimédias et des sites Web. Dans le cas d’un CMS qui gère un contenu dynamique, on parle de DCMS ou Dynamic Content Management System. Aussi, le CMS ne doit pas être confondu avec un système de gestion électronique des documents ou GED.

securite wordpress cms 

 

→  Le principe du Content Management System

 Le principe du CMS est simple : vous visualisez instantanément ce que vous obtiendrez une fois la publication effectuée. En anglais, ce principe tient aussi en un acronyme : What You See Is What You Get. En effet, jusqu’à ce que ce principe ne voit le jour, les textes et les images d’un contenu à publier étaient non mis en forme. Séparés de leurs aspects extérieurs, autrement dit, de leurs formes. De plus, les changements opérés dans un contenu étaient lents : ils pouvaient prendre plusieurs secondes avant d’être appliqués. Ce qui n’est désormais plus le cas avec le CMS, qui opère des modifications instantanées.

 

→ Les fonctionnalités du CMS

Avec un Content Management System, il est envisageable de travailler en équipe sur un même document. Le CMS fournit également des workflows ou chaînes de publication. Ces derniers permettent la mise en ligne du contenu des documents.

Avec un CMS, il est aussi possible d’aboutir à des séparations entre la forme et le contenu. Celui-ci peut maintenant être mieux structuré avec l’utilisation des forums de discussion, des blogs, des Foires Aux Questions (ou FAQ), ou encore la mise en ligne de documents.

Le CMS permet également la hiérarchisation des utilisateurs et l’attribution de rôles et de permissions. C’est ainsi que l’on peut retrouver des contributeurs, des administrateurs ou des utilisateurs pour l’administration d’un même site.

 

Pourquoi la sécurité d’un CMS est-elle importante ?

 

La sécurité d’un CMS fait partie intégrante de la cybersécurité. En effet, les CMS sont devenus de plus en plus vulnérables au fil des années. Vu qu’ils sont à présent très populaires, de nombreuses structures n’hésitent pas à en faire usage comme des logiciels tiers entre leur site web et leur contenu. Cependant, des études menées sur le sujet ont démontré que ces entreprises, une fois qu’elles décident d’adopter un CMS, ne pensent pas souvent à la possibilité que ce dernier soit piraté. Pourtant, la menace est bel et bien réelle.

Rendu public par Checkmarx, un article de recherche révèle que sur WordPress, 20 % des modules installés ne sont pas protégés contre les attaques. Aussi, grâce à la British Standards Institution, on apprend qu’en Allemagne, 20 % des failles de sécurité découvertes au sein des codes tiers provenaient du cœur même du CMS. Quant aux 80 % restants, elles trouvent leur source dans les plug-ins et les extensions.

Il est urgent de penser à la sécurité de ces CMS, puisque ces derniers et leurs compléments connaissent une évolution régulière. Les protéger reviendra alors à les stabiliser et améliorer leurs fonctionnalités. Il faut donc penser à éviter l’obsolescence technique et réduire le temps de réponse. La sécurité site web est ainsi optimale, la compatibilité des différents modules du CMS est assurée, et il est possible d’accéder à de nouveaux modules. Par ailleurs, l’importance de la sécurité d’un CMS est également importante pour le bon référencement d’un site dans les moteurs de recherche : Google prend aujourd’hui en considération ce paramètre.

 securite cms

Comparatif des CMS 2020 d’un point de vue sécurité

En se basant sur le nombre de cyberattaques envers les CMS, certains d’entre eux se révèlent être mieux protégés que d’autres.

Ci-dessous, un tableau comparatif des CMS en 2020 d’un point de vue sécurité :

Nom du CMSPart du marchéServeur WebDisponibilité du HTTPS et du Certificat SSL
WordPress62,6 %Supports MySQL / MariaDB et PHPOui
Joomla4,4 %Apache 2.0, MS IIS 7 et NGINXOui
TYPO30,7 %MS IIS, Apache et NGINXOui

 

Malgré des attaques régulières, WordPress demeure le plus sécurisé des CMS.
Il est suivi de TYPO3, très utilisé en Allemagne et de Joomla.

 

Quelles sont les menaces autour des CMS ?

Comme susmentionné, les CMS non protégés sont sujets aux attaques des hackers. 

 

✖ Le vol de données

Il s’agit là de la menace la plus fréquente qui pèse sur la sécurité des sites Internet qui ne sécurisent pas leurs CMS. C’est surtout le cas pour les entreprises qui créent des comptes clients. Les hackers peuvent à tout moment pénétrer dans le système et se servir des coordonnées bancaires de ces derniers. S’en suivent des alors des fraudes et des détournements de fonds.

 

✖ L’injection de malwares

Le malware n’est rien d’autre qu’un logiciel malveillant et nuisible. Il est inséré dans un système informatique dans l’unique but de le détruire, de lui nuire. Bien évidemment, cette action de destruction est faite sans le consentement du propriétaire et dans un cadre plus restreint, sans celui de l’utilisateur dont le PC est infecté. Les malwares,ou virus, permettent aux hackers de procéder à une modification des sites. Ils sont même capables d’en faire usage comme point de départ, afin de développer ces malwares sur Internet.

 

✖ L’hébergement de contenus illicites et les interruptions de service

En pénétrant dans les CMS via les systèmes informatiques, les hackers détiennent tous les secrets des sites infectés et sont alors capables d’y héberger d’autres types de contenus. Il pourrait ainsi s’agir de contenus complètement à l’opposé ou allant même à l’encontre des valeurs des structures concernées. Il pourrait également s’agir de contenus à caractère pornographique ou pédopornographique. Par la même occasion, ils pourraient mettre hors-service le site et par conséquent, faire perdre des clients ou même de l’argent aux entreprises.

 

 ✖ Le blacklistage par Google

Lorsque la sécurité site internet est totalement menacée ou que ce dernier est complètement contaminé par des virus, le site est désindexé par le moteur de recherche Google. Autrement dit, il ne figurera plus dans les pages de résultats. On parle également de sites bannis. Cette sorte de pénalité est aussi obtenue lorsque le site a eu à réaliser de trop nombreuses pratiques malsaines de référencement naturel.

 

Une sécurité adaptée à votre CMS

Les systèmes de gestion de contenu les plus en vue sont WordPress, Joomla, Prestashop, Drupal et Magento. 

 ✓ Sécurité WordPress

securite wordpress

WordPress a vu le jour en 2003. Depuis, ce système de gestion de contenu est devenu le plus utilisé : 34,7 % de sites web sont des sites WordPress. Son système d’exploitation est multi-plateforme et il est disponible en des centaines de langues. Même si chaque année des milliers de sites hébergés chez WordPress sont piratés, il est possible de ne pas en faire partie en prenant quelques précautions. Avant tout, il faut bloquer les backdoors en scannant son site WordPress et en bloquant les adresses IP malveillantes.

Il faut aussi prévenir le Pharma Hack en faisant des mises à jour régulières des extensions, des thèmes et des installations WordPress. Enfin, éviter à tout prix les attaques par brute-force. Pour ce faire, il faut limiter les tentatives de connexion et surveiller les connexions non autorisées.

V6Protect vous permet de piloter la sécurité de votre WordPress pour le scanner régulièrement et de profiter d’une vision synthétique de l’état de sa sécurité. Pour en lire plus, nous vous proposon un guide dédié à la sécurité sur WordPress.

 ✓ Sécurité Joomla

securite joomla

Joomla a vu le jour en 2005. Sous forme d’intégration continue, Joomla est écrit en PHP. Avec un environnement multi-plateforme, il est gratuit et libre.

Chez Joomla, les failles de sécurité se retrouvent au niveau de 4 zones :

  • les zones internes ;
  • les zones réseaux ;
  • les zones serveurs ;
  • les zones Joomla.

Pour se prémunir contre les risques internes, il faut crypter ses données et choisir des mots de passe forts. Dans le cas des risques réseaux, il est essentiel d’héberger son site via HTTPS ou SFTP. De plus, ces espaces doivent être validés par plusieurs certificats SSL. Quant aux zones serveurs, il faut avoir un serveur VPS ou dédié. Enfin, les risques Joomla peuvent être maîtrisés en mettant régulièrement à jour les extensions.

V6Protect vous permet de détecter et de réparer tous les risques liés à une mauvaise sécurité de votre site Joomla. Pour en savoir plus, nous vous invitons à lire notre guide de la sécurité Joomla.

✓ Sécurité Prestashop

securite prestashop

Prestashop est utilisé pour faire du commerce en ligne ou pour créer sa boutique sur Internet. Tout comme les autres applications CMS, Prestashop est régulièrement sujet à des attaques.

Le prisme de sécurité chez Prestashop passe principalement par l’installation d’un certificat SSL. Ensuite, il faut revoir les paramétrages de sa boutique en améliorant le front office, en autorisant les iframes et en se servant de la bibliothèque HTMLPurifier. Il faut également penser à quitter le mode “développement”, à ajouter plusieurs autres niveaux de sécurité et à mettre à jour les modules et logiciels.

✓ Sécurité Drupal

securite drupal

Également écrit en PHP, Drupal naît en janvier 2001 et est développé par Dries Buytaert. Ce système de gestion de contenu fait également partie des plus installés et des plus utilisés.

Pour maximiser la sécurité site web Drupal, il faut faire usage de la double authentification et éliminer les utilisateurs inactifs. Aussi, les fichiers d’accès Drupal doivent connaître une limitation d’accès. Par ailleurs, il faut procéder à des sauvegardes régulières et toujours activer le SSL.

✓ Sécurité Magento

securite magento

Cette plateforme de commerce électronique fut lancée en 2008. Magento draine des milliers d’utilisateurs, qui malheureusement, font aussi face à des attaques de leurs systèmes.

Sur un site Magento, le mot de passe doit être changé tous les trois mois. Les connexions ratées doivent être limitées et la récupération du mot de passe doit toujours avoir lieu par e-mail. Sur le backoffice, c’est le HTTPS qui doit être utilisé. Enfin, les extensions utilisées doivent avoir fait l’objet d’audit.

Créer un sitemap XML avec Python

Créer un sitemap XML avec Python

Qu’est-ce qu’un sitemap XML ?

Un sitemap XML est un fichier qui vise à lister l’ensemble de vos urls importantes pour le SEO. Vous pouvez en créer plusieurs par thématique ou type de pages. Il existe certaines limitations concernant les sitemaps XML. Pour rappel, les voici :

  • un fichier peut lister jusqu’à 50.000 URL
  • un index de sitemaps peut lister jusqu’à 50.000 fichiers sitemaps (mais pas de fichier index de sitemaps)
  • vous pouvez envoyer jusqu’à 500 fichiers d’index de sitemaps pour chaque site
  • une fois décompressé (car vous pouvez l’envoyer compressé), le fichier ne doit pas dépasser 50 Mo (52 428 800 octets). Pour information, cette limite de 50 Mo date de novembre 2016, avant c’était 10 Mo

source : Webrankinfo

De nombreux outils permettent de générer des sitemaps XML mais ils souvent souvent limités ou peu flexibles. Je vous propose aujourd’hui de voir comment il est possible de créer un sitemap XML via Python.

Découvrez aussi notre article pour crawler des sitemaps avec R

Script Python pour créer un sitemap XML

Avant de mettre les main dans le code, assurez-vous d’avoir la liste de vos urls. Comment faire ? Pour récupérer la liste de vos urls, utilisez un crawler. Il en existe plusieurs sur le marché : screaming frog (gratuit jusqu’à 500 urls) ou encore seolyzer (gratuit jusqu’à 10 000 urls). Sinon si vous souhaitez le faire vous même voici un tuto pour crawler son votre site avec R et RCrawler.

Quian

Etapes n°1 : Chargez les librairies

import pandas as pd
import os
import datetime 
from jinja2 import Template
import gzip

Etapes n°2: Charger votre liste d’urls

list_of_urls = pd.read_csv('list_of_urls.csv', sep=";")
list_of_urls

Etapes n°3: Préparer le(s) fichier(s)

# Set-Up Maximum Number of URLs (recommended max 50,000)
n = 50000
 
# Create New Empty Row to Store the Splitted File Number
list_of_urls.loc[:,'name'] = ''
 
# Split the file with the maximum number of rows specified
new_df = [list_of_urls[i:i+n] for i in range(0,list_of_urls.shape[0],n)]
 
# For Each File Created, add a file number to a new column of the dataframe
for i,v in enumerate(new_df):
    v.loc[:,'name'] = str(v.iloc[0,1])+'_'+str(i)
    print(v)

Etapes n°4: Créer le template du / des fichier(s)

           
# Create a Sitemap Template to Populate
 
sitemap_template='''<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    {% for page in pages %}
    <url>
        <loc>{{page[1]|safe}}</loc>
        <lastmod>{{page[3]}}</lastmod>
        <changefreq>{{page[4]}}</changefreq>
        <priority>{{page[5]}}</priority>        
    </url>
    {% endfor %}
</urlset>'''
 
template = Template(sitemap_template)
 
# Get Today's Date to add as Lastmod
lastmod_date = datetime.datetime.now().strftime('%Y-%m-%d')

Etapes n°5: Lancer la création de vos sitemaps

# Fill the Sitemap Template and Write File
for i in new_df:                           # For each URL in the list of URLs ...                                                          
    i.loc[:,'lastmod'] = lastmod_date      # ... add Lastmod date
    i.loc[:,'changefreq'] = 'daily'        # ... add changefreq
    i.loc[:,'priority'] = '1.0'            # ... add priority 
 
    # Render each row / column in the sitemap
    sitemap_output = template.render(pages = i.itertuples()) 
     
    # Create a filename for each sitemap like: sitemap_0.xml.gz, sitemap_1.xml.gz, etc.
    filename = 'sitemap' + str(i.iloc[0,1]) + '.xml.gz'
 
    # Write the File to Your Working Folder
    with gzip.open(filename, 'wt') as f:   
        f.write(sitemap_output)

Code complet  🤙

import pandas as pd
import os
import datetime 
from jinja2 import Template
import gzip
 
# Import List of URLs
list_of_urls = pd.read_csv('list_of_urls.csv')
list_of_urls
 
 
# Set-Up Maximum Number of URLs (recommended max 50,000)
n = 50000
 
# Create New Empty Row to Store the Splitted File Number
list_of_urls.loc[:,'name'] = ''
 
# Split the file with the maximum number of rows specified
new_df = [list_of_urls[i:i+n] for i in range(0,list_of_urls.shape[0],n)]
 
# For Each File Created, add a file number to a new column of the dataframe
for i,v in enumerate(new_df):
    v.loc[:,'name'] = str(v.iloc[0,1])+'_'+str(i)
    print(v)
             
# Create a Sitemap Template to Populate
 
sitemap_template='''<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    {% for page in pages %}
    <url>
        <loc>{{page[1]|safe}}</loc>
        <lastmod>{{page[3]}}</lastmod>
        <changefreq>{{page[4]}}</changefreq>
        <priority>{{page[5]}}</priority>        
    </url>
    {% endfor %}
</urlset>'''
 
template = Template(sitemap_template)
 
# Get Today's Date to add as Lastmod
lastmod_date = datetime.datetime.now().strftime('%Y-%m-%d')
 
# Fill the Sitemap Template and Write File
for i in new_df:                           # For each URL in the list of URLs ...                                                          
    i.loc[:,'lastmod'] = lastmod_date      # ... add Lastmod date
    i.loc[:,'changefreq'] = 'daily'        # ... add changefreq
    i.loc[:,'priority'] = '1.0'            # ... add priority 
 
    # Render each row / column in the sitemap
    sitemap_output = template.render(pages = i.itertuples()) 
     
    # Create a filename for each sitemap like: sitemap_0.xml.gz, sitemap_1.xml.gz, etc.
    filename = 'sitemap' + str(i.iloc[0,1]) + '.xml.gz'
 
    # Write the File to Your Working Folder
    with gzip.open(filename, 'wt') as f:   
        f.write(sitemap_output)

Python & Adwords : Récupérer les volumes de recherche pour une liste de mots clés

Python & Adwords : Récupérer les volumes de recherche pour une liste de mots clés

Pourquoi faire ?

Les MSV* (Monthly Search Volume) sont des données particulièrement précieuses pour les SEO. Ces MSV permettent souvent de donner une valeur à un mot clé. Aujourd’hui de nombreux outils fournissent cette information mais il sont généralement payants. Seul Ubersuggest propose un accès gratuit (mais limité) pour récupérer les volumes de recherche pour vos mots clés. Plutôt sympa avec Ubersuggest mais pour récupérer les volumes de recherches pour des centaines de mots clés, là ça se corse ! Alors comment faire ? Et bien il existe une solution en python qui consiste à requêter l’API Adwords

Pré-requis

Avoir un compte Adwords

Accédez simplement à votre compte administrateur, puis sélectionnez OUTILS ET PARAMÈTRES > CONFIGURATION > CENTRE D’API . Remplissez le formulaire et demandez votre jeton de développeur. Si vous avez déjà ce Jeton et bien conservez-le pour la suite.

Avoir un projet Google Cloud Platform.

Sur la page qui apparaît, vous devez copier l’ID client et le code secret client et les stocker pour la suite.

Avoir un Client ID client

L’identification finale dont nous avons besoin est l’ID client du compte Adwords. Il peut être trouvé à côté du nom du compte dans la plupart des endroits de l’interface Google Ads, par exemple le menu déroulant des comptes, au format xxx-xxx-xxxx. Sélectionnez le numéro correspondant à votre compte administrateur.

Le script décrit ci-dessous utilise ces informations d’identification pour demander un jeton d’accès au serveur d’autorisation Google. Ces jetons d’accès n’ont qu’une durée de vie limitée, donc si nous voulons pouvoir réutiliser le script à l’avenir, nous avons besoin d’un jeton d’actualisation. Ce jeton d’actualisation nous permet de renouveler notre jeton d’accès et nous permet donc d’envoyer d’autres demandes à l’API AdWords.

Comment générer un jeton d’actualisation

La façon la plus simple de générer notre jeton d’actualisation consiste à exécuter generate_refresh_token.py  (python 3+) à partir de la ligne de commande avec votre ID client et votre secret client comme arguments de ligne de commande comme ceci:

python generate_refresh_token.py --client_id INSERT_CLIENT_ID --client_secret INSERT_CLIENT_SECRET

Script Python pour récupérer les volumes de recherche pour une liste de mots clés

Ouvrez votre terminal et renseignez :

pip installer googleads pandas

Je charge les librairies nécessaires pour la suite :

import _locale
from pandas import DataFrame
import googleads
import pandas as pd
import traceback
from googleads import adwords
from googleads import oauth2

On s’assure que l’encodage soit bon

_locale._getdefaultlocale = (lambda * args: ['fr_FR', 'UTF-8'])

On charge un fichier csv listant des mots clés

keyword_list = pd.read_csv("xxxxx.csv")

Je transforme le dataframe en list

keyword_list = pd.DataFrame(keyword_list)
keyword_list = keyword_list['keyword'].to_list()
keyword_list

Il s’agit ici de lancer une fonction pour requêter l’API. Nous pouvons demander en masse le volume de recherche de centaines de mots clés en une seule demande d’API à la fois, nous allons donc diviser notre liste de mots clés en sous-listes de 700 mots clés. Cela réduit le nombre d’appels d’API nécessaires, accélère donc massivement le script et réduit considérablement les chances de renvoyer une erreur “ RateLimitExceeded ”.

class searchVolumePuller():
      def __init__(self,client_ID,client_secret,refresh_token,developer_token,client_customer_id):
            self.client_ID = client_ID
            self.client_secret = client_secret
            self.refresh_token = refresh_token
            self.developer_token = developer_token
            self.client_customer_id = client_customer_id
            
      def get_client(self):
          access_token = oauth2.GoogleRefreshTokenClient(self.client_ID,
                                                         self.client_secret,
                                                         self.refresh_token)
          adwords_client = adwords.AdWordsClient(self.developer_token,
                                                 access_token,
                                                 client_customer_id = self.client_customer_id,
                                                 cache=googleads.common.ZeepServiceProxy.NO_CACHE)
 
          return adwords_client
      
      def get_service(self,service,client):
 
          return client.GetService(service)

      def get_search_volume(self,service_client,keyword_list):
            #empty dataframe to append data into and keywords and search volume lists#
            keywords = []
            search_volume = []
            keywords_and_search_volume = pd.DataFrame()
            #need to split data into lists of 700#
            sublists = [keyword_list[x:x+700] for x in range(0,len(keyword_list),700)]
            for sublist in sublists:
                  # Construct selector and get keyword stats.
                  selector = {
                  'ideaType': 'KEYWORD',
                  'requestType' : 'STATS'
                    }
                    
                  #select attributes we want to retrieve#
                  selector['requestedAttributeTypes'] = [
                    'KEYWORD_TEXT',
                    'SEARCH_VOLUME'
                    ]
                    
                  #configure selectors paging limit to limit number of results#
                  offset = 0
                  selector['paging'] = {
                  'startIndex' : str(offset),
                  'numberResults' : str(len(sublist))
                        }
                    
                  #specify selectors keywords to suggest for#
                  selector['searchParameters'] = [{
                  'xsi_type' : 'RelatedToQuerySearchParameter',
                  'queries' : sublist
                        }]
                  
                  #pull the data#
                  page = service_client.get(selector)
                  #access json elements to return the suggestions#
                  for i in range(0,len(page['entries'])):
                        keywords.append(page['entries'][i]['data'][0]['value']['value'])
                        search_volume.append(page['entries'][i]['data'][1]['value']['value'])
                        
            keywords_and_search_volume['Keywords'] = keywords
            keywords_and_search_volume['Search Volume'] = search_volume
            
            return keywords_and_search_volume

Il ne vous reste plus qu’à renseigner : CLIENT_ID / CLIENT_SECRET / REFRESH_TOKEN / DEVELOPER_TOKEN / CLIENT_CUSTOMER_ID

if __name__ == '__main__':
     CLIENT_ID = 'YOUR-CLIENT-ID'
     CLIENT_SECRET = 'YOUR-CLIENT-SECRET'
     REFRESH_TOKEN = 'YOUR_REFRESH_TOKEN'
     DEVELOPER_TOKEN = 'YOUR-DEVELOPER-TOKEN'
     CLIENT_CUSTOMER_ID = 'YOUR-CLIENT-CUSTOMER-ID'
    

     volume_puller = searchVolumePuller(CLIENT_ID,
                                        CLIENT_SECRET,
                                        REFRESH_TOKEN,
                                        DEVELOPER_TOKEN,
                                        CLIENT_CUSTOMER_ID)

     adwords_client = volume_puller.get_client()
            
            
     targeting_service = volume_puller.get_service('TargetingIdeaService', adwords_client)

     kw_sv_df = volume_puller.get_search_volume(targeting_service,keyword_list)

Regardons le résultat …

kw_sv_df

Exporter la liste dans un fichier CSV

kw_sv_df.to_csv('demenagement_msv.csv', index = False)

Google Trend + Python + DataStudio : Suivre les tendances marché

Google Trend + Python + DataStudio : Suivre les tendances marché

Identifier les tendances d’un marché est un enjeu majeur pour la plupart des acteurs dans le monde du commerce. Aujourd’hui, l’un des outils les plus efficaces reste Google Trends. Trop souvent sous-estimé, cet outil est pourtant particulièrement riche en information. Le problème ? Comment rendre scalable la récupération et l’analyse des données issues de Google Trends ?

Nous avions vu précédemment comment exploiter récupérer les données Google Trends avec R. Voyons désormais comment nous pouvons aller plus loin avec Python.

En utilisant les codes de cet article, vous serez en mesure de :

  • Récupérer les données Google trend avec python
  • Créer automatiquement un google spreadsheet avec python
  • Afficher la donnée dans Google data studio
  • Créer un Cron pour exécuter le script tous les jours à la même heure

Passons aux choses sérieuses …

Tout d’abord, vous devez installer la bibliothèque:

pip install pytrends

Installons les librairies nécessaires pour la suite

import pytrends
from pytrends.request import TrendReq
import pandas as pd
import time
import datetime
from datetime import datetime, date, time
import pandas as pd
from pandas import DataFrame
#https://searchengineland.com/learn-how-to-chart-and-track-google-trends-in-data-studio-using-python-329119
pytrend = TrendReq()

Je récupère les “related queries” qui sont en mode “rising”

Dans l’exemple ci-dessous nous allons récupérer les mots clés relatif à “Jardin”, “Tondeuse” et “Decoration” pour la France sur les 3 derniers mois.

NB : Il est possible de sélectionner une catégorie spécifique pour sa requête. Ici dans l’exemple, j’ai renseigné “cat=11” car il s’agit de la catégorie “Home Garden”

Afin de voir toutes les fonctionnalités et les filtres, vous devriez vérifier ce référentiel sur Github et vous pouvez également trouver tous les codes de catégorie ici .

pytrend.build_payload(kw_list=['jardin','tondeuse','decoration'], geo = 'FR', timeframe = 'today 3-m', cat = 11)
related_queries= pytrend.related_queries()
jardin =related_queries.get('jardin').get('rising')
tondeuse =related_queries.get('tondeuse').get('rising')
decoration =related_queries.get('decoration').get('rising')

On récupère ici une bibliothèque avec les “tops” requêtes mais ici ce sont les “rising” requêtes qui nous intéressent

Les données sont là, plutôt cool non ? Bon par contre ce n’est pas encore terminé. Ajoutons maintenant une colonne avec la thématique associée à chaque query. Il ne reste plus qu’à concaténer les résultats :

maison['theme'] = 'maison' 
jardin['theme'] = 'jardin' 
bricolage['theme'] = 'bricolage' 
decoration['theme'] = 'decoration' 
result = pd.concat([maison,jardin,bricolage,decoration], axis=0)
Pour chaque query je sais à quelle thématique elle est associée

Comment envoyer la donnée directement dans un Googlesheet ?

Si vous souhaitez simplement exporter la donnée dans un fichier excel, vous pouvez vous arrêter là. La suite vise à envoyer automatiquement la donnée dans un Google sheet pour ensuite alimenter une Google Data Studio. C’est parti ! Mais avant toute chose, voici le pré-requis avant de lancer la suite du code :

Activer l’API Google Sheet et récupérer votre ID client et votre code secret client. Pour cela, suivez les étapes suivantes :

  1. Rendez-vous ici
  2. Créer un projet si vous n’en n’avez pas un sur Google cloud platform
  3. Cliquez sur « Bibliothèque » dans le menu
  4. Recherchez « Google sheet API » et cliquez sur le logo
  5. Cliquez sur « Activez »
  6. Cliquez sur « Identifiants » dans le menu
  7. Cliquez sur « créer des identifiants » (en haut de l’écran) et sur « ID client OAuth »
  8. Choisissez « Autre », renseigner un nom puis cliquez sur « Créer »
  9. Insérez votre code client et ID client dans le code ci-dessous

Créer un Google sheet et récupérer l’ID de ce dernier

  1. Créer un Google sheet
  2. Cliquez sur “partager” en haut à droite
  3. Copier le lien de partage
  4. Récupérer dans l’url, l’ID de votre Google Sheet (exemple :”1l7UEMs2Qv-YE96jAxYkvg9KAumYq3dYk0nlmG62g_-4″ )
  5. Insérer cet ID dans le code ci-dessous à la place de “my_google-sheet-id”

Télécharger le fichier Json

  1. Dans votre espace Google Cloud Platform, cliquez sur “identifiants”
  2. Téléchargez le fichier Json
  3. Déplacez le fichier Json dans le dossier où se trouve le script

Voici le code pour se connecter à votre Google sheet

Avant de lancer le code, vérifier que vous avez remplacer :

  • my_google-sheet-id >> l’ID de votre Google sheet
  • nom_du_fichier_json >> Le nom du fichier Json que vous avez téléchargé précédemment
import gspread as gc
from oauth2client.service_account import ServiceAccountCredentials
import pandas as pd
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow,Flow
from google.auth.transport.requests import Request
import os
import pickle

SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
# here enter the id of your google sheet
SAMPLE_SPREADSHEET_ID_input = 'my_google-sheet-id'
SAMPLE_RANGE_NAME = 'A1:AA1000'
def main():
    global values_input, service
    creds = None
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file('nom_du_fichier_json', SCOPES) # here enter the name of your downloaded JSON file
            creds = flow.run_local_server(port=0)
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    service = build('sheets', 'v4', credentials=creds)

    # Call the Sheets API
    sheet = service.spreadsheets()
    result_input = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID_input,
                                range=SAMPLE_RANGE_NAME).execute()
    values_input = result_input.get('values', [])

    if not values_input and not values_expansion:
        print('No data found.')

main()

df=pd.DataFrame(values_input[1:], columns=values_input[0])
#change this by your sheet ID
SAMPLE_SPREADSHEET_ID_input = 'my_google-sheet-id'

#change the range if needed
SAMPLE_RANGE_NAME = 'A1:AA1000'

def Create_Service(client_secret_file, api_service_name, api_version, *scopes):
    global service
    SCOPES = [scope for scope in scopes[0]]
    #print(SCOPES)
    
    cred = None

    if os.path.exists('token_write.pickle'):
        with open('token_write.pickle', 'rb') as token:
            cred = pickle.load(token)

    if not cred or not cred.valid:
        if cred and cred.expired and cred.refresh_token:
            cred.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file('nom_du_fichier_json', SCOPES)
            cred = flow.run_local_server()

        with open('token_write.pickle', 'wb') as token:
            pickle.dump(cred, token)

    try:
        service = build(api_service_name, api_version, credentials=cred)
        print(api_service_name, 'service created successfully')
        #return service
    except Exception as e:
        print(e)
        #return None
        
# change 'my_json_file.json' by your downloaded JSON file.
Create_Service('nom_du_fichier_json', 'sheets', 'v4',['https://www.googleapis.com/auth/spreadsheets'])
    
def Export_Data_To_Sheets():
    response_date = service.spreadsheets().values().update(
        spreadsheetId="my_google-sheet-id",
        valueInputOption='RAW',
        range=SAMPLE_RANGE_NAME,
        body=dict(
            majorDimension='ROWS',
            values=result.T.reset_index().T.values.tolist())
    ).execute()
    print('Sheet successfully Updated')

Export_Data_To_Sheets()
Et voilà les données sont directement envoyées dans Google Sheet ! 😎

Il ne vous reste plus qu’à créer un Google Data studio

Voici les étapes :

  1. Connectez-vous à Data studio
  2. Créer un nouveau rapport vierge
  3. Cliquez “ajouter des données”
  4. Sélectionnez “Google sheets”
  5. Cherchez et ajoutez le fichier que vous avez créé et alimenté automatiquement avec python
  6. Cliquez sur Ajouter un graphique puis un tableau
  7. Configurer votre tableau comme ceci :
Crawler un site avec R & RCrawler

Crawler un site avec R & RCrawler

Possible de crawler sans budget ? Oui avec RCrawler !

Crawler et scraper des données est devenu une pratique incontournable pour les SEO depuis plusieurs années. Des solutions payantes existent comme par exemple Screaming Frog, Oncrawl, Botify ou encore Seolyzer. Pour ceux et celles qui n’ont les budgets pour passer sur de telles plateformes, il existe des solutions qui s’appuient sur des languages de programmation comme python ou encore R.

Dans cet article, je vais vous expliquer comment crawler gratuitement en exploiter le package RCrawler. Nous verrons comment configurer les informations à scraper et comment organiser la donnée de sorte qu’elle soit exploitable par la suite. RCrawler est un package très intéressant car nativement il embarque de nombreuses fonctionnalités comme le stockage des fichiers HTML (vous n’aurez pas à re-crawler si vous avez oublié de récupérer des informations) ou encore le crawl en mode headless browser, particulièrement apprécié pour des sites conçus sur des framework Angular ou React.

RCrawler nous y voilà !

# define you setwd()
setwd("/path/")

# install to be run once
install.packages("Rcrawler")

# and loading
library(Rcrawler)


# what we want to extract
CustomLabels <- c("title",
                  "Meta_description",
                  "h1",
                  "h2",
                  "h3",
                  "Hreflang",
                  "canonical_tag",
                  "meta_robots"
                  )

# How to grab it, do not hesitate to add other stuff you want to grab by adding xpath
CustomXPaths <- c("///title",
                  "//meta[@name='description']/@content",
                  "///h1",
                  "///h2",
                  "///h3",
                  "//link[@rel='alternate']/@hreflang",
                  "//link[@rel='canonical']/@href",
                  "//meta[@rel='robots']/@content")

# create proxy configuration if you need it. In this exemple we do not need it
# proxy <- httr::use_proxy("190.90.100.205",41000)
# use proxy configuration

# Crawler settings : I add many options but there are not all compulsory
Rcrawler(Website = "https://www.v6protect.fr", 
         #Obeyrobots=TRUE, 
         #RequestsDelay = 10, 
         #dataUrlfilter ="/path", 
         #crawlUrlfilter="/path/",
         #MaxDepth = 1, 
         ExtractXpathPat = CustomXPaths, 
         PatternsNames = CustomLabels,
         #Useragent="Mozilla 3.11",
         NetworkData = TRUE, #inlinks
         NetwExtLinks =TRUE, #outlinks
         statslinks = TRUE,
         #use_proxy = proxy,
         #ignoreAllUrlParams = TRUE
         )

# I combine data
crawl <-data.frame(do.call("rbind", DATA))
crawl_complete <- cbind(INDEX,crawl)
Idurl = as.numeric(crawl_complete$Id)
crawl_complete = cbind(Idurl,crawl_complete)


# I count inlinks
count_to = NetwEdges[,1:2] %>%
  distinct() %>%
  group_by(To) %>%
  summarise(n = n())

# I rename columns
count_to = count_to %>% 
rename(Idurl = To, Inlinks = n)

# I join inlinks data with my crawl data
df_final = left_join(count_to, crawl_complete,by="Idurl")

# I remove columns that I do not need
df_final = select(df_final, -Idurl, -Id, -IN)

# I rename columns
df_final = df_final %>% 
rename(Outlinks = OUT, Depth = Level)


## PAGERANK calculation
links <- NetwEdges[,1:2] %>%
  #grabing the first two columns
  distinct() 
# loading igraph package
library(igraph)
# Loading website internal links inside a graph object
g <- graph.data.frame(links)
# this is the main function, don't ask how it works
pr <- page.rank(g, algo = "prpack", vids = V(g), directed = TRUE, damping = 0.85)

# I grab results inside a dedicated data frame
values <- data.frame(pr$vector)
values$names <- rownames(values)

# delating row names
row.names(values) <- NULL

# reordering column
values <- values[c(2,1)]

# renaming columns
names(values)[1] <- "PageID"
names(values)[2] <- "pagerank"

#replacing id with url
values$url <- NetwIndex
names(values)[3] <- "Url"

# out of 10
values$Pagerank<- round(values$pagerank / max(values$pagerank) * 10)

# I join my crawl with Pagerank information
crawl = left_join(values,df_final,by="Url")

# I clean my dataframe by removing columns
crawl = select(crawl, -PageID.x,pagerank,-PageID.y)

#HERE WE ARE ! You can export you crawl data in an csv file
write.csv(crawl, "my_crawl_data.csv", sep=";")


###  BONUS ###

# FIND MY LAST CRAWL : HTML
ListProjects()
LastHTMLDATA <- LoadHTMLFiles("xxxxxxx", type = "vector")
# or to simply grab the last one:
LastHTMLDATA <- LoadHTMLFiles(ListProjects()[1], type = "vector")

for(i in 1:nrow(LastHTMLDATA)) {
  LastHTMLDATA$title[i] <- ContentScraper(HTmlText = LastHTMLDATA$html[i] ,XpathPatterns = "//title")
  LastHTMLDATA$h1[i] <- ContentScraper(HTmlText = LastHTMLDATA$html[i] ,XpathPatterns = "//h1")
  LastHTMLDATA$h2[i] <- ContentScraper(HTmlText = LastHTMLDATA$html[i] ,XpathPatterns = "//h2")
  LastHTMLDATA$h3[i] <- ContentScraper(HTmlText = LastHTMLDATA$html[i] ,XpathPatterns = "//h3")
}

## REACT OR ANGULAR CRAWLING SETTINGS ##
# RCrawler handly includes Phantom JS, the classic headless browser.
# Download and install phantomjs headless browser
install_browser()
 
# start browser process 
br <-run_browser()
Rcrawler(Website = "https://www.example.com/", Browser = br)
 
# don't forget to stop browser afterwards
stop_browser(br)