Dernière mise à jour le : 6 Oct, 2020

Tutoriel : déployer une application Python avec Google App Engine

    Ce tutoriel est la suite de l’article Google Search Console to BigQuery avec Python. Dans cet article, nous avons créé une application Python qui va récupérer les données dans Google Search Console via l’API, pour les loguer dans BigQuery.

    Dans ce second tutoriel, nous allons voir comment déployer l’application dans le cloud (Google App Engine), et définir une tache journalière pour aller récupérer les dernières données disponibles.

    Nous allons utiliser les composants suivant :

    • Python 3
    • Flask
    • Google Cloud app Engine

    Si vous souhaitez découvrir Flask, je vous invite à préalablement effectuer le tutoriel suivant : https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-ii-templates

    A noter que nous aurions pu utiliser Google Cloud function, qui est probablement la solution la plus simple pour ce type de solutions. Avec GCloud Scheduler pour la tâche CRON.

    Rappel de l’épisode précédent

    Nous avions donc les fichiers suivant :

    • Un fichier “search_console_bq.py”, avec le code python
    • Un fichier “requirements.txt”, avec l’environnement Python nécessaire
    • Un fichier json, qui est une clé de connexion à un compte de service Google Cloud.

    https://github.com/Nicolas-Chollet/search-console-to-bigquery-python

    Modifier les fichiers afin de préparer le déploiement

    Rendre les dates dynamiques dans search_console_bq.py

    Tout d’abord, nous allons faire tourner le script tous les jours. Il faut donc que les dates de début et de fin varient en fonction du jour. Dans Google Search console, les données ne sont disponibles que 2 à 3 jours après le jour en question. Nous allons donc, chaque jour, récupérer les données d’il y a 3 jours.

    Pour cela, nous allons modifier notre config.

    Avant :
    start_date = '2020-08-01'
    end_date = '2020-08-20'
    Après :
    from datetime import datetime, timedelta
    start_date = datetime.strftime(datetime.now() - timedelta(3), '%Y-%m-%d')
    end_date = datetime.strftime(datetime.now() - timedelta(3), '%Y-%m-%d')

    C’est assez simple : on prend la date du jour, et on enlève 3 jour. Puis on formate la date conformément à ce qui est attendu par l’API.

    Réécrire l’application Python via Flask

    App Engine va nous permettre d’appeler des URLs via des requêtes http. Il nous faut donc réécrire légèrement l’application :

    from flask import Flask
    from google.oauth2 import service_account
    from googleapiclient.discovery import build
    import requests
    import json
    import pandas as pd
    from google.cloud import bigquery
    from datetime import datetime, timedelta
    
    ########### SET YOUR PARAMETERS HERE ####################################
    PROPERTIES = ["https://www.unnest.co"]
    BQ_DATASET_NAME = 'search_console_demo'
    BQ_TABLE_NAME = 'result_table_demo'
    SERVICE_ACCOUNT_FILE = 'primeval-door-282907-3cbe2bd9d463.json'
    start_date = datetime.strftime(datetime.now() - timedelta(3), '%Y-%m-%d')
    end_date = datetime.strftime(datetime.now() - timedelta(3), '%Y-%m-%d')
    ################ END OF PARAMETERS ######################################
    
    SCOPES = ['https://www.googleapis.com/auth/webmasters']
    credentials = service_account.Credentials.from_service_account_file(
            SERVICE_ACCOUNT_FILE, scopes=SCOPES)
    
    service = build(
        'webmasters',
        'v3',
        credentials=credentials
    )
    
    
    # If `entrypoint` is not defined in app.yaml, App Engine will look for an app
    # called `app` in `main.py`.
    app = Flask(__name__)
    
    @app.route('/update/', methods=['GET'])
    def update():
    
        def get_sc_df(site_url,start_date,end_date,start_row):
            """Grab Search Console data for the specific property and send it to BigQuery."""
    
            request = {
              'startDate': start_date,
              'endDate': end_date,
              'dimensions': ['query','device', 'page', 'date'], # uneditable to enforce a nice clean dataframe at the end!
              'rowLimit': 25000,
              'startRow': start_row
               }
    
            response = service.searchanalytics().query(siteUrl=site_url, body=request).execute()
    
            if len(response) > 1:
    
                x = response['rows']
    
                df = pd.DataFrame.from_dict(x)
                
                # split the keys list into columns
                df[['query','device', 'page', 'date']] = pd.DataFrame(df['keys'].values.tolist(), index= df.index)
                
                # Drop the key columns
                result = df.drop(['keys'],axis=1)
    
                # Add a website identifier
                result['website'] = site_url
    
                # establish a BigQuery client
                client = bigquery.Client.from_service_account_json(SERVICE_ACCOUNT_FILE)
                dataset_id = BQ_DATASET_NAME
                table_name = BQ_TABLE_NAME
                # create a job config
                job_config = bigquery.LoadJobConfig()
                # Set the destination table
                table_ref = client.dataset(dataset_id).table(table_name)
                job_config.destination = table_ref
                job_config.write_disposition = 'WRITE_APPEND'
    
                load_job = client.load_table_from_dataframe(result, table_ref, job_config=job_config)
                load_job.result()
    
                return result
            else:
                print("There are no more results to return.")
    
        # Loop through all defined properties, for up to 100,000 rows of data in each
        for p in PROPERTIES:
            for x in range(0,100000,25000):
                y = get_sc_df(p,start_date,end_date,x)
                if len(y) < 25000:
                    break
                else:
                    continue
    
        return 'update ok'
    
    
    if __name__ == '__main__':
        app.run(debug=True)

    En gros, nous allons simplement définir une route dans Flask (/update/) qui va déclencher notre fonction écrite en Python. De cette manière, pour lancer la mise à jour, il me suffira d’aller sur l’URL http://monapplication/update/

    Nous allons également le renommer main.py

    Modifier le fichier requirements.txt

    Il faut ajouter Flask. Le fichier est donc maintenant :

    Flask==1.1.2
    google-api-python-client==1.10.0
    google-auth-httplib2==0.0.4
    google-auth-oauthlib==0.4.1
    google-cloud==0.34.0
    google-cloud-bigquery==1.25.0
    pandas==1.0.5
    requests==2.22.0
    pyarrow==1.0.1

    Tester en local

    Afin de tester en local, c’est assez simple. Il faut se placer dans le répertoire dans lequel j’ai mes fichiers main.py, requirements.txt et ma clé json.

    • Créer un environnement vituel Python
    • Charger le fichier requirements.txt :
    • Lancer l’application :
    ```bash
    python3 -m venv env
    source env/bin/activate
    ```
    
    ```bash
    pip install -r requirements.txt
    ```
    
    ```bash
    python main.pi
    ```

    Normalement, le script tourne, et inscrit les données dans BigQuery.

    Déployer dans Google App Engine

    Créer un fichier app.yaml

    Avant de déployer dans Google App Engine, nous allons devoir créer un fichier app.yaml. Il est très simple. Il permet simplement de définir la version de Python qui sera déployée dans App Engine :

    #app.yaml
    runtime: python37

    Déployer dans App Engine

    Dans le terminal, se placer dans le répertoire contenant les fichiers nécessaires au déploiement. Vous devez avoir les 4 fichiers suivant :

    Screenshot 2020 08 31 at 18.45.39 | Tutoriel : déployer une application Python avec Google App Engine

    Puis :

    gcloud app deploy

    Vous devrez avoir le résultat suivant :

    Screenshot 2020 08 31 at 18.47.51 | Tutoriel : déployer une application Python avec Google App Engine

    Si ce n’est pas le cas, ou si ce n’est pas le bon projet Google Cloud, placez vous dans le bon projet Google Cloud :

    gcloud config set project PROJECT

    Tester

    Une fois déployé l’application est accessible sur une URL du type https://myproject.ew.r.appspot.com

    Vous pouvez tester votre application en allant sur l’adresse :

    https://myproject.ew.r.appspot.com/update/

    Normalement, cela devrait remplir la base de donnée BigQuery avec les données de J-3. Si vous rencontrez une erreur, aller dans le panneau “Error reporting” afin d’analyser les rapports d’erreur : https://console.cloud.google.com/errors

    Screenshot 2020 09 01 at 09.31.38 | Tutoriel : déployer une application Python avec Google App Engine

    Mettre à jour toutes les 24h

    Nous allons pour cela déployer une tache CRON sur Google App Engine. Il suffit de créer un fichier cron.yaml, qui contient les informations suivantes :

    cron:
    - description: Calls cronjob pour mise a jour GSC
      url: /update/
      schedule: every 24 hours

    Puis de le déployer via le terminal :

    gcloud app deploy cron.yaml

    Enfin, on peut se rendre sur la page qui liste les taches CRON dans l’interface Google Cloud :

    https://console.cloud.google.com/appengine/cronjobs

    Screenshot 2020 09 01 at 09.35.24 | Tutoriel : déployer une application Python avec Google App Engine

    Et voilà ! Vous avez maintenant déployé une application Python sur Google App Engine, avec une tache journalière.

    Suivez l'actualité Data

    Newsletter UnNest

    Ne manquez aucun contenu : recevez chaque mois la liste des derniers articles publiés.