« FormatBot » : différence entre les versions

De Wikipast
Aller à la navigation Aller à la recherche
Ligne 6 : Ligne 6 :


===Exemple===
===Exemple===
Prenons l'exemple suivant :
*[[1874.10.30]] / [[Woodstock, Oxfordshire]]. [[Naissance]] de '''Winston Churchill'''


==Performance==
==Performance==

Version du 9 mai 2017 à 11:27

Résumé

Scanne les différents articles et met à un format standard (AAAA.MM.JJ ou AAAA.MM ou AAAA) toutes les dates contenues dans un hyper-mot.

Description technique

Exemple

Prenons l'exemple suivant :

Performance

FormatBot est capable de détecter si un hypermot peut être interprété comme une date, selon plusieurs critères. Notre bot comporte des limites. En effet,

Code

# -*- coding: utf-8 -*-
import urllib
import requests
from bs4 import BeautifulSoup

user='formatbot'
passw='accjjlms'
baseurl='http://wikipast.epfl.ch/wikipast/'
summary='Wikipastbot update'
page=['Biographies']
names=['Testpage']

# Login request
payload={'action':'query','format':'json','utf8':'','meta':'tokens','type':'login'}
r1=requests.post(baseurl + 'api.php', data=payload)

#login confirm
login_token=r1.json()['query']['tokens']['logintoken']
payload={'action':'login','format':'json','utf8':'','lgname':user,'lgpassword':passw,'lgtoken':login_token}
r2=requests.post(baseurl + 'api.php', data=payload, cookies=r1.cookies)

#get edit token2
params3='?format=json&action=query&meta=tokens&continue='
r3=requests.get(baseurl + 'api.php' + params3, cookies=r2.cookies)
edit_token=r3.json()['query']['tokens']['csrftoken']

edit_cookie=r2.cookies.copy()
edit_cookie.update(r3.cookies)

for name in names:
    result=requests.post(baseurl+'api.php?action=query&titles='+name+'&export&exportnowrap')
    soup=BeautifulSoup(result.text, "lxml")
    #soup=BeautifulSoup(result.text)
    code=''
    for primitive in soup.findAll("text"):
        code+=primitive.string
    
    #print(code)
#fonction qui détecte le début d'une ligne et retourne l'indice du premier caractere apres '*'
def line_start_detect(code):
    line_index_lst=[]
    for i in range(len(code)):
        if (code[i]=='\n'):
            line_index_lst.append(i+2)
    line_index_lst.append(len(code))
    return line_index_lst

def hypertext(code, line_index1, line_index2):
    hypermot_lst=[]
    for i in range(line_index1, line_index2):
        if (code[i]== '[' and code[i+1]=='['):
            j=0
            while code[i+j]!=']' and code[i+j+1]!= ']':
                j+=1
            hypermot=''
            for k in range(i+2,i+j+1):
                hypermot+=code[k]
            hypermot_lst.append(hypermot)
            j=0
            i=i+j+2
    return hypermot_lst

def is_number(char):
    if(char=='0' or char=='1' or char=='2' or char=='3' or
       char=='4' or char=='5' or char=='6' or char=='7' or
       char=='8' or char=='9'):
        return True
    else :
        return False


