Skripte: Unterschied zwischen den Versionen

Aus Klexikon - Das Freie Kinderlexikon
Wechseln zu: Navigation, Suche
(+Logbuch, +Kleinigkeiten)
(+besseres Logbuch, +Testlauf-Option, +Kleinigkeiten)
Zeile 6: Zeile 6:
 
import locale
 
import locale
 
import datetime
 
import datetime
 +
 +
# dryrun = True # Ausgabe des Logbuchs in der Konsole ohne Änderungen am Klexikon
 +
dryrun = False # Änderungen werden direkt im Klexikon gespeichert.
  
 
# Verwende deutsches Zahlenformat mit Tausenderpunkt und Dezimalkomma
 
# Verwende deutsches Zahlenformat mit Tausenderpunkt und Dezimalkomma
Zeile 12: Zeile 15:
 
# Zuordnung von Wikidata-Abfrage-Feldern zu Vorlage-Parametern
 
# Zuordnung von Wikidata-Abfrage-Feldern zu Vorlage-Parametern
 
fieldmap = {
 
fieldmap = {
    'Name': 'itemLabel',
+
'Name': 'itemLabel',
    'Flagge': 'safeFlaggenDatei',
+
'Flagge': 'safeFlaggenDatei',
    'Hauptstadt': 'hauptstaedte',
+
'Hauptstadt': 'hauptstaedte',
    'Amtssprache': 'amtssprachen',
+
'Amtssprache': 'amtssprachen',
    'Staatsoberhaupt': 'oberhaeupter',
+
'Staatsoberhaupt': 'oberhaeupter',
    'Einwohnerzahl': 'max_ew_in_mio',
+
'Einwohnerzahl': 'max_ew_in_mio',
    'Fläche': 'max_flaeche_rund',
+
'Fläche': 'max_flaeche_rund',
    'Lagekarte': 'safeKartenDatei',
+
'Lagekarte': 'safeKartenDatei',
    'Lagebeschreibung': 'kontinente'
+
'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 = {
    'Eidgenossenschaft',
+
'Eidgenossenschaft',
    'Deutsches Kaiserreich',
+
'Deutsches Kaiserreich',
    'Schottland',
+
'Schottland',
    'Wales'
+
'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',
+
'Lagekarte',
    'Lagebeschreibung'
+
'Lagebeschreibung'
 
}
 
}
  
Zeile 44: Zeile 47:
 
with open('infobox_data_query.rq', 'r') as query_file: qry = query_file.read()
 
with open('infobox_data_query.rq', 'r') 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)'})
+
'User-Agent':f'{requests.utils.default_headers()["User-Agent"]} (Klexikon bot by User:Tkarcher)'})
 
data = r.json()
 
data = r.json()
  
# Initialisiere Log-Tabelle
+
# Initialisiere Logbuch-Eintrag
logheader = f'== Änderungen vom {datetime.datetime.now().strftime("%c")} ==\n' + \
+
logheader = f'== Logbuch vom {datetime.datetime.now().strftime("%c")} ==\n'
    '{| class="wikitable sortable"\n! Vorlage\n! Eigenschaft\n! Alter Wert\n! Neuer Wert\n'
+
newloghead = '=== Neu angelegte Infoboxen ===\n'
logcontent = ''
+
newlogdata = ''
logfooter = '|}\n\n'
+
chgloghead = '=== Änderungen an bestehenden Infoboxen ===\n' + \
 +
'{| class="wikitable sortable"\n! Vorlage\n! Eigenschaft\n! Alter Wert\n! Neuer Wert\n'
 +
chglogdata = ''
 +
chglogfoot = '|}\n\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']
+
title = item['titel_im_klexikon']['value']
  
    # Ignoriere Artikel, die in der Ausschlußliste enthalten sind
+
# Ignoriere Artikel, die in der Ausschlußliste enthalten sind
    if title not in blacklist:
+
if title not in blacklist:
  
        # Öffne Vorlagen-Seite oder lege sie neu an
+
# Öffne Vorlagen-Seite oder lege sie neu an
        page = pywikibot.Page(site, f'Vorlage:Infobox_{title}')
+
page = pywikibot.Page(site, f'Vorlage:Infobox_{title}')
        code = mwparserfromhell.parse(page.text)
