Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 7

# -*- coding: utf-8 -*import libxml2dom

import mechanize
import urllib
TUENTI_HOST = "http://m.tuenti.com"
PROFILE_URL = "/?m=profile&user_id="
URLS = {
'login': TUENTI_HOST + "/?m=login&func=process_login",
'friends': TUENTI_HOST + "/?m=friends&page=%s",
'profile': TUENTI_HOST + "/?m=profile&user_id=%s",
'comments': TUENTI_HOST + "/?m=profile&func=view_wall&user_id=%s&fpi=%s",
'my_profile': TUENTI_HOST + "/?m=profile&func=my_profile",
'set_status': TUENTI_HOST + "/?m=profile&func=process_set_status&from=home&c
sfr=%s",
'create_blog_entry': TUENTI_HOST + "/?t=profile_send_blog&ot=blog_entry&m=bl
og_entry&uid=%s",
}
MESSAGES = {
'login_error': "<small>Direccin de correo o contrasea invlidos.</small>",
'more_friends': ">Ver ms amigos</a>",
'more_comments': ">Ver ms comentarios del tabln</a>",
'wall': u"Tabln de",
'my_wall': u"Mi tabln",
'restricted_area': "<div class=\"h\">Acceso Restringido</div>",
'status': "<b>Estado</b>",
'status_verb': u"est",
}
HTTP_RESPONSE_CODES = {
'OK': 200,
'CREATED': 201,
'ACCEPTED': 202,
'BAD_REQUEST': 400,
'UNAUTHORIZED': 401,
'NOT_FOUND': 404,
'CONFLICT': 409,
'PRECONDITION_FAILED': 412
}
class StatusException(Exception):
"""Response Error class"""
def __init__(self, value, result=None):
self.value = value
self.responses = {
100: ('Continue', 'Request received, please continue'),
101: ('Switching Protocols',
'Switching to new protocol; obey Upgrade header'),
200: ('OK', 'Request fulfilled, document follows'),
201: ('Created', 'Document created, URL follows'),
202: ('Accepted',
'Request accepted, processing continues off-line'),
203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
204: ('No Content', 'Request fulfilled, nothing follows'),
205: ('Reset Content', 'Clear input form for further input.'),
206: ('Partial Content', 'Partial content follows.'),
300: ('Multiple Choices',
'Object has several resources -- see URI list'),
301: ('Moved Permanently', 'Object moved permanently -- see URI list'),

302: ('Found', 'Object moved temporarily -- see URI list'),


303: ('See Other', 'Object moved -- see Method and URL list'),
304: ('Not Modified',
'Document has not changed since given time'),
305: ('Use Proxy',
'You must use proxy specified in Location to access this '
'resource.'),
307: ('Temporary Redirect',
'Object moved temporarily -- see URI list'),
400: ('Bad Request',
'Bad request syntax or unsupported method'),
401: ('Unauthorized',
'No permission -- see authorization schemes'),
402: ('Payment Required',
'No payment -- see charging schemes'),
403: ('Forbidden',
'Request forbidden -- authorization will not help'),
404: ('Not Found', 'Nothing matches the given URI'),
405: ('Method Not Allowed',
'Specified method is invalid for this server.'),
406: ('Not Acceptable', 'URI not available in preferred format.'),
407: ('Proxy Authentication Required', 'You must authenticate with '
'this proxy before proceeding.'),
408: ('Request Timeout', 'Request timed out; try again later.'),
409: ('Conflict', 'Request conflict.'),
410: ('Gone',
'URI no longer exists and has been permanently removed.'),
411: ('Length Required', 'Client must specify Content-Length.'),
412: ('Precondition Failed', 'Precondition in headers is false.'),
413: ('Request Entity Too Large', 'Entity is too large.'),
414: ('Request-URI Too Long', 'URI is too long.'),
415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
416: ('Requested Range Not Satisfiable',
'Cannot satisfy request range.'),
417: ('Expectation Failed',
'Expect condition could not be satisfied.'),
500: ('Internal Server Error', 'Server got itself in trouble'),
501: ('Not Implemented',
'Server does not support this operation'),
502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
503: ('Service Unavailable',
'The server cannot process the request due to a high load'),
504: ('Gateway Timeout',
'The gateway server did not receive a timely response'),
505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),
}
if result:
self.result = "\n%s" % result
def __str__(self):
return "Error [%s]: %s. %s.%s" % (self.value,
self.responses[self.value][0], self.responses[self.value][1],
self.result)
class API(object):
"""Main class"""
def __init__(self, email, password, *args, **kwargs):
self._br = mechanize.Browser()
data = {'email': email, 'password': password}