#decode l'hypermot
#retourne s'il s'agit d'une date, si le format est correct, et le vecteur de date
#sortie : [is_date, (bool) est-ce que cet hypermot peut etre vu comme une date ?
#          date_format_correct, (bool) le format de date est-il respecte ?
#          date_format, (int) 1:aaaa    2:aaaa.mm    3:aaaa.mm.jj
#          ['aaaa','mm','jj']  ]   vecteur de la date interpretee
#Si is_date est False, le vecteur de date et data_format_correct sont incorrects
def date_decode(hypermot):
    date_format_correct=True
    is_date=True
    date_format=0;
    accepted_separator = ['.','-','. ',' .',' . ',',','/','\ ','_','pizza']
    temp_bool_separator_in_lst = False

    year_index=-1
    month_index=-1
    day_index=-1

    #cree si possible la liste des annee/mois/jours, et les listes des séparateurs
    number_lst=['']
    num_index=0
    separator_index_lst=[]
    separator_lst=[]
    sep_index=-1
    boo=False
    for i in range(len(hypermot)):
        if is_number(hypermot[i]):
            boo=True
    if boo==False:  
        return [False, False, 0,[]]
            
    if not is_number(hypermot[0]):
        if hypermot[0]== ' ':
            date_format_correct=False
            if not is_number(hypermot[1]): #un espace accepté mais pas deux
                is_date=False
                return [is_date,date_format_correct,date_format,number_lst]
        else:
            is_date=False
    else:
        number_lst[num_index]+=hypermot[0]
            
    for i in range(1,len(hypermot)):
        if not is_number(hypermot[i]):
            if is_number(hypermot[i-1]):
                num_index+=1
                number_lst.append('')
                sep_index+=1
                separator_lst.append(hypermot[i])
            else:
                separator_lst[sep_index]+=hypermot[i]
                
            separator_index_lst.append(i)
        else:
            number_lst[num_index]+=hypermot[i]

    #test de la validite des separateurs
    for i in range(len(separator_lst)):
        if separator_lst[i]!='.':
            date_format_correct=False
    if len(separator_lst)>2:
        date_format_correct=False
        if len(separator_lst)!=3 or separator_lst[2]!=' ':
            is_date=False
    for i in range(len(separator_lst)):
        temp_separator_in_lst = False
        for j in range(len(accepted_separator)):
            if separator_lst[i]== accepted_separator[j]:
                temp_bool_separator_in_lst = True
        if not temp_bool_separator_in_lst:
            is_date=False
    
    #test de la validite de la date, classification du format de date
    if len(number_lst)==4: 
        if number_lst[3]=='':
            date_format=3
    elif len(number_lst)<1 or len(number_lst)>3:
        is_date=False
        date_format_correct=False
    else:
        date_format=len(number_lst)

    #print(number_lst)
    
    for i in range(date_format): #detection de l'annee dans la liste
        if(len(number_lst[i])==3 or len(number_lst[i])==4):
            if(year_index !=-1): #s'il y a au moins deux nombres à 3 ou 4 chiffres
                is_date=False
                date_format_correct=False
            year_index=i
    #print(year_index)

    if year_index==-1: #si aucune annee n'a ete trouvee
        is_date=False
        date_format_correct=False
        return [is_date,date_format_correct,date_format,number_lst,'pas trouve year']

    if date_format==3:
        if year_index==0:
            day_index=2
            month_index=1
        elif year_index==2:
            day_index=0
            month_index=1
        else:
            is_date=False
            date_format_correct=False
            return [is_date,date_format_correct,date_format,number_lst]
        
        if (int(number_lst[month_index])>12 or int(number_lst[month_index])<0 or
            int(number_lst[day_index])>31 or int(number_lst[day_index])<0):
            is_date=False
            date_format_correct=False
            return [is_date,date_format_correct,date_format,number_lst]         

    if date_format==2:
        if year_index==0:
            month_index=1
        else:
            month_index=0
        if ( int(number_lst[month_index])>12 or int(number_lst[month_index])<0 ):
            is_date=False
            date_format_correct=False
            return [is_date,date_format_correct,date_format,number_lst]

    if int(number_lst[year_index])>2050:
        is_date=False
        date_format_correct=False

    if date_format==1:
        date_final=[ number_lst[year_index] ]
    if date_format==2:
        date_final=[number_lst[year_index],number_lst[month_index]]

    if date_format==3:
        date_final=[number_lst[year_index],number_lst[month_index], number_lst[day_index]]
        


    #rmq: separator_index_lst et separator_lst sont retournes uniquement pour la phase de debugging
    return [is_date,date_format_correct,date_format,date_final,separator_index_lst,separator_lst]
            
            

def date_format(decode_lst):
    date_temp="" 
 
    for i in range(0,decode_lst[2]) :
        if i<(decode_lst[2]-1):
            date_temp+=decode_lst[3][i]+decode_lst[5][i]
        else :
            date_temp+=decode_lst[3][i]

    char_lst=decode_lst[5]        
    for c in char_lst :
        date_temp=date_temp.replace(c,".")
        
    date_final=date_temp.replace(" ","")
    return date_final

## fonction qui reçoit en argument le code wiki complet la date à modifier et la date formatée
## la fonction ne retourne rien et écrit directement sur la page wiki
def wiki_write(code,old_date,new_date):
    
    code = code.replace(old_date,new_date)
    payload={'action':'edit','assert':'user','format':'json','utf8':'','text':code,'summary':summary,'title':name,'token':edit_token}
    r4=requests.post(baseurl+'api.php',data=payload,cookies=edit_cookie)
    print(r4.text)

def barre_detect(hypermot):
    barre=False
    syntax_part=""
    for i in range(len(hypermot)) :
        if hypermot[i]== "|" :
            barre=True
            for k in range(i+1, len(hypermot)) :
                syntax_part+=hypermot[k]
    if barre==False :
        syntax_part=hypermot
    return[barre,syntax_part]
        


line_index_lst=line_start_detect(code)
a=hypertext(code, line_index_lst[0], line_index_lst[len(line_index_lst)-1])

for i in range(len(a)):
    barre=barre_detect(a[i])
    b=date_decode(barre[1])
   
    if (b[0]==1 and b[1]==0) :
        date_final=date_format(b)
    
        wiki_write(code,barre[1],date_final)