+
code = mwparserfromhell.parse(page.text)
  
        # Ersetze Seiteninhalt mit {{Infobox Land}}, falls nicht vorhanden
+
# Ersetze Seiteninhalt mit {{Infobox Land}}, falls nicht vorhanden
        if not code.filter_templates(matches = lambda n: n.name.matches ('Infobox Land')):
+
if not code.filter_templates(matches = lambda n: n.name.matches ('Infobox Land')):
            code = mwparserfromhell.parse('{{Infobox Land\n}}')
+
code = mwparserfromhell.parse('{{Infobox Land\n}}')
 +
newlogdata += f'* [[Vorlage:Infobox {title}]]\n'
  
        # Fülle alle Vorlagen-Felder
+
# Fülle alle Vorlagen-Felder
        for prop, field in fieldmap.items():
+
for prop, field in fieldmap.items():
  
            # Ignoriere Vorlagen-Parameter, die leer oder in der Ausschlußliste enthalten sind
+
# Ignoriere Vorlagen-Parameter, die leer oder in der Ausschlußliste enthalten sind
            if field in item and f'{title}:{prop}' not in blacklist:
+
if field in item and f'{title}:{prop}' not in blacklist:
  
                # Ignoriere auch Parameter, die nicht überschrieben werden sollen
+
# Ignoriere auch Parameter, die nicht überschrieben werden sollen
                if not (
+
if not (
                    prop in preserved_values and
+
prop in preserved_values and
                    code.filter_templates()[0].has(prop) and
+
code.filter_templates()[0].has(prop) and
                    code.filter_templates()[0].get(prop).value != ''):
+
code.filter_templates()[0].get(prop).value.strip() != ''):
  
                    oldval = 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']
+
val = item[field]['value']
                    if prop == 'Einwohnerzahl':
+
if prop == 'Einwohnerzahl':
                        ew = float(val)
+
ew = float(val)
                        if ew > 1:
+
if ew > 1:
                            val = f'etwa {locale.format_string("%.0f", ew, grouping = True)} [[Million]]en'
+
val = f'etwa {locale.format_string("%.0f", ew, grouping = True)} [[Million]]en'
                        else:
+
else:
                            val = f'etwa {locale.format_string("%.0f", ew * 1000000, grouping = True)}'
+
val = f'etwa {locale.format_string("%.0f", ew * 1000000, grouping = True)}'
                    elif prop == 'Fläche':
+
elif prop == 'Fläche':
                        val = f'etwa {locale.format_string("%i", int(val), grouping = True)} [[Meter|Quadratkilometer]]'
+
val = f'etwa {locale.format_string("%i", int(val), grouping = True)} [[Meter|Quadratkilometer]]'
                    elif prop == 'Staatsoberhaupt':
+
elif prop == 'Staatsoberhaupt':
                        if 'oberhaupt_bezeichnung' in item:
+
if 'oberhaupt_bezeichnung' in item:
                            val = f'{item["oberhaupt_bezeichnung"]["value"]} {val}'
+
val = f'{item["oberhaupt_bezeichnung"]["value"]} {val}'
                    elif prop == 'Lagebeschreibung':
+
elif prop == 'Lagebeschreibung':
                        val = f'Wo das Land in {val} liegt'
+
val = f'Wo das Land in {val} liegt'
  
                    # Speichere die Änderung nur, wenn sie aus mehr besteht als
+
# Speichere die Änderung nur, wenn sie aus mehr besteht als
                    # einer geänderten Sortierreihenfolge in der Auslistung
+
# einer geänderten Sortierreihenfolge in der Auslistung
                    # (SPARQL 1.1 erlaubt kein ORDER BY in GROUP_CONCATs)
+
# (SPARQL 1.1 erlaubt kein ORDER BY in GROUP_CONCATs)
                    if sorted (val) != sorted (oldval):
+
if sorted (val) != sorted (oldval):
                        code.filter_templates()[0].add (f' {prop} ', f' {val}\n', preserve_spacing = False)
+
code.filter_templates()[0].add (f' {prop} ', f' {val}\n', preserve_spacing = False)
                        logcontent += f'|- \n| [[Infobox {title}]]\n| {prop}\n| {oldval}\n| {val}\n'
