Utilisateur:Probot/ArticlesRecents

  • Code original : Dake
  • Modifications, améliorations : Bayo
  • Licence : GPL

Script permettant de mettre à jour une liste semblable à la page articles récents du portail du jeu vidéo, en se basant sur une liste d'articles liés (ici Modèle:Portail jeu vidéo).

Il a été volontairement simplifié et n'a par exemple aucun contrôle d'erreurs. Si le bot plante, ce n'est de toute façon pas très grave car il n'aura sûrement pas eu le temps d'enregistrer la modification qu'il aurait faite, vous devrez au pire faire un revert.

Vous devez modifier les champs "utilisateur" et "mot de passe" dans le code.

Si tout fonctionne, vous pouvez modifier l'endroit où il va sauver la liste. Attention ! Il analyse la page existante plus la complète avant de la sauver. Il ne fait pas de grosse analyse, si par exemple un article récent est renommé, il est fort probable que le script va rajouter ce nouveau nom d'article en article récent, même si l'ancien nom y est déjà présent. Il est conçu pour laisser aux opérateurs humains la liberté de compléter l'article, ou de changer la mise en forme. Il ne fait que faciliter la recherche des articles récents.

Exemple de session modifier

Connexion à fr.wikipedia.org
Liste d'articles récupérées...
934 articles sont liés
Récupère l'article cible pour le compléter...
Fermeture de la connexion
Terminé sans mise à jour nécessaire

Code modifier

Important : à cause de problèmes techniques liés à l'affichage dans Mediawiki, il faut éditer cette page pour copier le code. Ne pas le copier depuis la page actuellement visible.


#!/usr/bin/python
# -*- coding: utf-8  -*-
                  
# Probot RC - Bot de mise à jour des articles récents sur les portails
# Code : Utilisateur:Dake, Utilisateur:bayo
# 2005 - (code sous license GPL)

import httplib
import urllib
import re
import sys
from datetime import datetime

def utf8(text):
    return unicode(text, 'UTF-8')

########################### PARAMETRAGE ###########################

mois = [
    '',
    utf8('janvier'),
    utf8('février'),
    utf8('mars'),
    utf8('avril'),
    utf8('mai'),
    utf8('juin'),
    utf8('juillet'),
    utf8('août'),
    utf8('septembre'),
    utf8('octobre'),
    utf8('novembre'),
    utf8('décembre'),
]


utilisateur = "XXXXXXXXXXXXXXXXXXX"
motDePasse = "XXXXXXXXXXXXXXXXXXX"

pageSrc = "Modèle:Portail_jeu_vidéo"
pageDest = "Modèle:Portail_jeu_vidéo/Articles_récents"
charset = 'UTF-8'

########################### FONCTIONS ###########################

# sauve la connexion (globale)
conn = None

## Récupère la liste des pages liée à la page passée en paramètre
#
def getWhatlinkshere(pageName):
    conn = httplib.HTTPConnection('fr.wikipedia.org')
    # attention, s'il y a plus de 5000 articles liés, il faut changer l'offset ci-dessous
    # (5000 = limite sur Wikipédia lors de la création d'une liste)
    conn.request('GET', "/w/wiki.phtml?title=Special:Whatlinkshere&target=%s&limit=5000&offset=0&action=edit" % pageName)

    # connexion serveur et lecture
    reponse = conn.getresponse()
    article = reponse.read()

    # expressions régulieres pour récuperer l'article
    #<!-- start content -->
    debut = re.search('<!-- start content -->', article).end()
    fin = re.search('<!-- end content -->', article).start()
    contenu = article[debut:fin]

    debut = re.search('.<ul>', contenu).end()
    fin = re.search('</ul>\nV', contenu).start()
    contenu = contenu[debut:fin]
    #print contenu[debut:fin]

    contenu = contenu.replace('<li>', '')
    contenu = contenu.replace('(page de redirection)', '</li>')
    elements = contenu.split('</li>')

    result = []
    # mise en forme du résultat
    for e in elements:
        i = e.find('>')
        e = e[i + 1:]
        i = e.find('</a>')
        e = e[:i]
        e = unicode(e, charset)

        # fixe quelques entitées html
        e = e.replace('<', '<')
        e = e.replace('>', '>')
        e = e.replace(''', "'")
        e = e.replace('"', '"')
        e = e.replace('&', '&') # doit être dernier
        result.append(e)
        
    return result

def getPage(pageName):
    conn.request('GET', "/w/wiki.phtml?title=%s&action=edit" % pageName)

    # connexion serveur et lecture
    reponse = conn.getresponse()
    article = reponse.read()

    # expressions régulieres pour récuperer l'article
    #<!-- start content -->
    debut = re.search('<textarea', article).end()
    debut = article.find('>', debut) + 1
    fin = re.search('</textarea>', article).start()
    contenu = article[debut:fin]

    # fixe quelques entitées html
    contenu = contenu.replace('<', '<')
    contenu = contenu.replace('>', '>')
    contenu = contenu.replace(''', "'")
    contenu = contenu.replace('"', '"')
    contenu = contenu.replace('&', '&') # doit être dernier
    
    return unicode(contenu, charset)

