Zammy Wiki


< TyBot | GEMWbot

2,249pages on
this wiki
Add New Page
Talk0 Share

Ad blocker interference detected!

Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

# -*- coding: utf-8 -*-
""" A mid-level wrapper for using MediaWiki API."""
from simplemediawiki import MediaWiki, DEFAULT_UA, build_user_agent
from urllib import urlencode
from langcodes import iso639_1 as isolangs
from time import strftime, gmtime
#from hashlib import md5
from BeautifulSoup import BeautifulSoup
import sys
import urllib2
import re
import cookielib
__all__ = ["WikiBot", "Page", "User"]
__version__ = "0.0.3"
__status__ = "Prototype"
class WikiBot(MediaWiki):
    def __init__(self, api_url, cookie_file=None, user_agent=DEFAULT_UA):
        MediaWiki.__init__(self, api_url, cookie_file, user_agent)
        # setting attributes to save API queries
        self.siteinfo ={"action":"query", "meta":"siteinfo"})["query"]["general"]
    def __repr__(self):
        q = self.siteinfo
        text = "{lang} {sitename} ({mw})"
        return text.format(lang=isolangs[q["lang"]]["name"], sitename=q["sitename"], mw=q["generator"])
    def safeprint(text, errors="replace"):
        print text.encode(sys.stdout.encoding or "utf-8", errors)
    def query(self, **kwargs):
    def setedittoken(self):
        query = {"action":"query", "prop":"info", "intoken":"edit", "titles":"Main Page"}
        q =["query"]["pages"]
        for c in q:
                self.edittoken = q[c]["edittoken"]
            except: # no edit privilege for us
                self.edittoken = None; return False
                return True
    def setmovetoken(self):
        query = {"action":"query", "prop":"info", "intoken":"move", "titles":"Main Page"}
        q =
        for x in q["query"]["pages"]:
                self.movetoken = q["query"]["pages"][x]["movetoken"]
            except: # no move privilege for us
                self.movetoken = None; return False
                return True
    def setindexurl(self):
        apiurl = self.normalize_api_url()
        if apiurl is None:
            self.index_url = None
            self.index_url = apiurl.split("api.php")[0]+"index.php"
    def page(self, title):
        return Page(self, title)
    def user(self, name):
        return User(self, name)
    def diff(self, diffid, oldid):
        #diff(484144434, 484144169), diff(487104284, 486959056) on enwp
        # action=render makes the page much more machine-readable
        params = {"diff":diffid, "oldid":oldid, "action":"render", "diffonly":1}
        ua = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko/20100101 Firefox/11.0"
        req = urllib2.Request(self.index_url+"?"+urlencode(params), headers={"User-Agent":ua})
        diff_ = urllib2.urlopen(req)
        html =; diff_.close();
        soup = BeautifulSoup(html)
        deleted2 = []; added2 = [];
        added = soup.findAll("td", attrs="diff-addedline")
        deleted = soup.findAll("td", attrs="diff-deletedline")
        # remove <td>, make it like <div>bla<span...>h</span></div>
        # this will get the span contents too
        for tags in added:
            if len(tags.contents) == 0:
            elif len(tags.contents[0].findAll("span", attrs="diffchange diffchange-inline")) == 0:
            added2.extend(tags.contents[0].findAll("span", attrs="diffchange diffchange-inline"))
        for tags in deleted:
            if len(tags.contents) == 0:
            elif len(tags.contents[0].findAll("span", attrs="diffchange diffchange-inline")) == 0:
            deleted2.extend(tags.contents[0].findAll("span", attrs="diffchange diffchange-inline"))
        added2 = [str(x.string) for x in added2]
        deleted2 = [str(x.string) for x in deleted2]
        return added2, deleted2
    def getpage(self, title, revid=None):
        query = {"action":"query", "titles":title, "prop":"revisions", "rvprop":"content"}
        if revid is not None:
            query["rvstartid"] = revid
        content =
        content = content["query"]["pages"]
        return content[content.keys()[0]]["revisions"][0]["*"]
    def editcount(self, user):
        query ={"action":"query", "list":"allusers", "auprop":"editcount", "aulimit":1, "aufrom":user})
        return query["query"]["allusers"][0]["editcount"]
    def gettransclusions(self, page, ns=[], eicontinue=None):
        #pages = []
        while True:
            query = {"action":"query", "list":"embeddedin", "eititle":page, "einamespace":"|".join(ns), "eilimit":100}
            if eicontinue is not None:
                query["eicontinue"] = eicontinue
            result =
            for x in result["query"]["embeddedin"]:
                yield x["title"]
            if "query-continue" not in result:
                #return pages
                eicontinue = result["query-continue"]["embeddedin"]["eicontinue"]
        #return pages
    def prefixindex(self, page, ns=[], apfrom=None):
        #pages = []
        while True:
            query = {"action":"query", "list":"allpages", "apprefix":page, "apnamespace":"|".join(ns), "aplimit":100}
            if apfrom is not None:
                query["apfrom"] = apfrom
            result =
            for x in result["query"]["allpages"]:
                yield x["title"]
            if "query-continue" not in result:
                #return pages
                apfrom = result["query-continue"]["allpages"]["apfrom"]
        #return pages
    def allpages(self, start, limit=500, apfrom=None):
        #pages = []
        while True:
            query = {"action":"query", "list":"allpages", "apfrom":start, "aplimit":limit}
            if start is not None:
                query["apfrom"] = start
            result =
            for x in result["query"]["allpages"]:
                yield x["title"]
            if "query-continue" not in result:
                #return pages
                start = result["query-continue"]["allpages"]["apfrom"]
        #return pages
    def randompages(self, ns=None, redir=False, limit=1):
        #pages = []
        query = {"action":"query", "list":"random", "rnlimit":limit}
        if ns is not None:
            query["rnnamespace"] = ""
        if redir is not False:
            query["rnredirect"] = ""
        for page in["query"]["random"]:
            yield page["title"]
        #return pages
    def exturlusage(self, url=None, limit=500, eucontinue=None):
        #links = []
        for counter in xrange(limit):#while True:
            query = {"action":"query", "list":"exturlusage", "eulimit":limit}
            if eucontinue is not None:
                query["eucontinue"] = eucontinue
            if url is not None:
                query["euquery"] = url
            result =
            for x in result["query"]["exturlusage"]:
                yield x["url"]
            if "query-continue" not in result:
                #return links
                eucontinue = result["query-continue"]["exturlusage"]["euoffset"]
                #print "Continuing (%d)" % counter
        #return links
    def movepage(self, old, target, reason="", *args):
        token_query = {"action":"query", "prop":"info", "intoken":"move", "titles":old}
        for x in["query"]["pages"]:
            token =["query"]["pages"][x]["movetoken"]
        move_params = {"action":"move", "from":old, "to":target, "reason":reason, "token":token}
        for arg in args:
            move_params[arg] = ""
    def rollback(page, user, reason=None, bot=False):
        token_query = {"action":"query", "prop":"revisions", "rvtoken":"rollback", "titles":page}
        for pageid in token_query:
            token = token_query[pageid]["revisions"][0]["rollbacktoken"]
        rollback_query = {"action":"rollback", "title":page, "user":user, "token":token}
        if reason is not None:
            rollback_query["summary"] = reason
    def createaccount(self, username, password, real_name="", email=""):
        except (AttributeError, ValueError):
            return False
        post_params = {"wpName":username,
        jar = cookielib.LWPCookieJar("cookies.tmp.cookies")
        opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar))
        form =, data=urlencode({"title":"Special:UserLogin", "type":"signup", "action":"submitlogin"}))
        text =; form.close(); del form
        create_token ="<input type=\"hidden\" name=\"wpCreateaccountToken\" value=\"([0-9a-zA-Z]+)\" />", text)#form.text)
        if create_token is not None:
            post_params["wpCreateaccountToken"] =
        for cookies in jar:
            opener.addheaders.append(("Cookie", "{name}={val}".format(, val=cookies.value)))
        return"?"+urlencode({"title":"Special:UserLogin", "type":"signup", "action":"submitlogin"}), data=urlencode(post_params))
