API:Bild-des-Tages-Betrachter

This page is a translated version of the page API:Picture of the day viewer and the translation is 99% complete.
Outdated translations are marked like this.

Überblick

In diesem Tutorial erfährst du, wie du mit der MediaWiki Action API einen Wikipedia:Bild des Tages Viewer erstellst.

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

Python aufsetzen

Diese Anleitung nutzt Python 3. Du kannst die aktuellste Python-Version hier herunterladen:

Siehe die Python-Anfängeranleitung für weitere Hinweise zur Installation von Python auf unterschiedlichen Betriebssystemen.

Flask aufsetzen

Pip ist eine Paketverwaltung, die du nutzen kannst, um Flask zu installieren: pip install flask. Wenn du pip noch nicht installiert hast, installiere es von der offiziellen Pip-Webseite.


Schritt 2: Eine einfache Flask-Anwendung erstellen

Wenn du alles erfolgreich installiert hast, setze in deinem Projekt-Ordner das folgende Skript in app.py ein: $HOME/picture-of-the-day-viewer/app.py. Wenn du es ausführst (mit flask run oder python app.py), sollte "Hello world" auf http://localhost:5000/ angezeigt werden:

#!/usr/bin/python3

from flask import Flask
APP = Flask(__name__)

@APP.route("/")
def hello():
  return "Hello World!"

if __name__ == "__main__":
  APP.run()

Schritt 3: Bild-des-Tages-Betrachter

Nachdem du nun alles aufgesetzt hast, kannst du damit beginnen, Code für den Bild-des-Tages-Betrachter zu schreiben. Das Bild des Tages oder POTD ist ein exzellentes Bild, das täglich auf der Hauptseite der Wikipedia angezeigt wird. Du wirst das Bild aus einer Wiki-Vorlage erhalten, die sich jeden Tag ändert.

Aktuelles Datum erhalten

Da das POTD täglich aktualisiert wird, benötigst du das Datum von heute, um auf die Archive zugreifen und eine stabile Version des korrekten Bildes erhalten zu können. Um dies zu tun, importiere die Python-Klasse date.

Definiere als nächstes eine neue Funktion index(). Index() wird die Webseite rendern und alle Daten, die mit unseren API-Abfragen zu tun haben, weitergeben. Siehe #Die Seite anzeigen für weitere Informationen zur index.html-Datei, die wir als Vorlage nutzen. Zunächst sollte index() eine Variable für das aktuelle Datum enthalten. Wir werden sie bald nutzen, um eine Abfrage zusammenzustellen, mit der wir auf das POTD zugreifen.

#!/usr/bin/python3
from datetime import date
from flask import Flask, render_template

APP = Flask(__name__)

@APP.route("/")
def index():
  todays_date = date.today().isoformat()

if __name__ == "__main__":
  APP.run()


Die Action API anrufen

Die Action API funktioniert, indem sie Daten als Antwort auf HTTP-Abfragen sendet. Um dies zu tun, musst du die Python-Abfrage-Bibliothek importieren.

Füge als nächstes zwei neue Variablen hinzu: SESSION = requests.Session() und ENDPOINT = "https://en.wikipedia.org/w/api.php". Du wirst das Objekt SESSION nutzen, um Abfragen an die URL ENDPOINT zu stellen.

Rufe in einer neuen Funktion fetch_potd() API:Bilder an, um das in eine geschützte POTD-Seite eingebundene Bild abzufragen (Beispiel). Nutze aus diesem Anruf den Dateinamen des Bildes, um API:Bildinfo anzurufen und erhalte die Quell-URL des Bildes. In diesem Beispiel wird der zweite API-Anruf in der Helfer-Funktion fetch_image_src() verarbeitet.

Die Wikipedia-Archive führen das Datum im ISO-Standard-Format auf -- zum Beispiel 2019-01-31 für den 31. Januar 2019. Du kannst das korrekte Format durch Nutzung der Datumsmethode isoformat() erhalten.

def fetch_potd(cur_date):
  date_iso = cur_date.isoformat()
  title = "Template:POTD_protected/" + date_iso

  params = {
    "action": "query",
    "format": "json",
    "formatversion": "2",
    "prop": "images",
    "titles": title
  }

  response = SESSION.get(url = ENDPOINT, params = params)
  data = response.json()
  filename = data["query"]["pages"][0]["images"][0]["title"]
  image_page_url = "https://en.wikipedia.org/wiki/" + title
    
  image_data = {
    "filename": filename,
    "image_page_url": image_page_url,
    "image_src": fetch_image_src(filename),
    "date": cur_date
  }

  return image_data

def fetch_image_src(filename):
  params = {
    "action": "query",
    "format": "json",
    "prop": "imageinfo",
    "iiprop": "url",
    "titles": filename
  }

  response = SESSION.get(url = ENDPOINT, params = params)
  data = response.json()
  page = next(iter(data["query"]["pages"].values()))
  image_info = page["imageinfo"][0]
  image_url = image_info["url"]

  return image_url

