API:Nahegelegene-Orte-Betrachter

From mediawiki.org
Jump to navigation Jump to search
This page is a translated version of the page API:Nearby places viewer and the translation is 100% complete.

Überblick

In dieser Anleitung wirst du lernen, wie du mit der MediaWiki Action API nach Wiki-Seiten in deiner Nähe suchen kannst.

Laden den Code von Github herunter Durchsuche die App auf Toolforge

In diesem Lernprogramm lernst du, wie du dies tun kannst:

Eine Schritt-für-Schritt-Anleitung, um diese Anwendung zu erstellen

Schritt 1: Python- und Flask-Entwicklungsumgebung aufsetzen

Um die Python-Entwicklungsumgebung für eine Flask-Anwendung aufzusetzen, musst du Python installieren, eine virtuelle Umgebung erstellen und Flask installieren.

Diese Anwendung nutzt Python3, die empfohlene Version für neue Python-Projekte. Lerne hier mehr über die Unterschiede zwischen Python2 und Python3 Um Python3 auf deiner lokalen Maschine zu installieren, befolge die Schritt-für-Schritt-Anleitung aus dem Installations-Leitfaden.

Die Entwicklungsumgebung, um die Anwendung aufzubauen, wird wie folgt aufgesetzt:

$ 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

Schritt 2: Eine einfache Flask-Anwendung erstellen

Eine einfache statische Seite rendern

Setze den folgenden Code in $HOME/nearby-places-viewer/nearby.py ein

#!/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()

Setze die Code-Zeile <h1>Nearby places viewer</h1> in eine HTML-Datei im Ordner templates ein: $HOME/nearby-places-viewer/templates/places.html

Hinweis: Bei dieser einfachen Anwendung nutzen wir die Methode render_template, die die Vorlage mit dem Namen places.html aus dem Verzeichnis templates rendert.

Führe als nächstes deine Flask-App mit dem Befehl python nearby.py aus und öffne http://127.0.0.1:5000/, um dir deine App im Browser anzusehen. Du solltest "Nearby places viewer" in deinem Browser-Fenster sehen können.

Gestalte deine App

Lass uns die App gestalten. Füge ein Schaltflächen-Element hinzu, um die Such-Eingabe in der HTML-Datei zu akzeptieren und verlinke Markierungen, um externe und interne Stylesheets zu laden. Externe Stylesheets sind in diesem Fall die URL einer CSS-Datei für einen Google-Font Amatic.

Ersetze den vorhandenen Code in $HOME/nearby-places-viewer/templates/places.html durch folgendes:

<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Amatic+SC:700">
<link rel="stylesheet" href="/static/style.css">

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

Setze den folgenden Code in $HOME/nearby-places-viewer/static/static.css ein

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;
}
Bildschirmfoto der Nahegelegenen-Orte-Betrachter-Demo-App (1)

Anwendungslayout

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

Schritt 3: Erhalte Koordinaten deines Aufenthaltsortes

Als erstes musst du die Koordinaten deines aktuellen Aufenthaltsortes erhalten, um nach Wiki-Seiten in der Nähe zu suchen. Um dies zu tun, kannst du die Geolocation-API zusammen mit JavaScript-Code nutzen.

Wenn du auf die Schaltfläche Click here to search klickst, ruft die App die Geolocation-API an und ruft den aktuellen Standort deines Gerätes über das Navigator.geolocation-Objekt der API ab. Die Antwort der API ist ein Position-Objekt, aus dem du den Breitengrad und Längengrad erhalten kannst.

Hinweis: Wenn deine App die API anruft, wirst du benachrichtigt und gebeten, deinem Browser die Berechtigung zu erteilen, auf deinen Standort zuzugreifen.

Setze den folgenden Code in $HOME/nearby-places-viewer/static/places.js ein

$( 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;
	}
});