self.encoded_data = urllib.urlencode(data)
response = self._br.open(URLS['login'], self.encoded_data)
status = response.code
body = response.read()
if (status == HTTP_RESPONSE_CODES['OK'] and
MESSAGES['login_error'] not in body):
self.Profile = Profile(self._br)
self.Friends = Friends(self._br)
self.Comments = Comments(self._br, self.Profile.id)
else:
raise StatusException(401, "Email or password are invalid.")
class User(object):
"""User base class"""
def __init__(self, br, user_id, *args, **kwargs):
self._br = br
self.id = user_id
def _get_first_name(self):
pass
first_name = property(_get_first_name)
def _get_last_name(self):
pass
last_name = property(_get_last_name)
def _get_name(self):
pass
name = property(_get_name)
def _get_birthdate(self):
pass
birthdate = property(_get_birthdate)
def _get_marital_status(self):
pass
marital_status = property(_get_marital_status)
def _get_province(self):
pass
province = property(_get_province)
def _get_locality(self):
pass
locality = property(_get_locality)
def _get_hobbies(self):
pass
hobbies = property(_get_hobbies)
def _get_films(self):
pass
films = property(_get_films)
def _get_quotes(self):
pass
quotes = property(_get_quotes)
def _get_music(self):

pass
music = property(_get_music)
def _get_books(self):
pass
books = property(_get_books)
class Profile(User):
"""Profile class"""
def __init__(self, br, *args, **kwargs):
self._br = br
user_id = self._get_user_id()
if not user_id:
raise StatusException(404, "User not found in tuenti.")
else:
super(Profile, self).__init__(br, user_id, *args, **kwargs)
self._csfr = self._get_csfr()
if not self._csfr:
raise StatusException(404, "csfr key not found in profile.")
def _get_user_id(self):
response = self._br.open(URLS['my_profile'])
status = response.code
body = response.read()
if status == HTTP_RESPONSE_CODES['OK']:
doc = libxml2dom.parseString(body, html=1)
fieldsets = doc.getElementsByTagName('fieldset')
for fieldset in fieldsets:
if fieldset.getAttribute('title') == MESSAGES['my_wall']:
anchor = fieldset.getElementsByTagName('a').pop()
user_id = anchor.getAttribute('href').split('user_id=')[1].s
plit('&')[0]
return user_id
def _get_csfr(self):
response = self._br.open(TUENTI_HOST)
status = response.code
body = response.read()
if status == HTTP_RESPONSE_CODES['OK']:
doc = libxml2dom.parseString(body, html=1)
forms = doc.getElementsByTagName('go')
if forms:
return forms[0].getAttribute('href').split('csfr=')[1].split('&'
)[0]
def _set_status(self, value):
if value:
data = {'status': value}
else:
data = {'status': ""}
self.encoded_data = urllib.urlencode(data)
response = self._br.open(URLS['set_status'] % self._csfr, self.encoded_d
ata)
status = response.code
body = response.read()
if (status != HTTP_RESPONSE_CODES['OK'] or
MESSAGES['restricted_area'] in body):
raise StatusException(304, "Status not modified.")
def _get_status(self):

