Afficheur de voisinage

This page is a translated version of the page API:Nearby places viewer and the translation is 100% complete.

Présentation

Dans ce tutoriel, vous apprendrez comment rechercher les pages wiki qui sont en rapport avec l'endroit géographique où vous vous trouvez en utilisant l'Api Action de MediaWiki.

Ce tutoriel vous montrera comment faire cela en utilisant :

Processus pas à pas pour construire cette application

Etape 1 : installer l'environnement de développement Python et Flask

Pour configurer l'environnement de développement Python pour une application Flask, vous devez installer Python, créer un environnement virtuel et installer Flask.

Cette application utilise Python3, qui est la version recommandée pour les nouveaux projets Python. En savoir plus sur les différences entre Python2 et Python3 Pour installer Python3 sur votre machine locale, suivez pas à pas les instructions de ces guides d'installation.

Voici comment configurer l'environnement de développement pour construire l'application :

$ mkdir nearby-places-viewer
$ cd nearby-places-viewer/
This will create a new directory and change into it
$ python3 --version #Python 3.6.5
This command checks your Python version 
$ python3 -m venv venv
This command will create a virtual environment named 'venv'
$ source venv/bin/activate
This will activate the virtual environment
$ pip install Flask
This command will install the Flask package with all its dependencies

Etape 2: créer une application Flask simple

Générer une page statique simple

Insérer le code suivant dans $HOME/nearby-places-viewer/nearby.py

#!/usr/bin/python3

"""
    nearby.py

    MediaWiki Action API Code Samples
    
    Nearby places viewer app: Demo of geo search for wiki pages 
    near a location using the Geolocation API and MediaWiki Action 
    API's Geosearch module. 

    MIT license
"""

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    """ Displays the index page accessible at '/'
    """
    return render_template('places.html')

if __name__ == '__main__':
    app.run()

Sauvegardez cette ligne unique de code <h1>Nearby places viewer</h1> dans un fichier HTML à l'intérieur du répertoire templates : $HOME/nearby-places-viewer/templates/places.html

Note : Dans cette application simple, nous utilisons la méthode render_template qui génère le modèle places.html du répertoire templates.

Puis exécutez votre application Flask avec la commande python nearby.py et ouvrez http://127.0.0.1:5000/ pour voir votre application dans le navigateur. Vous devriez voir l'Afficheur de voisinage dans la fenêtre de votre navigateur.

Mettre en forme votre application

Remettons en forme un peu l'application. Ajoutez un élément de type bouton pour valider les données à rechercher dans le fichier HTML et reliez les balises pour charger une feuille de style externe et une autre interne. La feuille de style externe est dans ce cas l'URL d'un fichier CSS pour la fonte Amatic.

Remplacer le code existant dans $HOME/nearby-places-viewer/templates/places.html par :

<link rel="stylesheet" href="//tools-static.wmflabs.org/fontcdn/css?family=Amatic+SC:700">
<link rel="stylesheet" href="/static/style.css">

<h1>Nearby places viewer</h1>
<button>Click here to search</button>

Insérer le code suivant dans $HOME/nearby-places-viewer/static/style.css

h1 {
    font-family: 'Amatic SC', cursive;
    font-size: 2.5em;
    font-weight: normal;
    color: black;
}

button {
    font-size: 16px;
    padding: 10px 25px;
    cursor: pointer;
    text-decoration: none;
    color: white;
    border-radius: 4px;
    background-color: #7c7ce0;
    margin-bottom: 20px;
}
 
Ecran de l'application de démonstration de l'afficheur de voisinage (1)

Affichage des applications

$HOME/nearby-places-viewer
├── templates/
│   └── places.html
├── static/
│   └── static.css
├── nearby.py
└── venv/

Etape 3 : obtenir les coordonnées de votre lieu actuel

D'abord, pour obtenir les pages wiki liées à votre voisinage, vous devrez disposer des coordonnées géographiques de là où vous vous trouvez. Pour faire cela, vous pouvez utiliser l'API Geolocation avec un peu de code JavaScript.

