API:Prohlížeč svátků
Tato stránka je součástí dokumentace k API Action MediaWiki. |
Přehled
Tento návod popisuje, jak vytvořit ukázkovou aplikaci, která načte svátky a dodržování pro dané datum z Wikipedie, s možností přihlášení a přidání nových svátků.
Nástroje a technologie použité k vytvoření demo aplikace jsou:
- Python 3 a Flask, framework Pythonu.
- jQuery a Bootstrap. They are loaded from Wikimedia Toolforge for privacy reasons.
- Moduly MediaWiki Action API: API:Parse , API:Přihlášení a API:Úpravy .
Postup pro vytvoření této aplikace krok za krokem
Krok 1: Nastavení vývojového prostředí Python a Flask
Python je předinstalovaný na většině distribucí Linuxu. Pro ostatní operační systémy viz Python příručka pro začátečníky, kde najdete pokyny k instalaci.
Nainstalujte Flask spuštěním pip install flask
.
Pokud Pip nemáte, získejte ho z oficiálního webu Pip
Krok 2: Vytvořte jednoduchou aplikaci Flask
Ve svém domovském adresáři vytvořte složku s názvem holidays-viewer
, která bude obsahovat všechny soubory aplikace.
Uvnitř složky vytvořte soubor s názvem app.py
a vložte do něj následující kód:
#!/usr/bin/python3
from flask import Flask
APP = Flask(__name__)
@APP.route("/")
def list_holidays():
return "Holidays and observances"
if __name__ == "__main__":
APP.run()
Spusťte aplikaci pomocí příkazu python app.py
a otevřete http://127.0.0.1:5000/
ve svém prohlížeči.
Měli byste vidět zobrazení "Holidays and observances".
Krok 3: Vytvořte základní návrh
Aplikace bude mít čtyři stránky: domovskou stránku, stránku vyhledávání, přihlašovací stránku a stránku pro přidání.
Každá stránka bude mít některé společné prvky, takže musíme vytvořit soubor základního návrhu nazvaný layout.html
, který bude tyto prvky obsahovat.
Všimněte si, že používáme třídy Bootstrap k aplikaci konkrétního stylu CSS na prvek, Materialize icons pro ikony přidání, vyhledávání a šipky zpět a Jinja k rozšíření základního rozvržení na další stránky a k předání proměnných z Pythonu. do HTML.
$HOME/holidays-viewer/templates/layout.html |
---|
<title>Holidays</title>
<link rel="stylesheet" href="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css">
<link rel="stylesheet" href="//tools-static.wmflabs.org/fontcdn/css?family=Material+Icons">
<div class="content bg-secondary rounded m-auto">
<div class="title-bar bg-primary-dark text-white pl-2">
<small>Holidays and observances</small>
</div>
<div class="header-bar bg-primary text-white shadow p-2">
{% if request.path != url_for('list_holidays') %}
<a class=" btn text-white" href="{{ url_for('list_holidays') }}">
<i class="material-icons">arrow_back</i>
</a>
{% endif %}
<h5>{{header}}</h5>
<div class="filler"></div>
<a class="btn text-white" href="{{ url_for('add') }}">
<i class="material-icons">add</i>
</a>
<a class="btn text-white" href="{{ url_for('search') }}">
<i class="material-icons">search</i>
</a>
</div>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-primary mb-0" role="alert">
{% for message in messages %}
{{ message }}
{% endfor %}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</div>
<script src="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.min.js"></script>
|
Ostatní stránky se rozšíří o layout.html
pomocí níže uvedeného kódu:
{% extends "layout.html" %}
{% block content %}
<!--content for other pages-->
{% endblock %}
Krok 4: Seznam svátků
Kořenová adresa URL aplikace spustí funkci list_holidays(...)
, která uvádí svátky pro určité datum.
Ve funkci a v celé aplikaci, holidays_date
odkazuje na datum svátků, které mají být uvedeny, header
odkazuje na název stránky a holidays_html
odkazuje na html, který obsahuje svátky, které mají být uvedeny.
Použijeme také funkci render_template(...)
, která vykreslí konkrétní html soubor z adresáře šablon.
Dalšími argumenty přidanými do funkce jsou proměnné, které jsou předávány do html souboru.
V app.py
aktualizujte list_holidays()
pomocí kódu níže:
@APP.route('/', methods=['GET', 'POST'])
@APP.route('/<holidays_date>', methods=['GET', 'POST'])
def list_holidays(holidays_date=None):
holidays_html = ""
return render_template("index.html", header=holidays_date.replace('_', ' '),
holidays_html=holidays_html)
$HOME/holidays-viewer/templates/index.html |
---|
{% extends "layout.html" %}
{% block content %}
<div class="holidays-html">
{{holidays_html|safe}}
</div>
{% endblock %}
|
Získání dnešního data
Pokud není zadáno žádné datum, uvedeme svátky pro dnešní datum.
Chcete-li použít modul datetime Pythonu k získání dnešního data, importujte modul s from datetime import datetime
a poté vytvořte následující funkci:
def get_todays_date():
current_month = datetime.now().strftime('%B')
current_day = datetime.now().strftime('%d')
if current_day.startswith('0'):
current_day = current_day.replace('0', '')
return current_month + "_" + current_day
Zavolejte funkci v list_holidays(...)
:
if holidays_date is None:
holidays_date = get_todays_date()
Získejte seznam svátků
Jakmile máme datum, získáme pro toto datum svátky. Wikipedia má stránku pro každé datum a svátky jsou v sekci s názvem "Holidays and observances". Abychom získali svátky, potřebujeme získat její číslo sekce a obsah v tomto čísle sekce.
Vytvořte funkci pro získání čísla sekce pomocí API:Parse :
def get_holidays_section(url, page, date_to_get):
params = {
"format":"json",
"action":"parse",
"prop":"sections",
"page":page
}
response = S.get(url=url, params=params)
data = response.json()
sections = data['parse']['sections']
section_number = "0"
for index, value in enumerate(sections):
if value['anchor'] == "Holidays_and_observances":
section_number = index + 1
if url == TEST_URL:
if value['anchor'] == date_to_get:
section_number = index + 1
return section_number
Vytvořte funkci nazvanou get_holidays(...)
, abyste získali svátky v této sekci také pomocí API:Parse , pak zavolejte funkce v list_holidays(...)
:
section_number = get_holidays_section(URL, holidays_date, None)
holidays = get_holidays(URL, holidays_date, section_number)
holidays_html = holidays
Aktualizace odkazů na svátky
Vrácený kód HTML svátků obsahuje interní odkazy, které ukazují na tyto svátky, např. "/wiki/New_Years_Day
".
K těmto odkazům musíme přidat "//en.wikipedia.org
" pomocí jQuery, abychom z nich vytvořili externí odkazy v naší aplikaci a otevřeli je na nové kartě.
Chcete-li to provést, přidejte následující kód do $HOME/holidays-viewer/static/update-links.js
:
$( document ).ready( function() {
$( ".holidays-html a" ).attr( "target", "_blank" );
$( ".holidays-html a" ).attr( "href", function( i, href ) {
return "//en.wikipedia.org" + href;
});
});
Poté přidejte jQuery do layout.html
pomocí:
<script src="//tools-static.wmflabs.org/cdnjs/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="static/update-links.js"></script>
Krok 5: Vyhledejte svátky jiných dat
Chcete-li získat svátky pro jiná data, vytvořte trasu pro vyhledávání, aby se zobrazil formulář, který shromažďuje měsíc a den k hledání:
@APP.route("/search")
def search():
return render_template("search.html", header="Search date")
$HOME/holidays-viewer/templates/search.html |
---|
{% extends "layout.html" %}
{% block content %}
<div class="instructions m-3">
Search for holidays by date
</div>
<div class="base rounded shadow bg-white m-3">
<form class="m-auto" action="/" method="POST">
<fieldset>
<div class="label-field">Select Month</div>
<select class="bg-secondary mb-5 border-0" name="monthList">
<option value="January">January
<option value="February">February
<option value="March">March
<option value="April">April
<option value="May">May
<option value="June">June
<option value="July">July
<option value="August">August
<option value="September">September
<option value="October">October
<option value="November">November
<option value="December">December
</select>
</fieldset>
<fieldset>
<div class="label-field">Select Day</div>
<select class="bg-secondary mb-5 border-0" name="dayList">
<option value="1">1
<option value="2">2
<option value="3">3
<option value="4">4
<option value="5">5
<option value="6">6
<option value="7">7
<option value="8">8
<option value="9">9
<option value="10">10
<option value="11">11
<option value="12">12
<option value="13">13
<option value="14">14
<option value="15">15
<option value="16">16
<option value="17">17
<option value="18">18
<option value="19">19
<option value="20">20
<option value="21">21
<option value="22">22
<option value="23">23
<option value="24">24
<option value="25">25
<option value="26">26
<option value="27">27
<option value="28">28
<option value="29">29
<option value="30">30
<option value="31">31
</select>
</fieldset>
<button type="submit" name="search" class="bg-primary btn btn-submit text-white">Submit</button>
</form>
</div>
{% endblock %}
|
Po odeslání vyhledávacího formuláře aktualizujte holidays_date
na datum, které jste zadali.
Chcete-li to provést, přidejte následující kód do list_holidays(...)
:
if request.method == 'POST' and 'search' in request.form:
search_month = str(request.form.get('monthList'))
search_day = str(request.form.get('dayList'))
holidays_date = search_month +"_"+search_day
Krok 6: Přidání svátku
Stránka, na kterou přidáme nový svátek, je chráněna před úpravami anonymních uživatelů, takže se musíme nejprve přihlásit pomocí API:Login#clientlogin.
Chcete-li přidat svátek, pošlete požadavek na API:Úpravy s datem a popisem svátku. Úprava přidává nové svátky na tuto stránku na Test Wikipedia: Sandbox/Holidays_and_observances. Je to proto, aby se zabránilo přidávání testovacích svátků do anglické Wikipedie.
Po přidání svátků přesměrujte na domovskou stránku, kde se zobrazí také přidané svátky a zformátujte je tučně, abyste je odlišili od skutečných svátků.
Chcete-li načíst zkušební svátky vedle skutečných svátků, aktualizujte list_holidays(...)
:
test_section_number = get_holidays_section(TEST_URL, TEST_PAGE, holidays_date)
test_holidays = get_holidays(TEST_URL, TEST_PAGE, test_section_number)
holidays_html = test_holidays + holidays
flash("Holidays added through this app are in bold")
$HOME/holidays-viewer/templates/login.html |
---|
{% extends "layout.html" %}
{% block content %}
<div class="instructions m-3">
<p>You need to login to Wikipedia in order to add a new holiday
</div>
<div class="base rounded shadow bg-white m-3">
<form class="m-auto" action="/login" method="POST">
<div class="form-group">
<div class="form-field">
<div class="label-field">Username</div>
<input class="bg-secondary mb-5 border-0" name="username">
</div>
<div class="form-field">
<div class="label-field">Password</div>
<input class="bg-secondary mb-5 border-0" type="password" name="password">
</div>
</div>
<button type="submit" name="login" class="bg-primary btn btn-submit text-white">Login</button>
</form>
</div>
{% endblock %}
|
$HOME/holidays-viewer/templates/add.html |
---|
{% extends "layout.html" %}
{% block content %}
<div class="instructions m-3">
<p>Add a new test holiday
</div>
<div class="base rounded shadow bg-white m-3">
<form class="m-auto" action="" method="POST">
<div class="form-group">
<div class="form-field">
<div class="label-field">Date [MMMM dd]</div>
<input class="bg-secondary border-0 mb-5" name="date" placeholder="e.g April 1">
</div>
<div class="form-field">
<div class="label-field">Description</div>
<input class="bg-secondary border-0 mb-5" name="description" placeholder="e.g April fools' day">
</div>
</div>
<button type="submit" name="add" class="bg-primary btn btn-submit text-white">Add</button>
</form>
</div>
{% endblock %}
|
Krok 7: Styling aplikace
Chcete-li do naší aplikace přidat další styl, vytvořte šablonu stylů s názvem style.css
a propojte ji z layout.html
přidáním <link rel="stylesheet" href="static/style.css">
.
$HOME/holidays-viewer/static/style.css |
---|
.content {
width: 420px;
min-height: 100vh;
}
.holidays-html{
overflow-y: auto;
overflow-x: hidden;
max-height: 88vh;
scrollbar-width: thin;
}
.base {
height: 400px;
display: flex;
}
input, select {
width: 300px;
height: 40px;
}
.btn-submit {
width: 300px;
}
.btn {
cursor: pointer;
align-content: center;
background-color: transparent;
}
.bg-primary {
background-color: #36c !important;
}
.bg-primary-dark {
background-color: #2a4b8d !important;
}
.bg-secondary {
background-color: #eaecf0 !important;
}
.header-bar {
height: 48px;
display: flex;
flex: 1;
align-items: center;
}
.filler {
flex-grow: 1;
text-align: center
}
h2 {
display: none;
}
ul {
margin: 5px;
padding: 0;
}
li {
list-style-type: none;
margin-bottom: 4px;
background-color: white;
padding: 8px;
border-radius: 5px;
}
ul li li {
box-shadow: 0 .5rem 1rem rgba(0,0,0,.15);
}
|
Rozvržení aplikace
V tomto okamžiku by struktura vaší aplikace měla být:
$HOME/holidays-viewer ├── templates/ │ └── add.html └── index.html └── layout.html └── login.html └── search.html ├── static/ │ └── style.css └── update-links.js ├── app.py
S app.py
a layout.html
jsou:
$HOME/holidays-viewer/app.py |
---|
#!/usr/bin/python3
"""
app.py
Ukázky MediaWiki API
Prohlížeč svátků: Ukázková aplikace, která načte den svátků z Wikipedie s možností vyhledávat svátky jiných dat a přihlásit se pro přidání nových svátků.
Licence MIT
"""
from datetime import datetime
from flask import Flask, render_template, flash, request, url_for, redirect
import requests
APP = Flask(__name__)
APP.secret_key = 'your_secret_key'
URL = "https://en.wikipedia.org/w/api.php"
TEST_URL = "https://test.wikipedia.org/w/api.php"
TEST_PAGE = "Sandbox/Holidays_and_observances"
S = requests.Session()
IS_LOGGED_IN = False
@APP.route('/', methods=['GET', 'POST'])
@APP.route('/<holidays_date>', methods=['GET', 'POST'])
def list_holidays(holidays_date=None):
""" Uvádí svátky pro aktuální datum nebo vlastní datum
"""
if holidays_date is None:
holidays_date = get_todays_date()
# Update date to a custom date
if request.method == 'POST' and 'search' in request.form:
search_month = str(request.form.get('monthList'))
search_day = str(request.form.get('dayList'))
holidays_date = search_month +"_"+search_day
# Get the section numbers for the holidays on Wikipedia and for those on the test page
section_number = get_holidays_section(URL, holidays_date, None)
test_section_number = get_holidays_section(TEST_URL, TEST_PAGE, holidays_date)
holidays = get_holidays(URL, holidays_date, section_number)
test_holidays = get_holidays(TEST_URL, TEST_PAGE, test_section_number)
holidays_html = test_holidays + holidays
flash('Holidays added through this app are in bold')
return render_template("index.html", header=holidays_date.replace('_', ' '),
holidays_html=holidays_html)
def get_todays_date():
""" Získá aktuální měsíc jako text a aktuální den jako číslo
"""
current_month = datetime.now().strftime('%B')
current_day = datetime.now().strftime('%d')
if current_day.startswith('0'):
current_day = current_day.replace('0', '')
return current_month + "_" + current_day
def get_holidays_section(url, page, date_to_get):
""" Získá číslo sekce pro svátky na Wikipedii a svátky na testovací stránce
"""
params = {
"format":"json",
"action":"parse",
"prop":"sections",
"page":page
}
response = S.get(url=url, params=params)
data = response.json()
sections = data['parse']['sections']
section_number = "0"
for index, value in enumerate(sections):
if value['anchor'] == "Holidays_and_observances":
section_number = index + 1
if url == TEST_URL:
if value['anchor'] == date_to_get:
section_number = index + 1
return section_number
def get_holidays(url, page, section_number):
""" Získá html, který obsahuje svátky
"""
params = {
"format":"json",
"action":"parse",
"prop":"text",
"page": page,
"section": section_number,
"disableeditsection":1
}
response = S.get(url=url, params=params)
data = response.json()
text = data['parse']['text']['*']
return text
@APP.route("/search")
def search():
""" Vyhledá svátky podle vlastních dat
"""
return render_template("search.html", header="Search date")
@APP.route("/login", methods=['GET', 'POST'])
def login():
""" Přihlásí se na Wikipedii
"""
if request.method == 'POST' and 'login' in request.form:
params_0 = {
"action": "query",
"meta": "tokens",
"type": "login",
"format": "json"
}
response = S.get(url=URL, params=params_0)
data = response.json()
login_token = data['query']['tokens']['logintoken']
params_1 = {
"action": "clientlogin",
"username": str(request.form.get('username')),
"password": str(request.form.get('password')),
"loginreturnurl": "http://127.0.0.1:5000/login",
"logintoken": login_token,
"format": "json"
}
response = S.post(url=URL, data=params_1)
data = response.json()
if data['clientlogin']['status'] != 'PASS':
flash('Oops! Something went wrong -- ' + data['clientlogin']['messagecode'])
else:
global IS_LOGGED_IN
IS_LOGGED_IN = True
flash('Login success! Welcome, ' + data['clientlogin']['username'] + '!')
return redirect(url_for('add'))
return render_template("login.html", header="Login")
@APP.route("/add", methods=['GET', 'POST'])
def add():
""" Přidá nový svátek na testovací stránku a přesměrujte se na svátky daného data, abyste zobrazili přidané svátky
"""
if not IS_LOGGED_IN:
return redirect(url_for('login'))
if request.method == 'POST' and 'add' in request.form:
# Wiki markup to format the added holiday's text as a list item and in bold
holiday_text = "* '''" + str(request.form.get('description')) + "'''"
date = str(request.form.get('date'))
params_2 = {
"action": "query",
"meta": "tokens",
"format": "json"
}
response = S.get(url=TEST_URL, params=params_2)
data = response.json()
csrf_token = data['query']['tokens']['csrftoken']
params_4 = {
"action": "edit",
"title": TEST_PAGE,
"token": csrf_token,
"format": "json",
"section": "new",
"sectiontitle": date,
"text": holiday_text,
}
response = S.post(url=TEST_URL, data=params_4)
data = response.json()
if data['edit']['result'] != 'Success':
flash('Oops! Something went wrong -- ' + data['clientlogin']['messagecode'])
else:
flash('New holiday added successfully!')
return redirect(url_for('list_holidays', holidays_date=date.replace(' ', '_')))
return render_template("add.html", header="Add holiday")
if __name__ == "__main__":
APP.run()
|
$HOME/holidays-viewer/templates/layout.html |
---|
<title>Holidays</title>
<link rel="stylesheet" href="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css">
<link rel="stylesheet" href="//tools-static.wmflabs.org/fontcdn/css?family=Material+Icons">
<link rel="stylesheet" href="static/style.css">
<script src="//tools-static.wmflabs.org/cdnjs/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="static/update-links.js"></script>
<div class="content bg-secondary rounded m-auto">
<div class="title-bar bg-primary-dark text-white pl-2">
<small>Holidays and observances</small>
</div>
<div class="header-bar bg-primary text-white shadow p-2">
{% if request.path != url_for('list_holidays') %}
<a class=" btn text-white" href="{{ url_for('list_holidays') }}">
<i class="material-icons">arrow_back</i>
</a>
{% endif %}
<h5>{{header}}</h5>
<div class="filler"></div>
<a class="btn text-white" href="{{ url_for('add') }}">
<i class="material-icons">add</i>
</a>
<a class="btn text-white" href="{{ url_for('search') }}">
<i class="material-icons">search</i>
</a>
</div>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-primary mb-0" role="alert">
{% for message in messages %}
{{ message }}
{% endfor %}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</div>
<script src="//tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.min.js"></script>
|
Další kroky
- Přispějte ukázkovou aplikací, kterou jste vyvinuli pomocí MediaWiki API, do tohoto úložiště ukázek kódu.
Související odkazy
- API:Hlavní stránka — Rychlý průvodce pro MediaWiki Action API.
- API:Analýza wikitextu — Analyzuje obsah stránky a získá výstup.
- API:Úpravy — Upraví stránku.
- API:Přihlášení — Umožňuje přihlášení do wiki.