def savePage(pageName, description, comment = ''):
    print utf8("Connexion utilisateur/mot de passe")
    parametres = urllib.urlencode({"wpName" : utilisateur,
                                   "wpPassword" : motDePasse, 
                                   "wpLoginattempt" : "Identification", 
                                   "wpRemember" : "1"})

    entetes = { "Content-type" : "application/x-www-form-urlencoded",
                "User-agent" : "Probot/1.0"}
    
    conn = httplib.HTTPConnection('fr.wikipedia.org')
    conn.request("POST", "/w/wiki.phtml?title=Special:Userlogin&action=submit", parametres, entetes);
    
    reponse = conn.getresponse()
    cookie = reponse.getheader("set-cookie")
    
    print utf8("Analyse de la réponse du serveur")
    
    # analyse de la réponse (cookie)
    cookieMatch = re.compile(': (.*?);')
    cookieString = ""
    
    for resultat in reponse.msg.getallmatchingheaders('set-cookie'):
            m = cookieMatch.search(resultat)
            if m:
                    cookieString += m.group(1) + "; "
    
    cookieString = cookieString[:-2]
    
    # lit la page à écrire
    pageName = urllib.quote(pageName)
    
    print utf8("Lecture de la page " + pageName)
    
    entetes = {"Content-type" : "application/x-www-form-urlencoded",
               "User-agent" : "Probot/1.0", 
               "Cookie" : cookie}
    
    conn.request('GET', "/w/wiki.phtml?title=%s&action=edit" % pageName, {}, entetes)
    
    reponse = conn.getresponse()
    body = reponse.read()
    
    # récupère les informations du temps d'édition et le jeton de session
    pattern = re.compile(r'value="(\d+)" name=\"wpEdittime\"') 
    editTime = pattern.search(body).group(1)
    
    pattern = re.compile(r'value="(\w+)" name=\"wpEditToken\"') 
    editToken = pattern.search(body).group(1)
    
    # préparation des paramètres et sauvegarde de l'article
    parametres = urllib.urlencode({"wpTextbox1"  : description.encode('utf-8'),
                                   "wpSummary"   : comment.encode('utf-8'),
                                   "wpEdittime"  : editTime,
                                   "wpMinoredit" : "1", 
                                   "wpWatchthis" : "0", 
                                   "wpEditToken" : editToken})
            
    print utf8("Ecriture de la page ") + utf8(pageName)
    
    conn.request("POST", "/w/wiki.phtml?title=%s&action=submit" % pageName, parametres, entetes)
    
    reponse = conn.getresponse()
    print utf8("Fermeture de la connexion")
    conn.close()

## analyse la description et la retourne complété par les articles recents
#
def analyseEtComplete(description, articles):
    # récupère les pages se trouvant dans les articles recents
    articlesPresent = re.findall("\[\[([^\|\]]*)", description)
    comment = ""
    
    # force une majuscule sur la première lettre
    # retire les underscore
    l = articlesPresent
    articlesPresent = []
    for a in l:
        a = a[0].upper() + a[1:]
        a = a.replace('_', ' ')
        articlesPresent.append(a)

    # retire les articles déjà trésents
    for a in articlesPresent:
        try:
            articles.remove(a)
        except ValueError:
            pass
    
    # il n'y a peut être rien a faire
    if len(articles) == 0:
        return '', ''
        
    comment = '+' + str(len(articles))
    
    # construit le texte à ajouter
    aajouter = ']] ;\n[['.join(articles)
    aajouter = '[[' + aajouter + ']]'
    
    # vérifie si une section pour le jour courant existe
    today = datetime.today()
    matching = "=[^0-9]*%d[^0-9]*%s.*=" % (today.day, mois[today.month])
    isSectionExist = re.search(matching, description)
    if isSectionExist:
        # complète la section existante
        # il est pratique de considère que c'est la première
        aajouter = '==\n' + aajouter + ' ;\n'
        description = description.replace('==\n', aajouter, 1)

    else:
        # la section du jour doit être créée
        comment = comment + utf8(' ; création de section')
        title = ""
        if today.day == 1:
            title = '1{{er}} ' + mois[today.month]
        else:
            title = str(today.day) + ' ' + mois[today.month]

        # utilise le niveau de titrage utilisé dans la page
        titleLevel = re.search('=+', description)
        if titleLevel:
            titleUse = titleLevel.group(0)
            title = titleUse + ' ' + title + ' ' + titleUse
        else:
            title = '==' + title + '=='
        
        aajouter = title + '\n' + aajouter + '.\n\n=='
        description = description.replace('==', aajouter, 1)
    
    return description, comment