Si vous cliquez sur le bouton Cliquez ici pour chercher, l'application fait un appel à l'API Geolocation et récupère la position actuelle de votre appareil via l'objet Navigator.geolocation de l'API. La réponse renvoyée par l'API est un objet Position à partir duquel vous pouvez obtenir la latitude et la longitude.

Note : Quand votre application réalise un appel à l'API, vous être notifié et on vous demande d'autoriser votre navigateur à accéder à votre emplacement.

Insérer le code suivant dans $HOME/nearby-places-viewer/static/places.js

$( document ).ready(function() {
	var x = document.getElementById( "places-list" );
	
	$( 'button' ).click(function() { 
		getLocation(); 
	});

	function getLocation() {
		x.innerHTML = "Searching your location..";

		if (navigator.geolocation) {
			navigator.geolocation.getCurrentPosition(fetchPlaces);
		} else { 
			x.innerHTML = "Geolocation is not supported by this browser.";
		}
	}

	function fetchPlaces(position) {
		x.innerHTML = position.coords.latitude + "|" + position.coords.longitude;
	}
});

Reliez le JavaScript personnalisé /static/places.js et jQuery à partir du fichier HTML : $HOME/nearby-places-viewer/templates/places.html

<!-- Add these two lines at the top -->
<script src="//tools-static.wmflabs.org/cdnjs/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="/static/places.js"></script> 

<!-- Add this line after the button element -->
<div id="places-list"></div>

Etape 4 : envoyer les coordonnées géographiques au serveur avec AJAX

Cette application utilise la méthode AJAX de jQuery pour envoyer les données de localisation obtenues à l'étape 3 au serveur et les POSTer sans rafraîchir la page vers une route Python Flask / dans $HOME/nearby-places-viewer/nearby.py.

Pour l'étape suivante, nous ajoutons un appel AJAX à la fonction fetchPlaces dans $HOME/nearby-places-viewer/static/places.js.

Note : A ce point, si vous essayez d'exécuter votre application, vous aurez probablement une erreur dans la fenêtre de votre navigateur parce que nous n'avons pas ajouté de support pour la route / pour de gérer nos requêtes POST.

function fetchPlaces(position) {
	var data = { 
		"latitude": position.coords.latitude, 
		"longitude": position.coords.longitude
	};

	$.ajax({
		url: "/",
		type: "POST",
		data: JSON.stringify(data),
		contentType: "application/json",
		dataType: "json",

		success: function (response) { 
			x.innerHTML = "Success!";
		}, 
		error: function () { 
			x.innerHTML = "An error occurred while fetching places!"; 
		}
	});
}

Etape 5 : récupérer les lieux du voisinage avec l'API Action de MediaWiki

D'abord, étendez la route Python Flask / dans $HOME/nearby-places-viewer/nearby.py pour gérer les requêtes POST. Vous pouvez faire cela en ajoutant à la fois GET et POST dans la liste des arguments de methods du paramètre de route. Ensuite, vous pouvez obtenir les données de géolocalisation disponibles au format JSON à partir de l'objet request et les passer à la fonction fetch_places_nearby() pour un traitement ultérieur.

@app.route('/', methods=['GET', 'POST'])
def index():
    """ Displays the index page accessible at '/'
    """

    if request.method == "POST":
        data = request.get_json()
        latitude = data['latitude']
        longitude = data['longitude']

        results = fetch_places_nearby(latitude, longitude)
        return jsonify(results=results)

    return render_template('places.html')

Le code de la fonction fetch_places_nearby() fait une requête GET à l'API Action pour rechercher les pages du wiki à proximité d'un lieu. L'appel de l'API se fait avec le point d'accès https://en.wikipedia.org/w/api.php et les paramètres de la chaîne de requête. Voici quelques paramètres clés :

  • action=query module principal pour demander les informations
  • generator=geosearch list des sous-modules du module de requête utilisé comme module générateur pour obtenir les résultats de recherche d'un ensemble de pages
  • prop=coordinates|pageimages|description|info indique les propriétés à renvoyer pour les pages