Ändere schließlich index(), um fetch_potd() anzurufen. Importiere render_template aus flask und lasse index() render_template("index.html", data=data) ausgeben.


Die Seite anzeigen

 
Bildschirmfoto der Bild-des-Tages-Betrachter-App

Flask-Vorlagen enthalten hauptsächlich HTML-Markup, sie nutzen jedoch auch Jinja, um dynamischen Inhalt zu rendern. Jinja-Markup sieht so aus -- {{ variable }} -- und wird genutzt, um Python-Variablen oder -Ausdrücke in unsere grundlegende Seitenstruktur einzuführen. Füge etwas Boilerplate in HTML 5 und ein paar Elemente zu index.html hinzu. Stelle sicher, es in einem Verzeichnis in deiner App namens /templates zu speichern.

<!DOCTYPE html>
<html lang="en">
  <meta charset="utf-8">
  <title>Picture of the Day</title>
  <link rel="stylesheet" href="/static/style.css">

  <main>
    <h1>Picture of the day:</h1>
    <div class="card">
      <div class="potd">
        <h2>{{ data.filename }}</h2>
        <a href="{{ data.image_page_url }}" target="blank">
        <figure>
          <img src="{{ data.image_src }}">
          <figcaption>View on Wikipedia</figcaption>
        </figure>
        </a>
      </div>
      <div class = "date-container">
      <div class = "current-date">{{ data.date.strftime("%d %B %Y") }}</div>
    </div>
    </div>
</main>

Es interaktiv machen

Füge ein ‎<form>-Element zu index.html hinzu und gib ihm für die Bestätigungs-Schaltflächen die folgenden Eingaben: Back und Next. Wenn eine der Schaltflächen ausgewählt wird, sendet das Formular eine POST-Abfrage und der ausgewählte Wert wird an app.py zurückgegeben. Dies ermöglicht es Benutzern, die Archive des Bild des Tages zu durchsuchen.

Aktualisiere als nächstes app.py mit einer change_date()-Funktion, um das Datum zu setzen, das dem Benutzer angezeigt wird. Erweitere auch die /-Route, um POST-Abfragen aus dem Formular verarbeiten zu können. Importiere die Request-Flask-Klasse, um app.py zu erlauben, die POST-Abfrage-Nachricht zu lesen.

Der vollständige Python- und HTML-Code:

$HOME/picture-of-the-day-viewer/app.py
"""
    app.py
    MediaWiki Action API Code Samples

    Fetches Wikipedia Picture of the Day (POTD) and displays it on a webpage.
    Also allows users to go backward or forward a date to view other POTD.

    MIT License
"""

#!/usr/bin/python3

from datetime import date, timedelta
from flask import Flask, render_template, request
import requests

APP = Flask(__name__)
SESSION = requests.Session()
ENDPOINT = "https://en.wikipedia.org/w/api.php"
CURRENT_DATE = date.today()

@APP.route("/", methods=["GET", "POST"])
def index():
    """
    Requests data from Action API via 'fetch_potd' function & renders it on the
    index page accessible at '/'
    """

    if request.method == "POST":
        change_date()

    data = fetch_potd(CURRENT_DATE)

    return render_template("index.html", data=data)

def change_date():
    """
    Changes current date in response to input from the web form
    """

    global CURRENT_DATE

    user_input = request.form["change_date"]
    new_date = CURRENT_DATE
    last_date = date.today()
    first_date = date(year=2004, month=5, day=14)

    if user_input == "← Back":
        new_date = new_date - timedelta(days=1)
    elif user_input == "Next →":
        new_date = new_date + timedelta(days=1)

    if new_date > last_date or new_date < first_date:
        return

    CURRENT_DATE = new_date

def fetch_potd(cur_date):
    """
    Returns image data related to the current POTD
    """

    date_iso = cur_date.isoformat()
    title = "Template:POTD protected/" + date_iso

    params = {
        "action": "query",
        "format": "json",
        "formatversion": "2",
        "prop": "images",
        "titles": title
    }

    response = SESSION.get(url=ENDPOINT, params=params)
    data = response.json()

    filename = data["query"]["pages"][0]["images"][0]["title"]
    image_src = fetch_image_src(filename)
    image_page_url = "https://en.wikipedia.org/wiki/Template:POTD_protected/" + date_iso

    image_data = {
        "filename": filename,
        "image_src": image_src,
        "image_page_url": image_page_url,
        "date": cur_date
    }

    return image_data

def fetch_image_src(filename):
    """
    Returns the POTD's image url
    """

    params = {
        "action": "query",
        "format": "json",
        "prop": "imageinfo",
        "iiprop": "url",
        "titles": filename
    }

    response = SESSION.get(url=ENDPOINT, params=params)
    data = response.json()
    page = next(iter(data["query"]["pages"].values()))
    image_info = page["imageinfo"][0]
    image_url = image_info["url"]

    return image_url

if __name__ == "__main__":
    APP.run()