response = self._br.open(URLS['my_profile'])
status = response.code
body = response.read()
if status == HTTP_RESPONSE_CODES['OK']:
doc = libxml2dom.parseString(body, html=1)
fieldsets = doc.getElementsByTagName("fieldset")
for fieldset in fieldsets:
if (len(fieldset.childNodes) > 2 and
fieldset.childNodes[0].toString() == MESSAGES['status']):
status_node_value = fieldset.childNodes[2].value
if status_node_value:
status_message = status_node_value.split(MESSAGES['statu
s_verb'])[1].strip()
return status_message
return None
status = property(_get_status, _set_status)
def _get_first_name(self):
pass
first_name = property(_get_first_name)
def _get_last_name(self):
pass
last_name = property(_get_last_name)
def _get_name(self):
pass
name = property(_get_name)
class Friends(object):
"""Friend collection class"""
def __init__(self, br, *args, **kwargs):
self._br = br
cont = 0
response = self._br.open(URLS['friends'] % str(cont))
status = response.code
body = response.read()
self._friends = []
while (status == HTTP_RESPONSE_CODES['OK'] and
MESSAGES['more_friends'] in body):
doc = libxml2dom.parseString(body, html=1)
anchors = doc.getElementsByTagName('a')
for anchor in anchors:
if anchor and anchor.getAttribute('href').startswith(PROFILE_URL
):
friend_dic = {}
friend_dic['user_id'] = anchor.getAttribute('href').split(PR
OFILE_URL)[1].split('&')[0]
friend_dic['nick'] = anchor.textContent
self._friends.append(friend_dic)
cont = cont + 1
response = self._br.open(URLS['friends'] % str(cont))
status = response.code
body = response.read()
doc = libxml2dom.parseString(body, html=1)
anchors = doc.getElementsByTagName('a')
for anchor in anchors:
if anchor and anchor.getAttribute('href').startswith(PROFILE_URL):
friend_dic = {}

friend_dic['user_id'] = anchor.getAttribute('href').split(PROFIL
E_URL)[1].split('&')[0]
friend_dic['nick'] = anchor.textContent
self._friends.append(friend_dic)
def get(self, index):
f = self._friends[index]
return Friend(self._br, f.get('user_id', None), f.get('nick', None))
def all(self):
friend_list = []
for f in self._friends:
friend_list.append(Friend(self._br, f.get('user_id', None), f.get('n
ick', None)))
return friend_list
class Friend(User):
"""Friend base class"""
def __init__(self, br, user_id, nick, *args, **kwargs):
super(Friend, self).__init__(br, user_id, *args, **kwargs)
self.nick = nick
self.Comments = Comments(self._br, user_id)
class Comments(object):
"""Comment collection class"""
def __init__(self, br, user_id, *args, **kwargs):
self._br = br
self.user_id = user_id
cont = 0
response = self._br.open(URLS['comments'] % (self.user_id, cont))
status = response.code
body = response.read()
self._comments = []
while(status == HTTP_RESPONSE_CODES['OK'] and
MESSAGES['more_comments'] in body):
doc = libxml2dom.parseString(body, html=1)
fieldsets = doc.getElementsByTagName('fieldset')
for fieldset in fieldsets:
if (fieldset.getAttribute('title') and
(fieldset.getAttribute('title') == MESSAGES['my_wall'] or
fieldset.getAttribute('title').startswith(MESSAGES['wall'])
)):
smalls = fieldset.getElementsByTagName('small')
for small in smalls[1:]:
comment_dic = {}
anchor = small.getElementsByTagName('a')[0]
if anchor and '?m=profile&user_id' in anchor.getAttribut
e('href'):
comment_dic.update({'friend_id': anchor.getAttribute
('href').split('user_id=')[1]})
comment_dic.update({'friend_name': anchor.textConten
t})
text = anchor.nextSibling.textContent
splitted_text = text.split('(')
time = splitted_text.pop()
time_parsed = time.split(')')[0]
text_parsed = text[2:len(text)-len(time)-3]
comment_dic.update({'text': text_parsed})

comment_dic.update({'time': time_parsed})
self._comments.append(comment_dic)
cont = cont + 3
response = self._br.open(URLS['comments'] % (self.user_id, cont))
status = response.code
body = response.read()
doc = libxml2dom.parseString(body, html=1)
fieldsets = doc.getElementsByTagName('fieldset')
for fieldset in fieldsets:
if (fieldset.getAttribute('title') and
(fieldset.getAttribute('title') == MESSAGES['my_wall'] or
fieldset.getAttribute('title').startswith(MESSAGES['wall']))):
smalls = fieldset.getElementsByTagName('small')
for small in smalls[1:]:
comment_dic = {}
anchor = small.getElementsByTagName('a')[0]
if anchor and '?m=profile&user_id' in anchor.getAttribute('h
ref'):
comment_dic.update({'friend_id': anchor.getAttribute('hr
ef').split('user_id=')[1]})
comment_dic.update({'friend_name': anchor.textContent})
text = anchor.nextSibling.textContent
splitted_text = text.split('(')
time = splitted_text.pop()
time_parsed = time.split(')')[0]
text_parsed = text[2:len(text)-len(time)-3]
comment_dic.update({'text': text_parsed})
comment_dic.update({'time': time_parsed})
self._comments.append(comment_dic)
def get(self, index):
# TODO: Create an Friend instance
return self._comments[index]
def all(self):
# TODO: Retrieve a Friend collection
return self._comments
def latest(self, entries=5):
# TODO: Retrieve a Friend collection
return self._comments[:entries]
class Comment(object):
"""Comment base class"""
def __init__(self, br, user_id, *args, **kwargs):
self._br = br
self.user_id
# TODO: Get Comment
__all__ = ['API']

You might also like