Note : Pour plus d'informations sur le module geosearch, voir API:Geosearch/fr .

def fetch_places_nearby(lat, lon):
    params = {
        "action": "query",
        "prop": "coordinates|pageimages|description|info",
        "inprop": "url",
        "pithumbsize": 144,
        "generator": "geosearch",
        "ggsradius": 10000,
        "ggslimit": 10,
        "ggscoord": str(lat) + "|" + str(lon),
        "format": "json",
    }

    res = SESSION.get(url=API_ENDPOINT, params=params)
    data = res.json()
    places = data['query'] and data['query']['pages'] 
    # TODO: further process 'places' list
    
    return places

Voir le code complet de Python et Flask avec les directives import et la liste places traitée. Cette application utilise le paquet Haversine disponible dans Python pour calculer la distance entre deux coordonnées géographiques.

$HOME/nearby-places-viewer/nearby.py
#!/usr/bin/python3

"""
    nearby.py

    MediaWiki Action API Code Samples

    Nearby places viewer app: Demo of geo search for wiki pages near a location using
    the Geolocation API and MediaWiki Action API's Geosearch module.

    MIT license
"""

from flask import Flask, request, render_template, jsonify
import requests
from haversine import haversine


APP = Flask(__name__)
SESSION = requests.Session()
API_ENDPOINT = 'https://en.wikipedia.org/w/api.php'


@APP.route('/', methods=['GET', 'POST'])
def index():
    """ Displays the index page accessible at '/'
    """

    if request.method == "POST":
        data = request.get_json()
        latitude = data['latitude']
        longitude = data['longitude']

        results = fetch_places_nearby(latitude, longitude)
        return jsonify(results=results)

    return render_template('places.html')

def fetch_places_nearby(lat, lon):
    """ Fetches nearby places via MediaWiki Action API's Geosearch module
    """
    params = {
        "action": "query",
        "prop": "coordinates|pageimages|description|info",
        "inprop": "url",
        "pithumbsize": 144,
        "generator": "geosearch",
        "ggsradius": 10000,
        "ggslimit": 10,
        "ggscoord": str(lat) + "|" + str(lon),
        "format": "json",
    }

    res = SESSION.get(url=API_ENDPOINT, params=params)
    data = res.json()
    places = data['query'] and data['query']['pages']
    results = []

    for k in places:
        title = places[k]['title']
        description = places[k]['description'] if "description" in places[k] else ''
        thumbnail = places[k]['thumbnail']['source'] if "thumbnail" in places[k] else ''
        article_url = places[k]['fullurl']

        cur_loc = (lat, lon)
        place_loc = (places[k]['coordinates'][0]['lat'], places[k]['coordinates'][0]['lon'])

        distance = round(haversine(cur_loc, place_loc, unit='mi'), 2)

        results.append({
            'title': title,
            'description': description,
            'thumbnail': thumbnail,
            'articleUrl': article_url,
            'distance': distance
        })

    return results

if __name__ == '__main__':
    APP.run(debug=True)

Etape 6 : créer une interface utilisateur pour lister les lieux à partir de la réponse JSON

Gère les données JSON renvoyées par le serveur dans la procédure de rappel AJAX success et utilise la propriété DOM innerHTML du HTML pour modifier le contenu de div .

success: function (response) { 
	var places = response["results"],
		no_thumb = "..";

	x.innerHTML = "";
	
	for (var p in places) {
		var thumbnail = places[p].thumbnail || no_thumb;

		x.innerHTML += "<div class=\"item\"><div class=\"col-xs-8 no-padding\"><h5><a href=\"" +
			places[p]["articleUrl"] + "\" target=\"_blank\">" +
			places[p]["title"] + "</a></h5><p>" +
			places[p]["description"] + "</p><span>📍" + places[p]["distance"] +
			" miles</p></div><div class=\"col-xs-4 no-padding\"><img src=\"" +
			thumbnail + " \"></div></div>";
	}
}

Afficher le code JavaScript complet avec la procédure de rappel AJAX avec succès.

