Utilisateur:MisterMatt Bot/Classes

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.

Class Article

modifier

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")

initialize(articleName,lang)

modifier

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

login()

modifier

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

getPageSource(url)

modifier

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

getWikiSource()

modifier

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

getWhatLinksHere()

modifier

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

reOrganizeCatAndInterwikis()

modifier

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

getInterwikis()

modifier

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

addInterwikis(newInterwikis,lang)

modifier

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

getCat()

modifier

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

addCat(newCat)

modifier

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

update(summary)

modifier

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

class Category<Article

modifier

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

listArticles()

modifier

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

listSubCat()

modifier

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

listImages()

modifier

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

findSubCat()

modifier

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