Vai al contenuto

Progetto:Bot/Programmi in Python per i bot/newXml.py

Da Wikisource.

Estrae da un file djvu.xml lo strato testo impaginato e ne permette il caricamento in nsPagina.

Requisiti

[modifica]
  • python 3
  • pywikibot

Programmi accessori utili:

  • DjvuLibre
  • Excel o simili
  • un buon editor di testo, es. Notepad++ o equivalenti, con supporto UTF-8 e regex.

Struttura del programma

[modifica]
  • si tratta di una libreria di routine pensate per uso interattivo (da interfaccia Idle o simili).
  • le routine prevedono due passi:
    • la funzione produci_upload() accetta un file djvu.xml e produce un file output.txt del tutto analogo, per struttura, all'output di Match;
    • la funzione upload() carica da output.txt a nsPagina utilizzando pywikibot.

Parametri

[modifica]

Una tipica chiamata di produci_upload ha questa forma:

  • produci_upload(xml,nPagina) dove: xml è il path completo del file djvu.xml; nPagina è il nome della base nsPagina;
  • upload(output,ini=None,fin=None, folder=r"..\data", overwrite=False, onlyempty=False, test=True): dove:
    • output è il nome del file txt da caricare, prodotto da produci_upload;
    • ini e fin (opzionali) sono i numeri pagina iniziale e finale da caricare;
    • folder è l'indirizzo della cartella che contiene output;
    • overwrite è l'opzione per sovrascrivere o non sovrascrivere pagine nsPagona esistenti (default False);
    • onlyempty è l'opzione per limitare il caricamento alle sole pagine prive di testo (default False);
    • test è l'opzione per verificare il funzionamento dello script, non carica il testo in nsPagina ma lo stampa sullo schermo (default True per prudenza..)


# -*- coding: utf-8 -*-
import re
import pywikibot as bot
import os
# oggetto Site per itwikisource
it=bot.Site("it","wikisource")
apos="’"
r2=re.compile(r'<WORD coords="(-*\d+),(-*\d+),(-*\d+),(-*\d+)".+>(.+)</WORD>')
r3=re.compile(r" ([,;.:?!])")
def find_stringa(stringa,idi,idf,dc=0,x=None,side="left"):
    if side=="right":
        idip=stringa.rfind(idi)
    else:
        idip=stringa.find(idi)
    idfp=stringa.find(idf,idip+len(idi))+len(idf)
    if idip>-1 and idfp>0:
        if x!=None:
            while stringa[idip:idfp].count(x)>stringa[idip:idfp].count(idf):
                if stringa[idip:idfp].count(x)>stringa[idip:idfp].count(idf):
                    idfp=stringa.find(idf,idfp)+len(idf)
                
        if dc==0:
            vvalore=stringa[idip+len(idi):idfp-len(idf)]
        else:
            vvalore=stringa[idip:idfp]
    else:
        vvalore=""
    return vvalore

def produci_lista(testo,idi,idf,dc=1,inizio=None):
    t=testo[:]
    lista=[]
    while not find_stringa(t,idi,idf,1,inizio)=="":
        el=find_stringa(t,idi,idf,1,inizio)
        t=t.replace(el,"",1)
        if dc==0:
            el=find_stringa(el,idi,idf,0,inizio)
        lista.append(el)
    return lista


def split_xml(filexml):
    #r=re.compile(r"-*\d+,-*(\d+),-*\d+,-*\d+")
    #r1=re.compile(r"(\d+),\d,\d+,\d+")
    r2=re.compile(r'<WORD coords="(-*\d+),(-*\d+),(-*\d+),(-*\d+)">(.+)</WORD>')
    xml=open(filexml, encoding="utf-8").read()
    # estrazione blocchi pagina
    pagine=[0]+produci_lista(xml,"<OBJECT","</OBJECT>",1)
    for i in range(1,len(pagine)):
        # estrazione blocchi WORD
        pagine[i]=produci_lista(pagine[i],"<WORD","</WORD>",1)
        for j in range(len(pagine[i])):
            try:
                # estrazione coordinate
                pagine[i][j]=list(r2.findall(pagine[i][j])[0])
                # conversione di comodo str->int delle coordinate
                for k in range(0,4):
                    pagine[i][j][k]=int(pagine[i][j][k])
            except:
                print(i)
                
        # identificazione linee
        pagine[i]=step1(pagine[i])
        #pagine[i]=correggi(pagine[i],i)
                           
    return pagine # lista di pagine, ciascuna costituita da lista di linee, ciascuna lista
                  # di parole con coordinate