+
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
+
# Speichere die Änderungen, falls vorhanden, und verschiebe
        # Artikel ggf. zurück in Kategorie "ungeprüfte Infobox"
+
# Artikel ggf. zurück in Kategorie "ungeprüfte Infobox"
        if page.text != str(code):
+
if (page.text != str(code)) and not dryrun:
  
            # Speichere Vorlage
+
# Speichere Vorlage
            page.text = str(code)
+
page.text = str(code)
            page.save('Automatische Anlage der Länder-Infobox (erste 12 Länder)')
+
page.save('Automatische Anlage der Länder-Infobox')
  
            # Öffne Länderartikel
+
# Öffne Länderartikel
            page = pywikibot.Page(site, title)
+
page = pywikibot.Page(site, title)
            code = mwparserfromhell.parse(page.text)
+
code = mwparserfromhell.parse(page.text)
  
            # Binde Länder-Infobox ein, falls noch nicht geschehen
+
# Binde Länder-Infobox ein, falls noch nicht geschehen
            # Mit "_" und " " wegen https://github.com/earwig/mwparserfromhell/issues/216
+
# Mit "_" und " " wegen https://github.com/earwig/mwparserfromhell/issues/216
            if not code.filter_templates(matches = lambda n:
+
if not code.filter_templates(matches = lambda n:
                n.name.matches ({f'Infobox_{title}', f'Infobox {title}'})):
+
n.name.matches ({f'Infobox_{title}', f'Infobox {title}'})):
                code = mwparserfromhell.parse(f'{{{{Infobox_{title}}}}}\n{str(code)}')
+
code = mwparserfromhell.parse(f'{{{{Infobox_{title}}}}}\n{str(code)}')
  
            # Lösche [[Kategorie:Artikel mit geprüfter Infobox]], falls vorhanden
+
# Lösche [[Kategorie:Artikel mit geprüfter Infobox]], falls vorhanden
            if '[[Kategorie:Artikel mit geprüfter Infobox]]' in str(code):
+
if '[[Kategorie:Artikel mit geprüfter Infobox]]' in str(code):
                code.remove ('[[Kategorie:Artikel mit geprüfter Infobox]]')
+
code.remove ('[[Kategorie:Artikel mit geprüfter Infobox]]')
  
            # Füge [[Kategorie:Artikel mit ungeprüfter Infobox]] ein, falls noch nicht geschehen
+
# Füge [[Kategorie:Artikel mit ungeprüfter Infobox]] ein, falls noch nicht geschehen
            if '[[Kategorie:Artikel mit ungeprüfter Infobox]]' not in str(code):
+
if '[[Kategorie:Artikel mit ungeprüfter Infobox]]' not in str(code):
                code.append ('\n[[Kategorie:Artikel mit ungeprüfter Infobox]]')
+
code.append ('\n[[Kategorie:Artikel mit ungeprüfter Infobox]]')
  
            # Speichere Länderartikel
+
# Speichere Länderartikel
            page.text = str(code)
+
page.text = str(code)
            page.save('Automatische Einbindung der Länder-Infobox (erste 12 Länder)')
+
page.save('Automatische Einbindung der Länder-Infobox')
  
 
# Dokumentiere Änderungen in Logbuch
 
# Dokumentiere Änderungen in Logbuch
page = pywikibot.Page(site, 'Benutzer:Klexibot/Logbuch')
+
log = \
page.text += logheader + logcontent + logfooter
+
logheader + \
page.save('Logbuch aktualisiert')
+
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>
 
</syntaxhighlight>

Version vom 12. April 2019, 22:39 Uhr

Skript zur Aktualisierung der Länder-Infoboxen

import requests
import pywikibot
import mwparserfromhell
import locale
import datetime
 
# dryrun = True # Ausgabe des Logbuchs in der Konsole ohne Änderungen am Klexikon
dryrun = False # Änderungen werden direkt im Klexikon gespeichert.
 
# 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 = {
	'Eidgenossenschaft',
	'Deutsches Kaiserreich',
	'Schottland',
	'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') 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'== 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\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 ew > 1:
							val = f'etwa {locale.format_string("%.0f", ew, grouping = True)} [[Million]]en'
						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')