class User(object):
    This was not designed for standalone use. Use WikiBot_instance.user instead.
    @param site - an instance of WikiBot
    @param name - string
    def __init__(self, site, name): = str(name) = site
    def __repr__(self):
        return "User:"
    def editcount(self, force=False):
        query ={"action":"query", "list":"allusers", "auprop":"editcount", "aulimit":1, "aufrom"})
        self.edits = query["query"]["allusers"][0]["editcount"]
        return self.edits
    def email(self, target, subject, text, cc=False):
        params = {"target":target, "subject":subject, "text":text}
        if cc is not False: params["ccme"] = True
class Page(object):
    This was not designed for standalone use. Use instead.
    @param site - an instance of WikiBot
    @param title - string
    def __init__(self, site, title):
        self.title = title
        self.namespace = title.split(":", 1)[0] = site
    def exists(self, force=True):
        if hasattr(self, "_exists") and not force:
            return self._exists
            query = {"action":"query", "titles":self.title, "prop":"info"}
            q =["query"]["pages"]
            if "missing" in q[q.keys()[0]]:
                self._exists = False
                self._exists = True
            return self._exists
    def getcontent(self, follow_redir=True, force=False, revid=None):
        Creates a self.content attribute and returns it
        @param follow_redir - If the page is a redirect, get the content of the target
        @param revid - Get the content of the page, at revision ID revid
        query = {"action":"query", "titles":self.title, "prop":"revisions", "rvprop":"content"}
        if revid is not None:
            query["rvstartid"] = revid
        content =
        content = content["query"]["pages"]
        self.content = content
        return content[content.keys()[0]]["revisions"][0]["*"]
    def edit(self, content, summary="", minor=False, bot=False, force=False):
        page = self.title
        token =
        edit_params = {"action":"edit", "title":page, "text":content, "token":token, "summary":summary, "notminor":1, "notbot":1}
        if minor:
            edit_params["minor"] = 1; del edit_params["notminor"]
        if bot:
            edit_params["bot"] = 1; del edit_params["notbot"]
        if force is False:
            detect_ec_query = {"action":"query", "prop":"revisions", "rvprop":"timestamp", "titles":page}
            ec_timestamp_ =["query"]["pages"]
            for x in ec_timestamp_:
                if "missing" in ec_timestamp_[x]:
                    return False, "{} does not exist".format(page)
                elif ec_timestamp_[x]["ns"] == -1:
                    return False, "{} is in the Special: namespace".format(page)
                ec_timestamp = ec_timestamp_[x]["revisions"][0]["timestamp"]
            edit_params["basetimestamp"] = ec_timestamp
            edit_params["starttimestamp"] = strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())

Also on Fandom

Random Wiki