Convert poivy to Browser2

This commit is contained in:
Florent 2014-03-20 15:07:10 +01:00
commit 8ec4f24c9a
4 changed files with 93 additions and 114 deletions

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2013 Florent Fourcot # Copyright(C) 2013-2014 Florent Fourcot
# #
# This file is part of weboob. # This file is part of weboob.
# #

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2013 Florent Fourcot # Copyright(C) 2013-2014 Florent Fourcot
# #
# This file is part of weboob. # This file is part of weboob.
# #
@ -52,17 +52,14 @@ class PoivyBackend(BaseBackend, ICapBill):
yield subscription yield subscription
def get_subscription(self, _id): def get_subscription(self, _id):
with self.browser: subscription = self.browser.get_subscription(_id)
subscription = self.browser.get_subscription(_id)
if subscription: if subscription:
return subscription return subscription
else: else:
raise SubscriptionNotFound() raise SubscriptionNotFound()
def iter_bills_history(self, subscription): def iter_bills_history(self, subscription):
with self.browser: return self.browser.get_history()
for history in self.browser.get_history():
yield history
# No details on the website # No details on the website
def get_details(self, subscription): def get_details(self, subscription):
@ -75,5 +72,5 @@ class PoivyBackend(BaseBackend, ICapBill):
balance.id = "%s-balance" % subscription.id balance.id = "%s-balance" % subscription.id
balance.price = subscription._balance balance.price = subscription._balance
balance.label = u"Balance %s" % subscription.id balance.label = u"Balance %s" % subscription.id
balance.currency = 'EUR' balance.currency = u'EUR'
return balance return balance

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2013 Fourcot Florent # Copyright(C) 2013-2014 Fourcot Florent
# #
# This file is part of weboob. # This file is part of weboob.
# #
@ -18,75 +18,55 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword, BrowserBanned from weboob.tools.browser2 import LoginBrowser, URL, need_login
from .pages import HomePage, LoginPage, HistoryPage, BillsPage, ErrorPage from .pages import HomePage, LoginPage, HistoryPage, BillsPage, ErrorPage
__all__ = ['PoivyBrowser'] __all__ = ['PoivyBrowser']
class PoivyBrowser(BaseBrowser): class PoivyBrowser(LoginBrowser):
DOMAIN = 'www.poivy.com' BASEURL = 'https://www.poivy.com'
PROTOCOL = 'https'
ENCODING = None # refer to the HTML encoding
PAGES = {'.*login': LoginPage,
'.*buy_credit.*': HomePage,
'.*/recent_calls': HistoryPage,
'.*purchases': BillsPage,
'.*warning.*': ErrorPage
}
def __init__(self, *args, **kwargs): login = URL('/login', LoginPage)
BaseBrowser.__init__(self, *args, **kwargs) homepage = URL('/buy_credit.*', HomePage)
history = URL('/recent_calls', HistoryPage)
bills = URL('/purchases', BillsPage)
warning = URL('/warning.*', ErrorPage)
def home(self): def do_login(self):
self.location('/login')
def is_logged(self):
return not self.is_on_page(LoginPage)
def login(self):
assert isinstance(self.username, basestring) assert isinstance(self.username, basestring)
assert isinstance(self.password, basestring) assert isinstance(self.password, basestring)
if not self.is_on_page(LoginPage): self.login.stay_or_go()
self.location('/login')
if not self.page.login(self.username, self.password): if not self.page.login(self.username, self.password):
raise BrowserBanned('Too many connections from you IP address: captcha enabled') raise BrowserBanned('Too many connections from you IP address: captcha enabled')
if self.is_on_page(LoginPage) or self.is_on_page(ErrorPage): if self.login.is_here() or self.warning.is_here():
raise BrowserIncorrectPassword() raise BrowserIncorrectPassword()
@need_login
def get_subscription_list(self): def get_subscription_list(self):
if not self.is_on_page(HomePage): return self.homepage.stay_or_go().get_list()
self.location('/buy_credit')
return self.page.get_list() def _find_id_list(self, mylist, _id):
for a in mylist:
def get_subscription(self, id): if a.id == _id:
assert isinstance(id, basestring)
l = self.get_subscription_list()
for a in l:
if a.id == id:
return a return a
return None return None
@need_login
def get_subscription(self, _id):
return self._find_id_list(self.get_subscription_list(), _id)
@need_login
def get_history(self): def get_history(self):
if not self.is_on_page(HistoryPage): return self.history.stay_or_go().get_calls()
self.location('/recent_calls')
return self.page.get_calls()
@need_login
def iter_bills(self, parentid): def iter_bills(self, parentid):
if not self.is_on_page(BillsPage): return self.bills.stay_or_go().get_bills()
self.location('/purchases')
return self.page.date_bills()
@need_login
def get_bill(self, id): def get_bill(self, id):
assert isinstance(id, basestring) return self._find_id_list(self.iter_bills(), _id)
l = self.iter_bills(id)
for a in l:
if a.id == id:
return a

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2013 Florent Fourcot # Copyright(C) 2013-2014 Florent Fourcot
# #
# This file is part of weboob. # This file is part of weboob.
# #
@ -17,7 +17,8 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.tools.browser import BasePage from weboob.tools.browser2.page import HTMLPage, LoggedPage, method, ListElement, ItemElement
from weboob.tools.browser2.filters import Env, CleanText, CleanDecimal, Field, Attr, Filter, Time, Date
from weboob.capabilities.bill import Subscription, Detail from weboob.capabilities.bill import Subscription, Detail
from decimal import Decimal, InvalidOperation from decimal import Decimal, InvalidOperation
from datetime import datetime, date, time from datetime import datetime, date, time
@ -27,15 +28,11 @@ import re
__all__ = ['LoginPage', 'HomePage', 'HistoryPage', 'BillsPage', 'ErrorPage'] __all__ = ['LoginPage', 'HomePage', 'HistoryPage', 'BillsPage', 'ErrorPage']
class ErrorPage(BasePage): class ErrorPage(HTMLPage):
def on_loaded(self):
pass pass
class LoginPage(BasePage): class LoginPage(HTMLPage):
def on_loaded(self):
pass
def _predicate_form(self, form): def _predicate_form(self, form):
try: try:
return form.attrs['class'] == "form-detail" return form.attrs['class'] == "form-detail"
@ -43,73 +40,78 @@ class LoginPage(BasePage):
return False return False
def login(self, login, password): def login(self, login, password):
captcha = self.document.xpath('//label[@class="label_captcha_input"]') captcha = self.doc.xpath('//label[@class="label_captcha_input"]')
if len(captcha) > 0: if len(captcha) > 0:
return False return False
form_newsletter = self.document.xpath('//form[@id="newsletter_form"]')[0] xpath_hidden = '//form[@id="newsletter_form"]/input[@type="hidden"]'
hidden_input = form_newsletter.xpath('./input[@type="hidden"]')[0] hidden_id = Attr(xpath_hidden, "value")(self.doc)
hidden_id = hidden_input.attrib["value"] hidden_name = Attr(xpath_hidden, "name")(self.doc)
hidden_name = hidden_input.attrib["name"]
# Form without name form = self.get_form(xpath="//form[@class='form-detail']")
self.browser.select_form(predicate=self._predicate_form) form['login[username]'] = login.encode('iso-8859-1')
self.browser.set_all_readonly(False) form['login[password]'] = password.encode('iso-8859-1')
self.browser['login[username]'] = login.encode('iso-8859-1') form[hidden_name] = hidden_id
self.browser['login[password]'] = password.encode('iso-8859-1') form.submit()
self.browser[hidden_name] = hidden_id
self.browser.submit(nologin=True)
return True return True
class HomePage(BasePage): class Insert2(Filter):
def on_loaded(self): """
pass Insert two Filters inside a string
"""
def __init__(self, selector, selector2, string):
super(Insert2, self).__init__(selector)
self.string = string
self.selector2 = selector2
def get_list(self): def __call__(self, item):
spanabo = self.document.xpath('//span[@class="welcome-text"]/b')[0] value = self.selector(item)
owner = spanabo.text_content() value2 = self.selector2(item)
credit = self.document.xpath('//span[@class="balance"]')[0].text_content() return self.filter(value, value2)
subscription = Subscription(owner) def filter(self, txt, txt2):
subscription.label = u"Poivy - %s - %s" % (owner, credit) return self.string % (txt, txt2)
subscription._balance = Decimal(re.sub(u'[^\d\-\.]', '', credit))
return [subscription]
class HistoryPage(BasePage): class HomePage(LoggedPage, HTMLPage):
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
def on_loaded(self): @method
pass class get_list(ListElement):
item_xpath = '.'
def get_calls(self): class item(ItemElement):
table = self.document.xpath('//table/tbody')[0] klass = Subscription
for tr in table.xpath('tr'):
tds = tr.xpath('td')
rawdate = tds[0].text_content() obj_id = CleanText('//span[@class="welcome-text"]/b')
splitdate = rawdate.split('-') obj__balance = CleanDecimal(CleanText('//span[@class="balance"]'), replace_dots=False)
month_no = self.months.index(splitdate[1]) + 1 obj_label = Insert2(Field('id'), Field('_balance'), u"Poivy - %s - %s")
mydate = date(int(splitdate[2]), month_no, int(splitdate[0]))
rawtime = tds[1].text_content()
mytime = time(*[int(x) for x in rawtime.split(":")])
price = re.sub(u'[^\d\-\.]', '', tds[6].text)
detail = Detail()
detail.datetime = datetime.combine(mydate, mytime)
detail.label = u"%s from %s to %s - %s" % (tds[2].text, tds[3].text, tds[4].text, tds[5].text)
try:
detail.price = Decimal(price)
except InvalidOperation:
detail.price = Decimal(0) # free calls
detail.currency = 'EUR'
yield detail
class BillsPage(BasePage): class HistoryPage(LoggedPage, HTMLPage):
def on_loaded(self):
pass @method
class get_calls(ListElement):
item_xpath = '//table/tbody/tr'
class item(ItemElement):
klass = Detail
obj_datetime = Env('datetime')
obj_price = CleanDecimal('td[7]', replace_dots=False)
obj_currency = u'EUR'
obj_label = Env('label')
def parse(self, el):
tds = el.xpath('td')
mydate = Date(CleanText('td[1]'))(el)
mytime = Time(CleanText('td[2]'))(el)
self.env['datetime'] = datetime.combine(mydate, mytime)
self.env['label'] = u"%s from %s to %s - %s" % (tds[2].text, tds[3].text, tds[4].text, tds[5].text)
#TODO
class BillsPage(HTMLPage):
pass