FormatBot
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 1
Prenons l'exemple suivant :
- 1874-10-30 / Woodstock, Oxfordshire. Naissance de Winston Churchill
Le bot va le lire et corriger la date de manière suivante :
- 1874.10.30 / Woodstock, Oxfordshire. Naissance de Winston Churchill
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)