Utilisateur:MisterMatt Bot/Classes

Un article de Wikipédia, l'encyclopédie libre.

Ceci n'est pas le code source dans son intégralité. J'ai enlevé quelques passages pour ne pas trop surcharger la page. Le code source complet est disponible sur demande.

Sommaire

[modifier] Class Article

C'est la classe la plus importante. Quand un nouvel objet est créé (un article), on se loggue si ce n'est pas déjà fait dans la langue correspondante à l'article. Ensuite, on récupère le code wiki de l'article pour remplir automatiquement certaines variables :

  • @articleName : nom de l'article
  • @lang : langue de l'article
  • @source : source wiki de l'article
  • @interwikis : liste des interwikis
  • @cat : liste des catégories
  • @wlh : liste des pages liées (variable récupérée sur demande car demande une nouvelle connection)

Le code pour modifier un article ressemble à cela :

bot = Article.new("Utilisateur:MisterMatt/Test1","fr")
bot.source = wiki         # 'wiki' étant la source wiki de l'article modifié
bot.update("MisterMat Bot : Modification automatisée")

[modifier] initialize(articleName,lang)

Tout ce qui est là est exécuté lors de la création d'un nouvel objet Article.

   
def initialize(articleName,lang)
        
        @articleName = articleName
        @lang = lang
        
        if (@@login[@lang] != true) then
                self.login()
        end

        self.getWikiSource()
        self.getInterwikis()
        self.getCat()
end

[modifier] login()

Méthode permettant de s'identifier à la Wikipédia courante

def login()
        loginfo = {
                "wpName" => @@user[@lang],
                "wpPassword" => @@password[@lang],
                "wpLoginattempt" => "Identification",
                "wpRemember" => "1"
        }
        @post_login = loginfo.keys.map{ |k| "#{k}=#{CGI.escape(loginfo[k].to_s)}" }.join("&")
        puts @post_login if LOG
        
        Net::HTTP.start(@lang+@@DOMAINE, 80) do |log|
                response = log.post(@@LOGIN, @post_login, @@headers)
                case response
                        when Net::HTTPRedirection
                        print " * Identification..." if TEST
                        else
                        print " * Identification (pas de redirection)..." if TEST
                        end
                        
                        location = response['location']
                        if location
                        puts " * Login to #{@lang}.wikipedia.org ..." # + " (#{location}.)"
                        p response.to_hash if LOG
                        p response['set-cookie'] if LOG
                        @@cookie = response['set-cookie']#.slice(/([a-z0-9]){32}/)
                        puts " * cookie : " + @@cookie if TEST
                        else
                        puts " ERREUR : le compte #{@user[lang]} n'existe pas !"
                        @@stopped = true
                        end
                end
                
        @@login[@lang] = true
        
end

[modifier] getPageSource(url)

Récupère le code source HTML d'une page

def getPageSource(url)
        
        @reconnecter = true
        
        # Connexion à  la page courante et modification
        @@headers['cookie'] = @@cookie
                
        url.gsub!(' ', '_')
        url = CGI.escape(url)
        url.gsub!('%3A', ':')
        url.gsub!('%2F', '/')
        url.gsub!('%3F', '?')
        url.gsub!('%3D', '=')
        url.gsub!('%26', '&')
        
        begin
                Net::HTTP.start("#{@lang + @@DOMAINE}", 80) do |page|
                @source = page.get(url, @@headers)
                #puts url
                #puts @source.body
                end
        rescue SocketError, RuntimeError
                if @reconnecter
                        @reconnecter = false
                        retry
                else
                        $stderr.puts "* Connexion impossible ! Page non traitée."
                        @error = true
                end
        end
        return @source.body
end

[modifier] getWikiSource()

Récupère le code wiki d'un article à partir du code HTML.

   
def getWikiSource()
        
        @reecrire = true
        @source = getPageSource("/w/index.php?title=#{@articleName}&action=edit")
        @error = false
        
        # Sauvegarde de la source pour rexml
        begin
                s = File.open("source", "w")
                s.write(@source)
        rescue SystemCallError
                if @reecrire
                        @reecrire = false
                        retry
                else
                        $stderr.puts "#{@articleName} n'a pu être enregistrée. Page non traitée."
                        @error = true
                end
        else
                #print " * #{@articleName} en cours...\n"
                @reecrire = false
        ensure
                s.close unless s.nil?
        end
        
        # parsing de la source
        if not @error
                @doc = Document.new File.new("source")
                # Ne pas traiter les pages bloquées
                if @doc.elements["html/body/div/div/div/div/form/textarea"] == nil
                        if @doc.elements["html/body/div/div/div/div/textarea"] != nil
                                puts "Page bloquée par un administrateur. Page non traitée."
                        else
                                puts "Page inaccessible bien que non bloquée. Page non traitée."
                        end
                        @error = true
                        break
                else
                        @data = @doc.elements["html/body/div/div/div/div/form/textarea"].text
                        @doc.elements.each("html/body/div/div/div/div/form/input") do |e|
                                @wpEdittime = e.attributes["value"] if e.attributes["name"] == "wpEdittime"
                                @wpEditToken = e.attributes["value"] if e.attributes["name"] == "wpEditToken"
                        end
                end
                
        end
        
        @source = @data
