Szerkesztő:BinBot/portalsablon.py
Portálsablonok terítésére való bot. Ebben a formában a filmművészetportál sablonját teríti a film infoboxot tartalmazó lapokra, de a portál nevét és a lapgenerátort átírva könnyen alkalmazható más feladatra is. A megbeszéléseket egyelőre lásd lent, amíg nem archiválódnak.
A bot a Wikipédia:Szócikkek felépítése alapján – ha még nincs portálsablon – ezeket keresi a cikk utolsó szakaszában:
- Testvérprojektek sablonjai: {{commons, {{wiki (de nem {{wikia), {{társproj, {{testvérproj (lehet nagybetűvel is, és folytatódhat bárhogy – nincs megbízható felsorolás, elnevezési minta vagy kategória, amelynek alapján tökéletesen felismerhető lenne az összes)
- Csonksablonok: {{csonk}} vagy {{csonk-valami}} (megtalálja a csonk-dátumosakat is)
- Kategóriák: {{DEFAULTSORT:, [[Kategória: vagy [[Category: (lehet kisbetűs is)
Ha bármelyiket megtalálja, akkor elépakolja a portált. Ha többet is, akkor a legelső elé. Ha egyiket sem, akkor a cikk végére. (Interwikikkel 2017-ben már nem foglalkoztam, ne legyenek szócikkben.) Ha ezek közül valamelyiket eleve nem a javasolt felépítés szerinti helyen találja, arról nem a bot tehet, és nem is tud ezen segíteni. Mivel a WP:FELÉP egy gépi elemzésre alkalmatlan szerkezetet javasol, ennél pontosabb algoritmust nehéz lenne észszerű munkával és mérhető haszonnal kitalálni.
Meglévő portálsablonba (bármelyik szakaszban), ha még van benne hely, új argumentumként írja bele a portált, ha már megtelt, akkor rögtön utána új sablonba; ez esetben nem vizsgálja a meglévő sablon helyét. Ha a sablon elemzése során hibát talál, akkor megjegyzést ír a vitalapra, és nem illeszti be az új portált a sablonba.
Forráskód[szerkesztés]
# -*- coding: utf-8 -*-
"""
Distributes portal template over several pages.
Written for Hungarian Wikipedia. Compat version.
Wikipédia:Botgazdák üzenőfala#Portálsablonok
TODO: making the generator more flexible, accepting the portal as parameter.
TODO: implementing multisession processing (continue where we stopped).
TODO: recognizing redirecting portals in the template.
TODO: search for a second template instead of creating new if the first one
is full (not really likely case).
"""
# (C)(D)(E)(F)(G)(A)(H)(C) Bináris, 2017
import sys, re
import wikipedia as pywikibot
import pagegenerators
from binbotutils import munkanaplo # Private
site = pywikibot.getSite()
stat = munkanaplo.emptystat() # Private
# All the lines that begin with 'stat' are for my administratve use only.
class PortalBot:
"""
This bot takes a pagegenerator, goes through the yielded pages,
determines if the portal template with the given portal exist in it,
and places the template or the new argument if neccessary.
Parameters:
gen - a pagegenerator that yields content pages (namespace=0)
portal - the required portal name (unicode, without namespace prefix)
ending - portal ending, see https://hu.wikipedia.org/wiki/Sablon:Port%C3%A1l
"""
def __init__(self, gen, portal, ending):
self.gen = gen
self.portal = portal
self.ending = ending
self.portalWithEnding = portal
if ending:
self.portalWithEnding += '|' + ending
self.portalRegex = regex(portal) # For searching this very portal
self.generalPortalRegex = re.compile(ur'(?is)\{\{portál\s*\|(.*?)\}\}')
sisterProjectTemplates = re.compile(
ur'(?i)\{\{(commons|wiki(?!a)|t(árs|estvér)proj).*?\}\}')
stubTemplates = re.compile(
ur'(?i)\{\{csonk(-.+?)?\}\}')
categories = re.compile(
ur'(?i)(\{\{DEFAULTSORT|\[\[(Kategória|Category)):')
self.followers = [sisterProjectTemplates, stubTemplates, categories]
def run(self):
sumbase = u'[[user:BinBot/portalsablon.py|' \
u'Portálsablonok automatikus terítése bottal.]] '
counter = 0 # Avoid black screen where nothing happens for a long time.
for page in self.gen:
counter += 1
if not (counter % 20):
print 'Counter=', counter
# An ugly workaround for continuing after a break:
# if counter < 2940:
# continue
try:
text = page.get()
except pywikibot.NoPage:
pywikibot.output(page.title() + " doesn't exist.")
stat['err'] += 1
continue
if self.portalRegex.search(text):
stat['skip'] += 1
# pywikibot.output(u'Rendben van: ' + page.title())
continue
try:
if re.search(ur'(?i)\{\{\s*portál\s*\|',text):
pywikibot.output(u'Van portálsablon: ' + page.title())
newtext = self.addPortalToExisting(text)
summary = sumbase + \
u' A cikkben már volt portálsablon, új argumentum kell.'
else:
pywikibot.output(u'Nincs portálsablon: ' + page.title())
newtext = self.addNewPortalTemplate(page, text)
summary = sumbase + \
u' A cikkben még nem volt portálsablon.'
# The following lines may be used for testing.
# This is the point where a manual mode may be implemented.
# pywikibot.showDiff(text, newtext)
# answer = raw_input(u'Mehet? ')
# if answer != 'y':
# print u'Tovább.'
# continue
# print 'Mentve!'
try:
page.put(newtext, summary)
stat['moda'] += 1
except:
stat['err'] += 1
except self.MalformedPortalTemplate:
stat['skip'] += 1
try:
self.malformedTemplateWarning(page)
stat['moda'] += 1
except:
pywikibot.output(u'Nem sikerült menteni a vitalapot: %s' %
page.title())
stat['err'] += 1
def addPortalToExisting(self, text):
match = self.generalPortalRegex.search(text)
if not match:
raise self.MalformedPortalTemplate
tpl = match.group()
tplParams = match.group(1)
pipes = tplParams.count('|')
if '|||' in tpl or tpl.endswith('||}}') or pipes > 11:
raise self.MalformedPortalTemplate
if tpl.endswith('|}}') and (pipes % 2 == 0):
raise self.MalformedPortalTemplate
if pipes > 9:
# This template is full, it has already 6 arguments.
portalTemplate = u'\n{{portál|%s}}' % self.portalWithEnding
text = text.replace(tpl, tpl + portalTemplate, 1)
return text
# We are ready to insert the new portal into the existing template.
# But we still have to decide if the last existing has a suffix or not.
if pipes % 2:
newPart = '|' + self.portalWithEnding
else:
newPart = '||' + self.portalWithEnding
newTemplate = tpl[:-2] + newPart + '}}'
newtext = text.replace(tpl, newTemplate, 1)
return newtext
def addNewPortalTemplate(self, page, text):
portalTemplate = u'{{portál|%s}}\n' % self.portalWithEnding
# The portal template should fit in the last section.
sectionlist = page.getSections()
try:
lastSectionByteOffset = sectionlist[-1][0]
except IndexError:
lastSectionByteOffset = 0 # No sections in the page.
beginning = text[:lastSectionByteOffset]
footer = text[lastSectionByteOffset:]
# pywikibot.output(footer)
# Try to determine the right place for the template regarding
# [[Wikipédia:Szócikkek felépítése]].
placeBeforeThis = ''
minpos = sys.maxint # Upon porting to Python 3 this must be changed to sys.maxsize!
for regex in self.followers:
match = regex.search(footer)
# We need the first match in the order of actual page content,
# not the supposed order of parts.
if match and match.start() < minpos:
minpos = match.start()
placeBeforeThis = match.group()
if placeBeforeThis:
footer = footer.replace(
placeBeforeThis, portalTemplate + placeBeforeThis, 1)
else:
footer += '\n' + portalTemplate[:-1]
# pywikibot.output(footer)
# Go home
newtext = beginning + footer
return newtext
def malformedTemplateWarning(self, page):
talk = page.toggleTalkPage()
try:
text = talk.get() + '\n\n'
except pywikibot.NoPage:
text = ''
text += u'==Hibás portálsablon?==\n'
text += (u"A(z) ''%s'' portál beillesztése " % self.portal.title())
text += u'közben a bot hibásan formázott portálsablont talált a '
text += u'cikkben. Ez fakadhat a szócikk vagy a bot hibájából is. ~~~~'
summary = u'/* Hibás portálsablon? */ (új szakasz)'
talk.put(text, summary, minorEdit=False, botflag=False)
class MalformedPortalTemplate(pywikibot.Error):
"""Indicates a malformed template that can not be handled by the bot."""
class Generator:
"""
A page generator that may be parametrized.
@param portal: If given, the generator checks the page for existance
of the given portal, and yields only pages without it.
@type portal: unicode
"""
def __init__(self, portal=None):
self.portal = portal
def pageGenerator(self):
# Variable pass: how to identify articles.
# Currently the behaviour is wired in.
templatePage = pywikibot.Page(site, u'Sablon:Film infobox')
return pagegenerators.ReferringPageGenerator(
templatePage, onlyTemplateInclusion=True)
def pageFilter(self):
# Constant part: filter to main namespace, excluding pages with
# existing template.
gen = self.pageGenerator()
gen = pagegenerators.NamespaceFilterPageGenerator(gen, namespaces=[0])
if not self.portal:
return gen
else:
return self.hasNoTemplate(gen)
def hasNoTemplate(self, gen):
for page in gen:
text = page.get()
if not regex(self.portal).search(text):
yield page
def regex(portal):
"""Regex for searching the given portal as a template argument."""
r = ur'(?is)\{\{\s*portál\s*\|[^}]*?%s[^}]*?\}\}' % portal
return re.compile(r)
def naploz(portal): # Private
log = munkanaplo(
u'Portálsablonok terítése',
u'user:BinBot/portalsablon.py',
portal.title(),
u'Portál:%s' % portal.title(),
stat,
u'automatikus',
)
log.run()
def main():
global portal
# Give the name in lower case.
# Currently wired in together with the generator.
portal = u'filmművészet'
ending = ''
# Check if the portal exists.
p = pywikibot.Page(site, u'Portál:' + portal)
if not p.exists():
pywikibot.output(u'Nincs ilyen portál: %s.' % portal)
return
# genbot = Generator(portal)
# For now, don't check for performance reasons, we should load the page
# and get the text later anyway. Pre-checking is useful if we collect
# candidates in a separate run.
genbot = Generator()
bot = PortalBot(genbot.pageFilter(), portal, ending)
bot.run()
if __name__ == '__main__':
try:
main()
finally:
naploz(portal) # Private
pywikibot.stopme()
Ideiglenes tárolóhely, amíg archiválódnak a szakaszok[szerkesztés]
Erről a témáról egy másik lapon (is) folyik megbeszélés.
|
Erről a témáról egy másik lapon (is) folyik megbeszélés.
|
Erről a témáról egy másik lapon (is) folyik megbeszélés.
|
Erről a témáról egy másik lapon (is) folyik megbeszélés.
|