Progetto:Bot/Programmi in Python per i bot/newXml.py
Aspetto
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)\
.replace("<","<")\
.replace(">",">")\
.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