« FormatBot » : différence entre les versions

De Wikipast
Aller à la navigation Aller à la recherche
Aucun résumé des modifications
Ligne 13 : Ligne 13 :
Prenons l'exemple suivant :
Prenons l'exemple suivant :


*[[1874-10-30]] / [[Woodstock, Oxfordshire]]. [[Naissance]] de '''Winston Churchill'''
*[[1874/10/30]] / [[Woodstock, Oxfordshire]]. [[Naissance]] de '''Winston Churchill'''


Le bot va le lire et corriger la date de manière suivante :
Le bot va le lire et corriger la date de manière suivante :


*[[1874.10.30]] / [[Woodstock, Oxfordshire]]. [[Naissance]] de '''Winston Churchill'''
*[[1874.10.30]] / [[Woodstock, Oxfordshire]]. [[Naissance]] de '''Winston Churchill'''
===Exemple 2===
Si la date en question a une redirection et elle doit être modifiée, la redirection n'est pas modifiée tandis que la date l'est.
Code wiki
<nowiki>
*[[1874-10-30|1874/10/30]] / [[Woodstock, Oxfordshire]]. [[Naissance]] de '''Winston Churchill'''
</nowiki>
Code wiki corrigé
<nowiki>
*[[1874-10-30|1874.10.30]] / [[Woodstock, Oxfordshire]]. [[Naissance]] de '''Winston Churchill'''
</nowiki>
Donc si l'on appuie sur le lien on sera redirigé vers la date [[1874-10-30]] même si le format de la date n'est pas affiché de la sorte.


==Performance==
==Performance==

Version du 9 mai 2017 à 11:41

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

Description

Pour chaque page récente et valide, FormatBot effectue sur les hypermots qu'il interprète comme une date les modifications suivantes :

Exemple 1

Prenons l'exemple suivant :

Le bot va le lire et corriger la date de manière suivante :

Exemple 2

Si la date en question a une redirection et elle doit être modifiée, la redirection n'est pas modifiée tandis que la date l'est.

Code wiki

*[[1874-10-30|1874/10/30]] / [[Woodstock, Oxfordshire]]. [[Naissance]] de '''Winston Churchill'''

Code wiki corrigé

*[[1874-10-30|1874.10.30]] / [[Woodstock, Oxfordshire]]. [[Naissance]] de '''Winston Churchill'''

Donc si l'on appuie sur le lien on sera redirigé vers la date 1874-10-30 même si le format de la date n'est pas affiché de la sorte.

Performance

FormatBot est capable de détecter si un hypermot peut être interprété comme une date, selon plusieurs critères et la réécrit selon un format standard si le format n'est pas correct. Notre bot comporte des limites. En effet, les critères de détection des dates ne permettent pas de détecter toutes les dates qui seraient écrites dans un mauvais format suivant sous quelle elle est écrite. Par exemple, si l'année et le mois sont inversés comme suit: "05.1828.08" FormatBot ne va pas corriger le format car il est impossible de séparer mois et jour dans tous les cas.

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)