Utilisateur:Daahbot/scripts/catauto.py
Apparence
#-*- coding: utf-8 -*-
#################################################################
# But : remplacer les catégories de types de mot par la
# catégorisation automatique par les modèles de titres de section
# Sur le Wiktionnaire fr
#
# ASCII pris en compte : alphabets latin et grec
#
# Bot nécessitant pywikipedia
# Note : Certaines parties de code proviennent du replace.py de pywikipedia
# (run de la class LectureRemplacement et main). Ils ont été plus ou moins modifiés.
#
#---------------------
# Paramètres :
#---------------------
# - afficher : mettre oui pour voir les titres défiler (ralenti le processus)
afficher = True
#
commentaire = u"Catégorisation automatique des modèles de titres"
#
################################################################
# Scripts placés dans un dossier différent de pywikipedia
# Séparation des informations dans plusieurs dossiers
# 1 dossier wiktio dans le même répertoire que pywikipedia
# contenant les dossiers data, temp, logs, scripts
from __future__ import generators
import sys, re
sys.path.append('../pywikipedia')
sys.path.append('../data')
import os
import time
# Récupération des données
os.chdir('../data')
from lists import majASCII, asciis, asciisation, ponctascii, ex_lang, exceptions, types, nom_types
# Le fichier lists doit être présent dans le dossier data
# récupération des début et fins
# Un fichier stop
st = open('stop', 'r')
stop = unicode(st.read(), 'utf-8')
stop = stop[:-1]
st.close
# Un fichier start_page
st = open('start_page', 'r')
start_page = unicode(st.read(), 'utf-8')
st.close
os.chdir("..")
# Import des modules pywikipedia
os.chdir('../pywikipedia')
import wikipedia, pagegenerators, catlib, config, watchlist
os.chdir('../wiktio')
# Répertoire de travail
os.chdir('temp')
#-----------------------------------------------------------
class LectureRemplacement:
"""
Un robot qui fait les remplacements
"""
def __init__(self, generator, acceptall = False):
"""
Arguments :
* generator - Générateur qui apporte les pages
* acceptall - Si vrai, pas de demande de confirmation à chaque modification
"""
self.generator = generator
self.acceptall = acceptall
def ChangeArticles(self, text, titre):
"""
1) Ajoute la langue aux titres de types
2) Ajoute l'ASCII aux titres de types
3) Enlève les catégories gérées automatiquement par les titres
"""
cat = False # Présence de catégories ?
# Recherche et isolation des catégories si présentes
try:
text = repl(text, u"[[catégorie:",u"[[Catégorie:") # harmonise
categorie_start = re.search(u"\[\[Catégorie:([^\]]*)\]\]", text).start()
text = text[:categorie_start]+ u"{{=:cat:=}}\n" + text[categorie_start:]
cat = True # catégories présentes
except:
#Affiche(u"Pas de catégories dans cette page")
0
# Séparation des sections de langue
parties = text.split("{{=")
selection = u""
langues = {} # liste des sections de langues
text_final = "" # contriendra l'article final
valeur = {} # type de la section
difference = 0 # différence entre les deux comptes
titrascii = '' # traduction ASCII du titre
askiwi = ''
error = ''
titrascii_commun = ''
askiwi_commun = ''
error_commun = ''
# sections de langues dans l'article
for i, p in enumerate(parties):
p = replex(p, u"^[^\{](.+?=)\|.*?(\}\})", r"\1\2")
trouve = re.search("=}}", p)
if trouve:
fin = trouve.start()
nom = p[:fin]
langues[nom] = "{{=" + p
valeur[i] = nom
else:
langues["0"] = p
valeur[n] = "0"
# types dans chaque section de langue
for i in langues:
if i == "conv" or i == "ine":
continue
if i != ":cat:" and i!="0":
# Cas particuliers ?
if i in ex_lang:
titrascii, askiwi, error = self.NormASCII(titre, i)
elif not titrascii_commun:
titrascii_commun, askiwi_commun, error_commun = self.NormASCII(titre, 0)
titrascii = titrascii_commun
askiwi = askiwi_commun
error = error_commun
else:
titrascii = titrascii_commun
askiwi = askiwi_commun
error = error_commun
typesec = langues[i].split("{{-")
for m, sec in enumerate(typesec):
if m!=0:
sec = "{{-" + sec
trouve = re.search("-.*?\}\}", sec)
tit = ""
if trouve:
tit = sec[:trouve.end()]
# D'une part s'il y a besoin d'ajouter l'ASCII
if askiwi:
for section in types:
# section avec langue avec ASCII (ASCII remplacés)
tit = replex(tit, "(\{\{-" + section +"-\|)"+i+"\|[^}\|=]+(\}\}|num=[0-9]\}\})", r"\1"+i+"|"+titrascii+r"\2")
# section avec langue sans ASCII (ASCII ajouté)
tit = replex(tit, "(\{\{-" + section +"-\|)"+i+"(\}\}|num=[0-9]\}\})", r"\1"+i+"|"+titrascii+r"\2")
# section sans langue avec ASCII (langue ajoutée et ASCII remplacé)
tit = replex(tit, "(\{\{-" + section +"-\|)\|[^}\|=]+(\}\}|num=[0-9]\}\})", r"\1"+i+"|"+titrascii+r"\2")
# section sans langue ni ASCII (langue et ASCII ajoutés)
tit = replex(tit, "(\{\{-" + section +"-)(\}\}|\|num=[0-9]\}\})", r"\1|"+i+"|"+titrascii+r"\2")
# D'autre part, s'il n'y a pas besoin d'ASCII
else:
for section in types:
# section avec langue avec ASCII (ASCII retiré)
tit = replex(tit, "(\{\{-" + section +"-\|)"+i+"\|[^}\|=]+(\}\}|\|num=[0-9]\}\})", r"\1"+i+r"\2")
# section avec langue sans ASCII (langue ajouté)
tit = replex(tit, "(\{\{-" + section +"-\|)"+i+"(\}\}|\|num=[0-9]\}\})", r"\1"+i+r"\2")
# section sans langue avec ASCII (langue ajoutée et ASCII retiré)
tit = replex(tit, "(\{\{-" + section +"-\|)\|[^}\|=]+(\}\}|\|num=[0-9]\}\})", r"\1"+i+r"\2")
# section sans langue ni ASCII (langue ajoutée)
tit = replex(tit, "(\{\{-" + section +"-)(\}\}|\|num=[0-9]\}\})", r"\1|"+i+r"\2")
typesec[m] = tit + sec[trouve.end():]
else:
typesec[m] = sec
langues[i] = ''.join(typesec)
if i == ":cat:": # s'il y a des catégories
langues[i] = replex(langues[i], '^.+?:cat:=\}\}', '')
langues[i] = replex(langues[i], '\n\n+', '')
# Rassemblement des sections de langue
for i in valeur:
text_final += langues[valeur[i]]
# Suppression des catégories grammaticales désormais gérées automatiquement
for ty in nom_types:
text_final = replex(text_final, u"(\r\n+)?\[\[Catégorie:" + ty + " en .+?\]\]\n?", "")
# Suppression des catégories langues seules (=seul rôle ASCII), prises en compte dans les modèles
# Attention ! N'est valable que sur les articles normaux avec au moins un titre normal
# Note : toutes les catégories contenant une minuscule sont considérées comme des langues
text_final = replex(text_final, u"(\r\n+)?\[\[Catégorie:[a-zéèà].+?\|(.+?)\]\]\n?", "")
# Catégories inutiles mais parasites
text_final = replex(text_final, u"(\r\n+)?\[\[Catégorie:[a-zéèà].+?\]\]\n?", "")
# Nettoyage des espaces en trop
text_final = replex(text_final, u"\r?\n\r?\n\r?\n\r?\n?\r?\n?", "\r\n\r\n\r\n")
return text_final, titrascii, error
def NormASCII(self, expression, langue):
"""
Transcrit le terme entré (un nom d'article) en ASCII
pour une catégorisation correcte
"""
expressionA = expression
# Ponctuation
for s, t in ponctascii:
expressionA = replex(expressionA, s, t)
# Transcription en ASCII
if langue:
for s, t in ex_lang[langue]:
expressionA = replex(expressionA, s, t)
else:
for s, t in asciisation:
expressionA = replex(expressionA, s, t)
expressionA = self.minusASCII(expressionA)
expressionB = self.minusASCII(expression)
error = False
askiwi = False
# Vérifie si le titre est déjà en ASCII (pas besoin alors de remplacer)
if expressionA == expressionB:
askiwi = False
error = False
print "Titre déjà en ascii :", expressionA
# Vérifie si le nouveau titre est bien tout en ascii
elif not self.isASCII(expressionA) and not langue:
askiwi = False
error = True
print "Titre changé non ASCII : ", expressionA
else:
askiwi = True
error = False
return expressionA, askiwi, error
def minusASCII(self, terme):
"""
Transforme en minuscules les ASCII uniquement
"""
for s, t in majASCII:
terme = repl(terme, s, t)
return terme
def isASCII(self, text):
"""
Vérifie que le texte contient les caractères ascii autorisés
"""
isasc = True
for x in text:
ascok = False
for a in asciis:
if a == x:
ascok = True
break
if ascok == False:
isasc = False
break
return isasc
def run(self):
"""
Fait fonctionner le truc
"""
Affiche(u"Au boulot !!")
ancien= ""
for page in self.generator:
if page.title() == stop:
Affiche(u""+stop+u" atteint, arrêt du bot.")
break
st = open('../data/start_page', 'w')
st.write(page.title().encode('utf-8'))
st.close
try:
ancien = page.get()
if not page.canBeEdited():
wikipedia.output(u'Saute la page protégée %s' % page.title())
except wikipedia.NoPage:
wikipedia.output(u'Page %s introuvable' % page.title())
except wikipedia.IsRedirectPage:
wikipedia.output(u'La page %s est un redirect' % page.title())
continue
titre = page.title()
continuer = True
for sauf in exceptions:
try:
if re.search(sauf, titre):
continuer = False
break
except:
Affiche("Erreur de " + titre + " avec " + sauf)
wikipedia.output("Erreur de " + titre + " avec " + sauf)
continue
nouveau, ascii, error = self.ChangeArticles(ancien, titre)
if error:
wikipedia.output(u"La page contient des caractères non reconnus : %s | %s" % (titre, ascii))
#conterror = wikipedia.input(u'Continuer ? (o/n)')
#if (conterror == 'n' or conterror == 'N'):
# break
if replex(nouveau, "\r|\n", "") == replex(ancien, "\r|\n", "") or not continuer:
Affiche(u"Pas de changements nécessaires dans %s" % titre)
else:
wikipedia.output('>>> %s <<<' % (titre))
Affiche('%s -> %s' % (titre, ascii))
wikipedia.output(unicode(time.strftime("%Hh%M | %D"), 'utf8'))
wikipedia.showDiff(ancien, nouveau)
# if difference > 0:
# if difference == 1:
# Affiche(u">> Attention : 1 catégorie semble avoir été effacée sans contrepartie apparente !\n")
# else:
# Affiche(u">>Attention : %s catégories semblent avoir été effacées sans contrepartie apparente !\n" % difference)
# if difference < 0:
# difference = -difference
# if difference == 1:
# Affiche(u">> Note : il semble qu'il manquait 1 catégorie.\n")
# else:
# Affiche(u">>Note : il semble qu'il manquait %s catégories.\n" % difference)
if not self.acceptall:
choice = wikipedia.inputChoice(u'Accepter les changements ?', ['Yes', 'No', 'All'], ['y', 'N', 'a'], 'N')
if choice in ['a', 'A']:
self.acceptall = True
if self.acceptall or choice in ['y', 'Y']:
page.put(nouveau, comment = commentaire, minorEdit = True)
Affiche(u"Bien joué !\n")
Affiche(u"Déjà fini ?")
def repl(original_text, old, new):
"""
Outils de remplacement de texte simple (sans expressions régulières)
"""
try:
new_text = old.sub(new, original_text)
except:
new_text = original_text.replace(old, new)
return new_text
def replex(texte, avant, apres):
"""
Outils de remplacement de texte avec expressions régulières
"""
avant = re.compile(avant, re.UNICODE)
texte = avant.sub(apres, texte)
return texte
def Affiche(texte):
"""
N'affiche les commentaires que si "Commentaires" est activé
"""
if afficher:
try:
print unicode(texte, 'utf-8')
except:
print texte
# wikipedia.output(texte)
return
def compte(texte, motif):
"""
Compte le nombre de motif dans le texte
"""
occurence = 0
for n in range(len(texte)-len(motif)):
mot = u""
for x in range(len(motif)):
mot += texte[n+x]
if mot == motif:
occurence +=1
return occurence
def main():
"""
arguments possibles :
-start
-page
-ref
-cat
-from
et :
-all
"""
acceptall = False
namespaces=["0"]
gen = None
PageTitles = []
for arg in sys.argv[1:]:
arg = wikipedia.argHandler(arg, 'catauto')
if arg:
if arg.startswith('-start'):
if len(arg) == 6:
firstPageTitle = wikipedia.input(u'Par quelle page commencer ?')
else:
firstPageTitle = arg[7:]
namespace = wikipedia.Page(wikipedia.getSite(), firstPageTitle).namespace()
gen = pagegenerators.AllpagesPageGenerator(firstPageTitle, namespace)
elif arg.startswith('-from'):
firstPageTitle = start_page
namespace = wikipedia.Page(wikipedia.getSite(), firstPageTitle).namespace()
gen = pagegenerators.AllpagesPageGenerator(firstPageTitle, namespace)
elif arg.startswith('-page'):
if len(arg) == 5:
PageTitles.append(wikipedia.input(u'Quelle page changer ?'))
else:
PageTitles.append(arg[6:])
pages = [wikipedia.Page(wikipedia.getSite(), PageTitle) for PageTitle in PageTitles]
gen = iter(pages)
elif arg.startswith('-ref'):
if len(arg) == 4:
referredPageTitle = wikipedia.input(u'Quelle page sert-elle de référence ?')
else:
referredPageTitle = arg[5:]
referredPage = wikipedia.Page(wikipedia.getSite(), referredPageTitle)
gen = pagegenerators.ReferringPageGenerator(referredPage)
elif arg.startswith('-cat'):
if len(arg) == 4:
categoryname = wikipedia.input(u'Nom de la catégorie : ')
else:
categoryname = arg[5:]
cat = catlib.Category(wikipedia.getSite(), 'Category:%s' % categoryname)
gen = pagegenerators.CategorizedPageGenerator(cat)
if arg.startswith('-all'):
acceptall = True
if not gen:
firstPageTitle = start_page
namespace = wikipedia.Page(wikipedia.getSite(), firstPageTitle).namespace()
gen = pagegenerators.AllpagesPageGenerator(firstPageTitle, namespace)
# syntax error, show help text from the top of this file
#wikipedia.output(__doc__, 'utf-8')
#wikipedia.stopme()
#sys.exit()
preloadingGen = pagegenerators.PreloadingGenerator(gen, pageNumber = 10)
bot = LectureRemplacement(preloadingGen, acceptall)
bot.run()
if __name__ == "__main__":
try:
main()
finally:
wikipedia.output(u"\nFin du processus.\n")
wikipedia.stopme()