MediaWiki:Dump.py

Z WikiSkript

Dump.py je jednoduchý skript napsaný v pythonu spouštěný každý den na serveru WikiSkript. Získává data z databáze, vytváří databázový dump ve formátu xml a ukládá je do souboru https://www.wikiskripta.eu/extensions/Dumps/dump.xml (cca 30 MB). Tento soubor může být využit botem OmniBotem, který má být „user-friendly“, s grafickým rozhraním a je určen všem členům redakce WikiSkript.

Dump obsahuje poslední verze článků a poslední verze diskuzních stránek. Je ve standardním formátu dle Media Wiki.

K získávání dat z databáze je využívána speciální stránka Special:Export.

Zdrojový kód

Skript je možné spustit z příkazové řádky příkazem:

python dump.py --file /cesta/k/souboru_dump.xml --url "https://www.wikiskripta.eu/"
#coding=utf-8
#!/usr/bin/python
import xml.dom.minidom
import urllib, urllib2
from optparse import OptionParser
debug = False

class Api:
	#apiurl = "https://www.wikiskripta.eu/api.php"
	apiurl = "http://www.wikilectures.eu/api.php"
	url = ""
	changedPages = []
	nonId = ['0', '1']
	mainNamespaceIds = []
	mainNamespacePages = []
	talkNamespacePages = []

	def __init__(self, url, pocetHodin):
		self.apiurl = url + "api.php"
		self.url = url
		self.mainNamespacePages = self.allpages(0)
		self.talkNamespacePages = self.allpages(1)
	def request(self, values, tagname):
		"""Provede žádost API o stránku. Je nutné, aby žádost byla koncipována tak, že vrací informace pouze v jednom tagu. Funkce frací informace v podobě dictionary, kam přidá i token pro pokračování (querycontinue)."""
		data = urllib.urlencode(values)
		request = urllib2.Request(self.apiurl, data)
		response = urllib2.urlopen(request)
		xmlText = response.read()
		dom = xml.dom.minidom.parseString(xmlText)
		if (debug): print dom.toprettyxml()
		returnValue = {}
		try:
			tag = dom.getElementsByTagName(tagname)[0]
			for key in tag.attributes.keys():
				returnValue[key] = tag.getAttribute(key)
			if (tag.firstChild):
				returnValue[u'text'] = tag.firstChild.nodeValue
		except Exception:
			print "Could not get DOM node:", tagname

		try:
			if (dom.getElementsByTagName("query-continue")):
				querycontinueNode = dom.getElementsByTagName("query-continue")[0].childNodes[0]
				for key in querycontinueNode.attributes.keys():
					returnValue[key] = querycontinueNode.getAttribute(key)
		except Exception:
			print "Could not get DOM node: query-continue"
		return returnValue

	def requestList(self, values, tagname, attribute):
		"""Provede žádost API o stránku. Je nutné, aby žádost byla koncipována tak, že vrací informace jsou v různých tazích, ale všechny tagy tohoto názvu mají stejnou strukturu atributů. Funkce vrací informace atributu v podobě list."""
		data = urllib.urlencode(values)
		request = urllib2.Request(self.apiurl, data)
		response = urllib2.urlopen(request)
		xmlText = response.read()
		dom = xml.dom.minidom.parseString(xmlText)
		if (debug): print dom.toprettyxml()
		returnValue = []
		try:
			tags = dom.getElementsByTagName(tagname)
			for tag in tags:
				if (attribute):
					returnValue.append(tag.getAttribute(attribute))
				else:
					returnValue.append(tag.childNodes[0].toxml())
		except Exception:
			print "Error: ", e
			print "Could not get DOM node:", tagname
		return returnValue

	def getText(self, pageid):
		values = {'action': 'query', 'prop': 'revisions', 'pageids': pageid, 'rvprop': 'content', 'format': 'xml' }
		request = self.request(values, 'rev')
		if (request != {} and u'text' in request.keys()):
			return request[u'text']
		else:
			return False

	def getExternalLinks(self, page):
		"""Získá externí odkazy ze článku. Vrací jako list."""
		values = {'action': 'query', 'prop': 'extlinks', 'titles': page, 'format': 'xml'}
		request = self.requestList(values, "el", None)
		if (debug): print request
		return request 

	def allpages(self, namespace):
		"""Funkce vrátí seznam všech článků (id) ve jmenném prostoru namespace."""
		pages = []
		values = {'action': 'query', 'list': 'allpages', 'apnamespace': str(namespace), 'apfilterredir': 'nonredirects', 'aplimit': '1', 'format': 'xml'}
		request = self.request(values, 'p')
		#pages.append(request[u'pageid'])
		pages.append(request[u'title'])
		while (u'apfrom' in request.keys()):
			values = {
				'action': 'query',
				'list': 'allpages',
				'apnamespace': str(namespace),
				'apfilterredir': 'nonredirects',
				'aplimit': '1',
				'apfrom': request[u'apfrom'].encode("utf-8"),
				'format': 'xml'
			}
			request = self.request(values, 'p')
			self.mainNamespaceIds.append(request[u'pageid'])
			pages.append(request[u'title'])
			if (debug): print request[u'title'],",",request[u'pageid']
		return pages

	def recentChanges(self, pocetHodin):
		"""Funkce vrátí seznam článků (id), u nichž doslo za posledních `pocetHodin` hodin ke změně. Vybírají se pouze editace z hlavního jmenného prostoru."""
		recentchanges = []
		#rcstart = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(time.time() - 12 * 3600))
		rcstart = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
		rcend = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(time.time() - 12 * 3600 - pocetHodin * 3600))
		values = {'action': 'query', 'list': 'recentchanges', 'rcprop': 'title|ids|timestamp', 'rclimit': 1, 'rcstart':	rcstart, 'rcend': rcend, 'format': 'xml'}
		request = self.request(values, "rc")
		while (u'rcstart' in request.keys()):
			values['rcstart'] = request[u'rcstart']
			request = self.request(values, "rc")
			if (not u":" in request[u'title'] and not request[u'pageid'] in recentchanges):
				recentchanges.append(request[u'pageid'])
		self.changedPages = recentchanges
	def getRevisionSummaries(self, pageTitle):
		"""Funkce vrátí seznam shrnutí všech editací daného článku."""
		request = []
		rvstart = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
		try:
			values = {'action': 'query', 'prop': 'revisions', 'titles': pageTitle.encode("utf-8"), 'rvprop': 'timestamp|user|comment', 'rvstart': rvstart, 'rvlimit': '500', 'format': 'xml'}
			request = self.requestList(values, 'rev', 'comment')
		except Exception:
			pass
		print request
		return request
	def getDumpXML(self, pages):
		exportURL = self.url + "index.php?title=Special:Export&action=submit"
		values = {'curonly': 1, 'pages': "\n".join([fromUnicode(page) for page in pages])}

		data = urllib.urlencode(values)
		request = urllib2.Request(exportURL, data)
		response = urllib2.urlopen(request)
		xmlText = response.read()
		return xmlText


