Χρήστης:Lou bot/catauto/script

Από Βικιλεξικό
Μετάβαση στην πλοήγηση Πήδηση στην αναζήτηση
#-*- coding: utf-8 -*-

#################################################################
# Σκοπός: αλλαγή των κατηγοριών προτύπων του λόγου
# με αυτόματη κατηγοριοποίηση χάρη στα πρότυπα τίτλων τομέα
# στο ελληνικό Βικιλεξικό
#
# Χρησιμοποιούνται ASCII για το ελληνικό και λατινικό αλφάβητο
#
# Το bot χρειάζεται την pywikipedia
# Σημείωση: μερικά κομμάτια του κώδικα προέρχονται 
# από το replace.py της pywikipedia
# (run της class LectureRemplacement και main),
# αλλά έχουν τροποποιηθεί ελαφρά.
#
#---------------------
# Παράμετροι:
#---------------------
# - show : εάν 'true', οι τίτλοι παρουσιάζονται
# (αλλά το script γίνεται πιο αργό)
show = True
#
commentaire = u"Αυτόματη κατηγοριοποίηση των προτύπων των τίτλων"
#
##################################################################
# Τα scripts  τοποθετούνται σε διαφορετικό directory
# από την pywikipedia
# Οι πληροφορίες χωρίζονται σε πολλά directory
# 1 directory ΒΛ στο ίδιο directory με την pywikipedia
# περιέχει τα directory data, temp, logs, scripts
from __future__ import generators
import sys, re
sys.path.append('../pywikipedia')
sys.path.append('../data')
import os
import time

# Ανάκτηση των δεδομένων
os.chdir('../data')
from lists import majASCII, asciis, asciisation, ponctascii, ex_lang, exceptions, types, nom_types
# Το αρχείο lists πρέπει να είναι παρόν στο directory data

# Ανάκτηση αρχής και τέλους
# Αρχείο stop
st = open('stop', 'r')
stop = unicode(st.read(), 'utf-8')
stop = stop[:-1]
st.close
# Αρχείο start_page
st = open('start_page', 'r')
start_page = unicode(st.read(), 'utf-8')
st.close
os.chdir("..")

# Εισαγωγή των modules της pywikipedia
os.chdir('../pywikipedia')
import wikipedia, pagegenerators, catlib, config, watchlist
os.chdir('../wiktio')

# Directory εργασίας
os.chdir('temp')