$HOME/nearby-places-viewer/static/places.js
$( document ).ready(function() {
	var x = document.getElementById( "places-list" );
	
	$( ".btn-search" ).click(function() { 
		getLocation(); 
	});

	function getLocation() {
		x.innerHTML = "Searching your location..";

		if (navigator.geolocation) {
			navigator.geolocation.getCurrentPosition(fetchPlaces);
		} else { 
			x.innerHTML = "Geolocation is not supported by this browser.";
		}
	}

	function fetchPlaces(position) {
		var data = { 
			"latitude": position.coords.latitude, 
			"longitude": position.coords.longitude
		};

		$.ajax({
			url: "/",
			type: "POST",
			data: JSON.stringify(data),
			contentType: "application/json",
			dataType: "json",

			success: function (response) { 
				var places = response["results"],
					no_thumb = "https://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Gnome-image-missing.svg/200px-Gnome-image-missing.svg.png";

				x.innerHTML = "";
				
				for (var p in places) {
					var thumbnail = places[p].thumbnail || no_thumb;

					x.innerHTML += "<div class=\"item\"><div class=\"col-xs-8 no-padding\"><h5><a href=\"" +
						places[p]["articleUrl"] + "\" target=\"_blank\">" +
						places[p]["title"] + "</a></h5><p>" +
						places[p]["description"] + "</p><span>📍" + places[p]["distance"] +
						" miles</p></div><div class=\"col-xs-4 no-padding\"><img src=\"" +
						thumbnail + " \"></div></div>";
				}
			}, 
			error: function () { x.innerHTML = "An error occurred while fetching places!"; }
		});
	}
});

Etape 7 : modification du style avec Bootstrap

Vous avez peut-être remarqué que l'extrait de code de l'Etape 6 utilise des noms de classe Bootstrap. Effectivement, nous intégrons l'environnement de développement Bootstrap à cette étape pour ajouter l'architecture d'un affichage dynamique à l'interface utilisateur des lieux. Pour faire cela, apportons quelques modifications supplémentaires aux fichiers CSS et HTML.

Afficher l'ensemble du code CSS et HTML.

$HOME/nearby-places-viewer/static/style.css
.places-container .no-padding {
    padding: 0;
}

.places-container .info {
    text-align: center;
}

.places-container .viewer-heading {
    font-family: 'Amatic SC', cursive;
    font-size: 2.5em;
    font-weight: normal;
    color: black;
}

.places-container .btn-search {
    font-size: 16px;
    padding: 10px 25px;
    cursor: pointer;
    text-decoration: none;
    color: white;
    border-radius: 4px;
    background-color: #7c7ce0;
}

.places-container .list {
    margin-top: 20px;
}

.places-container .item {
    min-height: 100px;
}

.places-container .item p,
span {
    font-size: 12px;
    margin: 2px;
}

.places-container .item span {
    color: gray;
}

.places-container .item img {
    float: right;
    width: 80px;
    height: 80px;
    border-radius: 5px;
    object-fit: cover;
}

.places-container .item a {
    color: #7c7ce0;
}
$HOME/nearby-places-viewer/templates/places.html
<title>Nearby places viewer</title>

<script src="//tools-static.wmflabs.org/cdnjs/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="/static/places.js"></script>

<link rel="stylesheet" href="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="//tools-static.wmflabs.org/fontcdn/css?family=Amatic+SC:700">
<link rel="stylesheet" href="/static/style.css">

<div class="container places-container col-lg-4 col-xs-12">
  <div class="col-xs-12 no-padding info">
    <h1 class="viewer-heading">Nearby places viewer</h1>
    <button class="btn-search">Click here to search</button>
  </div>
  <div class="col-xs-12 no-padding list" id="places-list">
  </div>
</div>
 
Ecran de l'application de démonstration de l'afficheur de voisinage (2)

Étapes suivantes

  • Contribuez en enregistrant l'application de démonstration que vous avez réalisée utilisant l'API MediaWiki, dans ce dépôt d'exemples de code.

Voir aussi