end

[modifier] getWhatLinksHere()

Récupère les pages liées à l'article et les stocke dans le tableau @wlh

def getWhatLinksHere()
        @reconnecter = true
        @reecrire = true
        
        @name = @articleName
        
        @name.gsub!(' ', '_')
        @name = CGI.escape(@name)
        @name.gsub!('%3A', ':')
        @name.gsub!('%2F', '/')
        @name.gsub!('%3F', '?')
        @name.gsub!('%3D', '=')
        @name.gsub!('%26', '&')
        
        @wlhURL = "http://#{@lang+@@DOMAINE}/w/index.php?title=Special:Whatlinkshere&target=#{CGI.escape(@name)}"
        
        begin
                # Connexion à  l'url wlh
                wiki = Net::HTTP.get_response(URI.parse(@wlhURL))
                @status = wiki.code
                @reponse = wiki.message
                puts " * url : #{@wlh} (#{@status} #{@reponse})" if TEST
        rescue SocketError, RuntimeError
                if @reconnecter
                @reconnecter = false
                retry
                else
                # Sauvegarde du couple anciennePage - nouvellePage dans tobedone
                puts "-------- Erreur ---------"
                $stderr.puts " * Connexion impossible : " + $! +"."
                puts " * Arrêt du bot."
                begin
                        f = File.open("tobebone", "a")
                        f.write(page + "|" + @nouvellePage + "\r")
                rescue SystemCallError
                        if @reecrire
                        @reecrire = false
                        retry
                        else
                        $stderr.puts " * #{@articleName} n'a pu être ajoutée à  la liste des pages à  traiter plus tard."
                        @@stopped = true
                        end
                else
                        puts " * La page #{@articleName} a été ajoutée à  la liste des pages à  traiter plus tard."
                ensure
                        f.close unless f.nil?
                end
                puts "-------------------------"
                end
        end
        
        # Parsing de wlh
        if @reponse == "OK" and not @@stopped
                catch(@status) do
                throw @status unless @status == "200"
                        puts " * #{@articleName} est disponible."
                        puts " * Construction de la liste des pages liées..."
                        (wiki.body.scan(/<li><a href="(.+)" title="(.+)">(.+)<\/a><\/li>/)).each do |page|
                        page[2].gsub!(' ', '_')
                        page[2].each do |lien| page[2] = CGI.escape(lien) end
                        @liste << page[2]
                        end
                        p @liste if LOG
                        if @liste.nitems == 0
                        puts " * Aucune page liée à #{@articleName}."
                        @@stopped = true
                        else
                        puts " * Construction de la liste achevée avec succès :"
                        #@liste.each do |page| puts "   - #{CGI.unescape(page)}" end
                        #puts
                        end
                end
        end
        @wlh = @liste
end

[modifier] reOrganizeCatAndInterwikis()

Réordonne la structure interne du code wiki de l'article en plaçant les interwikis et les catégories en haut.