#-----------------------------------------------------------
class LectureRemplacement:
        """
        Ρομπότ που κάνει αντικατάσταση κειμένου
        """

        def __init__(self, generator, acceptall = False):
                """
                Παράμετροι:
                        * generator - Γεννήτρια που φέρνει τις σελίδες
                        * acceptall  - Εάν "True", δεν ρωτά επιβεβαίωση σε κάθε αλλαγή
                """
                
                self.generator = generator
                self.acceptall = acceptall

        def ChangeArticles(self, text, titre):
                """
                1) Προσθέτει τη γλώσσα στους τίτλους μερών του λόγου
                2) Προσθέτει το ASCII στους τίτλους μερών του λόγου
                3) Αφαιρεί τις κατηγορίες που δημιουργήθηκαν αυτόματα από τους τίτλους
                """
                cat = False # Επαληθεύει την παρουσία κατηγοριών

                # Αναζητεί και απομονώνει τις κατηγορίες, εάν αυτές υπάρχουν
                try:
                        text = repl(text, u"[[κατηγορία:",u"[[Κατηγορία:") # εναρμονίζει
                        category_start = re.search(u"\[\[Κατηγορία:([^\]]*)\]\]", text).start()
                        text = text[:category_start]+ u"{{=:cat:=}}\n" + text[category_start:]
                        cat = True # Υπάρχουν κατηγορίες
                except:
                        #Affiche(u"Δεν υπάρχουν κατηγορίες σε αυτή τη σελίδα")
                        0
                
                # Διαχωρισμός τομέων γλώσσας
                parties = text.split("{{=")
                selection = u""
                langues = {}                                                            # λίστα τομέων γλωσσών
                text_final = ""                                                      # θα περιέχει το τελικό άρθρο
                valeur = {}                                                                 # τύπος του τομέα
                nombre_titre = 0                                                        # μετρά τους τίτλους τομέων
                n = 0                                                                      # μετρά τις κατηγορίες
                difference = 0                                                    # διαφορά ανάμεσα στις δύο μετρήσεις
                titrascii = ''   # μετάφραση του τίτλου σε ASCII
                askiwi = ''
                error = ''
                titrascii_commun = ''
                askiwi_commun = ''
                error_commun = ''
                
                # τομείς γλωσσών στο άρθρο
                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[n] = nom
                        else:
                                langues["0"] = p
                                valeur[n] = "0"
                        n+=1
                # τύποι σε κάθε τομέα γλώσσας
                for z, i in enumerate(langues):
                        if i == "conv" or i == "ine":
                                continue
                        if i <> ":cat:" and i<>"0":
                                # Cas particuliers ?
                                if i in ex_lang.keys():
                                        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:
                                                                # τομέας με γλώσσα και ASCII (αντικαθιστά το ASCII)
                                                                tit = replex(tit, "(\{\{-" + section +"-\|)"+i+"\|[^}\|=]+(\}\}|num=[0-9]\}\})", r"\1"+i+"|"+titrascii+r"\2")
                                                                # τομέας με γλώσσα χωρίς ASCII (προσθέτει το ASCII)
                                                                tit = replex(tit, "(\{\{-" + section +"-\|)"+i+"(\}\}|num=[0-9]\}\})", r"\1"+i+"|"+titrascii+r"\2")
                                                                # τομέας χωρίς γλώσσα αλλά με ASCII (προσθέτει τη γλώσσα, αντικαθιστά το ASCII)
                                                                tit = replex(tit, "(\{\{-" + section +"-\|)\|[^}\|=]+(\}\}|num=[0-9]\}\})", r"\1"+i+"|"+titrascii+r"\2")
                                                                # τομέας χωρίς γλώσσα ούτε ASCII (προσθέτει γλώσσα και ASCII)
                                                                tit = replex(tit, "(\{\{-" + section +"-)(\}\}|\|num=[0-9]\}\})", r"\1|"+i+"|"+titrascii+r"\2")

                                        # Διαφορετικά, εάν δεν χρειάζεται ASCII
                                                else:
                                                        for section in types:
                                                                # τομέας με γλώσσα και ASCII (αφαιρεί το ASCII)
                                                                tit = replex(tit, "(\{\{-" + section +"-\|)"+i+"\|[^}\|=]+(\}\}|\|num=[0-9]\}\})", r"\1"+i+r"\2")
                                                                # τομέας με γλώσσα χωρίς ASCII (προσθέτει τη γλώσσα)
                                                                tit = replex(tit, "(\{\{-" + section +"-\|)"+i+"(\}\}|\|num=[0-9]\}\})", r"\1"+i+r"\2")
                                                                # τομέας χωρίς γλώσσα αλλά με ASCII (προσθέτει γλώσσα, αφαιρεί ASCII)
                                                                tit = replex(tit, "(\{\{-" + section +"-\|)\|[^}\|=]+(\}\}|\|num=[0-9]\}\})", r"\1"+i+r"\2")
                                                                # τομέας χωρίς γλώσσα ούτε ASCII (προσθέτει τη γλώσσα)
                                                                tit = replex(tit, "(\{\{-" + section +"-)(\}\}|\|num=[0-9]\}\})", r"\1|"+i+r"\2")
                                                typesec[m] = tit + sec[trouve.end():]
                                        else:
                                                typesec[m] = sec
                                                                
                                        langues[i] = '' ;
                                        for n in range(len(typesec)):
                                                langues[i] += typesec[n]
                                                
                        if i == ":cat:": # εάν υπάρχουν κατηγορίες
                                langues[i] = replex(langues[i], '^.+?:cat:=\}\}', '')
                                langues[i] = replex(langues[i], '\n\n+', '')
                
                # Συγκεντρώνει τους τομείς γλώσσας
                for z, i in enumerate(valeur):
                        text_final += langues[valeur[i]]

                # Αφαιρεί τις γραμματικές κατηγορίες που γίνονται πια αυτόματα
                for ty in nom_types:
                        text_final = replex(text_final, u"(\r\n+)?\[\[Κατηγορία:" + ty + " en .+?\]\]\n?", "")

                # Suppression des catégories langues seules (=seul rôle ASCII), prises en compte dans les modèles
        # {{Προσοχή! Δεν ισχύει παρά στα κανονικά άρθρα με τουλάχιστον έναν κανονικό τίτλο
        # Note : toutes les catégories contenant une minuscule sont considérées comme des langues
                text_final = replex(text_final, u"(\r\n+)?\[\[Κατηγορία:[a-zéèà].+?\|(.+?)\]\]\n?", "")

        # Άχρηστες και παρασιτικές κατηγορίες
                text_final = replex(text_final, u"(\r\n+)?\[\[Κατηγορία:[a-zéèà].+?\]\]\n?", "")

                # Καθαρίζει τα πρόσθετα κενά
                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):
                """
                Μεταγράφει τον όρο (όνομα του άρθρου) σε ASCII
                για μια σωστή κατηγοριοποίηση
                """
                expressionA = expression
                
        # Στίξη
                for s, t in ponctascii:
                        expressionA = replex(expressionA, s, t)

        # Μεταγραφή σε 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
                # Επαληθεύει εάν ο τίτλος είναι ήδη σε ASCII (άρα δεν χρειάζεται αντικατάσταση)
                if expressionA == expressionB:
                        askiwi = False
                        error = False
                        print "Titre déjà en ascii :", expressionA
                # Επαληθεύει εάν ο νέος τίτλος είναι ολόκληρος σε ascii
                elif not self.isASCII(expressionA) and not langue:
                        askiwi = False
                        error = True
                        print "Μη ASCII αλλαγμένος τίτλος: ", expressionA
                else:
                        askiwi = True
                        error = False
                return expressionA, askiwi, error

        def minusASCII(self, terme):
                """
                Μετατρέπει μόνο τα ASCII σε πεζά γράμματα
                """
                for s, t in majASCII:
                        terme = repl(terme, s, t)
                return terme
                
        def isASCII(self, text):
                """
                Επαληθεύει εάν το κείμενο περιέχει τους επιτρεπόμενους χαρακτήρες ascii
                """
                isasc = True
                for i in range(len(text)):
                        ascok = False
                        for a in asciis:
                                if a == text[i]:
                                        ascok = True
                                        break
                        if ascok == False:
                                isasc = False
                                break
                return isasc

        def run(self):
                """
                Κάνει τη δουλειά
                """
                Affiche(u"Άντε να δουλέψουμε και λίγο!!")
                ancien= ""

                for page in self.generator:
                        if page.title() == stop:
                                Affiche(u""+stop+u" έγινε, σταματώ το 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'Αφήνω την προστατευμένη σελίδα %s' % page.title())
                        except wikipedia.NoPage:
                                wikipedia.output(u'Η σελίδα %s δεν υπάρχει' % page.title())
                        except wikipedia.IsRedirectPage:
                                wikipedia.output(u'Η σελίδα %s είναι ανακατεύθυνση' % page.title())
                                continue

                        titre = page.title()

                        continuer = True
                        for sauf in exceptions:
                                try:
                                        if re.search(sauf, titre):
                                                continuer = False
                                                break
                                except:
                                        Affiche("Λάθος στο " + titre + " με " + sauf)
                                        wikipedia.output("Λάθος στο " + titre + " με " + sauf)
                                        continue
                                        
                        nouveau, ascii, error = self.ChangeArticles(ancien, titre)
                        if error:
                                wikipedia.output(u"Η σελίδα περιέχει χαρακτήρες που δεν αναγνωρίζονται: %s | %s" % (titre, ascii))
                                #conterror = wikipedia.input(u'Να συνεχίσω; (y/n)')
                                #if (conterror == 'n' or conterror == 'N'):
                                #       break
                        if replex(nouveau, "\r|\n", "") == replex(ancien, "\r|\n", "") or not continuer:
                                Affiche(u"Δεν χρειάζονται αλλαγές στο %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">> Προσοχή: φαίνεται πως 1 κατηγορία σβήστηκε χωρίς αντιστάθμισμα!\n")
#                                       else:
#                                               Affiche(u">> Προσοχή: φαίνεται πως %s κατηγορίες σβήστηκαν χωρίς αντιστάθμισμα!\n" % difference)
#                               if difference < 0:
#                                       difference = -difference
#                                       if difference == 1:
#                                               Affiche(u">> Σημείωση: φαίνεται πως έλειπε 1 κατηγορία.\n")
#                                       else:
#                                               Affiche(u">> Σημείωση: φαίνεται πως έλειπαν %s κατηγορίες.\n" % difference)
                                if not self.acceptall:
                                        choice = wikipedia.inputChoice(u'Δέχεστε τις αλλαγές?',  ['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"Τελειώσαμε κιόλας;")

        
def repl(original_text, old, new):
        """
        Εργαλεία ανταλλαγής απλού κειμένου (χωρίς regular expressions)
        """
        try:
                new_text = old.sub(new, original_text)
        except:
                new_text = original_text.replace(old, new)
        return new_text

def replex(texte, avant, apres):
        """
        Εργαλεία ανταλλαγής κειμένου με regular expressions
        """
        avant = re.compile(avant, re.UNICODE)
        texte = avant.sub(apres, texte)
        return texte

def Affiche(texte):
        """
        Δεν εμφανίζει τα σχόλια παρά εάν "Σχόλια" είναι ενεργοποιημένο
        """
        if show:
                try:
                        print unicode(texte, 'utf-8')
                except:
                        print texte
#               wikipedia.output(texte)
        return

def compte(texte, motif):
        """
        Μετρά τον αριθμό μοτίβων στο κείμενο
        """
        occurence = 0
        n=0
        while n<len(texte)-len(motif):
                x=0
                mot = u""
                while x<len(motif):
                        mot += texte[n+x]
                        x += 1
                if mot == motif:
                        occurence +=1
                n +=1

        return occurence


def main():
        """
        Μπορούν να χρησιμοποιηθούν οι εξής παράμετροι:
        -start
        -page
        -ref
        -cat
        -from
        και:
        -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'Από ποια σελίδα να αρχίσω;')
                                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'Ποια σελίδα να αλλάξω;'))
                                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'Ποια σελίδα χρησιμεύει ως αναφορά;')
                                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'Όνομα της κατηγορίας: ')
                                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"\nΤέλος της διαδικασίας.\n")
                wikipedia.stopme()