daily pastebin goal
51%
SHARE
TWEET

Scratch Wiki API

blob8108 Feb 19th, 2013 147 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # A simple scratch wiki interface. Can:
  2. #   * list pages in category
  3. #   * read page (download wiki markup)
  4. # ~blob8108
  5. # http://wiki.scratch.mit.edu/
  6.  
  7. import httplib2
  8. from urllib import urlencode
  9. import json
  10.  
  11.  
  12.  
  13. class WikiError(Exception):
  14.     def __init__(self, error):
  15.         self.info = None
  16.         self.__dict__.update(error)
  17.    
  18.     def __str__(self):
  19.         return self.info
  20.  
  21. class PermissionDenied(WikiError): pass
  22.  
  23.  
  24.  
  25. ERRORS = {
  26.     'permissiondenied': PermissionDenied,
  27. }
  28.  
  29.  
  30.  
  31. class Page(object):
  32.     def __init__(self, wiki, **data):
  33.         self.wiki = wiki
  34.         self.title = None
  35.         self.__dict__.update(data)
  36.    
  37.     def __repr__(self):
  38.         return "<Page(%s)>" % repr(self.title)
  39.    
  40.     def __unicode__(self):
  41.         return self.title
  42.    
  43.     def query_info(self, **kwargs):
  44.         arguments = dict(
  45.             action = "query",
  46.             titles = self.title,
  47.         )
  48.         arguments.update(kwargs)
  49.         data = self.wiki.request(**arguments)
  50.         page_data = data["query"]["pages"].values()[0]
  51.         return page_data
  52.        
  53.     def read(self):
  54.         data = self.query_info(
  55.             prop = "revisions",
  56.             rvprop = "content",
  57.         )
  58.         return data["revisions"][0]["*"]
  59.        
  60.     def edit_token(self):
  61.         data = self.query_info(
  62.             prop = "info",
  63.             intoken = "edit",
  64.         )
  65.         return data["edittoken"]
  66.    
  67.     def edit(self, content, summary):
  68.         token = self.edit_token()
  69.        
  70.         return self.wiki.post_request(
  71.             action = "edit",
  72.             title = self.title,
  73.             token = token,
  74.             text = content,
  75.             summary = summary,
  76.             bot = 1,
  77.             nocreate = 1,
  78.         )
  79.        
  80.  
  81.  
  82.  
  83. class ScratchWiki(object):
  84.     URL = "http://wiki.scratch.mit.edu/"
  85.     API_ENDPOINT = URL + "api.php"
  86.     USER_AGENT = "PythonBot ~blob8108"
  87.    
  88.     def __init__(self):
  89.         self.http = httplib2.Http()
  90.    
  91.     def login(self, username, password):
  92.         # Seems broken -- maybe API login is disabled?
  93.         arguments = dict(
  94.             action = "login",
  95.             lgname = username,
  96.             lgpassword = password,
  97.         )
  98.         data = self.post_request(**arguments)["login"]
  99.         print data
  100.        
  101.         if data["result"] == "NeedToken":
  102.             arguments["lgtoken"] = data["token"]
  103.             data = self.post_request(**arguments)["login"]
  104.             return data
  105.        
  106.         # Login using HTML form
  107.         # return self.request(
  108.         #     _url = self.URL + "index.php",
  109.         #     _method = "POST",
  110.         #     _form = dict(
  111.         #         wpName = username,
  112.         #         wpPassword = password,
  113.         #         wpRemember = 1,
  114.         #         wpLoginattempt = "Log in",
  115.         #         wpLoginToken = "70a839b065603b5dfc4d5da213a3b197",
  116.         #     ),
  117.         #     title = "Special:UserLogin",
  118.         #     action = "submitlogin",
  119.         #     type = "login",
  120.         # )
  121.    
  122.     def request(self, **arguments):        
  123.         arguments = dict(filter(lambda (arg, value): value is not None, arguments.items()))
  124.         arguments["format"] = "json"
  125.         is_json = True
  126.        
  127.         url = self.API_ENDPOINT + "?" + urlencode(arguments)
  128.         arguments.setdefault("_url", url)
  129.         url = arguments.pop("_url")
  130.        
  131.         arguments.setdefault("_method", "GET")
  132.         method = arguments.pop("_method")
  133.        
  134.         arguments.setdefault("_headers", {
  135.             "User-Agent": self.USER_AGENT,
  136.         })
  137.         headers = arguments.pop("_headers")
  138.        
  139.         body = None
  140.         arguments.setdefault("_form", None)
  141.         form = arguments.pop("_form")
  142.         if form:
  143.             body = urlencode(form)
  144.             headers.update({
  145.                 "Content-Type": "application/x-www-form-urlencoded",
  146.             })
  147.             is_json = False
  148.        
  149.         (response, data) = self.http.request(url, method, body, headers)
  150.        
  151.         assert response["status"] == "200"
  152.        
  153.         if is_json:
  154.             data = json.loads(data)
  155.             if 'error' in data:
  156.                 error = data['error']
  157.                 error_code = error['code']
  158.                 if error_code in ERRORS:
  159.                     error_cls = ERRORS[error_code]
  160.                 else:
  161.                     raise WikiError(error)
  162.                 raise error_cls(error)
  163.        
  164.         return data
  165.    
  166.     def post_request(self, **arguments):
  167.         return self.request(_method = "POST", **arguments)
  168.    
  169.     def category_members(self, title, limit = 500):
  170.         if not title.startswith("Category:"):
  171.             title = "Category:" + title
  172.        
  173.         start_from = None
  174.         while 1:
  175.             data = self.request(
  176.                 action = "query",
  177.                 list = "categorymembers",
  178.                 cmtitle = title,
  179.                 cmlimit = limit,
  180.                 cmcontinue = start_from,
  181.             )
  182.             for page in data["query"]["categorymembers"]:
  183.                 yield Page(self, **page)
  184.            
  185.             if "query-continue" in data:
  186.                 start_from = data["query-continue"]["categorymembers"]["cmcontinue"]
  187.             else:
  188.                 break
  189.        
  190.  
  191.  
  192. wiki = ScratchWiki()
  193. #for page in wiki.category_members("Redirects"):
  194. #    print page.title
  195. page = wiki.category_members("Redirects").next()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top