def reOrganizeCatAndInterwikis()
        
        @data = @source
                
        @interwiki = ["en", "de", "ja", "fr", "pl", "nl", "sv", "it", "es", "zh", "pt", "he", "no", "fi", "eo", "da", "ru", "bg", "sl", "ca", "et", "hu", "cs", "sr", "nn", "id", "ro", "uk", "ko", "tt", "sk", "gl", "lt", "ms", "simple", "hr", "lb", "is", "vi", "bs", "th", "ar", "af", "su", "la", "io", "hy", "el", "tr", "wa", "cy", "nds", "fa", "ast", "be", "ia", "fy", "ku", "ka", "zh-min-nan", "lv", "ta", "li", "ang", "ga", "hi", "scn", "als", "tl", "eu", "ur", "sq", "sa", "kw", "mk", "gd", "mi", "kn", "jv", "br", "an", "mt", "oc", "sh", "ks", "fo", "tokipona", "csb", "qu", "se", "mn", "mr", "te", "tpi", "gu", "co", "ml", "nah", "ne", "jbo", "sw", "mo", "bn", "ie", "vo", "tlh", "rm", "az", "ln", "mg", "ht", "yi", "sc", "roa-rup", "na", "ps", "cv", "bo", "tum", "haw", "ug", "tk", "ky", "so", "bi", "nv", "iu", "km", "yo", "bm", "gn", "uz", "got", "ce", "ab", "gv", "sn", "nb"]
        
        @interwiki = @interwiki.sort  
        @interwiki = @interwiki.reverse         
                
        if ((@data =~ /\[\[Catégorie:(.*?)\]\]/i) != nil) then
                
                @data = "\n"+@data
                #puts " -  -  -  -  -  Catégorie présente  -  -  -  -  -"
                espace = false
                (@data.scan(/\[\[Catégorie:(.*?)\]\]/i)).reverse.each do |cat|
                        @data.gsub!(/(\n){0,1}\[\[Catégorie:#{Regexp.escape(cat[0])}\]\]( )*/i, "")   
                        if espace then
                                @data = "[[Catégorie:" + cat[0] + "]] " + @data
                        else
                                @data = "[[Catégorie:" + cat[0] + "]]" + @data
                        #       @firstCat = cat[0]
                                espace = true
                        end
                end
                
                
        end
                
        sauteLigne = true
        espace = false          
        @interwiki.each do |codeInterwiki|

                if ((@data =~ /\[\[#{codeInterwiki}:(.*?)\]\]/i) != nil) then
                        if sauteLigne then
                                @data = "\n"+@data
                                sauteLigne = false
                        end     
        
                        #puts " -  -  -  -  -  Interwiki #{codeInterwiki} présent  -  -  -  -  -"
                
                        (@data.scan(/\[\[#{codeInterwiki}:(.*?)\]\]/i)).reverse.each do |interwikilien|
                                @data.gsub!(/(\n){0,1}\[\[#{codeInterwiki}:#{Regexp.escape(interwikilien[0])}\]\]( )*/i, "")
                                
                                if espace then  
                                        @data = "[[" + codeInterwiki + ":" + interwikilien[0] + "]] " + @data
                                else
                                        @data = "[[" + codeInterwiki + ":" + interwikilien[0] + "]]" + @data
                                        espace = true
                                end     
                        end     
                end
        end

        @source = @data
end

[modifier] getInterwikis()

Récupère les interwikis et les stocke dans le tableau @interwikis.

def getInterwikis()
        @interwikis = {}        
        @data = @source
                
        @interwiki = ["en", "de", "ja", "fr", "pl", "nl", "sv", "it", "es", "zh", "pt", "he", "no", "fi", "eo", "da", "ru", "bg", "sl", "ca", "et", "hu", "cs", "sr", "nn", "id", "ro", "uk", "ko", "tt", "sk", "gl", "lt", "ms", "simple", "hr", "lb", "is", "vi", "bs", "th", "ar", "af", "su", "la", "io", "hy", "el", "tr", "wa", "cy", "nds", "fa", "ast", "be", "ia", "fy", "ku", "ka", "zh-min-nan", "lv", "ta", "li", "ang", "ga", "hi", "scn", "als", "tl", "eu", "ur", "sq", "sa", "kw", "mk", "gd", "mi", "kn", "jv", "br", "an", "mt", "oc", "sh", "ks", "fo", "tokipona", "csb", "qu", "se", "mn", "mr", "te", "tpi", "gu", "co", "ml", "nah", "ne", "jbo", "sw", "mo", "bn", "ie", "vo", "tlh", "rm", "az", "ln", "mg", "ht", "yi", "sc", "roa-rup", "na", "ps", "cv", "bo", "tum", "haw", "ug", "tk", "ky", "so", "bi", "nv", "iu", "km", "yo", "bm", "gn", "uz", "got", "ce", "ab", "gv", "sn", "nb"]
        
        @interwiki = @interwiki.sort  
        @interwiki = @interwiki.reverse         
        
        sauteLigne = true
        espace = false          
        @interwiki.each do |codeInterwiki|

                if ((@data =~ /\[\[#{codeInterwiki}:(.*?)\]\]/i) != nil) then

                        (@data.scan(/\[\[#{codeInterwiki}:(.*?)\]\]/i)).reverse.each do |interwikilien|
                                @interwikis["#{codeInterwiki}"] = interwikilien[0]
                        
                        end     
                end
        end
end

[modifier] addInterwikis(newInterwikis,lang)

Ajoute facilement un interwiki.

def addInterwikis(newInterwikis,lang)   
        
        @data = @source

        if ((@data =~ /\[\[#{lang}:#{newInterwikis}\]\]/i) == nil) then
                @data = @data + "[[#{lang}:#{newInterwikis}]]"
        end     
        @source = @data
        reOrganizeCatAndInterwikis()
        getInterwikis()
end

[modifier] getCat()

Récupère les catégories auxquelles l'article appartient et les stocke dans le tableau @cat.

def getCat()
        @cat = []       
        @data = @source

        if ((@data =~ /\[\[Catégorie:(.*?)\]\]/i) != nil) then

                (@data.scan(/\[\[Catégorie:(.*?)\]\]/i)).reverse.each do |cat|
                
                        cat = cat[0].split("|")       
                        @cat << cat[0]
                end     
        end
end

[modifier] addCat(newCat)

Ajoute une catégorie.

def addCat(newCat)      
        
        @data = @source

        if ((@data =~ /\[\[Catégorie:.?#{newCat}\]\]/i) == nil) then
                @data = @data + "[[Catégorie:#{newCat}]]"
        end     
        @source = @data
        reOrganizeCatAndInterwikis()
        getCat()
end

[modifier] update(summary)

Envoie la nouvelle version de la page sur le serveur avec 'summary' comme commentaire de la modification.

def update(summary)


        @reecrire = true
        @reconnecter = true

        donnees = {
            'wpTextbox1' => @source,
            'wpSummary' => summary,
            'wpEdittime' => @wpEdittime,
            'wpSave' => 'Sauvegarder',
            'wpSection' => '',
            'wpMinoredit' => '1',
            'wpWatchthis' => 'on',
            'wpEditToken' => @wpEditToken
        }
        
        @name = @articleName
        
        @name.gsub!(' ', '_')   
        @name = CGI.escape(@name)
        @name.gsub!('%3A', ':')
        @name.gsub!('%2F', '/')

        @name.gsub!('%3F', '?')
        @name.gsub!('%3D', '=')
        @name.gsub!('%26', '&')     
        
        @@headers['cookie'] = @@cookie
        @post_uri = "/w/index.php?title=#{@name}&action=submit"
        
        puts @post_uri
        @post_donnees = donnees.keys.map{ |k| "#{k}=#{CGI.escape(donnees[k].to_s)}" }.join("&")
        puts "   * données : #{post_donnees}" if TEST
        puts "   * sur : #{@lang+@@DOMAINE}/w/index.php?title=#{@name}&action=submit" if TEST
        
        begin
            Net::HTTP.start("#{@lang+@@DOMAINE}", 80) do |modifier|
                modification = modifier.post(@post_uri, @post_donnees, @@headers)
                
                case modification
                when Net::HTTPRedirection
                    print "sauvegarde... "
                else
                    print "sauvegarde (pas de redirection !) "
                end
                
                location = modification['location']
                if location
                    puts "OK."
                else
                    puts "ERREUR (#{location}) :"
                    puts "    - body :"
                    puts modification.body
                    puts "    - code/message :"
                    puts modification.code
                    puts modification.message
                end
           
           # Sauvegarde de la pageCourante pour mémoire
            begin
                l = File.open("done", "a")
                l.write(@name + "\r")
            rescue SystemCallError
                if @reecrire
                    @reecrire = false
                    retry
                else
                    $stderr.puts "#{@name} n'a pu être ajoutée au log." if TEST
                    @error = true
                end
            else
                puts "   * #{@name} ajoutée au log." if TEST
                @reecrire = false
            ensure
                l.close unless l.nil?
            end

           end
        rescue SocketError, RuntimeError
            if @reconnecter
                @reconnecter = false
                print " (2) "
                retry
            else
                puts "* Modification impossible. Page non traitée."
            end
        end
        sleep @PAUSE
end

[modifier] class Category<Article

Cette classe hérite de la superclasse Article. En gros, elle garde les mêmes caractéristiques que la classe Article, mais on va lui attribuer de nouvelles méthodes comme lister les articles à l'intérieur d'une catégorie.

Variables accessibles en dehors de la classe :

  • @articlesList
  • @subCatList
  • @imagesList
  • @subCatArbo

[modifier] listArticles()

Liste les articles appartenant à la catégorie et les rassemble dans le tableau @articlesList.

def listArticles()
                @articlesList = []
                @sourceURL = getPageSource("/wiki/#{@articleName}")
                
                (@sourceURL.scan(/<li><a href="(.*?)" title="(.*?)">(.*?)<\/a><\/li>/)).each do |page|
                        
                        # On coupe en deux pour voir si c'est une catégorie ou pas 
                        titre = page[1].split(":")
                        titre[0].each do |lien| titre[0] = CGI.escape(lien) end
                        
                        # On ne prends pas les catégories
                        if titre[0]!="Cat%C3%A9gorie" then                
                                page[2].gsub!(' ', '_')
                                page[2].each do |lien| page[2] = CGI.escape(lien) end
                                @articlesList << page[2]
                        end     

                                
                end
                p @articlesList if LOG
                if @articlesList.nitems == 0 then
                        puts " * Aucune article disponible"
                        puts " * Arrêt du bot."
                        @stopped = true
                else
                        puts " * Construction de la liste achevée avec succès :"
                        @articlesList.each do |page| puts "   - #{page}" end
                        puts
                end
end

[modifier] listSubCat()

Liste les sous-catégories appartenant à la catégorie et les rassemble dans le tableau @subCatList.

def listSubCat()
                @subCatList = []
                @sourceURL = getPageSource("/wiki/#{@articleName}")
                
                (@sourceURL.scan(/<li><a href="(.*?)" title="(.*?)">(.*?)<\/a><\/li>/)).each do |page|
                        
                        # On coupe en deux pour voir si c'est une catégorie ou pas 
                        titre = page[1].split(":")
                        titre[0].each do |lien| titre[0] = CGI.escape(lien) end
                        
                        # On prends les catégories
                        if titre[0]=="Cat%C3%A9gorie" then                
                                page[2].gsub!(' ', '_')
                                page[2].each do |lien| page[2] = CGI.escape(lien) end
                                @subCatList << page[2]
                        end     

                                
                end
                p @subCatList if LOG
                if @subCatList.nitems == 0 then
                #       puts " * Aucune article disponible"
                #       puts " * Arrêt du bot."
                        @stopped = true
                else
                #       puts " * Construction de la liste achevée avec succès :"
                #       @subCatList.each do |page| puts "   - #{page}" end
                #       puts
                end
end

[modifier] listImages()

Liste les imagess appartenant à la catégorie et les rassemble dans le tableau @imagesList.

def listImages()
                @imagesList = []
                @sourceURL = getPageSource("/wiki/#{@articleName}")
                
                (@sourceURL.scan(/<a href="\/wiki\/Image:(.*?)" title="Image:(.*?)"><img src="(.*?)<\/a>/)).each do |image|
                        @name = image[1]
                
                        @name.gsub!(' ', '_')
                        @name = CGI.escape(@name)
                        @name.gsub!('%3A', ':')
                        @name.gsub!('%2F', '/')
                        @name.gsub!('%3F', '?')
                        @name.gsub!('%3D', '=')
                        @name.gsub!('%26', '&')
                        
                        @imagesList << @name
                end     
                
                p @imagesList if LOG
                if @imagesList.nitems == 0 then
                        puts " * Aucune image disponible"
                        puts " * Arrêt du bot."
                        @stopped = true
                else
                        puts " * Construction de la liste achevée avec succès :"
                        @imagesList.each do |page| puts "   - #{page}" end
                        puts
                end
end

[modifier] findSubCat()

Génère la liste indentée des sous-catégories, sous-sous-catégories... de la catégorie. Cette liste à cette forme :

  • Cat
    • SubCat1
      • SubSubCat1
      • SubSubcat2
    • SubCat2
    • SubCat3
def findSubCat()
        self.findSubCat2(@articleName,0)
        @subCatArbo = $wiki
end     

# Fonction récursive pour trouver toutes les sous-catégories
def findSubCat2(cat,n)
        
        if n==0 then
                $wiki = ""
        end     
        
        cat2 = cat
        cat2.gsub!('_', ' ')
        n += 1
        donnees = "*"*n + "[[:Catégorie:"+CGI.unescape(cat2)+"|"+CGI.unescape(cat2)+"]]\n"
        $wiki = $wiki + donnees
        #puts $wiki
        
        cat = Category.new("Catégorie:"+CGI.unescape(cat),"fr")
        cat.listSubCat()

        cat.subCatList.each do |subCatName|

                findSubCat2(subCatName,n)

        end
        n -= 1
end

protected :findSubCat2