def step1(pagina):
    pagina=sorted(pagina,key=lambda word: word[1])
    linee=[]
    try:
        linea=[pagina[0]]
        for word in pagina[1:]:
            if abs(word[1]-linea[0][1])<20:
                linea.append(word)
            else:
                linee.append(sorted(linea, key=lambda x: x[0]))
                linea=[word]
        linee.append(sorted(linea, key=lambda x: x[0])) #prova
        return linee
    except: 
        return pagina

def estrai_testo(pagina):
    testo=""
    for linee in pagina:
        lista=[]
        for parole in linee:
            lista.append(parole[4])
        testo+=" ".join(lista)+"\n"
    testo=refine(testo)
    return testo

def refine(testo):
    testo=r3.sub(r"\1",testo) #eliminazione spazi prima di punteggiatura
    testo=testo.replace("&apos;",apos)\
        .replace("&lt;","<")\
        .replace("&gt;",">")\
        .replace("'",apos)
    return testo

def analisi(pagina):
    # margini sin
    marg_sin=[x[0][0] for x in pagina]
    marg_sin_m=sorted(marg_sin)[int(len(marg_sin)/4)]
    altezza_riga=[x[0][1]-x[0][3] for x in pagina]
    altezza_riga_m=sorted(altezza_riga)[int(len(altezza_riga)/2)]
    return marg_sin_m, altezza_riga_m

def correggi(pagina,numero_pagina):
    #pagina=pagine[n]
    try:
        if pagina==[]:
            print("Pagina ",numero_pagina,"vuota")
        else:
            if len(pagina)>10:
                x,h=analisi(pagina)
                for i in range(len(pagina)):
                    # algoritmo per Novelle
##                    if pagina[i][0][0]>x+h*.75 and pagina[i][0][0]<x+2*h:
##                        if pagina[i][0][4][0].islower():
##                            pagina[i][0][4]="— "+pagina[i][0][4]
##                            
##                        else:
##                            pagina[i][0][4]="\n"+pagina[i][0][4]
##                            
##                    elif pagina[i][0][0]>x+2*h and pagina[i][0][0]<x+4*h:
##                        pagina[i][0][4]="\n— "+pagina[i][0][4]
##                        if pagina[i][0][0]>x+h*.75 and pagina[i][0][0]<x+2*h:
##                            pagina[i][0][4]="\n"+pagina[i][0][4]
                    
                 #algoritmo per maschere nude
                    if pagina[i][0][4].isupper():
                        pagina[i][0][4]="\n"+pagina[i][0][4]
                     
                    
    except:
        if pagina==[]:
            print("Pagina ",numero_pagina,"vuota")
        else:
            print("Errore in pagina ",numero_pagina)
    return pagina
    
def produci_upload(xml,nPagina):
    pagine=split_xml(xml)
    base="==[[Pagina:%s/%d]]==\n"
    upload=""
    for i in range(1, len(pagine)):
        pagine[i]=correggi(pagine[i],i)
        upload+=base % (nPagina,i)
        if pagine[i]==[]:
            upload+='<noinclude><pagequality level="0" user="BrolloBot" /></noinclude><noinclude><references/></noinclude>\n'
        else:
            upload+=estrai_testo(pagine[i])
    open("../data/output.txt","w",encoding="utf-8").write(upload)
    print("../data/output.txt salvato")
    return 

def upload(output,ini=None,fin=None, folder=r"..\data", overwrite=False, onlyempty=False, test=True):
    testo=open(os.path.join(folder,output),  encoding="utf-8").read()
    r=re.compile(r"==\[\[(.+?)\]\]==\n")
    lp=r.split(testo)[1:]
    if ini==None:
        ini=0
    if fin==None:
        fin=len(lp)//2
    for i in range(ini,fin):
        nomePagina=lp[(i-1)*2]
        testoPagina=lp[(i-1)*2+1]
        pagina=bot.Page(it,nomePagina)
        if test:
            print(testoPagina)
        else:
            if overwrite:
                if pagina.exists():
                    #if not ('user="BrolloBot"' in pagina.get() or 'user=""' in pagina.get()):
                    if not 'level="1"' in pagina.get(): # or 'user=""' in pagina.get()):
                        print("Pagina level # 1: salto")
                        continue
            else:
                if pagina.exists():
                    print("Pagina esistente: salto")
                    continue
            if onlyempty:
                if not 'level="0"' in testoPagina:
                    continue
            pagina.put(testoPagina,"caricamento testo ")
    return