"""
Python wrapper for Microsoft.com web services
1) Get a developer's token from http://msdn.microsoft.com/webservices/building/livewebservices/mscomservices/default.aspx
2) Create a file called mstoken.py formatted like this:
token = '2346iusdflkjah9873562'
pin = 'aksjdhfliaugw34'
3) Call msweb.getVersion, msweb.getCultures, or msweb.getTopDownloads
"""
__AUTHOR__ = (('Mark Pilgrim', 'http://diveintomark.org/'),
('Sam Ruby', 'http://intertwingly.net/'))
__LICENSE__ = 'Python'
import random, binascii, urllib2, time, sha, types
from xml.sax.saxutils import escape
from xml.dom import minidom
import mstoken # required, see module doc
try:
from htmlentitydefs import codepoint2name
except:
import htmlentitydefs
codepoint2name={}
for (name,codepoint) in htmlentitydefs.entitydefs.iteritems():
if codepoint.startswith(''): codepoint=unichr(int(codepoint[2:-1]))
codepoint2name[ord(codepoint)]=name
endpoint = 'http://ws.microsoft.com/mscomservice/mscom.asmx'
def buildHeader(token=mstoken.token, pin=mstoken.pin):
nonce = sha.new(str(random.random())).digest()
created = time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime(time.time()))
digest = sha.new(nonce + created + pin).digest()
securityParams = {
'PasswordDigest': binascii.b2a_base64(digest),
'Username': token,
'Nonce': binascii.b2a_base64(nonce),
'Created': created,
'Expires': time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime(time.time()+180))
}
return """
%(Username)s
%(PasswordDigest)s
%(Nonce)s
%(Created)s
%(Expires)s
""" % securityParams
def buildBody(methodName, argDict):
soapHeader = buildHeader()
methodParams = ''
for k, v in argDict.items():
v = escape(str(v))
methodParams += '<%s>%s%s>\n' % (k, escape(v), k)
return """
%(soapHeader)s
<%(methodName)s xmlns="http://www.microsoft.com">
%(methodParams)s
%(methodName)s>
""" % vars()
def sendRequest(methodName, argDict):
request = urllib2.Request(endpoint, buildBody(methodName, argDict))
request.add_header("Content-type", "text/xml")
request.add_header("SOAPAction", '"http://www.microsoft.com/%s"' % methodName)
doc = minidom.parse(urllib2.urlopen(request)).documentElement
doc = doc.getElementsByTagNameNS("http://schemas.xmlsoap.org/soap/envelope/","Body")[0]
doc.normalize()
strip(doc)
doc = doc.childNodes[0].childNodes[0]
return doc
def strip(e):
for n in list(e.childNodes):
if n.nodeType == n.ELEMENT_NODE:
strip(n)
elif len(e.childNodes)>1:
e.removeChild(n)
def htmlescape(data):
"escape all entities and non-7bit ASCII characters"
for i in range(len(data)-1,-1,-1):
n=ord(data[i])
if n<128: continue
if n in codepoint2name:
data = '%s&%s;%s' % (data[:i], codepoint2name[n], data[i+1:])
else:
data = '%s%d;%s' % (data[:i], n, data[i+1:])
return str(data)
def getVersion():
data = sendRequest('GetVersion', {})
return htmlescape(data.childNodes[0].nodeValue)
def getCultures():
data = sendRequest('GetCultures', {})
return dict([[htmlescape(node.childNodes[0].nodeValue)
for node in child.childNodes] for child in data.childNodes])
def getTopDownloads(type="Popular", topN=10, cultureID="en-US"):
"""type in ('Popular', 'Recent')
1 <= topN <= 25
cultureID one of keys returned from getCultures
"""
data = sendRequest('GetTopDownloads', vars())
return [dict([(str(t.nodeName),htmlescape(t.childNodes[0].nodeValue))
for t in node.childNodes]) for node in data.childNodes]
def getDownloadDetail(downloadID, cultureID="en-US"):
"""downloadID one of IDs returned from getTopDownloads
cultureID one of keys returned from getCultures
"""
data = sendRequest('GetDownloadDetail', vars())
data = dict([(str(node.nodeName),node.childNodes) for node in data.childNodes])
for (name,value) in data.items():
if len(value)==0: continue
if value[0].nodeType == value[0].TEXT_NODE:
data[name]=htmlescape(value[0].nodeValue)
elif name=='Releases':
data[name] = [dict([(str(t.nodeName),
[dict([(str(y.nodeName),htmlescape(y.childNodes[0].nodeValue))
for y in x.childNodes]) for x in t.childNodes])
for t in node.childNodes]) for node in value]
else:
data[name]=[dict([(str(t.nodeName),htmlescape(t.childNodes[0].nodeValue))
for t in node.childNodes]) for node in value]
return data
if __name__ == '__main__':
from pprint import pprint
print getVersion()
pprint(getCultures())
pprint(getTopDownloads())
pprint(getDownloadDetail('141d5f9e-07c1-462a-baef-5eab5c851cf5'))