def fromUnicode(unicodeString):
	returnString = ""
	citliveZnaky = { 382: 'ž', 269: 'č', 283: 'ě', 237: 'í', 352: 'Š', 225: 'á', 345: 'ř', 353: 'š', 253: 'ý', 367: 'ů', 233: 'é', 381: 'Ž', 268: 'Č', 218: 'Ú', 250: 'ú', 357: 'ť', 271: 'ď', 328: 'ň', 243: 'ó', 8230: '…', 8222: '„', 8220: '“', 8722: '−', 318: 'ľ', 270: 'Ď', 244: 'ô', 154: 'š', 8211: '–', 327: 'Ň', 205: 'Í', 183: '·', 215: '×', 344: 'Ř', 9742: '☎', 9997: '✍', 322: 'ł', 232: 'è', 221: 'Ý', 8212: '—', 160: ' ', 167: '§', 61474: '', 252: 'ü', 177: '±', 945: 'α', 228: 'ä', 960: 'π', 246: 'ö', 946: 'β', 176: '°', 346: 'Ś', 282: 'Ě', 193: 'Á', 352: 'Š', 366: 'Ů', 180: '´', 8217: '’', 231: 'ç', 224: 'à', 201: 'É', 314: 'ĺ', 8218: '‚', 8219: '‛', 914: 'Β' }
	czKeys = citliveZnaky.keys()
	for char in unicodeString:
		if (ord(char) in czKeys):
			returnString = returnString + citliveZnaky[ord(char)]
		else:
			returnString = returnString + str(char)
	return returnString
if __name__ == '__main__':
	parser = OptionParser()
	parser.add_option("-d", "--debug",
					action="store_true", dest="debug", default=False, help="print status messages to stdout for debug")
	parser.add_option("-f", "--file",
					action="store", dest="file", default="dump.xml", help="name of the file where the dump shall be stored, default is \"dump.xml\"")
	parser.add_option("-u", "--url",
					action="store", dest="url", default="https://www.wikiskripta.eu/", help="url of the project (with slash)")
	(options, args) = parser.parse_args()
	debug = options.debug
	extlinks = []
	foo = Api(options.url, 24)
	dump = foo.getDumpXML(foo.mainNamespacePages + foo.talkNamespacePages)
	if (options.file):
		f = open(options.file, "w")
	else:
		f = open("dump.xml", "w")
	f.write(dump)
	f.close()

Použití

#!/bin/bash
cd /path/to/ws
previousDate="ws-dump-"`date --date="2 days ago" +%y-%m-%d`".xml"
today="ws-dump-"`date +%y-%m-%d`".xml"
echo "<html><head><title>WS Dumps</title></head><body>" > index.html
echo "<h1>" >> index.html
date >> index.html
echo "</h1>" >> index.html

chmod +r index.html
rm $previousDate
runningTime=`time python ../dump.py -u "https://www.wikiskripta.eu/" -f $today`
echo "<p>"$runningTime"</p>" >> index.html

echo "<table>" >> index.html
for fileName in `ls *.xml`
do
fileSize=`ls -l -h $fileName | awk "{print \\$5}"`
fileDate=`ls -l -h $fileName | awk "{print \\$6}"`
fileTime=`ls -l -h $fileName | awk "{print \\$7}"`
echo "<tr>" >> index.html
echo "<td><a href='http://path/to/ws/"$fileName"'>"$fileName"</a></td>" >> index.html
echo "<td>"$fileSize"</td>" >> index.html
echo "<td>"$fileDate"</td>" >> index.html
echo "<td>"$fileTime"</td>" >> index.html
echo "</tr>" >> index.html
done
echo "</table>" >> index.html

CRON

m h dom mon dow command
00 01 * * * /path/to/create-ws-dump.sh