Benutzer:Klexibot/Skripte: Unterschied zwischen den Versionen
Aus Klexikon – das Kinderlexikon
(Lagebeschreibung jetzt mit Kontinent, Blacklist um Schottland und Wales erweitert, + Kleinigkeiten) |
(→Anzahl neu erstellter Artikel: update) Markierung: 2017-Quelltext-Bearbeitung |
||
(18 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
== | __TOC__ | ||
== Aktualisierung der Länder-Infoboxen == | |||
=== Pywikibot-Skript === | |||
<syntaxhighlight lang="python"> | <syntaxhighlight lang="python"> | ||
import requests | import requests | ||
Zeile 5: | Zeile 8: | ||
import mwparserfromhell | import mwparserfromhell | ||
import locale | import locale | ||
import datetime | |||
# Testlauf: Ausgabe des Logbuchs in der Konsole ohne Änderungen am Klexikon | |||
dryrun_answer = input ('Nur Testlauf (j/n)? ') | |||
dryrun = dryrun_answer != 'n' | |||
# Verwende deutsches Zahlenformat mit Tausenderpunkt und Dezimalkomma | # Verwende deutsches Zahlenformat mit Tausenderpunkt und Dezimalkomma | ||
locale.setlocale(locale. | locale.setlocale(locale.LC_ALL, 'german') | ||
# Zuordnung von Wikidata-Abfrage-Feldern zu Vorlage-Parametern | # Zuordnung von Wikidata-Abfrage-Feldern zu Vorlage-Parametern | ||
fieldmap = { | fieldmap = { | ||
'Name': 'itemLabel', | |||
'Flagge': 'safeFlaggenDatei', | |||
'Hauptstadt': 'hauptstaedte', | |||
'Amtssprache': 'amtssprachen', | |||
'Staatsoberhaupt': 'oberhaeupter', | |||
'Einwohnerzahl': 'max_ew_in_mio', | |||
'Fläche': 'max_flaeche_rund', | |||
'Lagekarte': 'safeKartenDatei', | |||
'Lagebeschreibung': 'kontinente' | |||
} | } | ||
# Legt fest, welche Länder-Artikel bzw. Vorlagen-Parameter Klexibot nicht ändern soll | # Legt fest, welche Länder-Artikel bzw. Vorlagen-Parameter Klexibot nicht ändern soll | ||
blacklist = { | blacklist = { | ||
'Australien:Staatsoberhaupt', | |||
'Eidgenossenschaft', | |||
'Deutsches_Kaiserreich', | |||
'Schottland', | |||
'England', | |||
'Eswatini:Name', | |||
'Schweiz:Amtssprache', | |||
'St._Kitts_und_Nevis:Staatsoberhaupt', | |||
'St._Lucia:Staatsoberhaupt', | |||
'St._Vincent_und_die_Grenadinen:Staatsoberhaupt', | |||
'Vatikan:Fläche', | |||
'Vatikan:Hauptstadt', | |||
'Wales' | |||
} | } | ||
# Parameter aus dieser Liste werden nur gefüllt, falls bisher kein Wert enthalten war | # Parameter aus dieser Liste werden nur gefüllt, falls bisher kein Wert enthalten war | ||
preserved_values = { | preserved_values = { | ||
'Lagekarte', | |||
'Lagebeschreibung' | |||
} | } | ||
Zeile 41: | Zeile 58: | ||
# Lade Wikidata-Tabelle und speichere sie in "data"-Variable | # Lade Wikidata-Tabelle und speichere sie in "data"-Variable | ||
url = 'https://query.wikidata.org/sparql' | url = 'https://query.wikidata.org/sparql' | ||
with open('infobox_data_query.rq', 'r') as query_file: qry = query_file.read() | with open('infobox_data_query.rq', 'r', encoding="utf-8") as query_file: qry = query_file.read() | ||
r = requests.get(url, params = {'format': 'json', 'query': qry }, headers = { | r = requests.get(url, params = {'format': 'json', 'query': qry }, headers = { | ||
'User-Agent':f'{requests.utils.default_headers()["User-Agent"]} (Klexikon bot by User:Tkarcher)'}) | |||
data = r.json() | data = r.json() | ||
# Initialisiere Logbuch-Eintrag | |||
logheader = f'\n== Logbuch vom {datetime.datetime.now().strftime("%c")} ==\n' | |||
newloghead = '=== Neu angelegte Infoboxen ===\n' | |||
newlogdata = '' | |||
chgloghead = '=== Änderungen an bestehenden Infoboxen ===\n' + \ | |||
'{| class="wikitable sortable"\n! Vorlage\n! Eigenschaft\n! Alter Wert\n! Neuer Wert\n' | |||
chglogdata = '' | |||
chglogfoot = '|}\n' | |||
# Gehe Wikidata-Tabelle Zeile für Zeile durch | # Gehe Wikidata-Tabelle Zeile für Zeile durch | ||
for item in data['results']['bindings']: | for item in data['results']['bindings']: | ||
title = item['titel_im_klexikon']['value'] | |||
# Ignoriere Artikel, die in der Ausschlußliste enthalten sind | |||
if title not in blacklist: | |||
# Öffne Vorlagen-Seite oder lege sie neu an | |||
page = pywikibot.Page(site, f'Vorlage:Infobox_{title}') | |||
code = mwparserfromhell.parse(page.text) | |||
# Ersetze Seiteninhalt mit {{Infobox Land}}, falls nicht vorhanden | |||
if not code.filter_templates(matches = lambda n: n.name.matches ('Infobox Land')): | |||
code = mwparserfromhell.parse('{{Infobox Land\n}}') | |||
newlogdata += f'* [[Vorlage:Infobox {title}]]\n' | |||
# Fülle alle Vorlagen-Felder | |||
for prop, field in fieldmap.items(): | |||
# Ignoriere Vorlagen-Parameter, die leer oder in der Ausschlußliste enthalten sind | |||
if field in item and f'{title}:{prop}' not in blacklist: | |||
# Ignoriere auch Parameter, die nicht überschrieben werden sollen | |||
if not ( | |||
prop in preserved_values and | |||
code.filter_templates()[0].has(prop) and | |||
code.filter_templates()[0].get(prop).value.strip() != ''): | |||
oldval = code.filter_templates()[0].get(prop).value.strip() if code.filter_templates()[0].has(prop) else '' | |||
val = item[field]['value'] | |||
if prop == 'Einwohnerzahl': | |||
ew = float(val) | |||
if round(ew) > 1: | |||
val = f'etwa {locale.format_string("%.0f", ew, grouping = True)} [[Million]]en' | |||
elif ew > 0.9: | |||
val = f'etwa 1 [[Million]]' | |||
else: | |||
val = f'etwa {locale.format_string("%.0f", ew * 1000000, grouping = True)}' | |||
elif prop == 'Fläche': | |||
val = f'etwa {locale.format_string("%i", int(val), grouping = True)} [[Meter|Quadratkilometer]]' | |||
elif prop == 'Staatsoberhaupt': | |||
if 'oberhaupt_bezeichnung' in item: | |||
val = f'{item["oberhaupt_bezeichnung"]["value"]} {val}' | |||
elif prop == 'Lagebeschreibung': | |||
val = f'Wo das Land in {val} liegt' | |||
# Speichere die Änderung nur, wenn sie aus mehr besteht als | |||
# einer geänderten Sortierreihenfolge in der Auslistung | |||
# (SPARQL 1.1 erlaubt kein ORDER BY in GROUP_CONCATs) | |||
if sorted (val) != sorted (oldval): | |||
code.filter_templates()[0].add (f' {prop} ', f' {val}\n', preserve_spacing = False) | |||
if not newlogdata.endswith (f'* [[Vorlage:Infobox {title}]]\n'): | |||
chglogdata += f'|- \n| [[Vorlage:Infobox {title}]]\n| {prop}\n| {oldval}\n| {val}\n' | |||
# Speichere die Änderungen, falls vorhanden, und verschiebe | |||
# Artikel ggf. zurück in Kategorie "ungeprüfte Infobox" | |||
if (page.text != str(code)) and not dryrun: | |||
# Speichere Vorlage | |||
page.text = str(code) | |||
page.save('Automatische Anlage der Länder-Infobox') | |||
# Öffne Länderartikel | |||
page = pywikibot.Page(site, title) | |||
code = mwparserfromhell.parse(page.text) | |||
# Binde Länder-Infobox ein, falls noch nicht geschehen | |||
# Mit "_" und " " wegen https://github.com/earwig/mwparserfromhell/issues/216 | |||
if not code.filter_templates(matches = lambda n: | |||
n.name.matches ({f'Infobox_{title}', f'Infobox {title}'})): | |||
code = mwparserfromhell.parse(f'{{{{Infobox_{title}}}}}\n{str(code)}') | |||
# Lösche [[Kategorie:Artikel mit geprüfter Infobox]], falls vorhanden | |||
if '[[Kategorie:Artikel mit geprüfter Infobox]]' in str(code): | |||
code.remove ('[[Kategorie:Artikel mit geprüfter Infobox]]') | |||
# Füge [[Kategorie:Artikel mit ungeprüfter Infobox]] ein, falls noch nicht geschehen | |||
if '[[Kategorie:Artikel mit ungeprüfter Infobox]]' not in str(code): | |||
code.append ('\n[[Kategorie:Artikel mit ungeprüfter Infobox]]') | |||
# Speichere Länderartikel | |||
page.text = str(code) | |||
page.save('Automatische Einbindung der Länder-Infobox') | |||
# Dokumentiere Änderungen in Logbuch | |||
log = logheader \ | |||
+ newloghead + (newlogdata if newlogdata != '' else 'Es wurden keine neuen Infoboxen angelegt.\n') \ | |||
+ chgloghead + (chglogdata if chglogdata != '' else '|- \n| colspan=4 | Es wurden keine bestehenden Daten geändert.\n') + chglogfoot | |||
if dryrun: | |||
print (log) | |||
else: | |||
page = pywikibot.Page(site, 'Benutzer:Klexibot/Logbuch') | |||
page.text += log | |||
page.save('Logbuch aktualisiert') | |||
</syntaxhighlight> | |||
=== Wikidata-SPARQL-Abfrage === | |||
<syntaxhighlight lang="sparql"> | |||
#Länder-Infoboxen im Klexikon | |||
SELECT | |||
?item | |||
?itemLabel | |||
(MAX(?ew_in_millionen) AS ?max_ew_in_mio) | |||
(GROUP_CONCAT(DISTINCT (IF(BOUND(?asklextitel),CONCAT('[[',?asklextitel,'|',?amtssprachenLabel,']]'),?amtssprachenLabel)); SEPARATOR=", ") AS ?amtssprachen) | |||
(MAX(?flaeche_rund) AS ?max_flaeche_rund) | |||
(GROUP_CONCAT(DISTINCT (IF(BOUND(?hsklextitel),CONCAT('[[',REPLACE(?hsklextitel, "_", " "),']]'),?hauptstadtLabel)); SEPARATOR=", ") AS ?hauptstaedte) | |||
(GROUP_CONCAT(DISTINCT (COALESCE (?oberhaupt_titel_ausnahme, ?oberhaupt_bezLabel)); SEPARATOR=", ") AS ?oberhaupt_bezeichnung) | |||
(GROUP_CONCAT(DISTINCT (IF(BOUND(?ohklextitel),CONCAT('[[',REPLACE(?ohklextitel, "_", " "),']]'),?oberhauptLabel)); SEPARATOR=", ") AS ?oberhaeupter) | |||
(GROUP_CONCAT(DISTINCT (CONCAT('[[',?kontinentLabel,']]')); SEPARATOR=" und ") AS ?kontinente) | |||
?safeFlaggenDatei | |||
?safeKartenDatei | |||
?titel_im_klexikon | |||
WHERE | |||
{ | |||
?item p:P31 [ps:P31 wd:Q6256]. # Finde alle Länder | |||
?item wdt:P6573 ?titel_im_klexikon. # die es im Klexikon gibt | |||
?item wdt:P1082 ?ewzahl. # und zeige ihre Einwohnerzahl | |||
BIND (STR(ROUND(?ewzahl / 1000) / 1000) AS ?ew_in_millionen) # in Millionen | |||
?item wdt:P2046 ?flaeche. # ihre Fläche | |||
BIND (STR(IF(?flaeche > 9999, ROUND(?flaeche / 1000) * 1000,IF(?flaeche > 999, ROUND(?flaeche / 100) * 100,ROUND(?flaeche)))) AS ?flaeche_rund) # gerundet | |||
?item wdt:P37 ?amtssprache. # ihre Amtssprache | |||
# ?article schema:about ?amtssprache. # Zeige aber nur die bekannteren Amtssprachen, d.h. solche | |||
# ?article schema:inLanguage "de" . # für die ein deutschsprachiger Wikipedia-Artikel existiert | |||
OPTIONAL {?amtssprache wdt:P6573 ?asklextitel} | |||
OPTIONAL { # Optional wg. Vatikanstadt | |||
?item wdt:P36 ?hauptstadt. # ihre Hauptstädte | |||
OPTIONAL {?hauptstadt wdt:P6573 ?hsklextitel} | |||
} | |||
?item wdt:P35 ?oberhaupt. # das Staatsoberhaupt | |||
OPTIONAL {?oberhaupt wdt:P6573 ?ohklextitel} | |||
OPTIONAL { | |||
?item wdt:P1906/wdt:P279* ?oberhaupt_titel. | |||
FILTER (?oberhaupt_titel IN ( # einschränken auf bekannte / kinderverständliche Titel | |||
wd:Q30461, # Präsident | |||
wd:Q2304859, # Souverän | |||
wd:Q7645115, # Oberster Führer | |||
wd:Q166382, # Emir | |||
wd:Q683337, # Kofürst von Andorra | |||
wd:Q258045, # Capitano Reggente | |||
wd:Q844944 # Präsidium von Bosnien und Herzegowina | |||
)) | |||
OPTIONAL { | |||
?oberhaupt_titel wdt:P2521 ?oberhaupt_titel_weiblich. | |||
FILTER (LANG(?oberhaupt_titel_weiblich) = "de"). | |||
} | |||
} | |||
OPTIONAL {?oberhaupt wdt:P21 ?geschlecht.} | |||
BIND (IF (BOUND(?oberhaupt_titel_weiblich) && BOUND(?geschlecht) && (?geschlecht = wd:Q6581072), | |||
IF(STR(?oberhaupt_titel_weiblich) = "Souveränin", wd:Q16511993, ?oberhaupt_titel_weiblich), | |||
IF(?oberhaupt_titel = wd:Q2304859, wd:Q12097, ?oberhaupt_titel)) AS ?oberhaupt_bez | |||
) | |||
OPTIONAL { # Länderspezifische Titel | |||
VALUES (?item ?oberhaupt_titel_ausnahme) { | |||
(wd:Q794 "Religionsführer") # Iran | |||
(wd:Q17 "[[Kaiser]]") # Japan | |||
(wd:Q40 "Bundespräsident") # Österreich | |||
(wd:Q183 "Bundespräsident") # Deutschland | |||
(wd:Q32 "Großherzog") # Luxemburg | |||
(wd:Q237 "[[Papst]]") # Vatikan | |||
(wd:Q347 "Fürst") # Liechtenstein | |||
(wd:Q683 "Häuptling") #Samoa | |||
} | |||
} | |||
?item wdt:P41 ?flagge. | |||
BIND(REPLACE(wikibase:decodeUri(STR(?flagge)), "http://commons.wikimedia.org/wiki/Special:FilePath/", "") AS ?flaggenDatei). | |||
BIND(REPLACE(?flaggenDatei, " ", "_") AS ?safeFlaggenDatei) | |||
?item wdt:P30 ?kontinent_alt. | |||
OPTIONAL { | |||
?item wdt:P361*/wdt:P706*/wdt:P361* wd:Q27611 | |||
BIND (wd:Q29876 AS ?mittelamerika) | |||
} | |||
BIND (COALESCE(?mittelamerika, ?kontinent_alt) AS ?kontinent) | |||
OPTIONAL { # Lagekarte: Grünes Land auf dem Globus | |||
?item p:P242 ?p_karte1. | |||
?p_karte1 pq:P195 wd:Q21167586. | |||
?p_karte1 ps:P242 ?karte1. | |||
} | |||
OPTIONAL { # Lagekarte: Rotes Land auf dem Globus | |||
?item p:P242 ?p_karte2. | |||
?p_karte2 pq:P195 wd:Q47008743. | |||
?p_karte2 ps:P242 ?karte2. | |||
} | |||
# Nimm Globus, falls vorhanden, sonst 2:1-Ausschnitt | |||
BIND(REPLACE(wikibase:decodeUri(STR(COALESCE(?karte1, ?karte2))), "http://commons.wikimedia.org/wiki/Special:FilePath/", "") AS ?kartenDatei). | |||
BIND(REPLACE(?kartenDatei, " ", "_") AS ?safeKartenDatei) | |||
SERVICE wikibase:label { | |||
bd:serviceParam wikibase:language "[AUTO_LANGUAGE],de". | |||
?item rdfs:label ?itemLabel. | |||
?amtssprache rdfs:label ?amtssprachenLabel. | |||
?hauptstadt rdfs:label ?hauptstadtLabel. | |||
?oberhaupt_bez rdfs:label ?oberhaupt_bezLabel. | |||
?oberhaupt rdfs:label ?oberhauptLabel. | |||
?kontinent rdfs:label ?kontinentLabel. | |||
} | |||
} | |||
GROUP BY ?item ?itemLabel ?safeFlaggenDatei ?safeKartenDatei ?titel_im_klexikon | |||
ORDER BY ?itemLabel | |||
</syntaxhighlight> | |||
== Validierungen / Qualitätssicherung == | |||
=== Artikel mit Klammerfehlern === | |||
<syntaxhighlight lang="python"> | |||
import pywikibot | |||
opening = '{[' | |||
closing = '}]' | |||
mapping = dict(('{}', '[]')) | |||
pages_with_unmatched_brackets = [] | |||
site = pywikibot.Site() | |||
for page in site.allpages(namespace = ""): | |||
queue = [] | |||
if page.title() != 'ß': # Komische Sache! Die Seite gibt's, aber dann irgendwie doch nicht... | |||
for letter in page.text: | |||
if letter in opening: | |||
queue.append(mapping[letter]) | |||
elif letter in closing: | |||
if not queue or letter != queue.pop(): | |||
pages_with_unmatched_brackets.append(page.title()) | |||
if queue: pages_with_unmatched_brackets.append(page.title()) | |||
print ('[['+ ']], [['.join(list(dict.fromkeys(pages_with_unmatched_brackets))) + ']]') | |||
</syntaxhighlight> | |||
=== Artikel mit Links in Dateinamen === | |||
<syntaxhighlight lang="python"> | |||
import re | |||
import pywikibot | |||
pattern_1 = re.compile(r'atei\:[^\|]*\[\[') | |||
pattern_2 = re.compile(r'allery[\s\S]+\n[^\|]*\[\[[\s\S]+allery') | |||
pages_with_links_in_filename = [] | |||
site = pywikibot.Site() | |||
for page in site.allpages(namespace = ""): | |||
queue = [] | |||
if page.title() != 'ß': # Komische Sache! Die Seite gibt's, aber dann irgendwie doch nicht... | |||
if str(pattern_1.search(page.text)) != 'None' or str(pattern_2.search(page.text)) != 'None': | |||
pages_with_links_in_filename.append(page.title()) | |||
print ('[['+ ']], [['.join(list(dict.fromkeys(pages_with_links_in_filename))) + ']]') | |||
</syntaxhighlight> | |||
=== Wörter mit Wikilink im zweiten Teil === | |||
<syntaxhighlight lang="python"> | |||
import re | |||
import pywikibot | |||
pattern_1 = re.compile(r'\W(\w+\[\[[^\]]+\]\])') | |||
matches = '' | |||
site = pywikibot.Site() | |||
for page in site.allpages(namespace = ""): | |||
if page.title() != 'ß': # Komische Sache! Die Seite gibt's, aber dann irgendwie doch nicht... | |||
match = pattern_1.search(page.text) | |||
if match: matches += '* [[' + page.title() + ']]: "' + match.group(1) + '"\n' | |||
print (matches) | |||
</syntaxhighlight> | |||
=== Artikel mit 3 oder mehr Bildern in der Einleitung === | |||
<syntaxhighlight lang="python"> | |||
import re | |||
import pywikibot | |||
pattern_5 = re.compile(r'^\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:') | |||
pattern_4 = re.compile(r'^\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:') | |||
pattern_3 = re.compile(r'^\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:') | |||
matches = [] | |||
site = pywikibot.Site() | |||
for page in site.allpages(namespace = ""): | |||
if page.title() != 'ß': | |||
if pattern_5.search(page.text): | |||
matches.append("| [[" + page.title() + "]] || 5\n") | |||
elif pattern_4.search(page.text): | |||
matches.append("| [[" + page.title() + "]] || 4\n") | |||
elif pattern_3.search(page.text): | |||
matches.append("| [[" + page.title() + "]] || 3\n") | |||
print ('{| class="wikitable sortable"\n! Artikel !! Bilder zu Beginn\n|-\n'+ '|-\n'.join(matches) + '|}') | |||
</syntaxhighlight> | |||
== Statistik == | |||
=== Anzahl neu erstellter Artikel === | |||
<syntaxhighlight lang="python"> | |||
import pywikibot | |||
new_pages = {} | |||
target_user = pywikibot.User(pywikibot.Site(), "Thomas Karcher") | |||
for page, oldid, ts, comment in target_user.contributions(total = 5000, showMinor = False, namespaces = [0]): | |||
if page.oldest_revision.user == target_user.username: | |||
new_pages[page.title()] = {'title': page.title(), 'timestamp': page.oldest_revision.timestamp} | |||
print (target_user.username + ' hat ' + str(len(new_pages)) + ' Artikel erstellt:') | |||
print ('{| class = "wikitable sortable"\n! Artikel !! Erstellt am') | |||
for p in new_pages.values(): print ("|-\n| [[%s]] || %s"%(p['title'], p['timestamp'])) | |||
print ('|}') | |||
</syntaxhighlight> | </syntaxhighlight> |
Aktuelle Version vom 28. April 2021, 23:40 Uhr
Aktualisierung der Länder-Infoboxen
Pywikibot-Skript
import requests
import pywikibot
import mwparserfromhell
import locale
import datetime
# Testlauf: Ausgabe des Logbuchs in der Konsole ohne Änderungen am Klexikon
dryrun_answer = input ('Nur Testlauf (j/n)? ')
dryrun = dryrun_answer != 'n'
# Verwende deutsches Zahlenformat mit Tausenderpunkt und Dezimalkomma
locale.setlocale(locale.LC_ALL, 'german')
# Zuordnung von Wikidata-Abfrage-Feldern zu Vorlage-Parametern
fieldmap = {
'Name': 'itemLabel',
'Flagge': 'safeFlaggenDatei',
'Hauptstadt': 'hauptstaedte',
'Amtssprache': 'amtssprachen',
'Staatsoberhaupt': 'oberhaeupter',
'Einwohnerzahl': 'max_ew_in_mio',
'Fläche': 'max_flaeche_rund',
'Lagekarte': 'safeKartenDatei',
'Lagebeschreibung': 'kontinente'
}
# Legt fest, welche Länder-Artikel bzw. Vorlagen-Parameter Klexibot nicht ändern soll
blacklist = {
'Australien:Staatsoberhaupt',
'Eidgenossenschaft',
'Deutsches_Kaiserreich',
'Schottland',
'England',
'Eswatini:Name',
'Schweiz:Amtssprache',
'St._Kitts_und_Nevis:Staatsoberhaupt',
'St._Lucia:Staatsoberhaupt',
'St._Vincent_und_die_Grenadinen:Staatsoberhaupt',
'Vatikan:Fläche',
'Vatikan:Hauptstadt',
'Wales'
}
# Parameter aus dieser Liste werden nur gefüllt, falls bisher kein Wert enthalten war
preserved_values = {
'Lagekarte',
'Lagebeschreibung'
}
# Anmeldung beim Klexikon
site = pywikibot.Site()
# Lade Wikidata-Tabelle und speichere sie in "data"-Variable
url = 'https://query.wikidata.org/sparql'
with open('infobox_data_query.rq', 'r', encoding="utf-8") as query_file: qry = query_file.read()
r = requests.get(url, params = {'format': 'json', 'query': qry }, headers = {
'User-Agent':f'{requests.utils.default_headers()["User-Agent"]} (Klexikon bot by User:Tkarcher)'})
data = r.json()
# Initialisiere Logbuch-Eintrag
logheader = f'\n== Logbuch vom {datetime.datetime.now().strftime("%c")} ==\n'
newloghead = '=== Neu angelegte Infoboxen ===\n'
newlogdata = ''
chgloghead = '=== Änderungen an bestehenden Infoboxen ===\n' + \
'{| class="wikitable sortable"\n! Vorlage\n! Eigenschaft\n! Alter Wert\n! Neuer Wert\n'
chglogdata = ''
chglogfoot = '|}\n'
# Gehe Wikidata-Tabelle Zeile für Zeile durch
for item in data['results']['bindings']:
title = item['titel_im_klexikon']['value']
# Ignoriere Artikel, die in der Ausschlußliste enthalten sind
if title not in blacklist:
# Öffne Vorlagen-Seite oder lege sie neu an
page = pywikibot.Page(site, f'Vorlage:Infobox_{title}')
code = mwparserfromhell.parse(page.text)
# Ersetze Seiteninhalt mit {{Infobox Land}}, falls nicht vorhanden
if not code.filter_templates(matches = lambda n: n.name.matches ('Infobox Land')):
code = mwparserfromhell.parse('{{Infobox Land\n}}')
newlogdata += f'* [[Vorlage:Infobox {title}]]\n'
# Fülle alle Vorlagen-Felder
for prop, field in fieldmap.items():
# Ignoriere Vorlagen-Parameter, die leer oder in der Ausschlußliste enthalten sind
if field in item and f'{title}:{prop}' not in blacklist:
# Ignoriere auch Parameter, die nicht überschrieben werden sollen
if not (
prop in preserved_values and
code.filter_templates()[0].has(prop) and
code.filter_templates()[0].get(prop).value.strip() != ''):
oldval = code.filter_templates()[0].get(prop).value.strip() if code.filter_templates()[0].has(prop) else ''
val = item[field]['value']
if prop == 'Einwohnerzahl':
ew = float(val)
if round(ew) > 1:
val = f'etwa {locale.format_string("%.0f", ew, grouping = True)} [[Million]]en'
elif ew > 0.9:
val = f'etwa 1 [[Million]]'
else:
val = f'etwa {locale.format_string("%.0f", ew * 1000000, grouping = True)}'
elif prop == 'Fläche':
val = f'etwa {locale.format_string("%i", int(val), grouping = True)} [[Meter|Quadratkilometer]]'
elif prop == 'Staatsoberhaupt':
if 'oberhaupt_bezeichnung' in item:
val = f'{item["oberhaupt_bezeichnung"]["value"]} {val}'
elif prop == 'Lagebeschreibung':
val = f'Wo das Land in {val} liegt'
# Speichere die Änderung nur, wenn sie aus mehr besteht als
# einer geänderten Sortierreihenfolge in der Auslistung
# (SPARQL 1.1 erlaubt kein ORDER BY in GROUP_CONCATs)
if sorted (val) != sorted (oldval):
code.filter_templates()[0].add (f' {prop} ', f' {val}\n', preserve_spacing = False)
if not newlogdata.endswith (f'* [[Vorlage:Infobox {title}]]\n'):
chglogdata += f'|- \n| [[Vorlage:Infobox {title}]]\n| {prop}\n| {oldval}\n| {val}\n'
# Speichere die Änderungen, falls vorhanden, und verschiebe
# Artikel ggf. zurück in Kategorie "ungeprüfte Infobox"
if (page.text != str(code)) and not dryrun:
# Speichere Vorlage
page.text = str(code)
page.save('Automatische Anlage der Länder-Infobox')
# Öffne Länderartikel
page = pywikibot.Page(site, title)
code = mwparserfromhell.parse(page.text)
# Binde Länder-Infobox ein, falls noch nicht geschehen
# Mit "_" und " " wegen https://github.com/earwig/mwparserfromhell/issues/216
if not code.filter_templates(matches = lambda n:
n.name.matches ({f'Infobox_{title}', f'Infobox {title}'})):
code = mwparserfromhell.parse(f'{{{{Infobox_{title}}}}}\n{str(code)}')
# Lösche [[Kategorie:Artikel mit geprüfter Infobox]], falls vorhanden
if '[[Kategorie:Artikel mit geprüfter Infobox]]' in str(code):
code.remove ('[[Kategorie:Artikel mit geprüfter Infobox]]')
# Füge [[Kategorie:Artikel mit ungeprüfter Infobox]] ein, falls noch nicht geschehen
if '[[Kategorie:Artikel mit ungeprüfter Infobox]]' not in str(code):
code.append ('\n[[Kategorie:Artikel mit ungeprüfter Infobox]]')
# Speichere Länderartikel
page.text = str(code)
page.save('Automatische Einbindung der Länder-Infobox')
# Dokumentiere Änderungen in Logbuch
log = logheader \
+ newloghead + (newlogdata if newlogdata != '' else 'Es wurden keine neuen Infoboxen angelegt.\n') \
+ chgloghead + (chglogdata if chglogdata != '' else '|- \n| colspan=4 | Es wurden keine bestehenden Daten geändert.\n') + chglogfoot
if dryrun:
print (log)
else:
page = pywikibot.Page(site, 'Benutzer:Klexibot/Logbuch')
page.text += log
page.save('Logbuch aktualisiert')
Wikidata-SPARQL-Abfrage
#Länder-Infoboxen im Klexikon
SELECT
?item
?itemLabel
(MAX(?ew_in_millionen) AS ?max_ew_in_mio)
(GROUP_CONCAT(DISTINCT (IF(BOUND(?asklextitel),CONCAT('[[',?asklextitel,'|',?amtssprachenLabel,']]'),?amtssprachenLabel)); SEPARATOR=", ") AS ?amtssprachen)
(MAX(?flaeche_rund) AS ?max_flaeche_rund)
(GROUP_CONCAT(DISTINCT (IF(BOUND(?hsklextitel),CONCAT('[[',REPLACE(?hsklextitel, "_", " "),']]'),?hauptstadtLabel)); SEPARATOR=", ") AS ?hauptstaedte)
(GROUP_CONCAT(DISTINCT (COALESCE (?oberhaupt_titel_ausnahme, ?oberhaupt_bezLabel)); SEPARATOR=", ") AS ?oberhaupt_bezeichnung)
(GROUP_CONCAT(DISTINCT (IF(BOUND(?ohklextitel),CONCAT('[[',REPLACE(?ohklextitel, "_", " "),']]'),?oberhauptLabel)); SEPARATOR=", ") AS ?oberhaeupter)
(GROUP_CONCAT(DISTINCT (CONCAT('[[',?kontinentLabel,']]')); SEPARATOR=" und ") AS ?kontinente)
?safeFlaggenDatei
?safeKartenDatei
?titel_im_klexikon
WHERE
{
?item p:P31 [ps:P31 wd:Q6256]. # Finde alle Länder
?item wdt:P6573 ?titel_im_klexikon. # die es im Klexikon gibt
?item wdt:P1082 ?ewzahl. # und zeige ihre Einwohnerzahl
BIND (STR(ROUND(?ewzahl / 1000) / 1000) AS ?ew_in_millionen) # in Millionen
?item wdt:P2046 ?flaeche. # ihre Fläche
BIND (STR(IF(?flaeche > 9999, ROUND(?flaeche / 1000) * 1000,IF(?flaeche > 999, ROUND(?flaeche / 100) * 100,ROUND(?flaeche)))) AS ?flaeche_rund) # gerundet
?item wdt:P37 ?amtssprache. # ihre Amtssprache
# ?article schema:about ?amtssprache. # Zeige aber nur die bekannteren Amtssprachen, d.h. solche
# ?article schema:inLanguage "de" . # für die ein deutschsprachiger Wikipedia-Artikel existiert
OPTIONAL {?amtssprache wdt:P6573 ?asklextitel}
OPTIONAL { # Optional wg. Vatikanstadt
?item wdt:P36 ?hauptstadt. # ihre Hauptstädte
OPTIONAL {?hauptstadt wdt:P6573 ?hsklextitel}
}
?item wdt:P35 ?oberhaupt. # das Staatsoberhaupt
OPTIONAL {?oberhaupt wdt:P6573 ?ohklextitel}
OPTIONAL {
?item wdt:P1906/wdt:P279* ?oberhaupt_titel.
FILTER (?oberhaupt_titel IN ( # einschränken auf bekannte / kinderverständliche Titel
wd:Q30461, # Präsident
wd:Q2304859, # Souverän
wd:Q7645115, # Oberster Führer
wd:Q166382, # Emir
wd:Q683337, # Kofürst von Andorra
wd:Q258045, # Capitano Reggente
wd:Q844944 # Präsidium von Bosnien und Herzegowina
))
OPTIONAL {
?oberhaupt_titel wdt:P2521 ?oberhaupt_titel_weiblich.
FILTER (LANG(?oberhaupt_titel_weiblich) = "de").
}
}
OPTIONAL {?oberhaupt wdt:P21 ?geschlecht.}
BIND (IF (BOUND(?oberhaupt_titel_weiblich) && BOUND(?geschlecht) && (?geschlecht = wd:Q6581072),
IF(STR(?oberhaupt_titel_weiblich) = "Souveränin", wd:Q16511993, ?oberhaupt_titel_weiblich),
IF(?oberhaupt_titel = wd:Q2304859, wd:Q12097, ?oberhaupt_titel)) AS ?oberhaupt_bez
)
OPTIONAL { # Länderspezifische Titel
VALUES (?item ?oberhaupt_titel_ausnahme) {
(wd:Q794 "Religionsführer") # Iran
(wd:Q17 "[[Kaiser]]") # Japan
(wd:Q40 "Bundespräsident") # Österreich
(wd:Q183 "Bundespräsident") # Deutschland
(wd:Q32 "Großherzog") # Luxemburg
(wd:Q237 "[[Papst]]") # Vatikan
(wd:Q347 "Fürst") # Liechtenstein
(wd:Q683 "Häuptling") #Samoa
}
}
?item wdt:P41 ?flagge.
BIND(REPLACE(wikibase:decodeUri(STR(?flagge)), "http://commons.wikimedia.org/wiki/Special:FilePath/", "") AS ?flaggenDatei).
BIND(REPLACE(?flaggenDatei, " ", "_") AS ?safeFlaggenDatei)
?item wdt:P30 ?kontinent_alt.
OPTIONAL {
?item wdt:P361*/wdt:P706*/wdt:P361* wd:Q27611
BIND (wd:Q29876 AS ?mittelamerika)
}
BIND (COALESCE(?mittelamerika, ?kontinent_alt) AS ?kontinent)
OPTIONAL { # Lagekarte: Grünes Land auf dem Globus
?item p:P242 ?p_karte1.
?p_karte1 pq:P195 wd:Q21167586.
?p_karte1 ps:P242 ?karte1.
}
OPTIONAL { # Lagekarte: Rotes Land auf dem Globus
?item p:P242 ?p_karte2.
?p_karte2 pq:P195 wd:Q47008743.
?p_karte2 ps:P242 ?karte2.
}
# Nimm Globus, falls vorhanden, sonst 2:1-Ausschnitt
BIND(REPLACE(wikibase:decodeUri(STR(COALESCE(?karte1, ?karte2))), "http://commons.wikimedia.org/wiki/Special:FilePath/", "") AS ?kartenDatei).
BIND(REPLACE(?kartenDatei, " ", "_") AS ?safeKartenDatei)
SERVICE wikibase:label {
bd:serviceParam wikibase:language "[AUTO_LANGUAGE],de".
?item rdfs:label ?itemLabel.
?amtssprache rdfs:label ?amtssprachenLabel.
?hauptstadt rdfs:label ?hauptstadtLabel.
?oberhaupt_bez rdfs:label ?oberhaupt_bezLabel.
?oberhaupt rdfs:label ?oberhauptLabel.
?kontinent rdfs:label ?kontinentLabel.
}
}
GROUP BY ?item ?itemLabel ?safeFlaggenDatei ?safeKartenDatei ?titel_im_klexikon
ORDER BY ?itemLabel
Validierungen / Qualitätssicherung
Artikel mit Klammerfehlern
import pywikibot
opening = '{['
closing = '}]'
mapping = dict(('{}', '[]'))
pages_with_unmatched_brackets = []
site = pywikibot.Site()
for page in site.allpages(namespace = ""):
queue = []
if page.title() != 'ß': # Komische Sache! Die Seite gibt's, aber dann irgendwie doch nicht...
for letter in page.text:
if letter in opening:
queue.append(mapping[letter])
elif letter in closing:
if not queue or letter != queue.pop():
pages_with_unmatched_brackets.append(page.title())
if queue: pages_with_unmatched_brackets.append(page.title())
print ('[['+ ']], [['.join(list(dict.fromkeys(pages_with_unmatched_brackets))) + ']]')
Artikel mit Links in Dateinamen
import re
import pywikibot
pattern_1 = re.compile(r'atei\:[^\|]*\[\[')
pattern_2 = re.compile(r'allery[\s\S]+\n[^\|]*\[\[[\s\S]+allery')
pages_with_links_in_filename = []
site = pywikibot.Site()
for page in site.allpages(namespace = ""):
queue = []
if page.title() != 'ß': # Komische Sache! Die Seite gibt's, aber dann irgendwie doch nicht...
if str(pattern_1.search(page.text)) != 'None' or str(pattern_2.search(page.text)) != 'None':
pages_with_links_in_filename.append(page.title())
print ('[['+ ']], [['.join(list(dict.fromkeys(pages_with_links_in_filename))) + ']]')
Wörter mit Wikilink im zweiten Teil
import re
import pywikibot
pattern_1 = re.compile(r'\W(\w+\[\[[^\]]+\]\])')
matches = ''
site = pywikibot.Site()
for page in site.allpages(namespace = ""):
if page.title() != 'ß': # Komische Sache! Die Seite gibt's, aber dann irgendwie doch nicht...
match = pattern_1.search(page.text)
if match: matches += '* [[' + page.title() + ']]: "' + match.group(1) + '"\n'
print (matches)
Artikel mit 3 oder mehr Bildern in der Einleitung
import re
import pywikibot
pattern_5 = re.compile(r'^\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:')
pattern_4 = re.compile(r'^\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:')
pattern_3 = re.compile(r'^\[\[Datei\:.+\n?\[\[Datei\:.+\n?\[\[Datei\:')
matches = []
site = pywikibot.Site()
for page in site.allpages(namespace = ""):
if page.title() != 'ß':
if pattern_5.search(page.text):
matches.append("| [[" + page.title() + "]] || 5\n")
elif pattern_4.search(page.text):
matches.append("| [[" + page.title() + "]] || 4\n")
elif pattern_3.search(page.text):
matches.append("| [[" + page.title() + "]] || 3\n")
print ('{| class="wikitable sortable"\n! Artikel !! Bilder zu Beginn\n|-\n'+ '|-\n'.join(matches) + '|}')
Statistik
Anzahl neu erstellter Artikel
import pywikibot
new_pages = {}
target_user = pywikibot.User(pywikibot.Site(), "Thomas Karcher")
for page, oldid, ts, comment in target_user.contributions(total = 5000, showMinor = False, namespaces = [0]):
if page.oldest_revision.user == target_user.username:
new_pages[page.title()] = {'title': page.title(), 'timestamp': page.oldest_revision.timestamp}
print (target_user.username + ' hat ' + str(len(new_pages)) + ' Artikel erstellt:')
print ('{| class = "wikitable sortable"\n! Artikel !! Erstellt am')
for p in new_pages.values(): print ("|-\n| [[%s]] || %s"%(p['title'], p['timestamp']))
print ('|}')