« Creatobot » : différence entre les versions
Aucun résumé des modifications |
|||
(6 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 2 : | Ligne 2 : | ||
== Fonctionnement == | == Fonctionnement == | ||
[[Creatobot]] travaille sur les pages créés par les étudiants du cours SHS Humanités Digitals 2018 [http://wikipast.epfl.ch/wikipast/index.php/Biographies]. Son fonctionnement est le suivant : | [[Creatobot]] travaille sur les pages créés par les étudiants du cours SHS Humanités Digitals 2018 [http://wikipast.epfl.ch/wikipast/index.php/Biographies]. Son fonctionnement est le suivant : <br />D’abord il effectue une série d’initialisations : ouverture du dictionnaire, création d’une liste de prénoms francophones à partir de Wikipédia[https://fr.wikipedia.org/wiki/Liste_de_pr%C3%A9noms_fran%C3%A7ais_et_de_la_francophonie], collecte de la liste des pages à modifier (biographies), login sur [[Wikipast]] et finalement chargement du texte de la page à traîter. <br />L’algorithme pour la recherche de potentiels hypermots est le suivant : Le bot omet d’abord les titres, car la syntaxe [[Wikipast]] ne contient pas d'hypermot dans ces derniers. Il cherche ensuite toutes les occurrences du titre de la page dans le texte et les met entre crochet si elles ne le sont pas déjà. Puis il sépare le texte de la page en un tableau mot avec comme délimitant les espaces et il sépare les mots de la ponctuation qui peut se trouver avant ou après. <br />Le bot est programmé pour ne sélectionner que des groupes de noms composés de deux mots ou plus. Les prénoms ou noms seuls sont donc ignorés, ils génèreraient en effet trop d'erreur de type faux positif. Pour qu'un groupe de noms soit balisé par le bot il faut que tous les mots qui le composent ne contiennent que des lettres, commencent par une majuscule et ne soient pas déjà balisés. Il faut en plus que le premier nom respecte la condition suivante : n’est pas dans le dictionnaire ou est dans la liste des prénoms. | ||
D’abord il effectue une série d’initialisations : ouverture du dictionnaire, création d’une liste de prénoms francophones à partir de Wikipédia, collecte de la liste des pages à modifier (biographies), login sur [[Wikipast]] et finalement chargement du texte de la page à traîter. | |||
L’algorithme pour la recherche de potentiels hypermots est le suivant : Le bot omet d’abord les titres, car la syntaxe [[Wikipast]] ne contient pas d'hypermot dans ces derniers. Il cherche ensuite toutes les occurrences du titre de la page dans le texte et les met entre crochet si elles ne le sont pas déjà. Puis il sépare le texte de la page en un tableau mot avec comme délimitant les espaces et il sépare les mots de la ponctuation qui peut se trouver avant ou après. | |||
Le bot est programmé pour ne sélectionner que des groupes de noms composés de deux mots ou plus. Les prénoms ou noms seuls sont donc ignorés, ils génèreraient en effet trop d'erreur de type faux positif. Pour qu'un groupe de noms soit balisé par le bot il faut que tous les mots qui le composent ne contiennent que des lettres, commencent par une majuscule et ne soient pas déjà balisés. Il faut en plus que le premier nom respecte la condition suivante : n’est pas dans le dictionnaire ou est dans la liste des prénoms. | |||
== Généralités == | == Généralités == | ||
Ligne 20 : | Ligne 17 : | ||
* ''beginWithACapitalLetter'' : Teste si le mot commence avec une majuscule en utilisant aussi les "Regular Expression" [https://docs.python.org/2/library/re.html] | * ''beginWithACapitalLetter'' : Teste si le mot commence avec une majuscule en utilisant aussi les "Regular Expression" [https://docs.python.org/2/library/re.html] | ||
== Limite du Bot == | == Limite du Bot == | ||
*[[Creatobot]] ne s'occupe pas des mots uniques nécessitant un hyperlien. | *[[Creatobot]] ne s'occupe pas des mots uniques nécessitant un hyperlien. | ||
Ligne 118 : | Ligne 114 : | ||
def onlyContainLetters(word): | def onlyContainLetters(word): | ||
return not re.match("^[\ | return not re.match("^[\D]*$", word) == None | ||
def beginWithACapitalLetter(word): | def beginWithACapitalLetter(word): | ||
Ligne 137 : | Ligne 133 : | ||
punctuationAfter = re.search('[\p{P}]{1,3}$',word).group() | punctuationAfter = re.search('[\p{P}]{1,3}$',word).group() | ||
word = re.sub('(\p{P}){1,3}$',"", word) | word = re.sub('(\p{P}){1,3}$',"", word) | ||
if re.match ('^[\w\d_-]{0,1}(\p{P}){1}[\w\d_-]+$',word): #si on a une ponctuation avant un mot | if re.match ('^[\w\d_-]{0,1}(\p{P}){1,3}[\w\d_-]+$',word): #si on a une ponctuation avant un mot | ||
punctuationBefore = re.search('^[\w\d_-]{0,1}[\p{P}]{1}',word).group() | punctuationBefore = re.search('^[\w\d_-]{0,1}[\p{P}]{1,3}',word).group() | ||
word = re.sub('^[\w\d_-]{0,1}[\p{P}]{1}',"", word) | word = re.sub('^[\w\d_-]{0,1}[\p{P}]{1,3}',"", word) | ||
return [word, punctuationBefore, punctuationAfter] | return [word, punctuationBefore, punctuationAfter] | ||
Ligne 156 : | Ligne 153 : | ||
#Prend les groupes de noms composés de 2 noms ou plus. | #Prend les groupes de noms composés de 2 noms ou plus. | ||
#Il faut que le premier nom ne contienne que des lettres et commence par une majuscule et qu'il soit : | #Il faut que le premier nom ne contienne que des lettres et commence par une majuscule et qu'il soit : soit pas dans le dictionnaire, soit dans la liste des prénoms. | ||
#Pour les noms suivants ils doivent simplement ne contenir que des lettres et commencer par une majuscule. | #Pour les noms suivants ils doivent simplement ne contenir que des lettres et commencer par une majuscule. | ||
Ligne 163 : | Ligne 160 : | ||
#Découpage du texte en ligne | #Découpage du texte en ligne | ||
j=0 | |||
while j < len(lines) : | |||
line=lines[j] | |||
if not re.match('^[=]{1,6}.*[=]{1,6}$', line): #Si la ligne n'est pas un titre | if not re.match('^[=]{1,6}.*[=]{1,6}$', line): #Si la ligne n'est pas un titre | ||
#Mise en forme des référence au titre de la page | #Mise en forme des référence au titre de la page | ||
Ligne 171 : | Ligne 170 : | ||
words = line.split(" ") #Découpage du texte en mot | words = line.split(" ") #Découpage du texte en mot | ||
modifyFlag = False #Flag pour la gestion groupe de noms | modifyFlag = False #Flag pour la gestion groupe de noms | ||
firstWord = False | firstWord = False | ||
i=0 | i=0 | ||
while i < | while i < len(words): | ||
#Evitement des mots déjà balisés | #Evitement des mots déjà balisés | ||
if re.match('[\[]{2}(.)*', words[i]): #Si présence d'une balise | if re.match('[\[]{2}(.)*', words[i]): #Si présence d'une balise | ||
flag = True #Flag pour la gestion des mot déjà balisé | |||
wordID = i; | |||
while i < len(words)-1 and flag : | |||
[wordNoPunc, punctuationBefore, punctuationAfter]=separatePunctuation(words[i]) | |||
if i == wordID : | |||
if punctuationBefore != '[[' : | |||
words[wordID]=re.sub('^[\[]{2}',"", words[wordID]) | |||
flag = False | |||
i=-1 | |||
elif punctuationAfter == ']]' : | |||
flag = False | |||
elif punctuationAfter != '' : | |||
words[wordID]=re.sub('^[\[]{2}',"", words[wordID]) | |||
flag = False | |||
i=-1 | |||
else : | |||
if punctuationBefore != '' : | |||
words[wordID]=re.sub('^[\[]{2}',"", words[wordID]) | |||
flag = False | |||
i=-1 | |||
elif punctuationAfter == ']]' : | |||
flag = False | |||
elif punctuationAfter != '' : | |||
words[wordID]=re.sub('^[\[]{2}',"", words[wordID]) | |||
flag = False | |||
i=-1 | |||
i+=1 | |||
else : | |||
[wordNoPunc, punctuationBefore, punctuationAfter]=separatePunctuation(words[i]) | [wordNoPunc, punctuationBefore, punctuationAfter]=separatePunctuation(words[i]) | ||
Ligne 203 : | Ligne 228 : | ||
#Fermeture des balises si dernier mot ou si ponctuation après le mot | #Fermeture des balises si dernier mot ou si ponctuation après le mot | ||
if needBracketsLight(wordNoPunc) and (i == len(words)-1 or punctuationAfter != '') : | if modifyFlag and needBracketsLight(wordNoPunc) and (i == len(words)-1 or punctuationAfter != '') : | ||
modifyFlag=False | modifyFlag=False | ||
if not firstWord : | if not firstWord : | ||
words[i]=addBracketsAfter(words[i]) | words[i]=addBracketsAfter(words[i]) | ||
i+=1 | i+=1 | ||
line = ' '.join(words) | line = ' '.join(words) | ||
newText += line + '\n' | newText += line + '\n' | ||
j+=1 | |||
print(newText) | print(newText) | ||
Ligne 227 : | Ligne 249 : | ||
r4=requests.post(baseurl+'api.php',data=payload,cookies=edit_cookie) | r4=requests.post(baseurl+'api.php',data=payload,cookies=edit_cookie) | ||
print(r4.text) | print(r4.text) | ||
</nowiki> | </nowiki> |
Dernière version du 15 mai 2018 à 12:57
Creatobot est un bot codé en language Python, il a pour mission de rechercher des potentiels hypermots afin de rajouter les balises correspondant à des liens Wikipast.
Fonctionnement
Creatobot travaille sur les pages créés par les étudiants du cours SHS Humanités Digitals 2018 [1]. Son fonctionnement est le suivant :
D’abord il effectue une série d’initialisations : ouverture du dictionnaire, création d’une liste de prénoms francophones à partir de Wikipédia[2], collecte de la liste des pages à modifier (biographies), login sur Wikipast et finalement chargement du texte de la page à traîter.
L’algorithme pour la recherche de potentiels hypermots est le suivant : Le bot omet d’abord les titres, car la syntaxe Wikipast ne contient pas d'hypermot dans ces derniers. Il cherche ensuite toutes les occurrences du titre de la page dans le texte et les met entre crochet si elles ne le sont pas déjà. Puis il sépare le texte de la page en un tableau mot avec comme délimitant les espaces et il sépare les mots de la ponctuation qui peut se trouver avant ou après.
Le bot est programmé pour ne sélectionner que des groupes de noms composés de deux mots ou plus. Les prénoms ou noms seuls sont donc ignorés, ils génèreraient en effet trop d'erreur de type faux positif. Pour qu'un groupe de noms soit balisé par le bot il faut que tous les mots qui le composent ne contiennent que des lettres, commencent par une majuscule et ne soient pas déjà balisés. Il faut en plus que le premier nom respecte la condition suivante : n’est pas dans le dictionnaire ou est dans la liste des prénoms.
Généralités
- Concepteurs : Amandine Evard, Natalija Ljubic, Duruz Noé, Bourquin Vladimir
- UserName : Creatobot
Exemple de pages modifiées
- Page texte: [3]
- Page classique: Test Creatobot
Liste des fonctions
- existInDictionnary : Teste si le mot existe dans le dictionnaire[4] et si il existe dans la liste des prénoms francophones [5]
- onlyContainLetters : Teste si le mot ne contient que des lettres en utilisant les "Regular Expression" [6]
- beginWithACapitalLetter : Teste si le mot commence avec une majuscule en utilisant aussi les "Regular Expression" [7]
Limite du Bot
- Creatobot ne s'occupe pas des mots uniques nécessitant un hyperlien.
Code source
################################# ###### Creatobot #### ################################# import regex as re import requests from urllib.request import urlopen from bs4 import BeautifulSoup user='Creatobot' passw='creatobot_mdp' baseurl='http://wikipast.epfl.ch/wikipast/' summary='Wikipastbot Creatobot' ################################################################################################### ### Initialisations : #ouverture dictionnnaire dictionnaryFileName='Lexique382.txt' dictionnaryFile=open(dictionnaryFileName, encoding='utf-8') dictionnaryString=dictionnaryFile.read() dictionnaryLine=dictionnaryString.split('\n') dictionnary = [] for line in dictionnaryLine: dictionnary.append(line.split('\t')[0]) dictionnaryFile.close() #recherche des prénoms francais sur wikipédia response=urlopen("https://fr.wikipedia.org/wiki/Liste_de_pr%C3%A9noms_fran%C3%A7ais_et_de_la_francophonie") page_source=response.read() soupPrenoms=BeautifulSoup(page_source,'html.parser') prenoms=[] for dlTag in soupPrenoms.findAll('dl'): for ddTag in dlTag.findAll('dd'): bTag = ddTag.find('b') if bTag: aTag = bTag.find('a') if aTag: prenoms.append(aTag.string) #Accès aux biographies du wikipast response=urlopen("http://wikipast.epfl.ch/wikipast/index.php/Biographies") page_source=response.read() soupBiographies=BeautifulSoup(page_source,'html.parser') biographies=[] for primitive in soupBiographies.findAll("table"): for cap_and_count in primitive.findAll("td"): for text in cap_and_count.findAll("a"): if text.string != None: biographies.append(text.string) # 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) #récupération du texte dans la page voulue: title = 'Test Creatobot' #il faut remplacer par biographie[i] ici pour tourné sur toutes les pages. result=requests.post(baseurl+'api.php?action=query&titles='+title+'&export&exportnowrap') soup=BeautifulSoup(result.text, "lxml") #prend la partie de la page qui est le texte lines = soup.find('page').find('text').text.split('\n') ################################################################################################### ### Fonctions : def inDictionnary(word): return word.lower() in dictionnary def inPrenoms(word): return (word.lower()).capitalize() in prenoms def onlyContainLetters(word): return not re.match("^[\D]*$", word) == None def beginWithACapitalLetter(word): return not re.match("^[A-Z](.)*$", word) == None #Si le mot ne contient que des lettres et commence par une majuscule def needBracketsLight(word): return onlyContainLetters(word) and beginWithACapitalLetter(word) #Si le mot ne contient que des lettres, commence par une majuscule et n'est pas dans le dictionnaire ou est un prénom def needBracketsHard(word): return needBracketsLight(word) and (not inDictionnary(word) or inPrenoms(word)) def separatePunctuation(word): punctuationAfter = '' punctuationBefore = '' if re.match('^.+(\p{P}){1,3}$',word): #si on a une ponctuation après un mot punctuationAfter = re.search('[\p{P}]{1,3}$',word).group() word = re.sub('(\p{P}){1,3}$',"", word) if re.match ('^[\w\d_-]{0,1}(\p{P}){1,3}[\w\d_-]+$',word): #si on a une ponctuation avant un mot punctuationBefore = re.search('^[\w\d_-]{0,1}[\p{P}]{1,3}',word).group() word = re.sub('^[\w\d_-]{0,1}[\p{P}]{1,3}',"", word) return [word, punctuationBefore, punctuationAfter] def addBracketsAfter(word): [word, punctuationBefore, punctuationAfter]=separatePunctuation(word) return punctuationBefore+word+']]'+punctuationAfter def addBracketsBefore(word): [word, punctuationBefore, punctuationAfter]=separatePunctuation(word) return punctuationBefore+'[['+word+punctuationAfter ################################################################################################### ### Algorithme : #Prend les groupes de noms composés de 2 noms ou plus. #Il faut que le premier nom ne contienne que des lettres et commence par une majuscule et qu'il soit : soit pas dans le dictionnaire, soit dans la liste des prénoms. #Pour les noms suivants ils doivent simplement ne contenir que des lettres et commencer par une majuscule. newText = '' #Découpage du texte en ligne j=0 while j < len(lines) : line=lines[j] if not re.match('^[=]{1,6}.*[=]{1,6}$', line): #Si la ligne n'est pas un titre #Mise en forme des référence au titre de la page line=line.replace('[['+soup.title.text+']]',soup.title.text) line=line.replace(soup.title.text,'[['+soup.title.text+']]') words = line.split(" ") #Découpage du texte en mot modifyFlag = False #Flag pour la gestion groupe de noms firstWord = False i=0 while i < len(words): #Evitement des mots déjà balisés if re.match('[\[]{2}(.)*', words[i]): #Si présence d'une balise flag = True #Flag pour la gestion des mot déjà balisé wordID = i; while i < len(words)-1 and flag : [wordNoPunc, punctuationBefore, punctuationAfter]=separatePunctuation(words[i]) if i == wordID : if punctuationBefore != '[[' : words[wordID]=re.sub('^[\[]{2}',"", words[wordID]) flag = False i=-1 elif punctuationAfter == ']]' : flag = False elif punctuationAfter != '' : words[wordID]=re.sub('^[\[]{2}',"", words[wordID]) flag = False i=-1 else : if punctuationBefore != '' : words[wordID]=re.sub('^[\[]{2}',"", words[wordID]) flag = False i=-1 elif punctuationAfter == ']]' : flag = False elif punctuationAfter != '' : words[wordID]=re.sub('^[\[]{2}',"", words[wordID]) flag = False i=-1 i+=1 else : [wordNoPunc, punctuationBefore, punctuationAfter]=separatePunctuation(words[i]) if modifyFlag : if firstWord : firstWord=False if needBracketsLight(wordNoPunc) : words[i-1]=addBracketsBefore(words[i-1]) else : modifyFlag=False else : if not needBracketsLight(wordNoPunc) : words[i-1]=addBracketsAfter(words[i-1]) modifyFlag=False #Ouverture des balises si elles ne sont pas déjà ouvertes et si le test est ok elif needBracketsHard(wordNoPunc): modifyFlag = True firstWord = True #Fermeture des balises si dernier mot ou si ponctuation après le mot if modifyFlag and needBracketsLight(wordNoPunc) and (i == len(words)-1 or punctuationAfter != '') : modifyFlag=False if not firstWord : words[i]=addBracketsAfter(words[i]) i+=1 line = ' '.join(words) newText += line + '\n' j+=1 print(newText) ################################################################################################### ### Ecriture de la page : payload={'action':'edit','assert':'user','format':'json','utf8':'','text':newText,'summary':summary,'title':title,'token':edit_token} r4=requests.post(baseurl+'api.php',data=payload,cookies=edit_cookie) print(r4.text)