########################### TEST ###########################

descriptionTest1 = utf8("""<noinclude>{{Portail jeu vidéo/Retour}}</noinclude>__NOTOC__
N'hésitez pas à ajouter les articles récemment créés ainsi que ceux qui ont subit d'importantes modifications.

===12 novembre===
[[First Person Adventure|blabla]], un type de jeu vidéo.
===11 novembre===
[[Sega Chihiro]], une plateforme d'arcade basée sur la Xbox.
===8 novembre===
[[Sim City 3000]], un jeu de simulation de ville ; 
[[Twinklestar Sprites]], un ''shoot them up'' ;
""")

descriptionTest2 = utf8("""<noinclude>{{Portail jeu vidéo/Retour}}</noinclude>__NOTOC__
N'hésitez pas à ajouter les articles récemment créés ainsi que ceux qui ont subit d'importantes modifications.

=====18 novembre=====
[[Atotooto]].

=====12 novembre=====
[[First Person Adventure|blabla]], un type de jeu vidéo.
=====11 novembre=====
[[Sega Chihiro]], une plateforme d'arcade basée sur la Xbox.
=====8 novembre=====
[[Sim City 3000]], un jeu de simulation de ville ; 
[[Twinklestar Sprites]], un ''shoot them up'' ;
""")

descriptionTest3 = utf8("""<noinclude>{{Portail jeu vidéo/Retour}}</noinclude>__NOTOC__
N'hésitez pas à ajouter les articles récemment créés ainsi que ceux qui ont subit d'importantes modifications.

=====18 novembre=====
[[Atotooto]].

=====12 novembre=====
[[first Person Adventure|blabla]], un type de jeu vidéo.
=====11 novembre=====
[[Sega Chihiro]], une plateforme d'arcade basée sur la Xbox.
=====8 novembre=====
[[Sim_City_3000]], un jeu de simulation de ville ; 
[[Twinklestar Sprites]], un ''shoot them up'' ;
""")

articlesTest = ["a", "b", "Sim City 3000", "First Person Adventure"]

def test():
    print '---------------------------'
    description, comment = analyseEtComplete(descriptionTest1, articlesTest)
    print description
    print comment
    print '---------------------------'
    description, comment = analyseEtComplete(descriptionTest2, articlesTest)
    print description
    print comment
    print '---------------------------'
    description, comment = analyseEtComplete(descriptionTest3, articlesTest)
    print description
    print comment

########################### TRAITEMENT ###########################

def traitement():
    global conn
    print utf8("Connexion à fr.wikipedia.org")
    conn = httplib.HTTPConnection('fr.wikipedia.org')

    print utf8("Liste d'articles récupérée...")
    articles = getWhatlinkshere(pageSrc)
    print str(len(articles)) + utf8(" articles sont liés")
    
    # filtrage sur les noms d'article
    l = []
    for name in articles:
        if name == "":
            continue
        if name.find(utf8('Discuter:')) == 0:
            continue
        if name.find(utf8('Discussion ')) == 0:
            continue
        if name.find(utf8('Wikipédia:')) == 0:
            continue
        if name.find(utf8('Portail:')) == 0:
            continue
        if name.find(utf8('Utilisateur:')) == 0:
            continue
        if name.find(utf8('Modèle:')) == 0:
            continue
        if name.find(utf8('Aide:')) == 0:
            continue
        if name.find(utf8('Image:')) == 0:
            name = ':' + name
        if name.find(utf8('Catégorie:')) == 0:
            name = ':' + name
        l.append(name)
    articles = l

    # on ne traite que les 10 derniers
    if len(articles) > 10:
        articles = articles[len(articles) - 10:]
    articles.reverse()

    print utf8("Récupère l'article cible pour le compléter...")
    description = getPage(pageDest)
    description, comment = analyseEtComplete(description, articles)

    print utf8("Fermeture de la connexion")
    conn.close()

    if description == '':
        print utf8("Terminé sans mise à jour nécessaire")
        return
    
    savePage(pageDest, description, comment)
    print utf8("Terminé")

#####################################################

traitement()
#test()