Trabajo:Mejora de la wiki de ELP/Bots

De FdIwiki ELP
Revisión a fecha de 22:32 9 ene 2016; Rubr (Discusión | contribuciones)

(dif) ← Revisión anterior | Revisión actual (dif) | Revisión siguiente → (dif)
Saltar a: navegación, buscar

En esta página se muestra el código de los bots desarrollados y utilizados para el trabajo.

Los bots escritos en C# requieren la infraestructura de DotNetWikiBot (GPLv2). Los bots escritos en Python necesitan Pywikibot.

Para ejecutar los bots escritos en Python se necesita que el archivo user-config.py, con la información de la wiki y el usuario, esté accesible en el directorio donde se ejecute. El nombre de usuario se puede omitir si no se van a realizar cambios, en caso contrario la contraseña se solicitará por consola. Un ejemplo de archivo:

family_files['welp'] = 'http://wikis.fdi.ucm.es/ELP/api.php'

family='welp'
mylang = 'welp'

usernames['welp']['*'] = u'usuario'

El código de los bots está liberado licencia GPLv3.

Categorización de trabajos

Asocia los trabajos a su curso académico de acuerdo a las fechas en las que fueron creados. Por ejemplo, Categoría:Curso 2014-2015 y Categoría:Curso 2015-2016.

using System;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;

using DotNetWikiBot;

/**
 * Clase auxiliar válida para distintos bot que operen sobre la wiki de ELP.
 */
class BotELP : Bot
{

	/**
	 * Registra al bot en la wiki.
	 *
	 * Pide nombre de usuario y contraseña por consola.
	 *
	 * @returns En caso de error devuelve {@code null}.
	 */
	public static Site iniciar()
	{
		// Pide nombre de usuario y contraseña

		Console.Write("Nombre usuario: ");
		string usu = Console.ReadLine();
		Console.Write("Contraseña: ");
		string cña = ReadPassword();
		Console.WriteLine();

		try {
			Site welp = new Site("http://wikis.fdi.ucm.es/ELP/", usu, cña);

			return welp;
		}
		catch (WikiBotException wbe) {
			Console.Error.WriteLine(wbe.Message);

			return null;
		}
	}

	/**
	 * Lee distintas opciones en la línea de comandos.
	 *	-v para modo verboso
	 *	-d para depuración (simulación, no se escriben cambios)
	 */
	public static void leerOpciones(string[] ops)
	{
		if (Array.Exists(ops, "-v".Equals))
			DisableSilenceMode();
		else
			EnableSilenceMode();

		simulado	= Array.Exists(ops, "-d".Equals);
	}

	/**
	 * Lee una contraseña desde la consola.
	 */
	public static string ReadPassword()
	{
		StringBuilder pwd = new StringBuilder();

		while (true)
		{
			ConsoleKeyInfo c = Console.ReadKey(true);

			if (c.Key == ConsoleKey.Enter)
			{
				break;
			}
			else if (c.Key == ConsoleKey.Backspace)
                	{
				if (pwd.Length > 0)
				{
					pwd.Remove(pwd.Length - 1, 1);
					Console.Write("\b \b");
				}
			}
			else
			{
				pwd.Append(c.KeyChar);
				Console.Write("*");
			}
		}

		return pwd.ToString();
	}

	/**
	 * Indica si el bot escribe cambios en la wiki o únicamente lo simula.
	 *
	 * Útil para depuración.
	 */
	protected static bool simulado = false;
}

/**
 * Categoriza los trabajos de la wiki de ELP según el curso académico.
 */
class Categorizador : BotELP
{
	public static int Main()
	{

		// Se registra en la página y configura el bot
		Site welp = iniciar();

		leerOpciones(Environment.GetCommandLineArgs());

		if (welp == null)
			return 1;

		// Cuenta del número de ediciones
		int cuenta = 0;

		// Obtiene todos los trabajos (de momento en el espacio de nombre Principal)
		PageList todas = new PageList(welp);

		todas.FillFromAllPages("Trabajo:", 0, false, Int32.MaxValue, "Trabajo;");

		foreach (Page pag in todas)
		{
			pag.Load();

			// Si ya hay indicación de curso no hace nada
			List<string> cats = pag.GetCategories();

			if (cats.Exists(patronCCurso.IsMatch))
				continue;

			// Para averiguar el curso obtiene la fecha de la
			// primera edición
			PageList hist = new PageList(welp);

			hist.FillFromPageHistory(pag.title, Int32.MaxValue);

			DateTime fc = hist[hist.Count()-1].timestamp;

			// Distingue en base a ella el curso
			int año = fc.Year;

			// Si es antes del 29 de septiembre (aprox) es que es
			// del curso que empieza en el año anterior
			if (fc.Month < 9 || fc.Month == 9 && fc.Day < 29)
				año--;

			string curso = "Curso " + año + "-" + (año + 1);

			// Muestra información por consola
			Console.Error.WriteLine("«" + pag.title + "» creado en " + fc + " => " + curso);

			cuenta++;

			if (!simulado) {
				pag.AddToCategory(curso);

				pag.Save("bot: categorización de trabajos por curso", true);
			}
		}

		// Resumen de las operaciones
		Console.Error.WriteLine("El bot " + (simulado ? "hubiera realizado " : "realizó ") + cuenta + " ediciones.");

		return 0;
	}

	/**
	 * Patrón en el que encajan las categorías de curso académico.
	 */
	private static Regex patronCCurso = new Regex("^Categoría:Curso \\d+-\\d+$", RegexOptions.Compiled);
}

Enlaces rotos

Revisa todas las páginas de la wiki en busca de enlaces rotos, tanto internos como externos. El tiempo de acceso a enlaces externos se limita a 10 segundos. Tarda en ejecutarse debido al gran número de peticiones web que realiza y a que revisa todas las páginas de la wiki. Podría mejorarse atendiendo sólo a los cambios recientes con APISite.recentchanges.

No efectúa cambios sobre la wiki.

#!/usr/bin/python3
#
# Bot para generar listas de enlaces rotos (internos y externos)
#
# Require pywikibot: https://www.mediawiki.org/wiki/Manual:Pywikibot

import pywikibot
import urllib.request
import sys

# Establece la conexión
site = pywikibot.Site()

# Explora toda las páginas
todas = site.allpages()

for pag in todas :

	# Explora los enlaces internos de cada página en busca
	# de páginas para completar

	enls = pag.linkedPages()

	for p in enls :
		if not p.exists() :
			print('No existe la página:', p.title())

	# Explora los enlaces externos de cada página en busca
	# de enlaces rotos

	enls = pag.extlinks();

	for url in enls :
		print('Procesando', url, file=sys.stderr)

		try :
			# Se podrían hacer peticiones HEAD por eficiencia
			res = urllib.request.urlopen(url, timeout=10)

		except Exception as e :
			print('Problema con el enlace', url, 'en', pag.title(), '::', e)