imported aum as a backend
This commit is contained in:
parent
4065f7efcd
commit
da1369ef7b
19 changed files with 1613 additions and 1 deletions
1
weboob/backends/aum/__init__.py
Normal file
1
weboob/backends/aum/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from adopte import AdopteUnMec
|
||||
215
weboob/backends/aum/adopte.py
Normal file
215
weboob/backends/aum/adopte.py
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008-2010 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
import time
|
||||
from logging import warning
|
||||
|
||||
from weboob.tools.browser import Browser
|
||||
from weboob.backends.aum.exceptions import AdopteWait
|
||||
|
||||
from weboob.backends.aum.pages.home import HomePage
|
||||
from weboob.backends.aum.pages.contact_list import ContactListPage
|
||||
from weboob.backends.aum.pages.contact_thread import ContactThreadPage
|
||||
from weboob.backends.aum.pages.baskets import BasketsPage
|
||||
from weboob.backends.aum.pages.profile import ProfilePage
|
||||
from weboob.backends.aum.pages.search import SearchPage
|
||||
from weboob.backends.aum.pages.login import LoginPage, RedirectPage, BanPage, ErrPage, RegisterPage, RegisterWaitPage, RegisterConfirmPage
|
||||
from weboob.backends.aum.pages.edit import EditPhotoPage, EditPhotoCbPage, EditAnnouncePage, EditDescriptionPage, EditSexPage, EditPersonalityPage
|
||||
from weboob.backends.aum.pages.wait import WaitPage
|
||||
|
||||
class AdopteUnMec(Browser):
|
||||
DOMAIN = 'www.adopteunmec.com'
|
||||
PROTOCOL = 'http'
|
||||
PAGES = {'http://www.adopteunmec.com/': LoginPage,
|
||||
'http://www.adopteunmec.com/index.html': LoginPage,
|
||||
'http://www.adopteunmec.com/index.php': LoginPage,
|
||||
'http://www.adopteunmec.com/loginErr.php.*': ErrPage,
|
||||
'http://www.adopteunmec.com/bans.php\?who=auto': BanPage,
|
||||
'http://www.adopteunmec.com/redirect.php\?action=login': RedirectPage,
|
||||
'http://www.adopteunmec.com/wait.php': WaitPage,
|
||||
'http://www.adopteunmec.com/register2.php': RegisterPage,
|
||||
'http://www.adopteunmec.com/register3.php.*': RegisterWaitPage,
|
||||
'http://www.adopteunmec.com/register4.php.*': RegisterConfirmPage,
|
||||
'http://www.adopteunmec.com/home.php': HomePage,
|
||||
'http://www.adopteunmec.com/mails.php': ContactListPage,
|
||||
'http://www.adopteunmec.com/mails.php\?type=1': BasketsPage,
|
||||
'http://www.adopteunmec.com/thread.php\?id=([0-9]+)': ContactThreadPage,
|
||||
'http://www.adopteunmec.com/edit.php\?type=1': EditPhotoPage,
|
||||
'http://s\d+.adopteunmec.com/upload2.php\?.*': EditPhotoCbPage,
|
||||
'http://www.adopteunmec.com/edit.php\?type=2': EditAnnouncePage,
|
||||
'http://www.adopteunmec.com/edit.php\?type=3': EditDescriptionPage,
|
||||
'http://www.adopteunmec.com/edit.php\?type=4': EditSexPage,
|
||||
'http://www.adopteunmec.com/edit.php\?type=5': EditPersonalityPage,
|
||||
'http://www.adopteunmec.com/search.php.*': SearchPage,
|
||||
'http://www.adopteunmec.com/rencontres-femmes/(.*)/([0-9]+)': ProfilePage,
|
||||
'http://www.adopteunmec.com/catalogue-hommes/(.*)/([0-9]+)': ProfilePage,
|
||||
'http://www.adopteunmec.com/view2.php': ProfilePage, # my own profile
|
||||
'http://www.adopteunmec.com/(\w+)': ProfilePage, # a custom profile url
|
||||
}
|
||||
|
||||
def login(self):
|
||||
if not self.isOnPage(LoginPage):
|
||||
self.home()
|
||||
self.page.login(self.username, self.password)
|
||||
|
||||
def isLogged(self):
|
||||
return not self.isOnPage(LoginPage)
|
||||
|
||||
def home(self):
|
||||
return self.location('http://www.adopteunmec.com/home.php')
|
||||
|
||||
def pageaccess(func):
|
||||
def inner(self, *args, **kwargs):
|
||||
if self.isOnPage(WaitPage):
|
||||
if not self.page.check():
|
||||
raise AdopteWait()
|
||||
self.home()
|
||||
if not self.page or self.isOnPage(LoginPage) and self.password:
|
||||
self.home()
|
||||
|
||||
return func(self, *args, **kwargs)
|
||||
return inner
|
||||
|
||||
def register(self, nickname, password, sex, birthday_d, birthday_m, birthday_y, zipcode, country, godfather=''):
|
||||
if not self.isOnPage(RegisterPage):
|
||||
self.location('http://www.adopteunmec.com/register2.php')
|
||||
|
||||
return self.page.register(nickname, password, sex, birthday_d, birthday_m, birthday_y, zipcode, country, godfather)
|
||||
|
||||
@pageaccess
|
||||
def addPhoto(self, name, f):
|
||||
if not self.isOnPage(EditPhotoPage):
|
||||
self.location('/edit.php?type=1')
|
||||
return self.page.addPhoto(name, f)
|
||||
|
||||
@pageaccess
|
||||
def setNickname(self, nickname):
|
||||
if not self.isOnPage(EditAnnouncePage):
|
||||
self.location('/edit.php?type=2')
|
||||
return self.page.setNickname(nickname)
|
||||
|
||||
@pageaccess
|
||||
def setAnnounce(self, title=None, description=None, lookingfor=None):
|
||||
if not self.isOnPage(EditAnnouncePage):
|
||||
self.location('/edit.php?type=2')
|
||||
return self.page.setAnnounce(title, description, lookingfor)
|
||||
|
||||
@pageaccess
|
||||
def score(self):
|
||||
if time.time() - self.__last_update > 60:
|
||||
self.home()
|
||||
return self.page.score()
|
||||
|
||||
@pageaccess
|
||||
def getMyName(self):
|
||||
if time.time() - self.__last_update > 60:
|
||||
self.home()
|
||||
return self.page.getMyName()
|
||||
|
||||
@pageaccess
|
||||
def getMyID(self):
|
||||
if not self.isOnPage(HomePage):
|
||||
self.home()
|
||||
return self.page.getMyID()
|
||||
|
||||
@pageaccess
|
||||
def nbNewMails(self):
|
||||
if time.time() - self.__last_update > 60:
|
||||
self.home()
|
||||
return self.page.nbNewMails()
|
||||
|
||||
@pageaccess
|
||||
def nbNewBaskets(self):
|
||||
if time.time() - self.__last_update > 60:
|
||||
self.home()
|
||||
return self.page.nbNewBaskets()
|
||||
|
||||
@pageaccess
|
||||
def nbNewVisites(self):
|
||||
if time.time() - self.__last_update > 60:
|
||||
self.home()
|
||||
return self.page.nbNewVisites()
|
||||
|
||||
@pageaccess
|
||||
def nbAvailableCharms(self):
|
||||
self.home()
|
||||
return self.page.nbAvailableCharms()
|
||||
|
||||
@pageaccess
|
||||
def getBaskets(self):
|
||||
self.location('/mails.php?type=1')
|
||||
return self.page.getProfilesIDsList()
|
||||
|
||||
@pageaccess
|
||||
def getContactList(self):
|
||||
if not self.isOnPage(ContactListPage):
|
||||
self.location('/mails.php')
|
||||
|
||||
return self.page.getContactList()
|
||||
|
||||
@pageaccess
|
||||
def getThreadMails(self, id):
|
||||
self.page.openThreadPage(id)
|
||||
return self.page.getMails()
|
||||
|
||||
@pageaccess
|
||||
def postMail(self, id, content):
|
||||
self.page.openThreadPage(id)
|
||||
self.page.post(content)
|
||||
|
||||
@pageaccess
|
||||
def sendCharm(self, id):
|
||||
result = self.openurl('http://www.adopteunmec.com/fajax_addBasket.php?id=%s' % id).read()
|
||||
warning('Charm: %s' % result)
|
||||
return result.find('noMoreFlashes') < 0
|
||||
|
||||
@pageaccess
|
||||
def addBasket(self, id):
|
||||
result = self.openurl('http://www.adopteunmec.com/fajax_addBasket.php?id=%s' % id).read()
|
||||
warning('Basket: %s' % result)
|
||||
# TODO check if it works (but it should)
|
||||
return True
|
||||
|
||||
@pageaccess
|
||||
def rate(self, id, what, rating):
|
||||
print 'rate "%s"' % id, what, rating
|
||||
result = self.openurl('http://www.adopteunmec.com/fajax_vote.php', 'member=%s&what=%s&rating=%s' % (id, what, rating)).read()
|
||||
print result
|
||||
return True
|
||||
|
||||
@pageaccess
|
||||
def searchProfiles(self, **kwargs):
|
||||
self.location('/search.php?display=1')
|
||||
self.page.search(**kwargs)
|
||||
return self.page.getProfilesIDs()
|
||||
|
||||
@pageaccess
|
||||
def getProfile(self, link):
|
||||
if isinstance(link, (str,unicode)) and link.startswith('/'):
|
||||
link = link[1:]
|
||||
self.location('/%s' % link)
|
||||
return self.page
|
||||
|
||||
@pageaccess
|
||||
def isSlutOnline(self, id):
|
||||
result = self.openurl('http://www.adopteunmec.com/%s' % id).read()
|
||||
r = result.find('<td align="right" style="font-size:12px;font-weight:bold">en ligne</td>') >= 0
|
||||
print 'isSlutOnline(%s) = %s' % (id, r)
|
||||
return r
|
||||
30
weboob/backends/aum/exceptions.py
Normal file
30
weboob/backends/aum/exceptions.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008-2010 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
from weboob.tools.browser import BrowserUnavailable
|
||||
|
||||
class AdopteWait(BrowserUnavailable):
|
||||
pass
|
||||
|
||||
class AdopteBanned(BrowserUnavailable):
|
||||
pass
|
||||
|
||||
class AdopteCantPostMail(Exception):
|
||||
pass
|
||||
69
weboob/backends/aum/mail.py
Normal file
69
weboob/backends/aum/mail.py
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
import time
|
||||
import datetime
|
||||
|
||||
class Mail:
|
||||
|
||||
def __init__(self, id, name):
|
||||
self.id = id
|
||||
self.reply_date = 0
|
||||
self.name = name
|
||||
self.sender = name
|
||||
self.profile_link = ''
|
||||
|
||||
self.new = False
|
||||
self.content = ''
|
||||
self.date = datetime.datetime.utcnow()
|
||||
|
||||
def getDateInt(self):
|
||||
return int(time.strftime('%Y%m%d%H%M%S', self.getDate().timetuple()))
|
||||
|
||||
def getMsgID(self, sender):
|
||||
return '<%s.%d@%s>' % (self.getDateInt(), self.id, sender)
|
||||
|
||||
def getReplyID(self, sender):
|
||||
if self.reply_date:
|
||||
return '<%s.%d@%s>' % (self.reply_date, self.id, sender)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def getID(self):
|
||||
return self.id
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getDate(self):
|
||||
return self.date
|
||||
|
||||
def getProfileLink(self):
|
||||
return self.profile_link
|
||||
|
||||
def getFrom(self):
|
||||
return self.sender
|
||||
|
||||
def getContent(self):
|
||||
return self.content
|
||||
|
||||
def isNew(self):
|
||||
return self.new
|
||||
|
||||
0
weboob/backends/aum/pages/__init__.py
Normal file
0
weboob/backends/aum/pages/__init__.py
Normal file
96
weboob/backends/aum/pages/base.py
Normal file
96
weboob/backends/aum/pages/base.py
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008-2010 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
from logging import error, warning
|
||||
from weboob.tools.browser import BasePage
|
||||
|
||||
class PageBase(BasePage):
|
||||
def openContactListPage(self):
|
||||
self.browser.follow_link(url_regex=r"/mails.php$")
|
||||
|
||||
def openThreadPage(self, id):
|
||||
self.browser.location('/thread.php?id=%d' % int(id))
|
||||
|
||||
def score(self):
|
||||
"""
|
||||
<table width="220">
|
||||
<tr>
|
||||
<td align=left class=header>popularité</td>
|
||||
<td align=right class=header><big style="color:#ff0198;" id=popScore>7.230</big> pts</td>
|
||||
</tr>
|
||||
</table>
|
||||
"""
|
||||
|
||||
l = self.document.getElementsByTagName('table')
|
||||
for tag in l:
|
||||
if tag.getAttribute('width') == '220':
|
||||
# <table><tbody(implicit)><td>
|
||||
child = tag.childNodes[1].childNodes[0].childNodes[3]
|
||||
return child.childNodes[0].childNodes[0].data
|
||||
|
||||
error("Error: I can't find the score :(")
|
||||
return '0'
|
||||
|
||||
def __get_indicator(self, elementName):
|
||||
""" <span id=mailsCounter><blink>1</blink></span> """
|
||||
|
||||
l = self.document.getElementsByTagName('span')
|
||||
for tag in l:
|
||||
if tag.getAttribute('id') == elementName:
|
||||
child = tag.childNodes[0]
|
||||
|
||||
if not hasattr(child, 'data'):
|
||||
if child.tagName != u'blink':
|
||||
warning("Warning: %s counter isn't a blink and hasn't data" % elementName)
|
||||
child = child.childNodes[0]
|
||||
if not hasattr(child, 'data'):
|
||||
break
|
||||
|
||||
return int(child.data)
|
||||
|
||||
error("Error: I can't find the %s counter :(" % elementName)
|
||||
return 0
|
||||
|
||||
MYNAME_REGEXP = re.compile("Bonjour (.*)")
|
||||
def getMyName(self):
|
||||
""" <span class=header2>Bonjour Romain</span> """
|
||||
|
||||
tags = self.document.getElementsByTagName('span')
|
||||
for tag in tags:
|
||||
if hasattr(tag.firstChild, 'data'):
|
||||
m = self.MYNAME_REGEXP.match(tag.firstChild.data)
|
||||
if m:
|
||||
return m.group(1)
|
||||
|
||||
warning('Warning: Unable to fetch name')
|
||||
return '?'
|
||||
|
||||
def nbNewMails(self):
|
||||
|
||||
return self.__get_indicator(u'mailsCounter')
|
||||
|
||||
def nbNewBaskets(self):
|
||||
|
||||
return self.__get_indicator(u'flashsCounter')
|
||||
|
||||
def nbNewVisites(self):
|
||||
|
||||
return self.__get_indicator(u'visitesCounter')
|
||||
26
weboob/backends/aum/pages/baskets.py
Normal file
26
weboob/backends/aum/pages/baskets.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
from weboob.backends.aum.pages.profileslist_base import ProfilesListBase
|
||||
|
||||
class BasketsPage(ProfilesListBase):
|
||||
|
||||
pass
|
||||
|
||||
117
weboob/backends/aum/pages/contact_list.py
Normal file
117
weboob/backends/aum/pages/contact_list.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from weboob.backends.aum.pages.base import PageBase
|
||||
|
||||
class ContactItem:
|
||||
u"""
|
||||
<tr bgcolor="#ff7ccb" height=1><td colspan=10></td></tr>
|
||||
<tr style="background:#ffd5ee" height=74 onmouseover="this.style.background='#f3d5e7'" onmouseout="this.style.background='#ffd5ee'">
|
||||
<td class=a onclick="window.location='/thread.php?id=110921'" width=4></td>
|
||||
<td class=a onclick="window.location='/rencontres-femmes/france/ile-de-france/Hen/110921'" width=70 align=left>
|
||||
<table><tr valign="bottom"><td style="background:url(http://p1.adopteunmec.com/1/2/9/0/1/thumb0_7.jpg);width:66px;height:66px" align="right"> </td></tr></table>
|
||||
</td>
|
||||
<td class=a onclick="window.location='/thread.php?id=110921'" width=150 align=left><big><b>Hen</b></big><br>
|
||||
19ans, Montreuil</td>
|
||||
<td class=a onclick="window.location='/thread.php?id=110921'" width=320 align=left><b>Comme ça, on est deux.</b><br>
|
||||
il y a 1 heure</td>
|
||||
<td class=a onclick="window.location='/thread.php?id=110921'" width=100 align=right>nouveau <img src="http://img.adopteunmec.com/img/ico_mail0.gif" />
|
||||
</td>
|
||||
<td class=a onclick="window.location='/thread.php?id=110921'" width=30 align=left></td>
|
||||
<td width=20 align=right><input id='fcc_suppr_545615' name='suppr[]' type='hidden' /><img id='cc_suppr_545615' src='http://img.adopteunmec.com/img/i/check0.png' onclick='customCheckClick(this)' align="absmiddle"/> </td>
|
||||
<script>supprs[supprs.length] = 'cc_suppr_545615';</script>
|
||||
|
||||
</td>
|
||||
<td width=7></td>
|
||||
</tr>
|
||||
"""
|
||||
|
||||
fields = ['thread_link', 'photo', 'useless3', 'name', 'resume', 'status', 'useless', 'remove', 'useless2']
|
||||
|
||||
def __init__(self, tr):
|
||||
self.tr = tr
|
||||
|
||||
def __get_element(self, id):
|
||||
|
||||
return self.tr.getElementsByTagName('td')[self.fields.index(id)]
|
||||
|
||||
def getName(self):
|
||||
tag = self.__get_element('name')
|
||||
node = tag.getElementsByTagName('b')[0].firstChild
|
||||
if node:
|
||||
name = node.data
|
||||
else:
|
||||
# it is possible if the user has left site and hasn't any nickname
|
||||
name = ''
|
||||
|
||||
return name
|
||||
|
||||
def getStatus(self):
|
||||
|
||||
tag = self.__get_element('status')
|
||||
|
||||
return tag.firstChild.data
|
||||
|
||||
def isNew(self):
|
||||
return self.getStatus() == u'nouveau'
|
||||
|
||||
def isAnswered(self):
|
||||
return self.getStatus() == u'répondu'
|
||||
|
||||
def getResume(self):
|
||||
tag = self.__get_element('resume')
|
||||
|
||||
return tag.getElementsByTagName('b')[0].firstChild.data.split('\n')[0]
|
||||
|
||||
def getID(self):
|
||||
tag = self.__get_element('thread_link')
|
||||
|
||||
text = tag.getAttribute('onclick')
|
||||
|
||||
regexp = re.compile("window.location='/thread.php\?id=(.*)'")
|
||||
m = regexp.match(text)
|
||||
|
||||
if m:
|
||||
return int(m.group(1))
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
class ContactListPage(PageBase):
|
||||
|
||||
def loaded(self):
|
||||
|
||||
self.items = []
|
||||
|
||||
tags = self.document.getElementsByTagName('form')[0].childNodes[3].childNodes[1].childNodes
|
||||
|
||||
for tag in tags:
|
||||
if not hasattr(tag, 'tagName') or tag.tagName != u'tr':
|
||||
continue
|
||||
|
||||
if tag.hasAttribute('bgcolor'):
|
||||
continue
|
||||
|
||||
self.items += [ContactItem(tag)]
|
||||
|
||||
def getContactList(self):
|
||||
return self.items
|
||||
314
weboob/backends/aum/pages/contact_thread.py
Normal file
314
weboob/backends/aum/pages/contact_thread.py
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008-2010 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
from datetime import datetime
|
||||
from dateutil import tz
|
||||
from logging import error, warning
|
||||
from mechanize import FormNotFoundError
|
||||
|
||||
from weboob.backends.aum.pages.base import PageBase
|
||||
from weboob.backends.aum.exceptions import AdopteCantPostMail
|
||||
from weboob.backends.aum.mail import Mail
|
||||
|
||||
class MailParser(Mail):
|
||||
|
||||
"""
|
||||
<td>
|
||||
<table width="100%">
|
||||
<tr valign="top">
|
||||
<td width="1" bgcolor="black">
|
||||
<td width="88" align="center">
|
||||
<table class=a onclick="window.location='romainn'" style="background:url(http://img.adopteunmec.com/img/bg_mini.png);width:74px;height:85px">
|
||||
<tr height=4>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr valign=top height=66>
|
||||
<td width=74 align=center style="-moz-opacity:0.5;opacity:0.5">
|
||||
<table class=a onclick="window.location='romainn'" style="width:66px;background-image:url(http://p7.adopteunmec.com/7/7/0/8/7/4/thumb0_3.jpg);background-repeat:no-repeat">
|
||||
<tr height=2><td></td></tr>
|
||||
<tr height=31 valign=top>
|
||||
<td width=2></td>
|
||||
<td align=left><img width=7 heght=7 src='http://img.adopteunmec.com/img/i/null.png'id=status_ /></td>
|
||||
</tr>
|
||||
<tr height=31 valign=bottom>
|
||||
<td width=2></td>
|
||||
<td width=63 align=right id=online_>
|
||||
<blnk><blink><img src="http://img.adopteunmec.com/img/online0.png" width=7 height=7 /></blink></blnk>
|
||||
<img src="http://img.adopteunmec.com/img/online1.png" width=25 height=10 />
|
||||
</td>
|
||||
<td width=3></td>
|
||||
</tr>
|
||||
<tr height=2><td></td></tr>
|
||||
<tr><td colspan=10 align=center style="font-size:10px;font-weight:bold;letter-spacing:-1px">Romain</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td>
|
||||
<p style="color:#444444;font-size:10px">27 octobre 2008, 01:11:32, nouveau
|
||||
<br />
|
||||
</p>
|
||||
<br>Moi en g<EFBFBD>n<EFBFBD>ral j'aime sortir tout simplement dans des bars, pour discuter avec mes amis et/ou coll<6C>gues, et rencontrer des gens. Sinon je fais de la guitare, et je d<>veloppe des projets perso.</p>
|
||||
</td>
|
||||
<td width="1" bgcolor="black">
|
||||
</tr>
|
||||
<tr height="6"><td width="1" bgcolor="black"><td colspan="2"></td><td width="1" bgcolor="black"></tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
"""
|
||||
|
||||
DATETIME_REGEXP = re.compile(u'([0-9]{1,2}) ([a-zéû]*) ([0-9]{4}), ([0-9]{2}):([0-9]{2}):([0-9]{2})(.*)')
|
||||
months = [u'', u'janvier', u'février', u'mars', u'avril', u'mai', u'juin', u'juillet', u'août', u'septembre', u'octobre', u'novembre', u'décembre']
|
||||
SMILEY_REGEXP = re.compile('http://s.adopteunmec.com/img/smile/([0-9]+).gif')
|
||||
smileys = {0: ':)',
|
||||
1: ':D',
|
||||
2: ':o',
|
||||
3: ':p',
|
||||
4: ';)',
|
||||
5: ':(',
|
||||
6: ':$',
|
||||
7: ':\'(',
|
||||
11: ':#',
|
||||
14: ':\\',
|
||||
15: ':|',
|
||||
10: '(L)',
|
||||
}
|
||||
|
||||
def __init__(self, id, name, tr):
|
||||
# <td> <table> implicit<tbody> <tr>
|
||||
Mail.__init__(self, id, name)
|
||||
self.tr = tr.childNodes[0].childNodes[1].childNodes[0].childNodes[0]
|
||||
|
||||
tds = self.tr.childNodes
|
||||
|
||||
counter = 0
|
||||
for td in tds:
|
||||
if not hasattr(td, 'tagName') or td.tagName != u'td':
|
||||
continue
|
||||
|
||||
counter += 1
|
||||
|
||||
if counter == 3:
|
||||
date = u''
|
||||
for child in td.childNodes[1].childNodes:
|
||||
if hasattr(child, 'data'):
|
||||
date += child.data
|
||||
self.parseDate(date)
|
||||
content = ''
|
||||
for c in td.childNodes[3].childNodes:
|
||||
if hasattr(c, 'data'):
|
||||
content += ''.join(c.data.split('\n')) # to strip \n
|
||||
elif hasattr(c, 'tagName'):
|
||||
if c.tagName == 'br':
|
||||
content += '\n'
|
||||
elif c.tagName == 'img' and c.hasAttribute('src'):
|
||||
m = self.SMILEY_REGEXP.match(c.getAttribute('src'))
|
||||
if m and self.smileys.has_key(int(m.group(1))):
|
||||
try:
|
||||
content += self.smileys[int(m.group(1))]
|
||||
except KeyError:
|
||||
error('Mail: unable to find this smiley: %s' % c.getAttribute('src'))
|
||||
self.content = content
|
||||
break
|
||||
|
||||
self.parseProfileLink()
|
||||
self.parseFrom()
|
||||
|
||||
def parseDate(self, date_str):
|
||||
|
||||
|
||||
# To match regexp, we have to remove any return chars in string
|
||||
# before the status ('nouveau', 'lu', etc)
|
||||
date_str = u''.join(date_str.split(u'\n'))
|
||||
|
||||
m = self.DATETIME_REGEXP.match(date_str)
|
||||
if m:
|
||||
day = int(m.group(1))
|
||||
month = self.months.index(m.group(2))
|
||||
year = int(m.group(3))
|
||||
hour = int(m.group(4))
|
||||
minute = int(m.group(5))
|
||||
sec = int(m.group(6))
|
||||
# build datetime object with local timezone
|
||||
d = datetime(year, month, day, hour, minute, sec, tzinfo=tz.tzlocal())
|
||||
# then, convert it to UTC timezone
|
||||
d = d.astimezone(tz.tzutc())
|
||||
# and get timestamp
|
||||
self.date = d
|
||||
|
||||
if m.group(7).find('nouveau') >= 0:
|
||||
self.new = True
|
||||
else:
|
||||
error('Error: unable to parse the datetime string "%s"' % date_str)
|
||||
|
||||
def parseProfileLink(self):
|
||||
tables = self.tr.getElementsByTagName('div')
|
||||
|
||||
for table in tables:
|
||||
if table.hasAttribute('class') and table.getAttribute('class') == 'mini' and table.hasAttribute('onclick'):
|
||||
|
||||
text = table.getAttribute('onclick')
|
||||
|
||||
regexp = re.compile("window.location='(.*)'")
|
||||
m = regexp.match(text)
|
||||
|
||||
if m:
|
||||
self.profile_link = m.group(1)
|
||||
return
|
||||
|
||||
warning('Unable to find the profile URL in the message %s@%s' % (self.getFrom(), self.getID()))
|
||||
|
||||
def parseFrom(self):
|
||||
tds = self.tr.getElementsByTagName('div')
|
||||
|
||||
for td in tds:
|
||||
if not td.hasAttribute('class') or td.getAttribute('class') != 'mini_pseudo':
|
||||
continue
|
||||
|
||||
self.sender = td.childNodes[0].data
|
||||
return
|
||||
|
||||
warning('Warning: unable to find from in the mail %s' % self.getID())
|
||||
|
||||
class ContactThreadPage(PageBase):
|
||||
|
||||
"""
|
||||
<form name=sendMsg method="post" action="/thread.php?id=1567992">
|
||||
<table align=center width=700>
|
||||
<tr valign="top"><td width=370 align="left">
|
||||
<table width=370>
|
||||
<tr height=25 style="background:url(http://img.adopteunmec.com/img/bg_list1.gif)"><td colspan=4> <font color=#ff0198>Ecrire <20> <big><b>zoe</b></big></font></td></tr>
|
||||
<tr height=193 valign=top><td width=1 bgcolor=black></td><td colspan=2 bgcolor=white><textarea id=message name=message style="width:366px;height:190px;border:none"></textarea></td><td width=1 bgcolor=black></td></tr>
|
||||
<tr height=1><td width=1 bgcolor=black></td><td bgcolor="#d15c91" colspan=2></td><td width=1 bgcolor=black></td></tr>
|
||||
<tr height=1><td width=1 bgcolor=black></td><td bgcolor="#ffffff" colspan=2></td><td width=1 bgcolor=black></td></tr>
|
||||
<tr><td width=1 bgcolor=black></td><td bgcolor="#ffe8f3">
|
||||
<table><tr>
|
||||
<td width=8></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/0.gif" style="cursor:pointer" onclick="emote(':)')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/1.gif" style="cursor:pointer" onclick="emote(':D')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/2.gif" style="cursor:pointer" onclick="emote(':o')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/3.gif" style="cursor:pointer" onclick="emote(':p')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/4.gif" style="cursor:pointer" onclick="emote(';)')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/5.gif" style="cursor:pointer" onclick="emote(':(')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/6.gif" style="cursor:pointer" onclick="emote(':$')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/7.gif" style="cursor:pointer" onclick="emote(':\'(')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/11.gif" style="cursor:pointer" onclick="emote(':#')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/14.gif" style="cursor:pointer" onclick="emote(':\\')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/15.gif" style="cursor:pointer" onclick="emote(':|')"></td>
|
||||
<td width=23><img src="http://img.adopteunmec.com/img/smile/10.gif" style="cursor:pointer" onclick="emote('(L)')"></td>
|
||||
</tr></table>
|
||||
</td><td bgcolor="#ffe8f3" align=right><input type="image" src="http://img.adopteunmec.com/img/buttonSendMail.jpg" style="border:none"></td><td width=1 bgcolor=black></td></tr>
|
||||
<tr height=1><td width=1 bgcolor=black colspan=4></tr>
|
||||
</table>
|
||||
</td><td width=304 align="right">
|
||||
<iframe frameborder=0 scrolling=NO style='width:300px;height:250px;boder:0' src='http://graphs.adopteunmec.com/ads/index.php?i=5'></iframe>
|
||||
</td></tr>
|
||||
</table>
|
||||
<input type=hidden id=link name=link>
|
||||
</form>
|
||||
"""
|
||||
|
||||
def post(self, content):
|
||||
try:
|
||||
self.browser.select_form(name="sendMsg")
|
||||
if isinstance(content, unicode):
|
||||
content = content.encode('iso-8859-15', 'replace')
|
||||
self.browser['message'] = content
|
||||
|
||||
self.browser.submit() # submit current form
|
||||
except FormNotFoundError:
|
||||
error = 'Unknown error'
|
||||
p_list = self.document.getElementsByTagName('p')
|
||||
for p in p_list:
|
||||
if p.hasAttribute('align') and p.getAttribute('align') == 'center':
|
||||
error = p.firstChild.data
|
||||
break
|
||||
|
||||
raise AdopteCantPostMail(error)
|
||||
|
||||
|
||||
"""
|
||||
<table align=center style="width:700px;background:black">
|
||||
<tr style="height:1px">
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr bgcolor="#ffe9f6" valign="top">
|
||||
content
|
||||
</tr>
|
||||
...
|
||||
<tr height="25" style="background:url(http://img.adopteunmec.com/img/bg_list1.gif)"><td> <a href="/thread.php?id=1567992&see=all">voir tous les messages</a></td></tr>
|
||||
</table>
|
||||
|
||||
"""
|
||||
|
||||
id_regexp = re.compile("/thread.php\?id=([0-9]+)")
|
||||
|
||||
def loaded(self):
|
||||
|
||||
self.items = []
|
||||
|
||||
a_list = self.document.getElementsByTagName('a')
|
||||
self.id = 0
|
||||
for a in a_list:
|
||||
if a.hasAttribute('href'):
|
||||
m = self.id_regexp.match(a.getAttribute('href'))
|
||||
if m:
|
||||
self.id = int(m.group(1))
|
||||
break
|
||||
|
||||
self.name = ''
|
||||
big_list = self.document.getElementsByTagName('big')
|
||||
for big in big_list:
|
||||
child = big.firstChild
|
||||
if hasattr(child, 'tagName') and child.tagName == u'b':
|
||||
self.name = child.firstChild.data
|
||||
break
|
||||
|
||||
tables = self.document.getElementsByTagName('table')
|
||||
table = None
|
||||
for t in tables:
|
||||
if t.hasAttribute('style') and t.getAttribute('style') == 'width:700px;background:black':
|
||||
table = t
|
||||
break
|
||||
|
||||
if not table:
|
||||
# It is probably the 'sent' page
|
||||
return
|
||||
|
||||
for tag in table.childNodes[1].childNodes[1:]:
|
||||
if not hasattr(tag, 'tagName') or tag.tagName != u'tr':
|
||||
continue
|
||||
|
||||
if not tag.hasAttribute('valign'):
|
||||
continue
|
||||
|
||||
mail = MailParser(self.id, self.name, tag)
|
||||
|
||||
if self.items:
|
||||
self.items[-1].reply_date = mail.getDateInt()
|
||||
self.items += [mail]
|
||||
|
||||
def getMails(self):
|
||||
|
||||
return self.items
|
||||
58
weboob/backends/aum/pages/edit.py
Normal file
58
weboob/backends/aum/pages/edit.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008-2010 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
from weboob.backends.aum.pages.base import PageBase
|
||||
|
||||
class EditPhotoPage(PageBase):
|
||||
def addPhoto(self, name, f):
|
||||
self.browser.select_form(name="form")
|
||||
self.browser.find_control('uploaded').add_file(f, 'image/jpeg', name)
|
||||
self.browser.submit()
|
||||
self.browser.openurl('http://www.adopteunmec.com/home.php')
|
||||
|
||||
class EditPhotoCbPage(PageBase):
|
||||
# Do nothing
|
||||
pass
|
||||
|
||||
class EditAnnouncePage(PageBase):
|
||||
def setNickname(self, nickname):
|
||||
self.browser.select_form(name="form")
|
||||
self.browser['pseudo'] = nickname
|
||||
self.browser.submit()
|
||||
|
||||
def setAnnounce(self, title=None, description=None, lookingfor=None):
|
||||
self.browser.select_form(name="form")
|
||||
if title is not None:
|
||||
self.browser['title'] = title
|
||||
if description is not None:
|
||||
self.browser['about1'] = description
|
||||
if lookingfor is not None:
|
||||
self.browser['about2'] = lookingfor
|
||||
|
||||
self.browser.submit()
|
||||
|
||||
class EditDescriptionPage(PageBase):
|
||||
pass
|
||||
|
||||
class EditSexPage(PageBase):
|
||||
pass
|
||||
|
||||
class EditPersonalityPage(PageBase):
|
||||
pass
|
||||
55
weboob/backends/aum/pages/home.py
Normal file
55
weboob/backends/aum/pages/home.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008-2010 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from weboob.backends.aum.pages.base import PageBase
|
||||
from logging import error
|
||||
|
||||
class HomePage(PageBase):
|
||||
|
||||
MYID_REGEXP = re.compile("http://www.adopteunmec.com/\?mid=(\d+)")
|
||||
|
||||
def getMyID(self):
|
||||
fonts = self.document.getElementsByTagName('font')
|
||||
for font in fonts:
|
||||
m = self.MYID_REGEXP.match(font.firstChild.data)
|
||||
if m:
|
||||
return m.group(1)
|
||||
|
||||
error("Error: Unable to find my ID")
|
||||
return 0
|
||||
|
||||
def nbAvailableCharms(self):
|
||||
tables = self.document.getElementsByTagName('table')
|
||||
for table in tables:
|
||||
if table.hasAttribute('style') and table.getAttribute('style') == 'background-color:black;background-image:url(http://s.adopteunmec.com/img/barmec.gif);background-repeat:no-repeat':
|
||||
|
||||
fonts = table.getElementsByTagName('font')
|
||||
i = 0
|
||||
|
||||
for font in fonts:
|
||||
if font.hasAttribute('color') and font.getAttribute('color') == '#ff0198':
|
||||
i += 1
|
||||
if i == 3:
|
||||
return int(font.firstChild.data)
|
||||
|
||||
error('Error: Unable to find the available charms counter')
|
||||
return 0
|
||||
81
weboob/backends/aum/pages/login.py
Normal file
81
weboob/backends/aum/pages/login.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008-2010 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
from weboob.backends.aum.pages.base import PageBase
|
||||
from weboob.tools.browser import BrowserIncorrectPassword
|
||||
|
||||
class LoginPage(PageBase):
|
||||
def login(self, login, password):
|
||||
self.browser.select_form(name="form_login")
|
||||
self.browser['login'] = login
|
||||
self.browser['password'] = password
|
||||
|
||||
self.browser.submit() # submit current form
|
||||
|
||||
class RegisterPage(PageBase):
|
||||
def register(self, nickname, password, sex, birthday_d, birthday_m, birthday_y, zipcode, country, godfather):
|
||||
""" form2:
|
||||
- pseudo
|
||||
- email
|
||||
- password
|
||||
- sex (0=m, 1=f)
|
||||
- birthday0 (0-31)
|
||||
- birthday1 (0-12)
|
||||
- birthday2 (1930-1999)
|
||||
- zip
|
||||
- country (fr,be,ch,ca)
|
||||
- godfather
|
||||
"""
|
||||
self.browser.select_form(name="form2")
|
||||
self.browser.controls.pop()
|
||||
|
||||
if isinstance(nickname, unicode):
|
||||
nickname = nickname.encode('iso-8859-15', 'ignore')
|
||||
self.browser['pseudo'] = nickname
|
||||
self.browser['email'] = self.browser.login
|
||||
self.browser['pass'] = password
|
||||
self.browser['sex'] = [str(sex)]
|
||||
self.browser['birthday0'] = [str(birthday_d)]
|
||||
self.browser['birthday1'] = [str(birthday_m)]
|
||||
self.browser['birthday2'] = [str(birthday_y)]
|
||||
self.browser['zip'] = str(zipcode)
|
||||
self.browser['country'] = [str(country)]
|
||||
self.browser['godfather'] = godfather
|
||||
|
||||
self.browser.submit()
|
||||
|
||||
class RegisterWaitPage(PageBase):
|
||||
pass
|
||||
|
||||
class RegisterConfirmPage(PageBase):
|
||||
pass
|
||||
|
||||
class RedirectPage(PageBase):
|
||||
def loaded(self):
|
||||
for link in self.browser.links():
|
||||
print link
|
||||
self.browser.location('/wait.php')
|
||||
|
||||
class BanPage(PageBase):
|
||||
pass
|
||||
|
||||
class ErrPage(PageBase):
|
||||
def loaded(self):
|
||||
raise BrowserIncorrectPassword()
|
||||
405
weboob/backends/aum/pages/profile.py
Normal file
405
weboob/backends/aum/pages/profile.py
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008-2010 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
from weboob.backends.aum.pages.base import PageBase
|
||||
from copy import deepcopy
|
||||
from logging import warning
|
||||
import re
|
||||
|
||||
class FieldBase:
|
||||
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
|
||||
def putValue(self, d, value):
|
||||
raise NotImplementedError
|
||||
|
||||
class FieldString(FieldBase):
|
||||
def putValue(self, d, value):
|
||||
d[self.key] = unicode(value)
|
||||
|
||||
class FieldList(FieldBase):
|
||||
def putValue(self, d, value):
|
||||
d[self.key] = value.split(', ')
|
||||
|
||||
class FieldWideList(FieldBase):
|
||||
|
||||
def putValue(self, d, value):
|
||||
d[self.key] += [value]
|
||||
|
||||
class FieldOld(FieldBase):
|
||||
regexp = re.compile('([0-9]+) ans')
|
||||
def putValue(self, d, value):
|
||||
m = self.regexp.match(value)
|
||||
if m:
|
||||
d[self.key] = int(m.group(1))
|
||||
|
||||
class FieldLocation(FieldBase):
|
||||
location = re.compile('(.*) \(([0-9]{5})\), (.*)')
|
||||
|
||||
def __init__(self):
|
||||
FieldBase.__init__(self, '')
|
||||
def putValue(self, d, value):
|
||||
# TODO: determine distance, or something like
|
||||
m = self.location.match(value)
|
||||
if m:
|
||||
d['location'] = m.group(1)
|
||||
d['zipcode'] = int(m.group(2))
|
||||
d['country'] = m.group(3)
|
||||
else:
|
||||
warning('Unable to parse the location "%s"' % value)
|
||||
d['location'] = unicode(value)
|
||||
|
||||
class FieldMeasurements(FieldBase):
|
||||
height = re.compile('([0-9]{1,3}) cm')
|
||||
weight = re.compile('([0-9]{1,3}) kg')
|
||||
# TODO: parse third parameter
|
||||
|
||||
def __init__(self):
|
||||
FieldBase.__init__(self, '')
|
||||
def putValue(self, d, value):
|
||||
for s in value.split(', '):
|
||||
m = self.height.match(s)
|
||||
if m:
|
||||
d['height'] = int(m.group(1))
|
||||
continue
|
||||
m = self.weight.match(s)
|
||||
if m:
|
||||
d['weight'] = int(m.group(1))
|
||||
continue
|
||||
if d['height'] and d['weight']:
|
||||
bmi = (d['weight']/float(pow(d['height']/100.0, 2)))
|
||||
if bmi < 15.5:
|
||||
d['fat'] = 'severely underweight'
|
||||
elif bmi < 18.4:
|
||||
d['fat'] = 'underweight'
|
||||
elif bmi < 24.9:
|
||||
d['fat'] = 'normal'
|
||||
elif bmi < 30:
|
||||
d['fat'] = 'overweight'
|
||||
else:
|
||||
d['fat'] = 'obese'
|
||||
d['BMI'] = bmi
|
||||
|
||||
class FieldParticularSignes(FieldBase):
|
||||
def __init__(self): FieldBase.__init__(self, '')
|
||||
def putValue(self, d, value):
|
||||
for s in value.split(', '):
|
||||
if s.find('tatouages') >= 0:
|
||||
d['tatoos'] = True
|
||||
elif s.find('piercing') >= 0:
|
||||
d['piercing'] = True
|
||||
elif s.find('lunettes') >= 0:
|
||||
d['glasses'] = True
|
||||
elif s.find('rousseur') >= 0:
|
||||
d['freckle'] = True
|
||||
|
||||
class ProfilePage(PageBase):
|
||||
|
||||
empty_table = {'details': {'old': 0,
|
||||
'zipcode': 0,
|
||||
'location': '',
|
||||
'country': '',
|
||||
'eyes': '',
|
||||
'hairs': [],
|
||||
'height': 0,
|
||||
'weight': 0,
|
||||
'BMI': 0,
|
||||
'fat': '',
|
||||
'from': '',
|
||||
'tatoos': False,
|
||||
'piercing': False,
|
||||
'freckle': False,
|
||||
'glasses': False,
|
||||
'job': '',
|
||||
'style': '',
|
||||
'alimentation': '',
|
||||
'alcool': '',
|
||||
'tabac': '',
|
||||
},
|
||||
'liking': {'activities': '',
|
||||
'music': [],
|
||||
'cinema': [],
|
||||
'books': [],
|
||||
'tv': [],
|
||||
},
|
||||
'sex': {'underwear': [],
|
||||
'top': [],
|
||||
'bottom': [],
|
||||
'interval': '',
|
||||
'practices': [],
|
||||
'favorite': '',
|
||||
'toys': [],
|
||||
},
|
||||
'personality': {'snap': '',
|
||||
'exciting': '',
|
||||
'hate': '',
|
||||
'vices': '',
|
||||
'assets': '',
|
||||
'fantasies': '',
|
||||
'is': [],
|
||||
},
|
||||
}
|
||||
|
||||
tables = {'tab_0': 'details',
|
||||
'tab_1': 'liking',
|
||||
'tab_2': 'sex',
|
||||
'tab_3': 'personality'
|
||||
}
|
||||
|
||||
fields = {'details': {'Age': FieldOld('old'),
|
||||
u'Réside à': FieldLocation(),
|
||||
'Yeux': FieldString('eyes'),
|
||||
'Cheveux ': FieldList('hairs'),
|
||||
'Mensurations ': FieldMeasurements(),
|
||||
'Origines ': FieldString('from'),
|
||||
'Signes particuliers ': FieldParticularSignes(),
|
||||
'Style ': FieldString('style'),
|
||||
'Profession ': FieldString('job'),
|
||||
'Alimentation': FieldString('alimentation'),
|
||||
'Alcool': FieldString('alcool'),
|
||||
'Tabac': FieldString('tabac'),
|
||||
},
|
||||
'liking': {'Hobbies ': FieldString('activities'),
|
||||
'Musique ': FieldWideList('music'),
|
||||
u'Cinéma': FieldWideList('cinema'),
|
||||
'Livres ': FieldWideList('books'),
|
||||
u'Télé': FieldWideList('tv'),
|
||||
},
|
||||
'sex': {u'Sous-v\xeatements ': FieldList('underwear'),
|
||||
'... en haut ': FieldList('top'),
|
||||
'... en bas ': FieldList('bottom'),
|
||||
u'Fréquence idéale des rapports sexuels ':
|
||||
FieldString('interval'),
|
||||
'Pratiques sexuelles ': FieldList('practices'),
|
||||
u'Accessoires préférés ':FieldList('toys'),
|
||||
u'Position favorite ': FieldString('favorite'),
|
||||
},
|
||||
'personality': {u'Ça la fait craquer ': FieldString('snap'),
|
||||
u'Ça l\'excite ': FieldString('exciting'),
|
||||
u'Elle déteste ': FieldString('hate'),
|
||||
'Ses vices ': FieldString('vices'),
|
||||
'Ses atouts ': FieldString('assets'),
|
||||
'Ses fantasmes ': FieldString('fantasies'),
|
||||
'Elle est ': FieldList('is'),
|
||||
},
|
||||
}
|
||||
|
||||
ID_REGEXP = re.compile('(charm|addBasket|openAlbum)\(([0-9]+)(,[\s\'\d]+)?\)')
|
||||
PHOTO_REGEXP = re.compile('http://(s|p)([0-9]+)\.adopteunmec\.com/(.*)')
|
||||
|
||||
STATS2ID = {'visites': 'visits',
|
||||
'charmes': 'charms',
|
||||
'paniers': 'baskets',
|
||||
'mails': 'mails',
|
||||
'POPULARIT': 'score',
|
||||
}
|
||||
STATS_VALUE_REGEXP = re.compile('([0-9\s]+).*')
|
||||
|
||||
def __repr__(self):
|
||||
if isinstance(self.name, unicode):
|
||||
name = self.name.encode('ascii', 'backslashreplace')
|
||||
else:
|
||||
name = self.name
|
||||
return '<Profile name="%s">' % name
|
||||
|
||||
def loaded(self):
|
||||
self.name = u''
|
||||
self.description = u''
|
||||
self.table = deepcopy(self.empty_table)
|
||||
self.id = 0
|
||||
self.photos = []
|
||||
self.status = ''
|
||||
self.stats = {'score': 0,
|
||||
'visits': 0,
|
||||
'charms': 0,
|
||||
'baskets': 0,
|
||||
'mails': 0,
|
||||
}
|
||||
|
||||
divs = self.document.getElementsByTagName('td')
|
||||
for div in divs:
|
||||
if (div.hasAttribute('style') and
|
||||
div.getAttribute('style') == "color:#ffffff;font-size:32px;font-weight:bold;letter-spacing:-2px" and
|
||||
hasattr(div.firstChild, 'data')):
|
||||
self.name = div.firstChild.data
|
||||
if (div.hasAttribute('style') and
|
||||
div.getAttribute('style') == "font-size:12px;font-weight:bold" and
|
||||
hasattr(div.firstChild, 'data')):
|
||||
self.status = div.firstChild.data
|
||||
if div.hasAttribute('background'):
|
||||
m = self.PHOTO_REGEXP.match(div.getAttribute('background'))
|
||||
if m:
|
||||
self.photos += [re.sub(u'thumb[0-2]_', u'image', div.getAttribute('background'))]
|
||||
if div.hasAttribute('width') and str(div.getAttribute('width')) == '226':
|
||||
trs = div.getElementsByTagName('tr')
|
||||
for tr in trs:
|
||||
tds = tr.getElementsByTagName('td')
|
||||
if len(tds) > 2 and hasattr(tds[2].firstChild, 'data'):
|
||||
label = tds[0].firstChild.data
|
||||
value = tds[2].firstChild.data
|
||||
elif len(tds) == 2:
|
||||
label = unicode(tds[0].childNodes[1].data)
|
||||
value = tds[1].childNodes[1].data
|
||||
else:
|
||||
continue
|
||||
|
||||
m = self.STATS_VALUE_REGEXP.match(value)
|
||||
if m and self.STATS2ID.has_key(label):
|
||||
self.stats[self.STATS2ID[label]] = int(m.group(1).replace(' ', ''))
|
||||
|
||||
divs = self.document.getElementsByTagName('div')
|
||||
for div in divs:
|
||||
if div.hasAttribute('id'):
|
||||
if div.getAttribute('id') == 'about_div':
|
||||
self.parseDescription(div)
|
||||
|
||||
if div.getAttribute('id').startswith('tab_'):
|
||||
self.parseTable(div)
|
||||
|
||||
for tag in ('img', 'td'):
|
||||
imgs = self.document.getElementsByTagName(tag)
|
||||
for img in imgs:
|
||||
if img.hasAttribute('onclick'):
|
||||
m = self.ID_REGEXP.match(img.getAttribute('onclick'))
|
||||
if m:
|
||||
self.id = int(m.group(2))
|
||||
break
|
||||
if self.id:
|
||||
break
|
||||
|
||||
def parseDescription(self, div):
|
||||
# look for description
|
||||
|
||||
description = ''
|
||||
for c in div.childNodes:
|
||||
if hasattr(c, 'data'):
|
||||
description += ''.join(c.data.split('\n')) # to strip \n
|
||||
elif hasattr(c, 'tagName') and c.tagName == 'br':
|
||||
description += '\n'
|
||||
|
||||
self.description = description
|
||||
|
||||
def parseTable(self, div):
|
||||
|
||||
d = self.table[self.tables[div.getAttribute('id')]]
|
||||
fields = self.fields[self.tables[div.getAttribute('id')]]
|
||||
table = div.getElementsByTagName('table')[1]
|
||||
|
||||
field1 = None
|
||||
field2 = None
|
||||
|
||||
for tr in table.getElementsByTagName('tr'):
|
||||
tds = tr.getElementsByTagName('td')
|
||||
if len(tds) != 2:
|
||||
continue
|
||||
|
||||
label1 = ''
|
||||
label2 = ''
|
||||
value1 = ''
|
||||
value2 = ''
|
||||
# Check for first column
|
||||
if len(tds[0].childNodes) > 2:
|
||||
b = tds[0].childNodes[2]
|
||||
if hasattr(b, 'tagName') and b.tagName == 'b':
|
||||
for child in b.childNodes:
|
||||
label1 += child.data
|
||||
else:
|
||||
for child in tds[0].childNodes[2:]:
|
||||
value1 += child.data
|
||||
|
||||
# Check for second column
|
||||
if len(tds[1].childNodes) > 2:
|
||||
b = tds[1].childNodes[2]
|
||||
if hasattr(b, 'tagName') and b.tagName == 'b':
|
||||
for child in b.firstChild.childNodes:
|
||||
label2 += child.data
|
||||
else:
|
||||
for child in tds[1].childNodes[2:]:
|
||||
if hasattr(child, 'data'):
|
||||
value2 += child.data
|
||||
|
||||
if label1 and value2:
|
||||
# This is a typically tuple of key/value on the line.
|
||||
try:
|
||||
fields[label1].putValue(d, value2)
|
||||
except KeyError:
|
||||
warning('Unable to find "%s" (%s)' % (label1, repr(label1)))
|
||||
elif label1 and label2:
|
||||
# two titles, so there will have a list of value in
|
||||
# next lines on each columns
|
||||
field1 = fields[label1]
|
||||
field2 = fields[label2]
|
||||
elif not label1 and not label1:
|
||||
# two values, so it is a line of values
|
||||
if field1 and value1:
|
||||
field1.putValue(d, value1)
|
||||
if field2 and value2:
|
||||
field2.putValue(d, value2)
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getDescription(self):
|
||||
return self.description
|
||||
|
||||
def getTable(self):
|
||||
return self.table
|
||||
|
||||
def getID(self):
|
||||
return self.id
|
||||
|
||||
def getPhotos(self):
|
||||
return self.photos
|
||||
|
||||
def getStatus(self):
|
||||
return self.status
|
||||
|
||||
def isOnline(self):
|
||||
return self.status.find('en ligne') >= 0
|
||||
|
||||
def getStats(self):
|
||||
return self.stats
|
||||
|
||||
def getProfileText(self):
|
||||
body = u'Status: %s' % unicode(self.status)
|
||||
if self.photos:
|
||||
body += u'\nPhotos:'
|
||||
for photo in self.photos:
|
||||
body += u'\n\t\t%s' % unicode(photo)
|
||||
body += u'\nStats:'
|
||||
for label, value in self.getStats().iteritems():
|
||||
body += u'\n\t\t%-15s %s' % (label + ':', value)
|
||||
body += u'\n\nInformations:'
|
||||
for section, d in self.getTable().iteritems():
|
||||
body += u'\n\t%s\n' % section
|
||||
for key, value in d.items():
|
||||
key = '%s:' % key
|
||||
if isinstance(value, list):
|
||||
body += u'\t\t%-15s %s\n' % (key, u', '.join([unicode(s) for s in value]))
|
||||
elif isinstance(value, float):
|
||||
body += u'\t\t%-15s %.2f\n' % (key, value)
|
||||
else:
|
||||
body += u'\t\t%-15s %s\n' % (key, unicode(value))
|
||||
body += u'\n\nDescription:\n%s' % unicode(self.getDescription())
|
||||
|
||||
return body
|
||||
|
||||
|
||||
50
weboob/backends/aum/pages/profileslist_base.py
Normal file
50
weboob/backends/aum/pages/profileslist_base.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
from weboob.backends.aum.pages.base import PageBase
|
||||
import re
|
||||
|
||||
class ProfilesListBase(PageBase):
|
||||
|
||||
PROFILE_REGEXP = re.compile(".*window\.location='(.*)'")
|
||||
PHOTO_REGEXP = re.compile(".*background-image:url\(([A-Za-z0-9_\-:/\.]+)\).*")
|
||||
WITHOUT_PHOTO = 'http://s.adopteunmec.com/img/thumb1.gif'
|
||||
SHOW_WITHOUT_PHOTO = True
|
||||
|
||||
def loaded(self):
|
||||
|
||||
self.id_list = []
|
||||
|
||||
a_list = self.document.getElementsByTagName('div')
|
||||
for a in a_list:
|
||||
if a.hasAttribute('onclick') and a.hasAttribute('class') and a.getAttribute('class') in ('small', 'mini'):
|
||||
m = self.PROFILE_REGEXP.match(a.getAttribute('onclick'))
|
||||
if m:
|
||||
url = m.group(1).split('/')[-1]
|
||||
m = self.PHOTO_REGEXP.match(a.getElementsByTagName('div')[0].getAttribute('style'))
|
||||
if url != 'home.php' and not url in self.id_list and \
|
||||
m and (self.SHOW_WITHOUT_PHOTO or m.group(1) != self.WITHOUT_PHOTO):
|
||||
self.id_list.append(url)
|
||||
|
||||
def getProfilesIDs(self):
|
||||
return set(self.id_list)
|
||||
|
||||
def getProfilesIDsList(self):
|
||||
return self.id_list
|
||||
54
weboob/backends/aum/pages/search.py
Normal file
54
weboob/backends/aum/pages/search.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
import ClientForm
|
||||
from weboob.backends.aum.pages.profileslist_base import ProfilesListBase
|
||||
|
||||
class SearchPage(ProfilesListBase):
|
||||
|
||||
SHOW_WITHOUT_PHOTO = False
|
||||
|
||||
def set_field(self, args, label, field=None, value=None, is_list=False):
|
||||
try:
|
||||
if not field:
|
||||
field = label
|
||||
if args.get(label, None) is not None:
|
||||
if not value:
|
||||
if is_list:
|
||||
value = [str(args[label])]
|
||||
else:
|
||||
value = str(args[label])
|
||||
self.browser[field] = value
|
||||
except ClientForm.ControlNotFoundError:
|
||||
return
|
||||
|
||||
def search(self, **kwargs):
|
||||
|
||||
self.browser.select_form(name="form")
|
||||
self.browser.set_all_readonly(False)
|
||||
|
||||
self.set_field(kwargs, 'ageMin', is_list=True)
|
||||
self.set_field(kwargs, 'ageMax', is_list=True)
|
||||
self.set_field(kwargs, 'country', is_list=True)
|
||||
self.set_field(kwargs, 'dist', is_list=True)
|
||||
self.set_field(kwargs, 'nickname', field='pseudo')
|
||||
self.set_field(kwargs, 'save', value='true')
|
||||
|
||||
self.browser.submit()
|
||||
39
weboob/backends/aum/pages/wait.py
Normal file
39
weboob/backends/aum/pages/wait.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Copyright(C) 2008-2010 Romain Bignon
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
"""
|
||||
|
||||
from weboob.backends.aum.pages.base import PageBase
|
||||
from weboob.backends.aum.exceptions import AdopteWait
|
||||
from time import sleep
|
||||
|
||||
class WaitPage(PageBase):
|
||||
|
||||
def loaded(self):
|
||||
raise AdopteWait()
|
||||
|
||||
def check(self):
|
||||
result = self.browser.openurl('http://www.adopteunmec.com/fajax_checkEnter.php?anticache=0.46168455299380795').read()
|
||||
return result == 'Ok'
|
||||
|
||||
def processWait(self):
|
||||
while not self.check(self):
|
||||
sleep(10)
|
||||
|
||||
self.browser.location('/home.php')
|
||||
|
||||
|
|
@ -22,8 +22,8 @@ from weboob.tools.browser import Browser
|
|||
from weboob.backends.dlfp.pages.index import IndexPage, LoginPage
|
||||
|
||||
class DLFP(Browser):
|
||||
|
||||
DOMAIN = 'linuxfr.org'
|
||||
PROTOCOL = 'https'
|
||||
PAGES = {'https://linuxfr.org/': IndexPage,
|
||||
'https://linuxfr.org/pub/': IndexPage,
|
||||
'https://linuxfr.org/my/': IndexPage,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
"""
|
||||
|
||||
from logging import warning
|
||||
import feedparser
|
||||
import re
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ class Browser(mechanize.Browser):
|
|||
# ------ Class attributes --------------------------------------
|
||||
|
||||
DOMAIN = None
|
||||
PROTOCOL = 'http'
|
||||
PAGES = {}
|
||||
USER_AGENT = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/2008111318 Ubuntu/8.10 (intrepid) Firefox/3.0.3'
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue