Trabajo:Mejora de la wiki de ELP/Bots
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)