Code SimilarBot
Aller à la navigation
Aller à la recherche
# 2018. École Polytechnique Fédérale de Lausanne (EPFL). # SHS Digital Humanities # Rémi PETITPIERRE, Elisa VIDAL-REVEL, Christian BERTONI, Ludovico MACHET, Mathieu SUTER # -*- coding: utf-8 -*- from bs4 import BeautifulSoup import re import time import requests class Place(object): """ Classe qui définit un lieu """ def __init__(self,denomination,weight): super(Place, self).__init__() self.denomination = denomination self.weight = weight """ Affiche le lieu """ def __printPlace__(self): print(" " + self.denomination + " : " + str(100*(self.weight))[:4] + "%") class Person(object): """ Classe qui définit une personne possédant une page Wikipast """ def __init__(self,name,places,lifespan,work,acquaintanceNames): super(Person, self).__init__() self.name = name self.places = places self.lifespan = lifespan self.work = work self.acquaintanceNames = acquaintanceNames def __printPlacesWeights__(self): """ Affiche tous les lieux relatifs au personnage et leur poids fréquentiels """ print("Lieux :") for j in self.places: j.__printPlace__() def __printLifespan__(self): """ Imprime la période sur laquelle le personnage a probablement vécu """ print("Période :") print(" de",self.lifespan[0],'à',self.lifespan[1]) def __printWork__(self): """ Imprime les coefficients d'activité """ print("Poids des principaux domaines d'activité :") for domain,coef in (self.work[0]).items() : if coef > 0.0: print (" ",domain," :",str(coef*100)[:4]+"%") print("Poids des domaines d'activité secondaires :") for domain,coef in (self.work[1]).items() : if coef > 0.0: print (" ",domain," :",str(coef*100)[:4]+"%") def __printAcquaintanceNames__(self): """ Imprime la liste des connaissances """ print("Connaissances :") if len(self.acquaintanceNames) > 1 : for acquaintance in self.acquaintanceNames : print(" "+acquaintance+",") else : print(" aucune") def normalize(dico): ''' Normalise les poids des dictionnaires de la forme { string : double } ''' total = 0.0 for key,val in dico.items(): if key != '-': total += val dicoNorm = dico noneIncluded = False if total == 0.0: for key,val in dicoNorm.items(): dicoNorm[key] = 0.0 return dicoNorm for key,val in dico.items(): if key != '-': dicoNorm[key] = val/total else: noneIncluded = True if noneIncluded: del dicoNorm['-'] return dicoNorm def computePlaceCorrelation(person1,person2): ''' Calcule le score de corrélation par rapport aux lieux où les personnages ont vécu. ''' score = 0.0 bestScore = 0.0 bestPlace = '' for element1 in person1.places: for element2 in person2.places: if element1.denomination == element2.denomination: score += min(element1.weight,element2.weight) if min(element1.weight,element2.weight) > bestScore: bestScore = min(element1.weight,element2.weight) bestPlace = element1.denomination return [score,bestPlace] def computeWorkCorrelation(person1,person2): ''' Calcule le score de corrélation lié aux domaines d'activités des personnages. ''' score, subscore, bestscore, bestsubscore = 0.0, 0.0, 0.0, 0.0 # Ce tableau permettra de créer la justification de la proposition de corrélation entre personnages justif = { 'sport':'sportif', 'arts':'artistique', 'litterature':'littéraire', 'musique':'musical', \ 'cinema':'cinématographique','sciences_nat':'des sciences naturelles', 'sciences_hum':'des sciences sociales',\ 'mathematiques':'des mathématiques', 'politique':'politique','philo-psycho':'de la philosophie et de la psychologie',\ 'medecine':'de la médecine', 'militaire':'militaire', 'business':'des affaires' } # Pas implémenté pour le moment #subjustif = { 'tennis':0.0, 'echecs':0.0, 'football':0.0, 'natation':0.0, 'automobile':0.0, 'peinture':0.0,\ #'sculpture':0.0,'architecture':0.0, 'romanesque':0.0, 'essais':0.0, 'poesie':0.0, 'classique':0.0, 'moderne':0.0,\ #'television':0.0, 'cinema':0.0,'theatre':0.0, 'physique-chimie':0.0,'ingenierie':0.0, 'histoire':0.0,\ #'anthropo-sociologie':0.0, 'democratie':0.0,'monarchie':0.0, 'dictature':0.0,'philo':0.0, 'psycho':0.0 } cat1, cat2 = (person1.work)[0], (person2.work)[0] subcat1, subcat2 = (person1.work)[1], (person2.work)[1] ijustif, isubjustif = "", "" for category1,value1 in cat1.items(): for category2,value2 in cat2.items(): if category1 == category2: score += min(value1,value2) if bestscore < min(value1,value2): bestscore = min(value1,value2) ijustif = justif[category1] for category1,value1 in subcat1.items(): for category2,value2 in subcat2.items(): if category1 == category2: subscore += min(value1,value2) return [(score + 0.5*subscore)/1.5,ijustif] def computeLifespanCorrelation(person1,person2): ''' Calcul le score de corrélation lié à la période où deux personnages ont vécu. ''' if (person1.lifespan[0] == 0): return [0,'0'] elif (person1.lifespan[1] == 1): return [0,'0'] elif (person2.lifespan[0] == 0): return [0,'0'] elif (person2.lifespan[1] == 1): return [0,'0'] else : iLifespan = person1.lifespan[1]-person1.lifespan[0] lastBorn = max(person1.lifespan[0],person2.lifespan[0]) firstDead = min(person1.lifespan[1],person2.lifespan[1]) yearCount = firstDead - lastBorn justif = "[["+str(lastBorn)+"]]"+"-"+"[["+str(firstDead)+"]]" score = 0.0 if yearCount >= 0: score = yearCount/iLifespan return [score,justif] else: return [0,'0'] def computeacquaintanceCorrelation(person1,person2): ''' Calcule le score de corrélation dans la catégorie "familles, amis et connaissances" ''' score = 0.0 for j in person1.acquaintanceNames: if j == person2.name: score += 1.0 return score def computeCorrelation(person1,person2): ''' Calcule le score total de corrélation entre les personnages ''' score = 0.0 cptPlace = computePlaceCorrelation(person1,person2) cptLifespan = computeLifespanCorrelation(person1,person2) cptWork = computeWorkCorrelation(person1,person2) #print(person1.name) #DEBUG #print("Lieux :",cptPlace[0],"Lifespan :",cptLifespan[0],"Work :",cptWork[0]) #DEBUG scores = [cptPlace[0],0.8*(cptLifespan[0]),1.5*(cptWork[0]),computeacquaintanceCorrelation(person1,person2)] justification = "" if max(scores) == scores[0]: justification = "Il semble que les personnages aient été actifs dans les mêmes lieux. Notamment à [["+cptPlace[1]+"]]." elif max(scores) == scores[1]: justification = "Il semble que les personnages aient été contemporains sur la période "+cptLifespan[1]+"." elif max(scores) == scores[2]: justification = "Il semble que les personnages aient tous deux été actifs dans le domaine "+cptWork[1] +"." elif max(scores) == scores[3]: justification = "Il semble que les personnages se connaissaient." #print("TOTAL",scores[0]+scores[1]+scores[2]+scores[3]) #DEBUG return [scores[0]+scores[1]+scores[2]+scores[3],justification] def getacquaintance(code,inames): ''' Détermine les interactions entre personnages, à partir du code source de leur biographie. ''' acquaintanceNames = [] for iname in inames: if (iname.replace('_',' ')) in code: acquaintanceNames.append(iname.replace('_',' ')) return acquaintanceNames def getPlaces(code): ''' Détermine, à partir du code source de la biographie, les lieux où le personnage s'est trouvé. ''' # Code adapté de Biopathbot cities = {} events = code.split("*") for j in events : place = re.findall("(?<=/\s\[\[)[A-zÀ-ÿ\-]*(?=\]\])",j) if(len(place)==0): place = re.findall("(?<=/\[\[)[A-zÀ-ÿ\-]*(?=\]\])",j) if len(place) != 0: if place[0] in cities: cities[place[0]] += 1 else: newCity = {place[0]:1} cities.update(newCity) cities = normalize(cities) places = [] for denomination,weight in cities.items(): newPlace = Place(denomination,weight) places.append(newPlace) return places def getLifespan(code,name): ''' Détermine, à l'aide du code source de la biographie, les dates de naissance et de décès du personnage.''' birthDate = ["0"] deathDate = ["1"] events = code.split("*") for j in events : j = "\n\n"+j if (("[[Naissance]] de [["+name.replace('_',' ')+"]]") in j): birthDate = [] birthDate = re.findall("(?<=\[\[)[0-9]*(?=\.[0-9])",j) if len(birthDate)==0: birthDate = re.findall("(?<=\[\[)[0-9]*(?=\]\])",j) if ((("[[Décès]] de [["+name.replace('_',' ')+"]]") in j) or \ (("[[Mort]] de [["+name.replace('_',' ')+"]]") in j)) or \ (("[[Exécution]] de [["+name.replace('_',' ')+"]]") in j): deathDate = [] deathDate = re.findall("(?<=\[\[)[0-9]*(?=\.[0-9])",j) if len(deathDate)==0: deathDate = re.findall("(?<=\[\[)[0-9]*(?=\]\])",j) if (len(birthDate)<1) or (len(deathDate)<1): print("ERREUR : Les dates de Naissance et/ou de mort de la page",name.replace('_',' '),"sont mal rédigées.") return False if int(birthDate[0]) <= int(deathDate[0]): return [int(birthDate[0]),int(deathDate[0])] elif (int(birthDate[0]) == 0) and (int(deathDate[0]) != 1): firstEntry = re.findall("(?<=\[\[)[0-9]*(?=\.[0-9])",j) if len(firstEntry)==0: firstEntry = re.findall("(?<=\[\[)[0-9]*(?=\]\])",j) birthDate[0] = int(firstEntry) return [int(birthDate[0]),int(deathDate[0])] elif (int(birthDate[0]) != 0) and (int(deathDate[0]) == 1): if int(birthDate[0]) > 1930: deathDate[0] = 2018 else: deathDate[0] = int(birthDate[0])+70 return [int(birthDate[0]),int(deathDate[0])] else: print("ERREUR dans getLifespan : la date de Décès précède la date de Naissance.") return [0,1] def getWork(code): ''' Détermine, à l'aide d'une liste de mots clé et du code source de la biographie, les domaines où le personnage était actif''' weights = { 'sport':0.0, 'arts':0.0, 'litterature':0.0, 'musique':0.0, 'cinema':0.0, 'sciences_nat':0.0, 'sciences_hum':0.0, 'mathematiques':0.0, 'politique':0.0, 'philo-psycho':0.0, 'medecine':0.0, 'militaire':0.0, 'business':0.0 } subweights = { 'tennis':0.0, 'echecs':0.0, 'football':0.0, 'natation':0.0, 'automobile':0.0, 'peinture':0.0,\ 'sculpture':0.0,'architecture':0.0, 'romanesque':0.0, 'essais':0.0, 'poesie':0.0, 'classique':0.0, 'moderne':0.0,\ 'television':0.0, 'cinema':0.0,'theatre':0.0, 'physique-chimie':0.0,'ingenierie':0.0, 'histoire':0.0,\ 'anthropo-sociologie':0.0, 'democratie':0.0,'monarchie':0.0, 'dictature':0.0,'philo':0.0, 'psycho':0.0 } keywords = { 'sport':['sport','olympiq','champion','compétit','victoire','joueur','entraîneu'], 'arts':['musée','exposition','photograph','bande dessinée'], 'litterature':['publication','livre','ouvrage','litté','traduction',' écri','académie française','lettre'], 'musique':['musique','chanson',' chant ','chanteu'], 'cinema':['cinéma'], 'sciences_nat':['sciences','biologi','laboratoire','scientifique','EPF','théorie'], 'sciences_hum':['sciences humaines'], 'mathematiques':['math','théorème','algèbre','géométr','calcul','comptab','statisti'], 'politique':['socialis','gouverne','communis','capital','traité','chancell','politique','municipal',\ 'cantonal','état','etat','décret','pouvoir','national'], 'philo-psycho':['philosophie-psychologie'], 'medecine':['médecin','hôpital','anatomie','vaccin','remède','infirm','soin','blessure','blessé','accident',\ 'chirurgie','malad','malaria','médica','croix rouge','variole','épidém'], 'militaire':['armée','soldat','guerre','militaire','fusil',' arme','sergent','lieutenant','major','général',\ 'officier','bombe','maréchal','neutralité','occupation','blindé','cuirass','armure'], 'business':['business','entreprise','PDG','multinationale',"chiffre d'affaire",'bénéfice','fortune',\ 'financ','banque','revenu','Wall Street','milliardaire','dollar','investisseur','start-up','entrepreneu',\ 'marché','économie','économique','rouble',' actionnaire'] } subkeywords = { 'tennis':['sport','tennis','chelem','Roland-Garros','Wimbledon','tournoi du Masters','circuit ATP'], 'echecs':['sport','échecs'], 'football':['sport','football'], 'natation':['sport','natation',' nage ','nageu','piscine','plonge'], 'automobile':['sport','automobil','formule un','formule 1'], 'peinture':['arts',' peint','tableau',' toile','portrait'], 'sculpture':['arts','sculpt',' buste','statue','marbre'], 'architecture':['arts','architect','chantier','bâtiment','monument','constru'], 'romanesque':['litterature','récit','roman'], 'essais':['litterature','essai','nouvelle'], 'poesie':['litterature','poésie','poème','poète','alexandrin'], 'classique':['musique','piano','menuet','sonate','orchestre','opéra','symphonie','clavecin','violon','flûte',\ 'liturgi','choeur','chœur','conservatoire','opera'], 'moderne':['musique','concert','rap ','rappeu','rock','blues','jazz','hip-hop','CD','festival','album',\ 'vinyl','guitare'], 'television':['cinema','télévis','téléjournal','RTS','TSR'], 'cinema':['cinema','cinéma','avant-première','acteur','actrice','tournage','film','[[Rôle]]'], 'theatre':['cinema','comédie','tragédie','farce','théâtre','scène','drame'], 'physique-chimie':['sciences_nat','atom','physique','physicien','radiation','radium','électron','photon'\ 'chimie','proton','radioacti','gravité','gravitation','espace-temps'], 'ingenierie':['sciences_nat','électri','mécani','informatique','ordinateur','comput','techn','invente','invention'], 'histoire':['sciences_hum','histoire','archéo','antiqu','histori','paléo'], 'anthropo-sociologie':['sciences_hum','ethnolog','civilization','anthropo','sociolog','sciences sociales',\ 'ethni','féminis',"droits de l'Homme"], 'democratie':['politique','election','élection','vote','votation','conseill','confédération','canton',\ 'société des Nations','ONU','UNESCO','société des nations','USA','maison Blanche','préside','déput',\ 'sénat','libéra','capital','républi','droits','citoyen','civique','européen','paix','pacifisme',\ 'communauté','union','liberté',' socialis','assemblée','indépendan'], 'monarchie':['politique',' roi ',' Roi ','majesté','monarque','monarchie','royaume','tsar','couronne','trône',\ ' duc ',' Duc ','duchesse','duché','baron','comte','tsar','empire','empereur','impératrice','reine','monarque',\ 'noble','aristocrat'], 'dictature':['politique','dictat','URSS','nazi','fascis','national-social','soviet','soviétique','reich','attentat',\ 'junte','détenu','détention','prison','complot','révolution','révolt','exécution','interdi','autocrat'], 'philo':['philo-psycho','philosoph'], 'psycho':['philo-psycho','psych'] } events = code.split("*") for j in events : # À chaque fois qu'une ligne de la biographie est reliée à une catégorie d'activité par un des # mot-clés s'y rapportant, augmente l'importance de cette catégorie pour le personnage concerné. for category,words in keywords.items(): counter = 0 for word in words: counter += j.count(word)+j.count(word.capitalize()) ''' # DEBUG : permet de vérifier les mots-clé repérés, voir aussi la suite du code DEBUG plus bas if (j.count(word)+j.count(word.capitalize())) >= 1 : print(word) ''' # Idem pour les mots clés des sous-catégories for subcategory,subwords in subkeywords.items(): subcounter = 0 if subwords[0]==category: for subword in subwords[1:]: searchCount = j.count(subword)+j.count(subword.capitalize()) counter += searchCount subcounter += searchCount ''' # DEBUG : permet de vérifier les mots-clé repérés (suite) if searchCount >= 1 : print(subword) ''' if subcounter > 0: subweights[subcategory] += 1 if counter > 0: weights[category] += 1 return [normalize(weights),normalize(subweights)] def checkAquaintanceReciprocity(people): ''' Vérifie et corrige la liste des connaissances de chaque personnage ''' for item1 in people: for item2 in people: for acquaintance1 in item1.acquaintanceNames: if acquaintance1 == item2.name: if (item1.name in item2.acquaintanceNames) == False: (item2.acquaintanceNames).append(item1.name) for acquaintance2 in item2.acquaintanceNames: if acquaintance2 == item1.name: if (item2.name in item1.acquaintanceNames) == False: (item1.acquaintanceNames).append(item2.name) return True def ranking(people, item1): ''' Établit le top 3 des meilleures corrélations, puis affiche celles qui présentent un score élevé ''' similarBotRanking = "" bestScore = [0.0,0.0,0.0] bestName = ["","",""] bestjustif = ["","",""] for item2 in people: score = computeCorrelation(item1,item2)[0] if (score >= bestScore[0]) and (item1.name != item2.name): bestScore[2],bestName[2],bestjustif[2] = bestScore[1],bestName[1],bestjustif[1] bestScore[1],bestName[1],bestjustif[1] = bestScore[0],bestName[0],bestjustif[0] bestScore[0],bestName[0],bestjustif[0] = score,item2.name,computeCorrelation(item1,item2)[1] elif (score >= bestScore[1]) and (item1.name != item2.name): bestScore[2],bestName[2],bestjustif[2] = bestScore[1],bestName[1],bestjustif[1] bestScore[1],bestName[1],bestjustif[1] = score,item2.name,computeCorrelation(item1,item2)[1] elif (score >= bestScore[2]) and (item1.name != item2.name): bestScore[2],bestName[2],bestjustif[2] = score,item2.name,computeCorrelation(item1,item2)[1] similarBotRanking += "\n== Recommandation(s) automatique(s) pour " + person.name + " == \n" if bestScore[0] > 0.86: similarBotRanking += "* [[" + bestName[0] + "]]. Recouvrement : " + str(bestScore[0]/0.043)[:4] similarBotRanking += "%." + " " +bestjustif[0] + "\n" else: similarBotRanking += "Aucune recommandation proposée. \n" if bestScore[1] > 1.075: similarBotRanking += "* [[" + bestName[1] + "]]. Recouvrement : " + str(bestScore[1]/0.043)[:4] similarBotRanking += "%." + " " +bestjustif[1] + "\n" if bestScore[2] > 1.29: similarBotRanking += "* [[" + bestName[2] + "]]. Recouvrement : " + str(bestScore[2]/0.043)[:4] similarBotRanking += "%." + " " +bestjustif[2] + "\n" return similarBotRanking def getInfo(people): for person in people : print("\n") print("Nom :",person.name) person.__printLifespan__() person.__printPlacesWeights__() person.__printWork__() person.__printAcquaintanceNames__() return True ############################################################################################################################## ############################################################ MAIN ############################################################ ############################################################################################################################## def main(*args): timeInit = time.time() user='MasterBot' passw='dhbot2019' baseurl='http://wikipast.epfl.ch/wikipast/' summary="Test bot" # Liste des pages biographiques complètes bio=['Adolf_Hitler','Nicolas_II','Albert_Einstein','Jeanne_Hersch','John_Lennon','Victor_Hugo','Fidel_Castro',\ 'Bjorn_Borg','Ferdinand_Hodler','Alberto_Giacometti','Auguste_Piccard','Wolfgang_Pauli','Gustave_Ador',\ 'Arthur_Honegger','Wolfgang_Amadeus_Mozart','Mao_Zedong','Robert_Oppenheimer','Richard_Wagner','Simone_de_Beauvoir',\ 'Le_Corbusier','Joseph_Staline','Paul_Klee','Steffi_Graf','Phil_Collins','Charles_de_Gaulle','Benito_Mussolini',\ 'Michael_Jackson','Mahatma_Gandhi','Jean-Paul_Sartre','Jean-Luc_Godard','Charlie_Chaplin','Philippe_Jaccottet',\ 'Marguerite_Yourcenar','Marguerite_Duras','Pierre_de_Coubertin','Louise_Michel','Jacques_Chirac','Stanley_Kubrick',\ 'Ayrton_Senna','Enzo_Ferrari','Kurt_Cobain','Audrey_Hepburn','Hermann_Hesse','John_Fitzgerald_Kennedy',\ 'Maurice_Cosandey','Charles_Aznavour','Michael_Schumacher','Donald_Trump','Henry_Dunant','Sigmund_Freud',\ 'Franz_Beckenbauer','Roman_Polanski','Guillaume_Henri_Dufour','Walter_Mittelholzer','Magic_Johnson','Bill_Gates',\ 'Gioachino_Rossini','Thomas_Edison','Ernesto_Rafael_Guevara','Philippe_Suchard','Nicolas_Bouvier',\ 'Jacques-Yves_Cousteau','Winston_Churchill','Bobby_Fischer','Paul_Maillefer','Claude_Nicollier',\ 'Louis_De_Funès','Salvador_Dalí','Louis_Lumière','Henri_Dès','Daniel_Brélaz','Hergé','Nicéphore_Niépce',\ 'Élisabeth_II','Lénine','André_Breton','Franklin_D._Roosevelt','Jean_Tinguely'] names = "" if len(args) == 0: names = bio else: names = args print("Longueur names :",len(names)) # 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) people = [] # Retrouver le contenu et créer un objet Person pour chaque personnage for name in names: result=requests.post(baseurl+'api.php?action=query&titles='+name+'&export&exportnowrap') soup=BeautifulSoup(result.text, "html.parser") code='' for primitive in soup.findAll("text"): code+=primitive.string codeToConsider = code # éviter de lire la section Recommandations déjà écrite, ainsi que les éventuelles autres sections réalisées # par des Bots, comme SummarizingBot. recomText = "== Recommandation(s) automatique(s) pour " if ("== Biographie ==" in code) : codeToConsider = code[code.find("== Biographie ==")+len("== Biographie =="):] codeToConsider = codeToConsider[:codeToConsider.find("==")] elif (recomText in code) : codeToConsider = code[:code.find(recomText)+len(recomText)] code = codeToConsider someone = Person(name.replace('_',' '),getPlaces(codeToConsider),getLifespan(code,name),getWork(code),getacquaintance(code,names)) people.append(someone) ''' fonction getInfo pour le DEBUG ''' #getInfo(people) checkAquaintanceReciprocity(people) for person in people: time.sleep(3) similarBotRanking = ranking(people, person) result=requests.post(baseurl+'api.php?action=query&titles='+(person.name).replace(' ','_')+'&export&exportnowrap') soup=BeautifulSoup(result.text, "html.parser") code='' for primitive in soup.findAll("text"): code+=primitive.string intro = "\n== Recommandation(s) automatique(s) pour " + person.name + " ==" # si SimilarBot a déjà été utilisé, simplement mettre à jour la section avec les nouvelles recommandations if (intro in code): afterCode = code[code.find(intro)+len(intro):] otherSection = re.findall("==",afterCode) if len(otherSection) >= 1: afterCode = afterCode[afterCode.find("=="):] else: afterCode = "" beforeCode = code[:code.find(intro)] content= beforeCode + similarBotRanking + afterCode payload={'action':'edit','assert':'user','format':'json','utf8':'','text':content,'summary':summary,\ 'title':(person.name).replace(' ','_'),'token':edit_token} r4=requests.post(baseurl+'api.php',data=payload,cookies=edit_cookie) print(r4.text) elif ("== Biographie ==" in code): afterCode = code[code.find("== Biographie ==")+len("== Biographie =="):] otherSection = re.findall("==",afterCode) # s'il n'y a pas d'autres sections dans la page que Biographie, juste ajouter à la fin de la page if len(otherSection) == 0: content = similarBotRanking payload={'action':'edit','assert':'user','format':'json','utf8':'','appendtext':content,'summary':summary,\ 'title':(person.name).replace(' ','_'),'token':edit_token} r4=requests.post(baseurl+'api.php',data=payload,cookies=edit_cookie) print(r4.text) # si la section Biographie existe et que d'autres sections existent également, la recommandation est placée # juste après la Biographie else: afterCode = code[code.find("== Biographie ==")+len("== Biographie =="):] afterCode = afterCode[afterCode.find("=="):] beforeCode = code[:code.find(afterCode)] content= beforeCode + similarBotRanking + afterCode payload={'action':'edit','assert':'user','format':'json','utf8':'','text':content,'summary':summary,\ 'title':(person.name).replace(' ','_'),'token':edit_token} r4=requests.post(baseurl+'api.php',data=payload,cookies=edit_cookie) print(r4.text) # Si aucun de ces cas n'est repéré, SimilarBot ajoute simplement la recommandation à la fin de la page Wikipast else: content=similarBotRanking payload={'action':'edit','assert':'user','format':'json','utf8':'','appendtext':content,'summary':summary,\ 'title':(person.name).replace(' ','_'),'token':edit_token} r4=requests.post(baseurl+'api.php',data=payload,cookies=edit_cookie) print(r4.text) print("\n","TEMPS DE CALCUL :",str(time.time()-timeInit)[:4],"s") ############################################################################################################################## ############################################################################################################################## ##############################################################################################################################