RObot
Z Wikiverzity
Obsah |
[editovat] Summary
This page descripts the evolution of the RObot, i.e. Read/Only bot, the bot helping with common tasks coupled with the maintenance of the wikiversity and other projects. It should also serve as the learning material to understand how such a bot can work and how to write another bot scripts. At the starting phase of programming bots, for security reason, this bot makes no real editations: it will only traverse the name spaces, the category trees etc. while reporting some statistics and info about structure or giving some suggestions to improving it. In such way even a beginner is able to do some experiments without risk of damaging of useful data.
[editovat] Status
- Name of the bot: RObot
- Contributions: None
- Operator: Kychot
- Functions: Read/Only bot; Info about Category tree, some statistics etc.
[editovat] Úvod
Údržba všech wikiprojektů je náročná záležitost, některé úlohy je ale možno automatizovat. Velkou práci zde zastanou boti, autonomní agenti, kteří mohou systematicky prohledávat zadanou oblast a provádět zde naprogramované operace. Za práci každého bota je plně zodpovědný operátor, který je registrovaným uživatelem, a který pro svého bota vytvořil zvláštní účet. V tomto případě se nejedná o loutkový účet, za kterým by uživatel skrýval svou identitu, ale je zde jasně uvedeno, že se jedná o účet bota s odkazem na jeho operátora, který reguje rovněž na jeho diskusní stránku.
Ke spouštění bota potřebuje jeho operátor souhlas od byrokratů, kteří takto vytvořenému účtu nastaví tzv. příznak bota, který je důležitý např. k tomu, aby bylo možno v historiích článků odlišit editace, prováděné uživateli-lidmi, o editací, prováděných automaticky boty. Administrativní podrobnosti, platné na anglické wikiversitě, nejdeme na en:Wikiversity:Bots. Česká Wikiverzita dosud nemá stanovena vlastní pravidla, do té doby se držíme pravidel anglické wikiverzity. (Může být ovšem sporné, zda je nutno mít souhlas k provozu bota, který neprovádí žádné reálné editace.)
Programy botů jsou zpravidla skripty, napsané v nějakém interpretovaném jazyce, jakými je např. Perl nebo Python. K usnadnění tvorby takových skriptů jsou vytvářeny knihovny. V našem kursu začneme s knihovnou meta:Using_the_python_wikipediabot, který je napsána v Pythonu. Prokud v tomto jazyce neprogramujeme, stačí pro si pro první orientaci přečíst alespoň článek Python.
[editovat] Užitečné stránky
[editovat] Úkoly pro bota
- Upload multiple files at once http://mwusers.com/forums/showthread.php?t=8812
- Mirrorovat wikiverzitu: Wiki mecum porto#Mirror
[editovat] Pywikipedia
[editovat] Instalace
Předpokladem je, že máme funkční interpret jazyka Python. Instalace balíku Pywikipedia spočívá prakticky jen v jeho stažení a umístění do příslušného adresáře. Budeme postupovat podle m:Using the python wikipediabot.
Předpokládejme, že již máme pro různé experimenty s wiki vytvořený nějaký adresář ~/wiky Přepneme se do něj, vytvoříme si v něm adresář např. RObot a do něj jako další podadresář distribuci Pywikipedia. Tu můžeme stáhnot buď jako každonoční download anebo nejnovější verzi přes svn (k tomu musíme mít nainstalovaný balík subversion):
cd cd wiki mkdir RObot cd RObot
a dále buď:
wget http://toolserver.org/~valhallasw/pywiki/package/pywikipedia/pywikipedia-nightly.tar.bz2 tar xjf pywikipedia-nightly.tar.bz2
anebo:
svn checkout http://svn.wikimedia.org/svnroot/pywikipedia/trunk/pywikipedia/ pywikipedia
V obou případech se nám v adresáři RObot vytvoří podadresář pywikipedia, obsahující celou distribuci.
[editovat] Konfigurace
Před prvním použití knihovny Pywikipedia ji musíme zkonfigurovat. Nejjednodušší řešení je vygenerovat si konfigurační soubor pomocí skriptu generate_user_files.py:
cd pywikipedia
python generate_user_files.py
a jen odpovíme na jednotlivé otázky:
1: Create user_config.py file 2: Create user_fixes.py file 3: The two files What do you do? 1 1: southernapproach 2: wikiversity 3: gentoo 4: supertux 5: betawiki 6: wikinews 7: krefeldwiki 8: wikibooks 9: wikia 10: wikibond 11: lyricwiki 12: botwiki 13: loveto 14: anarchopedia 15: test 16: i18n 17: freeciv 18: wikisource 19: battlestarwiki 20: incubator 21: memoryalpha 22: species 23: pakanto 24: wiktionary 25: mediawiki 26: mdc 27: wikipedia 28: wikitech 29: wikitravel_shared 30: mozilla 31: commons 32: omegawiki 33: openttd 34: uncyclopedia 35: wikiquote 36: wikitravel 37: wesolve 38: mac_wikicities 39: meta Select family of sites we are working on (default: wikipedia): 2 The language code of the site we're working on (default: 'en'): cs Username (cs wikiversity): RObot 'user-config.py' written.
Výsledný soubor user-config.py má asi 220 řádek, ale nejdůležitější na něm jsou řádky:
family = 'wikiversity' mylang = 'cs' usernames['wikiversity']['cs'] = u'RObot'
Pokud bude náš bot pracovat na více projektech, může mít v konfiguračním souboru více usernames, např:
usernames['wikiversity']['cs'] = u'RObot' usernames['wikiversity']['en'] = u'RObot' usernames['wikinews']['cs'] = u'RObot'
Nakonec se vrátíme zpět do adresáře RObot, ve kterém budeme vytvářet svoje první skripty.
cd ..
[editovat] Stažení stránky: RObot-page.get.py
Dále zkusíme experimentovat podle en:Pywikipediabot. Pokud se prokoušeme až k 5. lekci, budeme mít v adresáři RObot hotový např. takovýto skript ke stažení domácí stránky Uživatel:RObot z české Wikiverzity:
#!/usr/bin/python # -*- coding: utf-8 -*- mydir = "./" pwbdir = mydir + "pywikipedia/" import sys sys.path.append(pwbdir) from wikipedia import * language = "cs" family = "wikiversity" site = getSite(language,family) pagename = "Uživatel:RObot" page = Page(site,pagename) pagetext = page.get() print pagetext
Nastavíme našemu prvnímu botovi (tj. souboru s tímto skriptem) příznak executability a spustíme jej:
chmod u+x RObot-page.get.py ./RObot-page.get.py
Výsledkem je překvapení:
Checked for running processes. 1 processes currently running, including the current process.
Traceback (most recent call last):
File "./RObot.py", line 15, in <module>
page = Page(site,pagename)
File "./pywikipedia/wikipedia.py", line 347, in __init__
t = html2unicode(title)
File "./pywikipedia/wikipedia.py", line 4060, in html2unicode
result += text
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 1: ordinal not in range(128)
Na 15. řádku, kde vznikla chyba máme příkaz:
page = Page(site,pagename)
Mluví se tam cosi o kódování a tak tušíme problém v předchozím řádku:
pagename = "Uživatel:RObot"
Pokud tento řádek nahradíme ekvivalentem:
pagename = "Uživatel:RObot"
dostaneme kýženou stránku. Vkrádá se zlé tušení, že tvůrci knihovny Pywikipedia nějak pozapomněli na možnost znaků UTF-8. Po delším pátrání v bugreportech zjistíme, že chyba naštěstí není v knihovně, ale jen že si anglofonní pisatelé kursu na en:Pywikipediabot nedělali problém s nějakými nabodeníčky. A získáme poučení, že v Pythonu musíme všechny řetězce, které vkládáme v UTF-8, uvozovat znakem u. Správný zápis inkriminovaného řádku tudíž bude:
pagename = u"Uživatel:RObot"
[editovat] Speciální stránky
Myslíme na první úkol pro našeho RObota, a to získání seznamu všech naposledy změněných stránek za určité období. Vypadá to, že není nic znažšího než v našem skriptu použít řádek:
pagename = u"Speciální:Poslední změny"
Výsledkem je chyba:
Checked for running processes. 1 processes currently running, including the current process.
Traceback (most recent call last):
File "./RObot-page.get.py", line 19, in <module>
pagetext = page.get()
File "./pywikipedia/wikipedia.py", line 654, in get
raise NoPage('%s is in the Special namespace!' % self.aslink())
Nepomůžou ani pokusy, uvést jméno stránky jako:
pagename = u"Speciální:Recentchanges" pagename = u"Speciální:Recentchanges" pagename = "Special:Recentchanges"
Stále tatáž chybová hláška nám říká, že jméno stránky je ve jmenném prostoru Special, což sice víme, ale proč to tak vadí?
Zkusíme se podívat do zdroje. Najdeme soubor, který tu hlášku generuje:
grep 'Special namespace' pywikipedia/* pywikipedia/wikipedia.py: raise NoPage('%s is in the Special namespace!' % self.aslink()) Binární soubor pywikipedia/wikipedia.pyc odpovídá
Příslušný kus kódu nám říká:
# NOTE: The following few NoPage exceptions could already be thrown at
# the Page() constructor. They are raised here instead for convenience,
# because all scripts are prepared for NoPage exceptions raised by
# get(), but not for such raised by the constructor.
# \ufffd represents a badly encoded character, the other characters are
# disallowed by MediaWiki.
for illegalChar in u'#<>[]|{}\n\ufffd':
if illegalChar in self.sectionFreeTitle():
if verbose:
output(u'Illegal character in %s!' % self.aslink())
raise NoPage('Illegal character in %s!' % self.aslink())
if self.namespace() == -1:
raise NoPage('%s is in the Special namespace!' % self.aslink())
if self.site().isInterwikiLink(self.title()):
raise NoPage('%s is not a local page on %s!'
% (self.aslink(), self.site()))
Tušíme, že to má cosi dělat se třídou Page. Kde se definuje?
grep 'class Page' * archivebot.py:class PageArchiver(object): BeautifulSoup.py:class PageElement: followlive.py:class PageHandler: pagefromfile.py:class PageFromFileRobot: pagefromfile.py:class PageFromFileReader: wikipedia.py:class PageNotSaved(Error): wikipedia.py:class PageNotFound(Error): wikipedia.py:class Page(object):
Tak vše je zřejmě v tom největším souboru wikipedia.py. Předpokládáme, že bychom se tam mohli o tom něco dočíst:
class Page(object): """Page: A MediaWiki page Constructor has two required parameters: 1) The wiki Site on which the page resides [note that, if the title is in the form of an interwiki link, the Page object may have a different Site than this] 2) The title of the page as a unicode string Optional parameters: insite - the wiki Site where this link was found (to help decode interwiki links) defaultNamespace - A namespace to use if the link does not contain one Methods available: title : The name of the page, including namespace and section if any urlname : Title, in a form suitable for a URL namespace : The namespace in which the page is found titleWithoutNamespace : Title, with the namespace part removed section : The section of the page (the part of the title after '#', if any) sectionFreeTitle : Title, without the section part aslink : Title in the form [[Title]] or [[lang:Title]] site : The wiki this page is in encoding : The encoding of the page isAutoTitle : Title can be translated using the autoFormat method autoFormat : Auto-format certain dates and other standard format page titles isCategory : True if the page is a category isDisambig (*) : True if the page is a disambiguation page isImage : True if the page is an image isRedirectPage (*) : True if the page is a redirect, false otherwise getRedirectTarget (*) : The page the page redirects to isTalkPage : True if the page is in any "talk" namespace toggleTalkPage : Return the talk page (if this is one, return the non-talk page) get (*) : The text of the page latestRevision (*) : The page's current revision id userName : Last user to edit page isIpEdit : True if last editor was unregistered editTime : Timestamp of the last revision to the page previousRevision (*) : The revision id of the previous version permalink (*) : The url of the permalink of the current version getOldVersion(id) (*) : The text of a previous version of the page getRestrictions : Returns a protection dictionary getVersionHistory : Load the version history information from wiki getVersionHistoryTable: Create a wiki table from the history data fullVersionHistory : Return all past versions including wikitext contributingUsers : Return set of users who have edited page exists (*) : True if the page actually exists, false otherwise isEmpty (*) : True if the page has 4 characters or less content, not counting interwiki and category links interwiki (*) : The interwiki links from the page (list of Pages) categories (*) : The categories the page is in (list of Pages) linkedPages (*) : The normal pages linked from the page (list of Pages) imagelinks (*) : The pictures on the page (list of ImagePages) templates (*) : All templates referenced on the page (list of Pages) templatesWithParams(*): All templates on the page, with list of parameters getReferences : List of pages linking to the page canBeEdited (*) : True if page is unprotected or user has edit privileges botMayEdit (*) : True if bot is allowed to edit page put(newtext) : Saves the page put_async(newtext) : Queues the page to be saved asynchronously move : Move the page to another title delete : Deletes the page (requires being logged in) protect : Protect or unprotect a page (requires sysop status) removeImage : Remove all instances of an image from this page replaceImage : Replace all instances of an image with another loadDeletedRevisions : Load all deleted versions of this page getDeletedRevision : Return a particular deleted revision markDeletedRevision : Mark a version to be undeleted, or not undelete : Undelete past version(s) of the page (*) : This loads the page if it has not been loaded before; permalink might even reload it if it has been loaded before """
Kromě spousty zajímavých věcí jmse možná hledali tuhle informaci:
"""
Optional parameters:
defaultNamespace - A namespace to use if the link does not contain one
"""
Je to divné, protože sz toho vyrozumívám, že jestliže název jmenného prostoru uvedu před jménem stránky, tak bych nemusel nastavovat defaultní jmenný prostor. Ale kdoví. Pythonu neznajíce, pokusíme se trochu experimentovat s kódem:
#!/usr/bin/python # -*- coding: utf-8 -*- mydir = "./" pwbdir = mydir + "pywikipedia/" import sys sys.path.append(pwbdir) from wikipedia import * language = "cs" family = "wikiversity" site = getSite(language,family) #defaultNamespace = u"Speciální" defaultNamespace = u"Speciální:" pagename = u"Poslední změny" page = Page(site,pagename,defaultNamespace) pagetext = page.get() print pagetext
Obdržená chyba je zase o jakési chybě v kódování:
Checked for running processes. 1 processes currently running, including the current process.
Traceback (most recent call last):
File "./RObot-page.get.py", line 22, in <module>
page = Page(site,pagename,defaultNamespace)
File "./pywikipedia/wikipedia.py", line 353, in __init__
t = url2unicode(t, site = insite, site2 = site)
File "./pywikipedia/wikipedia.py", line 3959, in url2unicode
encList = [site.encoding()] + list(site.encodings())
AttributeError: 'unicode' object has no attribute 'encoding'
(Tak zatím jsem nezjistil, co s tím, třeba nám s tím někdo zkušenější poradí. Zkouším googlit:
pywikipedia special namespace
ale zatím bez většího úspěchu. --Kychot 28. 12. 2008, 14:10 (UTC))