$HOME/picture-of-the-day-viewer/templates/index.html
<!DOCTYPE html>
<html lang="en">
  <meta charset="utf-8">
  <title>Picture of the Day</title>
  <link rel="stylesheet" href="/static/style.css">

  <main>
    <h1>Picture of the day:</h1>
    <div class="card">
      <div class="potd">
        <h2>{{ data.filename }}</h2>
        <a href="{{ data.image_page_url }}" target="blank">
        <figure>
          <img src="{{ data.image_src }}">
          <figcaption>View on Wikipedia</figcaption>
        </figure>
        </a>
      </div>
      <div class="date-container">
        <time class="current-date">{{ data.date.strftime("%d %B %Y") }}</time>
        <div class="date-navigator">
          <form action="/" method="POST">
            {% if data.date.strftime("%d %B %Y") == "14 May 2004" %}
            <input type="submit" name="change_date" value="← Back" disabled>
            {% else %}
            <input type="submit" name="change_date" value="← Back">
            {% endif %}
            {% if data.date == data.date.today() %}
            <input type="submit" name="change_date" value="Next →" disabled>
            {% else %}
            <input type="submit" name="change_date" value="Next →">
            {% endif %}
          </form>
        </div>
      </div>
    </div>
</main>

Deine App gestalten

Flask nutzt ein Verzeichnis namens static, das alle Helfer-Dateien enthält, die während des gesamten Lebenszyklus der App gleich bleiben. Dies ist ein hilfreicher Ort, um dort Stylesheets oder zusätzliche Skripte zu speichern. Unser Stylesheet wird einige Farben und visuelle Motive, basierend auf dem Wikimedia Style Guide, nutzen. Platziere eine CSS-Datei in $HOME/picture-of-the-day-viewer/static/style.css.

$HOME/picture-of-the-day-viewer/static/style.css
html {
    margin: 0;
    padding: 0;
    height: 100vh;
    width: 100vw;
}

body {
    margin: 0;
    background: #f8f9fa; /* light grey */
    font-family: Arial, Helvetica, sans-serif;
    font-size: 16px;
}

h1 {
    margin: 0;
    padding: 12px;
    background: #2a4b8d; /* dark blue */
    color: #ffffff;
}

h2 {
    margin-top: 8px;
    padding: 12px;
    font-size: 1em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    background: #f3f9ff; /* very light blue */
    border: 1px solid #2a4b8d; /* dark blue */
}

a {
    color: #3366cc; /* blue */
}

p {
    margin: 8px;
}

.card {
    position: relative;
    margin: auto;
    min-width: 200px;
    max-width: 67vw;
    height: 90vh;
    background: #ffffff;
    border-radius: 8px;
    box-shadow: 3px 6px 10px rgba(0, 0, 0, 0.16);
}

.potd {
    width: inherit;
    height: 60vh;
}

figure {
    width: 100%;
    margin: auto;
    text-align: center;
}

figure img {
    display: block;
    margin: 12px auto; 
    max-width: 64vw;
    max-height: 50vh;
    border: 1px solid#3366cc; /* blue */
}

figure a {
    margin: 8px;
}

.date-container {
    display: block;
    position: absolute;
    bottom: 0;
    left: 0;
    right:0;
    text-align: center;
    font-weight: bold;
}

.current-date {
    margin: 16px auto;
    font-size: 2em;
    background: #ffffff;
    color: #72777d; /* grey */
}

.date-navigator {
    margin: 16px auto;
    font-size: 2em;
    text-transform: uppercase;
    text-align: center;
    background: #3366cc; /* blue */
    color: #ffffff;
}

.date-navigator input {
    margin: 8px;
    min-height: 44px;
    width: 45%;
    font-size: 0.67em;
    font-weight: inherit;
    text-transform: none;
    background: #3366cc; /* blue */
    color: inherit;
    border: 1px solid #ffffff;
    box-shadow: 3px 6px 10px rgba(0, 0, 0, 0.16);
    cursor: pointer;
}

.date-navigator input:hover {
    background: #447FF5; /* light blue */
}

.date-navigator input:active {
    background: #2a4b8d; /* dark blue */
    border: none;
    box-shadow: none;
}

.footer {
    text-align: center;
}

.date-navigator input:disabled {
    color: #c8cdff; /* grey */
    border: 1px solid #c8cdff; /* grey */
    box-shadow: none;
    cursor: default;
}

.date-navigator input:disabled:hover {
    background: #3366cc; /* blue */
}

Nächste Schritte

  • Trage eine Demo-App, die du mithilfe der MediaWiki API entwickelt hast, zu dem Code-Beispiel-Repositorium bei.
  • Lerne etwas zu Möglichkeiten, um beschreibenden Text zur Seite Picture of the day hinzuzufügen:
    • API:Suche bietet snippets, was als Link-Vorschau genutzt werden kann.
    • action=cirrusdump kann genutzt werden, um den gesamten geparsten Text aus Artikeln in Wikis, in denen die Cirrussearch -Erweiterung installiert ist, zu erhalten (siehe Beispiel).

Siehe auch