Verlinke das benutzerdefinierte JavaScript /static/places.js und jQuery von der HTML-Datei: $HOME/nearby-places-viewer/templates/places.html

<!-- Add these two lines at the top -->
<script src="//ajax.googleapis.com/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>

Schritt 4: Sende Standortdaten an den Server mit AJAX

Diese App nutzt die AJAX-Methode von jQuery, um die in Schritt 3 erhaltenen Standort-Daten an den Server zu senden und sie ohne Neuladen der Seite an eine Python-Flask-Route / in $HOME/nearby-places-viewer/nearby.py zu senden.

Lass uns als nächsten den AJAX-Anruf zur Funktion fetchPlaces in $HOME/nearby-places-viewer/static/places.js hinzufügen.

Hinweis: Wenn du an diesem Punkt versuchst, deine App auszuführen, ist es wahrscheinlich, dass dir im Browser-Fenster ein Fehler angezeigt wird, da wir die Unterstützung der /-Route, um mit POST-Abfragen umzugehen, noch nicht hinzugefügt haben.

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 occured while fetching places!"; 
		}
	});
}

Schritt 5: Nahegelegene Orte über die MediaWiki Action API erhalten

Erweitere als erstes die Python-Flask-Route / in $HOME/nearby-places-viewer/nearby.py, um POST-Abfragen zu nutzen. Du kannst dies tun, indem du GET und POST zur methods-Argumentliste im Route-Decorator hinzufügst. Du kannst als nächstes die in einem JSON-Format verfügbaren Standort-Daten aus dem request-Objekt erhalten und es zur weiteren Verarbeitung an die fetch_places_nearby()-Funktion übergeben.

@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')

Der Code in der Funktion fetch_places_nearby() stellt eine GET-Abfrage an die Action API, um nach Wiki-Seiten in der Nähe eines Ortes zu suchen. Der API-Anruf besteht aus einem Endpunkt https://en.wikipedia.org/w/api.php und Parametern der Abfrage-Zeichenkette. Einige der Schlüsselparameter sind:

  • action=query Hauptmodul zur Informationsabfrage
  • generator=geosearch Submodul list des Abfrage-Moduls, genutzt als Generator-Modul, um Suchergebnisse für eine Reihe von Seiten zu erhalten
  • prop=coordinates|pageimages|description|info Gibt an, welche Eigenschaften für Seiten zurückgegeben werden sollen

Hinweis: Für weitere Informationen zum Geosuche-Modul besuche API:Geosuche .

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

Sieh dir den vollständigen Python- und Flask-Code mit Import-Aussagen und verarbeiteter places-Liste an. Diese App nutzt das in Python verfügbare Haversine-Paket, um Entfernungen zwischen zwei geografischen Koordinaten zu berechnen.

$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)

Schritt 6: Aus der JSON-Antwort eine Benutzeroberfläche für Listen von Orten erstellen

Behandle die vom Server zurückgegebenen JSON-Daten im AJAX-success-Callback und nutze die HTML-DOM-innerHTML-Eigenschaft, um die div-Inhalte zu ändern.

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>";
	}
}

Sieh dir den vollständigen JavaScript-Code mit erfolgreichem AJAX-Callback an.

$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 occured while fetching places!"; }
		});
	}
});

Schritt 7: Gestaltung ändern mit Bootstrap

Du hast vielleicht bemerkt, dass der Code-Ausschnitt in Schritt 6 Namen von Bootstrap-Klassen nutzt. Ja, wir integrieren in diesem Schritt das Bootstrap-Framework, um ein responsoves Layout-Design zum Orte-UI hinzuzufügen. Lass uns CSS- und HTML-Dateien optimieren, um dies zu tun.

Sieh dir den vollständigen CSS- und HTML-Code an.

$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="//ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="/static/places.js"></script>

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="//fonts.googleapis.com/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>
Bildschirmfoto der Nahegelegenen-Orte-Betrachter-Demo-App (2)

Nächste Schritte

Siehe auch