def get_list(self): accounts = OrderedDict() for tr in self.document.getiterator('tr'): first_td = tr.getchildren()[0] if (first_td.attrib.get('class', '') == 'i g' or first_td.attrib.get('class', '') == 'p g') \ and first_td.find('a') is not None: a = first_td.find('a') link = a.get('href', '') if link.startswith('POR_SyntheseLst'): continue url = urlparse(link) p = parse_qs(url.query) if not 'rib' in p: continue for i in (2,1): balance = FrenchTransaction.clean_amount(tr.getchildren()[i].text.strip(' EUR')) if len(balance) > 0: break balance = Decimal(balance) id = p['rib'][0] if id in accounts: account = accounts[id] if not account.coming: account.coming = Decimal('0.0') account.coming += balance account._card_links.append(link) continue account = Account() account.id = id account.label = unicode(a.text).strip().lstrip(' 0123456789').title() account._link_id = link account._card_links = [] account.balance = balance accounts[account.id] = account return accounts.itervalues()
def __new__(cls, name, bases, attrs): fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)] fields.sort(key=lambda x: x[1]._creation_counter) new_class = super(_BaseObjectMeta, cls).__new__(cls, name, bases, attrs) if new_class._fields is None: new_class._fields = OrderedDict() else: new_class._fields = deepcopy(new_class._fields) new_class._fields.update(fields) if new_class.__doc__ is None: new_class.__doc__ = '' for name, field in fields: doc = '(%s) %s' % (', '.join([':class:`%s`' % v.__name__ if isinstance(v,type) else v for v in field.types]), field.doc) if field.value is not NotLoaded: doc += ' (default: %s)' % field.value new_class.__doc__ += '\n:var %s: %s' % (name, doc) return new_class
class GanAssurancesModule(Module, CapBank): NAME = 'ganassurances' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '1.2' DESCRIPTION = u'Groupama' LICENSE = 'AGPLv3+' website_choices = OrderedDict([ (k, u'%s (%s)' % (v, k)) for k, v in sorted({ 'espaceclient.groupama.fr': u'Groupama Banque', 'espaceclient.ganassurances.fr': u'Gan Assurances', }.iteritems(), key=lambda k_v: (k_v[1], k_v[0])) ]) CONFIG = BackendConfig( Value('website', label='Banque', choices=website_choices, default='espaceclient.ganassurances.fr'), ValueBackendPassword('login', label=u'Numéro client', masked=False), ValueBackendPassword('password', label=u"Code d'accès")) BROWSER = GanAssurances def create_default_browser(self): return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): return self.browser.get_accounts_list() def get_account(self, _id): return find_object(self.browser.get_accounts_list(), id=_id, error=AccountNotFound) def iter_history(self, account): return self.browser.get_history(account) def iter_coming(self, account): return self.browser.get_coming(account)
def get_accounts(self): accounts = OrderedDict() for table in self.document.getiterator('table'): if table.attrib.get('cellspacing') == '2': for tr in table.cssselect('tr.hdoc1, tr.hdotc1'): tds = tr.findall('td') id = tds[1].text.replace(u'\xa0', u'') label = tds[0].text if label is None and tds[0].find('nobr') is not None: label = tds[0].find('nobr').text send_checkbox = tds[4].find( 'input').attrib['value'] if tds[4].find( 'input') is not None else None receive_checkbox = tds[5].find( 'input').attrib['value'] if tds[5].find( 'input') is not None else None account = Account(id, label, send_checkbox, receive_checkbox) accounts[id] = account return accounts
def get_transfer_target_accounts(self): target_accounts = OrderedDict() for select in self.document.xpath('//select'): if not select.attrib.get( 'id', '') == 'compte-emmet' and not select.attrib.get( 'id', '') == 'devise': count = select.xpath('count(//option)') j = 1 for i in range(1, int(count)): opttextraw = select.xpath('//option[%s]/text()' % i) optvalueraw = select.xpath('//option[%s]/@value' % i) for opttext in opttextraw: s = re.search('^\s*(.*)\s*(\w{2,}\d{14,})', opttext) if not (s is None): target_account_value = j j = j + 1 account = Account_perso(target_account_value, s.group(2)) target_accounts[target_account_value] = account return target_accounts
def get_list(self): accounts = OrderedDict() # Old website for table in self.document.xpath('//table[@cellpadding="1"]'): account_type = Account.TYPE_UNKNOWN for tr in table.xpath('./tr'): tds = tr.findall('td') if tr.attrib.get('class', '') == 'DataGridHeader': account_type = self.ACCOUNT_TYPES.get(tds[1].text.strip(), Account.TYPE_UNKNOWN) else: # On the same row, there are many accounts (for example a # check accound and a card one). for i, a in enumerate(tds[2].xpath('./a')): label = self.parser.tocleanstring(a) balance = self.parser.tocleanstring(tds[-2].xpath('./a')[i]) self._add_account(accounts, a, label, account_type, balance) if len(accounts) == 0: # New website for table in self.document.xpath('//div[@class="panel"]'): title = table.getprevious() if title is None: continue account_type = self.ACCOUNT_TYPES.get(self.parser.tocleanstring(title), Account.TYPE_UNKNOWN) for tr in table.xpath('.//tr'): tds = tr.findall('td') for i in xrange(len(tds)): a = tds[i].find('a') if a is not None: break if a is None: continue label = self.parser.tocleanstring(tds[0]) balance = self.parser.tocleanstring(tds[-1]) self._add_account(accounts, a, label, account_type, balance) return accounts.itervalues()
def do_list(self, line): """ list [CAPS ..] Show backends. """ caps = line.split() for instance_name, name, params in sorted( self.weboob.backends_config.iter_backends()): module = self.weboob.modules_loader.get_or_load_module(name) if caps and not module.has_caps(*caps): continue row = OrderedDict([('Name', instance_name), ('Module', name), ('Configuration', ', '.join( '%s=%s' % (key, ('*****' if key in module.config and module.config[key].masked \ else value)) \ for key, value in params.iteritems())), ]) self.format(row) self.flush()
def get_accounts(self): accounts = OrderedDict() first = True for table in self.document.xpath('//table[@class="tableCompte"]'): if first: first = False for tr in table.cssselect('tr.hdoc1, tr.hdotc1'): tds = tr.findall('td') id = tds[1].text.replace(u'\xa0', u'') label = tds[0].text.replace(u'\xa0', u' ') if label is None and tds[0].find('nobr') is not None: label = tds[0].find('nobr').text send_checkbox = tds[4].find( 'input').attrib['value'] if tds[4].find( 'input') is not None else None receive_checkbox = tds[5].find( 'input').attrib['value'] if tds[5].find( 'input') is not None else None account = Account(id, label, send_checkbox, receive_checkbox) accounts[id] = account return accounts
class NewspaperPresseuropBrowser(BaseBrowser): "NewspaperPresseuropBrowser class" PAGES = OrderedDict(( ("http://www.presseurop.eu/.*/todays-front-pages/.*", DailyTitlesPage), ("http://www.presseurop.eu/.*/front-page/.*", DailyTitlesPage), ("http://www.presseurop.eu/.*/cartoon/.*", CartoonPage), ("http://www.presseurop.eu/.*", PresseuropPage), )) def is_logged(self): return False def login(self): pass def fillobj(self, obj, fields): pass def get_content(self, _id): "return page article content" self.location(_id) return self.page.get_article(_id)
class Contact(CapBaseObject): """ A contact. """ STATUS_ONLINE = 0x001 STATUS_AWAY = 0x002 STATUS_OFFLINE = 0x004 STATUS_ALL = 0xfff name = StringField('Name of contact') status = IntField('Status of contact (STATUS_* constants)') url = StringField('URL to the profile of contact') status_msg = StringField('Message of status') summary = StringField('Description of contact') photos = Field('List of photos', dict, default=OrderedDict()) profile = Field('Contact profile', dict) def __init__(self, id, name, status): CapBaseObject.__init__(self, id) self.name = name self.status = status def set_photo(self, name, **kwargs): """ Set photo of contact. :param name: name of photo :type name: str :param kwargs: See :class:`ContactPhoto` to know what other parameters you can use """ if not name in self.photos: self.photos[name] = ContactPhoto(name) photo = self.photos[name] for key, value in kwargs.iteritems(): setattr(photo, key, value)
def do_list(self, line): """ list [CAPS ..] Show backends. """ caps = line.split() for backend_name, module_name, params in sorted(self.weboob.backends_config.iter_backends()): try: module = self.weboob.modules_loader.get_or_load_module(module_name) except ModuleLoadError as e: self.logger.warning('Unable to load module %r: %s' % (module_name, e)) continue if caps and not module.has_caps(*caps): continue row = OrderedDict([('Name', backend_name), ('Module', module_name), ('Configuration', ', '.join( '%s=%s' % (key, ('*****' if key in module.config and module.config[key].masked else value)) for key, value in params.iteritems())), ]) self.format(row)
class Contact(BaseObject): """ A contact. """ STATUS_ONLINE = 0x001 STATUS_AWAY = 0x002 STATUS_OFFLINE = 0x004 STATUS_ALL = 0xfff name = StringField('Name of contact') status = IntField('Status of contact (STATUS_* constants)') status_msg = StringField('Message of status') summary = StringField('Description of contact') photos = Field('List of photos', dict, default=OrderedDict()) profile = Field('Contact profile', dict, default=OrderedDict()) def __init__(self, id, name, status, url=None): BaseObject.__init__(self, id, url) self.name = name self.status = status def set_photo(self, name, **kwargs): """ Set photo of contact. :param name: name of photo :type name: str :param kwargs: See :class:`ContactPhoto` to know what other parameters you can use """ if name not in self.photos: self.photos[name] = ContactPhoto(name) photo = self.photos[name] for key, value in kwargs.iteritems(): setattr(photo, key, value) def get_text(self): def print_node(node, level=1): result = u'' if node.flags & node.SECTION: result += u'\t' * level + node.label + '\n' for sub in node.value.itervalues(): result += print_node(sub, level + 1) else: if isinstance(node.value, (tuple, list)): value = ', '.join(unicode(v) for v in node.value) elif isinstance(node.value, float): value = '%.2f' % node.value else: value = node.value result += u'\t' * level + u'%-20s %s\n' % (node.label + ':', value) return result result = u'Nickname: %s\n' % self.name if self.status & Contact.STATUS_ONLINE: s = 'online' elif self.status & Contact.STATUS_OFFLINE: s = 'offline' elif self.status & Contact.STATUS_AWAY: s = 'away' else: s = 'unknown' result += u'Status: %s (%s)\n' % (s, self.status_msg) result += u'URL: %s\n' % self.url result += u'Photos:\n' for name, photo in self.photos.iteritems(): result += u'\t%s%s\n' % (photo, ' (hidden)' if photo.hidden else '') result += u'\nProfile:\n' for head in self.profile.itervalues(): result += print_node(head) result += u'Description:\n' for s in self.summary.split('\n'): result += u'\t%s\n' % s return result
class AgendadulibreModule(Module, CapCalendarEvent): NAME = 'agendadulibre' DESCRIPTION = u'agendadulibre website' MAINTAINER = u'Bezleputh' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.2' ASSOCIATED_CATEGORIES = [CATEGORIES.CONF] BROWSER = AgendadulibreBrowser region_choices = OrderedDict([ (k, u'%s (%s)' % (v, k)) for k, v in sorted({ "http://www.agendadulibre.org": u'--France--', "http://www.agendadulibre.org#1": u'Alsace', "http://www.agendadulibre.org#2": u'Aquitaine', "http://www.agendadulibre.org#3": u'Auvergne', "http://www.agendadulibre.org#4": u'Basse-Normandie', "http://www.agendadulibre.org#5": u'Bourgogne', "http://www.agendadulibre.org#6": u'Bretagne', "http://www.agendadulibre.org#7": u'Centre', "http://www.agendadulibre.org#8": u'Champagne-Ardenne', "http://www.agendadulibre.org#9": u'Corse', "http://www.agendadulibre.org#10": u'Franche-Comté', "http://www.agendadulibre.org#23": u'Guadeloupe', "http://www.agendadulibre.org#24": u'Guyane', "http://www.agendadulibre.org#11": u'Haute-Normandie', "http://www.agendadulibre.org#12": u'Île-de-France', "http://www.agendadulibre.org#13": u'Languedoc-Roussillon', "http://www.agendadulibre.org#14": u'Limousin', "http://www.agendadulibre.org#15": u'Lorraine', "http://www.agendadulibre.org#25": u'Martinique', "http://www.agendadulibre.org#16": u'Midi-Pyrénées', "http://www.agendadulibre.org#17": u'Nord-Pas-de-Calais', "http://www.agendadulibre.org#18": u'Pays de la Loire', "http://www.agendadulibre.org#19": u'Picardie', "http://www.agendadulibre.org#20": u'Poitou-Charentes', "http://www.agendadulibre.org#21": u'Provence-Alpes-Côte d\'Azur', "http://www.agendadulibre.org#26": u'Réunion', "http://www.agendadulibre.org#22": u'Rhône-Alpes', "http://www.agendadulibre.be": u'--Belgique--', "http://www.agendadulibre.be#11": u'Antwerpen', "http://www.agendadulibre.be#10": u'Brabant wallon', "http://www.agendadulibre.be#9": u'Bruxelles-Capitale', "http://www.agendadulibre.be#8": u'Hainaut', "http://www.agendadulibre.be#7": u'Liege', "http://www.agendadulibre.be#6": u'Limburg', "http://www.agendadulibre.be#5": u'Luxembourg', "http://www.agendadulibre.be#4": u'Namur', "http://www.agendadulibre.be#3": u'Oost-Vlaanderen', "http://www.agendadulibre.be#2": u'Vlaams-Brabant', "http://www.agendadulibre.be#1": u'West-Vlaanderen', "http://www.agendadulibre.ch": u'--Suisse--', "http://www.agendadulibre.ch#15": u'Appenzell Rhodes-Extérieures', "http://www.agendadulibre.ch#16": u'Appenzell Rhodes-Intérieures', "http://www.agendadulibre.ch#19": u'Argovie', "http://www.agendadulibre.ch#13": u'Bâle-Campagne', "http://www.agendadulibre.ch#12": u'Bâle-Ville', "http://www.agendadulibre.ch#2": u'Berne', "http://www.agendadulibre.ch#10": u'Fribourg', "http://www.agendadulibre.ch#25": u'Genève', "http://www.agendadulibre.ch#8": u'Glaris', "http://www.agendadulibre.ch#18": u'Grisons', "http://www.agendadulibre.ch#26": u'Jura', "http://www.agendadulibre.ch#3": u'Lucerne', "http://www.agendadulibre.ch#24": u'Neuchâtel', "http://www.agendadulibre.ch#7": u'Nidwald', "http://www.agendadulibre.ch#6": u'Obwald', "http://www.agendadulibre.ch#17": u'Saint-Gall', "http://www.agendadulibre.ch#14": u'Schaffhouse', "http://www.agendadulibre.ch#5": u'Schwytz', "http://www.agendadulibre.ch#11": u'Soleure', "http://www.agendadulibre.ch#21": u'Tessin', "http://www.agendadulibre.ch#20": u'Thurgovie', "http://www.agendadulibre.ch#4": u'Uri', "http://www.agendadulibre.ch#23": u'Valais', "http://www.agendadulibre.ch#22": u'Vaud', "http://www.agendadulibre.ch#9": u'Zoug', "http://www.agendadulibre.ch#1": u'Zurich', }.iteritems()) ]) CONFIG = BackendConfig( Value('region', label=u'Region', choices=region_choices)) def create_default_browser(self): choice = self.config['region'].get().split('#') selected_region = '' if len(choice) < 2 else choice[-1] return self.create_browser(website=choice[0], region=selected_region) def search_events(self, query): return self.browser.list_events(query.start_date, query.end_date, query.city, query.categories) def list_events(self, date_from, date_to=None): return self.browser.list_events(date_from, date_to) def get_event(self, event_id): return self.browser.get_event(event_id) def fill_obj(self, event, fields): event = self.browser.get_event(event.id, event) choice = self.config['region'].get().split('#') selected_region = '' if len(choice) < 2 else choice[-1] if selected_region == '23': event.timezone = 'America/Guadeloupe' elif selected_region == '24': event.timezone = 'America/Guyana' elif selected_region == '26': event.timezone = 'Indian/Reunion' elif selected_region == '25': event.timezone = 'America/Martinique' else: event.timezone = 'Europe/Paris' return event OBJECTS = {AgendadulibreBrowser: fill_obj}
def __init__(self, info): status = Contact.STATUS_OFFLINE last_seen = parse_date(info['modification_date']) if last_seen >= datetime.datetime.now( tzlocal()) - datetime.timedelta(minutes=30): status = Contact.STATUS_ONLINE super(HappnContact, self).__init__(info['id'], info['display_name'], status) self.summary = info['about'] for photo in info['profiles']: self.set_photo(photo['id'], url=photo['url']) self.status_msg = u'Last seen at %s' % last_seen.strftime( '%Y-%m-%d %H:%M:%S') self.url = NotAvailable self.profile = OrderedDict() self.set_profile('info', 'id', info['id']) self.set_profile( 'info', 'full_name', ' '.join([info['first_name'] or '', info['last_name'] or '']).strip()) if info['fb_id'] is not None: self.set_profile( 'info', 'facebook', 'https://www.facebook.com/profile.php?id=%s&fref=ufi&pnref=story' % info['fb_id']) if info['twitter_id'] is not None: self.set_profile('info', 'twitter', info['twitter_id']) self.set_profile('stats', 'accepted', info['is_accepted']) self.set_profile('stats', 'charmed', info['is_charmed']) self.set_profile('stats', 'unread_conversations', info['unread_conversations']) self.set_profile('stats', 'credits', info['credits']) if info['last_meet_position'] is not None: self.set_profile( 'geoloc', 'last_meet', 'https://www.google.com/maps/place//@%s,%s,17z' % (info['last_meet_position']['lat'], info['last_meet_position']['lon'])) if info['distance'] is not None: self.set_profile('geoloc', 'distance', '%.2f km' % (info['distance'] / 1000.0)) self.set_profile('details', 'gender', info['gender']) self.set_profile('details', 'age', '%s yo' % info['age']) self.set_profile('details', 'birthday', info['birth_date']) self.set_profile('details', 'job', info['job']) self.set_profile('details', 'company', info['workplace']) self.set_profile('details', 'school', info['school']) if info['matching_preferences'] is not None: self.set_profile('settings', 'age_min', '%s yo' % info['matching_preferences']['age_min']) self.set_profile('settings', 'age_max', '%s yo' % info['matching_preferences']['age_max']) self.set_profile('settings', 'distance', '%s m' % info['matching_preferences']['distance']) self.set_profile('settings', 'female', info['matching_preferences']['female']) self.set_profile('settings', 'male', info['matching_preferences']['male'])
def __init__(self, *args, **kwargs): super(ListElement, self).__init__(*args, **kwargs) self.logger = getLogger(self.__class__.__name__.lower()) self.objects = OrderedDict()
class MonsterModule(Module, CapJob): NAME = 'monster' DESCRIPTION = u'monster website' MAINTAINER = u'Bezleputh' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.2' BROWSER = MonsterBrowser type_contrat_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ '97': u'Interim ou CDD ou mission', '98': u'CDI', '99': u'Stage', '000100': u'Autres', '101': u'Indépendant/Freelance/Franchise', '102': u'Journalier', '103': u'Titulaire de la fonction publique', '104': u'Temps Partiel', '105': u'Temps Plein', }.iteritems()) ]) JobCategory_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ ' ': u'Choisir…', '78': u'Architecture, Création et Spectacle', '92': u'Autres', '76': u'BTP et second oeuvre', '95': u'Commercial / Vente', '72': u'Comptabilité et Finance', '80': u'Edition et Ecriture', '81': u'Formation / Education', '93': u'Gestion de projet / programme', '83': u'Hôtellerie, Restauration et Tourisme', '86': u'Informatique et Technologies', '82': u'Ingénierie', '85': u'Installation, Maintenance et Réparation', '87': u'Juridique', '88': u'Logistique, Approvisionnement et Transport', '90': u'Marketing', '89': u'Production et Opérations', '94': u'Qualité / Inspection', '75': u'Recherche et Analyses', '84': u'Ressources Humaines', '91': u'Santé', '96': u'Sécurité', '73': u'Services administratifs', '79': u'Services clientèle et aux particuliers', '77': u'Stratégie et Management', }.iteritems()) ]) activityDomain_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted( { ' ': u'Choisir…', '16': u'Aéronautique / Aérospatiale (civil et militaire)', '17': u'Agriculture / Sylviculture / Pêche / Chasse', '39': u'Agroalimentaire', '18': u'Architecture / Design et services associés', '53': u'Art / Culture / Loisirs', '51': u'Associations / Bénévolat', '43': u'Assurance et Mutualité', '23': u'Audiovisuel / Media / Diffusion Audio et Vidéo', '14': u'Audit / Comptabilité / Fiscalité', '20': u'Automobile - Vente, Maintenance et Réparations', '52': u'Autres', '24': u'Autres Services aux entreprises', '21': u'Banques / Organismes financiers', '32': u'Biens de consommation courante / Cosmétiques', '31': u'BTP / Construction - bâtiments commerciaux, habitations', '30': u'BTP / Construction - usines, infrastructures, TP', '45': u'Cabinets et Services Juridiques', '46': u'Cabinets conseils en Management et Stratégie', '25': u'Chimie', '67': u'Commerce de gros et Import/Export', '55': u'Edition / Imprimerie', '35': u'Energie et Eau', '33': u'Enseignement et Formation', '66': u'Gestion des déchêts et Recyclage', '59': u'Grande Distribution et Commerce de détail', '42': u'Hôtellerie', '56': u'Immobilier', '47': u'Industrie / Production, autres', '19': u'Industrie Automobile - Constructeurs / Équipementiers', '34': u'Industrie électronique', '22': u'Industrie pharmaceutique / Biotechnologies', '26': u'Industrie Textile, Cuir et Confection', '27': u'Informatique - Hardware', '29': u'Informatique - Services', '28': u'Informatique - Software', '36': u'Ingénierie et services associés', '44': u'Internet / e-commerce', '57': u'Location', '48': u'Marine / Aéronautique', '15': u'Marketing / Communication / Publicité / RP', '50': u'Métaux et Minéraux', '37': u'Parcs d attraction et salles de spectacles', '62': u'Recrutement / Intérim et bureaux de placement', '58': u'Restauration', '41': u'Santé', '49': u'Santé - Equipement et appareils', '40': u'Secteur Public', '60': u'Sécurité et Surveillance', '54': u'Services aux particuliers', '38': u'Services financiers', '61': u'Sport - Equipements et infrastructures', '63': u'Télécommunication', '65': u'Tourisme, voyages et transport de personnes', '64': u'Transport de marchandises, entreprosage, stockage', }.iteritems())]) date_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ '-1': u'N importe quelle date', '000000': u'Aujourd hui', '1': u'2 derniers jours', '3': u'3 derniers jours', '7': u'Les 7 derniers jours', '14': u'Les 14 derniers jours', '30': u'30 derniers jours', }.iteritems())]) CONFIG = BackendConfig( Value('job_name', label='Job name', masked=False, default=''), Value('place', label='Place', masked=False, default=''), Value('contract', label=u'Contract', choices=type_contrat_choices, default='000100'), Value('job_category', label=u'Job Category', choices=JobCategory_choices, default=''), Value('activity_domain', label=u'Activity Domain', choices=activityDomain_choices, default=''), Value('limit_date', label=u'Date', choices=date_choices, default='-1'), ) def search_job(self, pattern=None): return self.browser.search_job(pattern) def advanced_search_job(self): return self.browser.advanced_search_job( job_name=self.config['job_name'].get(), place=self.config['place'].get(), contract=self.config['contract'].get(), job_category=self.config['job_category'].get(), activity_domain=self.config['activity_domain'].get(), limit_date=self.config['limit_date'].get()) def get_job_advert(self, _id, advert=None): return self.browser.get_job_advert(_id, advert) def fill_obj(self, advert, fields): return self.get_job_advert(advert.id, advert) OBJECTS = {BaseJobAdvert: fill_obj}
# # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see <http://www.gnu.org/licenses/>. from weboob.tools.backend import Module, BackendConfig from weboob.capabilities.base import StringField from weboob.capabilities.gauge import CapGauge, GaugeSensor, Gauge, GaugeMeasure, SensorNotFound from weboob.tools.value import Value from weboob.tools.ordereddict import OrderedDict from .browser import VelibBrowser __all__ = ['jcvelauxModule'] SENSOR_TYPES = OrderedDict(((u'available_bikes', u'Available bikes'), (u'available_bike_stands', u'Free stands'), (u'bike_stands', u'Total stands'))) CITIES = ("Paris", "Rouen", "Toulouse", "Luxembourg", "Valence", "Stockholm", "Goteborg", "Santander", "Amiens", "Lillestrom", "Mulhouse", "Lyon", "Ljubljana", "Seville", "Namur", "Nancy", "Creteil", "Bruxelles-Capitale", "Cergy-Pontoise", "Vilnius", "Toyama", "Kazan", "Marseille", "Nantes", "Besancon") class BikeMeasure(GaugeMeasure): def __repr__(self): return '<GaugeMeasure level=%d>' % self.level class BikeSensor(GaugeSensor):
class MonsterModule(Module, CapJob): NAME = 'monster' DESCRIPTION = u'monster website' MAINTAINER = u'Bezleputh' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.2' BROWSER = MonsterBrowser type_contrat_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ 'Interim-ou-CDD-ou-mission_8': u'Interim ou CDD ou mission', 'CDI_8': u'CDI', 'Stage-Apprentissage-Alternance_8': u'Stage/Apprentissage/Alternance', ' ': u'Autres', 'Indépendant-Freelance-Saisonnier-Franchise_8': u'Indépendant/Freelance/Saisonnier/Franchise', 'Journalier_8': u'Journalier', 'Temps-Partiel_8': u'Temps Partiel', 'Temps-Plein_8': u'Temps Plein', }.iteritems()) ]) date_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ '-1': u'N importe quelle date', '000000': u'Aujourd hui', '1': u'2 derniers jours', '3': u'3 derniers jours', '7': u'Les 7 derniers jours', '14': u'Les 14 derniers jours', '30': u'30 derniers jours', }.iteritems())]) CONFIG = BackendConfig( Value('job_name', label='Job name', masked=False, default=''), Value('place', label='Place', masked=False, default=''), Value('contract', label=u'Contract', choices=type_contrat_choices, default=''), Value('limit_date', label=u'Date', choices=date_choices, default='-1'), ) def search_job(self, pattern=None): return self.browser.search_job(pattern) def advanced_search_job(self): return self.browser.advanced_search_job( job_name=self.config['job_name'].get(), place=self.config['place'].get(), contract=self.config['contract'].get(), limit_date=self.config['limit_date'].get()) def get_job_advert(self, _id, advert=None): return self.browser.get_job_advert(_id, advert) def fill_obj(self, advert, fields): return self.get_job_advert(advert.id, advert) OBJECTS = {BaseJobAdvert: fill_obj}
class SenscritiqueModule(Module, CapCalendarEvent): NAME = 'senscritique' DESCRIPTION = u'senscritique website' MAINTAINER = u'Bezleputh' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.1' ASSOCIATED_CATEGORIES = [CATEGORIES.TELE] BROWSER = SenscritiqueBrowser tv_settings_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ '000000': u'-- Indifférent --', '9': u'TNT', '1': u'Canalsat', '2': u'Numericable', '10': u'Orange', '11': u'Free', '12': u'SFR', '15': u'Darty box via ADSL', '16': u'Bouygues', }.iteritems())]) """ dict that represents ids list of general-interest channels included in a tv package {'tv package id': ['general-interest channels ids list']} """ general = { 9: [46, 2, 48, 56], 1: [ 49, 46, 21, 2, 36, 59, 54, 48, 56, 50, 32, 1, 51, 24, 38, 34, 37, 6, 25, 11, 53, 26, 47 ], 2: [ 49, 46, 21, 2, 36, 59, 54, 48, 56, 50, 32, 1, 51, 24, 38, 34, 37, 6, 25, 11, 53, 26, 47 ], 10: [46, 46, 2, 36, 59, 54, 32, 24, 34, 37, 53, 47], 11: [46, 46, 2, 36, 59, 54, 32, 24, 34, 37, 53, 47], 12: [49, 46, 2, 36, 59, 54, 32, 24, 34, 37, 53, 47], 15: [49, 46, 2, 36, 32, 24, 34, 37, 53, 47], 16: [49, 46, 2, 36, 59, 54, 32, 24, 34, 37, 53, 47], } """ dict that represents ids list of cinema channels included in a tv package {'tv package id': ['cinema channels ids list']} """ cinema = { 9: [10, 7], 1: [ 10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 4055, 44, 3, 45, 42, 41, 43, 13, 12 ], 2: [ 10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 4055, 44, 3, 45, 42, 41, 43, 13, 12 ], 10: [ 10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 44, 3, 45, 42, 41, 43, 13, 12 ], 11: [ 10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 4055, 44, 3, 45, 42, 41, 43, 13, 12 ], 12: [ 10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 44, 3, 45, 42, 41, 43, 13, 12 ], 15: [ 10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 44, 3, 45, 42, 41, 43, 13, 12 ], 16: [ 10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 4055, 44, 3, 45, 42, 41, 43, 13, 12 ], } CONFIG = BackendConfig( Value('tv_settings', label=u'T.V. package', choices=tv_settings_choices), ValueBool('general', label='General', default=True), ValueBool('cinema', label='Cinema', default=False), ) def get_package_and_channels(self): package = int(self.config['tv_settings'].get()) channels = [] if package: if self.config['general'].get(): channels += self.general[package] if self.config['cinema'].get(): channels += self.cinema[package] return package, channels def search_events(self, query): if self.has_matching_categories(query): package, channels = self.get_package_and_channels() return self.browser.list_events(query.start_date, query.end_date, package, channels) def list_events(self, date_from, date_to=None): items = [] package, channels = self.get_package_and_channels() for item in self.browser.list_events(date_from, date_to, package, channels): items.append(item) items.sort(key=lambda o: o.start_date) return items def get_event(self, _id, event=None): package, channels = self.get_package_and_channels() return self.browser.get_event(_id, event, package=package, channels=channels) def fill_obj(self, event, fields): return self.get_event(event.id, event) OBJECTS = {SensCritiquenCalendarEvent: fill_obj}
class Contact(_Contact): TABLE = OrderedDict(( ( '_info', OrderedDict(( ('title', FieldStr('title')), # ipaddr is not available anymore. #('IPaddr', FieldIP('last_ip', 'first_ip')), ('admin', FieldBool('admin')), ('ban', FieldBool('isBan')), ('first', FieldStr('first_cnx')), ('godfather', FieldProfileURL('godfather')), ))), ('_stats', OrderedDict(( ('mails', FieldPopu('mails')), ('charms', FieldPopu('charmes')), ('visites', FieldPopu('visites')), ('baskets', FieldPopu('panier')), ('invits', FieldPopu('invits')), ('bonus', FieldPopu('bonus')), ('score', FieldStr('points')), ('ratio', FieldPopuRatio('mails', 'charmes')), ('mailable', FieldBool('can_mail')), ))), ( 'details', OrderedDict(( #('old', FieldStr('age')), ('old', FieldOld('birthdate')), ('birthday', FieldStr('birthdate')), ('zipcode', FieldStr('zip')), ('location', FieldStr('city')), ('distance', FieldDist('dist')), ('country', FieldStr('country')), ('phone', FieldStr('phone')), ('eyes', FieldConst('eyes_color')), ('hair_color', FieldConst('hair_color')), ('hair_size', FieldConst('hair_size')), ('height', FieldConst('size')), ('weight', FieldConst('weight')), ('BMI', FieldBMI('size', 'weight')), ('fat', FieldBMI('size', 'weight', fat=True)), ('shape', FieldConst('shape')), ('origins', FieldConst('origins')), ('signs', FieldConst('features')), ('job', FieldStr('job')), ('style', FieldConst('styles')), ('food', FieldConst('diet')), ('favorite_food', FieldConst('favourite_food')), ('drink', FieldConst('alcohol')), ('smoke', FieldConst('tobacco')), ))), ('tastes', OrderedDict(( ('hobbies', FieldStr('hobbies')), ('music', FieldList('music')), ('cinema', FieldList('cinema')), ('books', FieldList('books')), ('tv', FieldList('tvs')), ))), ('+sex', OrderedDict(( ('underwear', FieldConst('underwear')), ('practices', FieldConst('sexgames')), ('favorite', FieldConst('arousing')), ('toys', FieldConst('sextoys')), ))), ('+personality', OrderedDict(( ('snap', FieldStr('fall_for')), ('exciting', FieldStr('turned_on_by')), ('hate', FieldStr('cant_stand')), ('vices', FieldStr('vices')), ('assets', FieldStr('assets')), ('fantasies', FieldStr('fantasies')), ('is', FieldConst('character')), ))), ('-personality', OrderedDict(( ('accessories', FieldConst('accessories')), ('skills', FieldConst('skills')), ('socios', FieldConst('socios')), ('family', FieldConst('family')), ('pets', FieldConst('pets')), ))))) def parse_profile(self, profile, consts): if profile['online']: self.status = Contact.STATUS_ONLINE self.status_msg = u'online' self.status_msg = u'since %s' % profile['last_cnx'] else: self.status = Contact.STATUS_OFFLINE self.status_msg = u'last connection %s' % profile['last_cnx'] self.summary = unicode(unescape(profile.get('announce', '').strip())) if len(profile.get('shopping_list', '')) > 0: self.summary += u'\n\nLooking for:\n%s' % unescape( profile['shopping_list'].strip()) for photo in profile['pics']: self.set_photo(photo.split('/')[-1], url=photo + '/full', thumbnail_url=photo + '/small', hidden=False) self.profile = OrderedDict() if 'sex' in profile: for section, d in self.TABLE.iteritems(): flags = ProfileNode.SECTION if section.startswith('_'): flags |= ProfileNode.HEAD if (section.startswith('+') and int(profile['sex']) != 1) or \ (section.startswith('-') and int(profile['sex']) != 0): continue section = section.lstrip('_+-') s = ProfileNode(section, section.capitalize(), OrderedDict(), flags=flags) for key, builder in d.iteritems(): try: value = builder.get_value(profile, consts[int(profile['sex'])]) except KeyError: pass else: s.value[key] = ProfileNode( key, key.capitalize().replace('_', ' '), value) self.profile[section] = s self._aum_profile = profile def get_text(self): def print_node(node, level=1): result = u'' if node.flags & node.SECTION: result += u'\t' * level + node.label + '\n' for sub in node.value.itervalues(): result += print_node(sub, level + 1) else: if isinstance(node.value, (tuple, list)): value = ', '.join(unicode(v) for v in node.value) elif isinstance(node.value, float): value = '%.2f' % node.value else: value = node.value result += u'\t' * level + u'%-20s %s\n' % (node.label + ':', value) return result result = u'Nickname: %s\n' % self.name if self.status & Contact.STATUS_ONLINE: s = 'online' elif self.status & Contact.STATUS_OFFLINE: s = 'offline' elif self.status & Contact.STATUS_AWAY: s = 'away' else: s = 'unknown' result += u'Status: %s (%s)\n' % (s, self.status_msg) result += u'URL: %s\n' % self.url result += u'Photos:\n' for name, photo in self.photos.iteritems(): result += u'\t%s%s\n' % (photo, ' (hidden)' if photo.hidden else '') result += u'\nProfile:\n' for head in self.profile.itervalues(): result += print_node(head) result += u'Description:\n' for s in self.summary.split('\n'): result += u'\t%s\n' % s return result
class AmazonModule(Module, CapShop, CapBill): NAME = 'amazon' MAINTAINER = u'Oleg Plakhotniuk' EMAIL = '*****@*****.**' VERSION = '1.2' LICENSE = 'AGPLv3+' DESCRIPTION = u'Amazon' website_choices = OrderedDict([ (k, u'%s (%s)' % (v, k)) for k, v in sorted({ 'www.amazon.com': u'Amazon.com', 'www.amazon.fr': u'Amazon France', }.iteritems()) ]) BROWSERS = { 'www.amazon.com': Amazon, 'www.amazon.fr': AmazonFR, } CONFIG = BackendConfig( Value('website', label=u'Website', choices=website_choices, default='www.amazon.com'), ValueBackendPassword('email', label='Username', masked=False), ValueBackendPassword('password', label='Password')) def create_default_browser(self): self.BROWSER = self.BROWSERS[self.config['website'].get()] return self.create_browser(self.config['email'].get(), self.config['password'].get()) def get_currency(self): return self.browser.get_currency() def get_order(self, id_): return self.browser.get_order(id_) def iter_orders(self): return self.browser.iter_orders() def iter_payments(self, order): if not isinstance(order, Order): order = self.get_order(order) return self.browser.iter_payments(order) def iter_items(self, order): if not isinstance(order, Order): order = self.get_order(order) return self.browser.iter_items(order) def iter_resources(self, objs, split_path): if Order in objs: self._restrict_level(split_path) return self.iter_orders() if Subscription in objs: self._restrict_level(split_path) return self.iter_subscription() def iter_subscription(self): return self.browser.get_subscription_list() def get_subscription(self, _id): return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound) def get_bill(self, _id): subid = _id.split('.')[0] subscription = self.get_subscription(subid) return find_object(self.iter_bills(subscription), id=_id, error=BillNotFound) def iter_bills(self, subscription): if not isinstance(subscription, Subscription): subscription = self.get_subscription(subscription) return self.browser.iter_bills(subscription) def download_bill(self, bill): if not isinstance(bill, Bill): bill = self.get_bill(bill) if bill._url: return self.browser.open(bill._url).content return None
class ArteModule(Module, CapVideo, CapCollection): NAME = 'arte' MAINTAINER = u'Bezleputh' EMAIL = '*****@*****.**' VERSION = '1.2' DESCRIPTION = 'Arte French and German TV' LICENSE = 'AGPLv3+' order = { 'AIRDATE_DESC': 'Date', 'VIEWS': 'Views', 'ALPHA': 'Alphabetic', 'LAST_CHANCE': 'Last chance' } versions_choice = OrderedDict([(k, u'%s' % (v.get('label'))) for k, v in VERSION_VIDEO.items]) format_choice = OrderedDict([(k, u'%s' % (v)) for k, v in FORMATS.items]) lang_choice = OrderedDict([(k, u'%s' % (v.get('label'))) for k, v in LANG.items]) quality_choice = [u'%s' % (k) for k, v in QUALITY.items] CONFIG = BackendConfig( Value('lang', label='Lang of videos', choices=lang_choice, default='FRENCH'), Value('order', label='Sort order', choices=order, default='AIRDATE_DESC'), Value('quality', label='Quality of videos', choices=quality_choice, default=QUALITY.HD), Value('format', label='Format of videos', choices=format_choice, default=FORMATS.HTTP_MP4), Value('version', label='Version of videos', choices=versions_choice)) BROWSER = ArteBrowser def create_default_browser(self): return self.create_browser(lang=self.config['lang'].get(), quality=self.config['quality'].get(), order=self.config['order'].get(), format=self.config['format'].get(), version=self.config['version'].get()) def parse_id(self, _id): sites = '|'.join(k.get('id') for k in SITE.values) m = re.match('^(%s)\.(.*)' % sites, _id) if m: return m.groups() m = re.match('https?://www.arte.tv/guide/\w+/(?P<id>.+)/(.*)', _id) if m: return SITE.PROGRAM.get('id'), m.group(1) m = re.match('https?://(%s).arte.tv/(\w+)/(.*)' % (sites), _id) if m: return m.group(1), '/%s/%s' % (m.group(2), m.group(3)) if not _id.startswith('http'): return 'videos', _id return None, None def get_video(self, _id): site, _id = self.parse_id(_id) if not (site and _id): return None if site in [value.get('id') for value in SITE.values]: _site = (value for value in SITE.values if value.get('id') == site).next() return getattr(self.browser, _site.get('video'))(_id) else: return self.browser.get_video(_id) def search_videos(self, pattern, sortby=CapVideo.SEARCH_RELEVANCE, nsfw=False): return self.browser.search_videos(pattern) def fill_arte_video(self, video, fields): if fields != ['thumbnail']: video = self.browser.get_video(video.id, video) if 'thumbnail' in fields and video and video.thumbnail: video.thumbnail.data = self.browser.open( video.thumbnail.url).content return video def fill_site_video(self, video, fields): if fields != ['thumbnail']: for site in SITE.values: m = re.match('%s\.(.*)' % site.get('id'), video.id) if m: video = getattr(self.browser, site.get('video'))(m.group(1), video) break if 'thumbnail' in fields and video and video.thumbnail: try: video.thumbnail.data = self.browser.open( video.thumbnail.url).content except BrowserHTTPSDowngrade: pass return video def iter_resources(self, objs, split_path): if BaseVideo in objs: collection = self.get_collection(objs, split_path) if collection.path_level == 0: yield Collection([u'arte-latest'], u'Latest Arte videos') for site in SITE.values: yield Collection([site.get('id')], site.get('label')) if collection.path_level == 1: if collection.split_path == [u'arte-latest']: for video in self.browser.latest_videos(): yield video else: for site in SITE.values: if collection.split_path[0] == site.get( 'id') and collection.path_level in site.keys(): for item in getattr( self.browser, site.get(collection.path_level))(): yield item if collection.path_level >= 2: for site in SITE.values: if collection.split_path[0] == site.get( 'id') and collection.path_level in site.keys(): for item in getattr(self.browser, site.get(collection.path_level))( collection.split_path): yield item def validate_collection(self, objs, collection): if collection.path_level == 0: return if BaseVideo in objs and (collection.split_path == [u'arte-latest'] or collection.split_path[0] in [ value.get('id') for value in SITE.values ]): return if BaseVideo in objs and collection.path_level >= 2 and\ collection.split_path[0] in [value.get('id') for value in SITE.values]: return raise CollectionNotFound(collection.split_path) OBJECTS = {ArteVideo: fill_arte_video, ArteSiteVideo: fill_site_video}
class CragrModule(Module, CapBank): NAME = 'cragr' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '1.1' DESCRIPTION = u'Crédit Agricole' LICENSE = 'AGPLv3+' website_choices = OrderedDict([ (k, u'%s (%s)' % (v, k)) for k, v in sorted({ 'm.ca-alpesprovence.fr': u'Alpes Provence', 'm.ca-alsace-vosges.fr': u'Alsace-Vosges', 'm.ca-anjou-maine.fr': u'Anjou Maine', 'm.ca-aquitaine.fr': u'Aquitaine', 'm.ca-atlantique-vendee.fr': u'Atlantique Vendée', 'm.ca-briepicardie.fr': u'Brie Picardie', 'm.ca-cb.fr': u'Champagne Bourgogne', 'm.ca-centrefrance.fr': u'Centre France', 'm.ca-centreloire.fr': u'Centre Loire', 'm.ca-centreouest.fr': u'Centre Ouest', 'm.ca-centrest.fr': u'Centre Est', 'm.ca-charente-perigord.fr': u'Charente Périgord', 'm.ca-cmds.fr': u'Charente-Maritime Deux-Sèvres', 'm.ca-corse.fr': u'Corse', 'm.ca-cotesdarmor.fr': u'Côtes d\'Armor', 'm.ca-des-savoie.fr': u'Des Savoie', 'm.ca-finistere.fr': u'Finistere', 'm.ca-franchecomte.fr': u'Franche-Comté', 'm.ca-guadeloupe.fr': u'Guadeloupe', 'm.ca-illeetvilaine.fr': u'Ille-et-Vilaine', 'm.ca-languedoc.fr': u'Languedoc', 'm.ca-loirehauteloire.fr': u'Loire Haute Loire', 'm.ca-lorraine.fr': u'Lorraine', 'm.ca-martinique.fr': u'Martinique Guyane', 'm.ca-morbihan.fr': u'Morbihan', 'm.ca-nmp.fr': u'Nord Midi-Pyrénées', 'm.ca-nord-est.fr': u'Nord Est', 'm.ca-norddefrance.fr': u'Nord de France', 'm.ca-normandie-seine.fr': u'Normandie Seine', 'm.ca-normandie.fr': u'Normandie', 'm.ca-paris.fr': u'Ile-de-France', 'm.ca-pca.fr': u'Provence Côte d\'Azur', 'm.ca-reunion.fr': u'Réunion', 'm.ca-sudmed.fr': u'Sud Méditerranée', 'm.ca-sudrhonealpes.fr': u'Sud Rhône Alpes', 'm.ca-toulouse31.fr': u'Toulouse 31', # m.ca-toulousain.fr redirects here 'm.ca-tourainepoitou.fr': u'Tourraine Poitou', 'm.ca-valdefrance.fr': u'Val de France', 'm.lefil.com': u'Pyrénées Gascogne', }.iteritems()) ]) CONFIG = BackendConfig( Value('website', label=u'Région', choices=website_choices), ValueBackendPassword('login', label=u'N° de compte', masked=False), ValueBackendPassword('password', label=u'Code personnel', regexp=r'\d{6}')) BROWSER = Cragr def create_default_browser(self): try: return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) except Cragr.WebsiteNotSupported: self.logger.debug('falling-back on mobile version') self.BROWSER = CragrMobile return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): return self.browser.get_accounts_list() def get_account(self, _id): account = self.browser.get_account(_id) if account: return account else: raise AccountNotFound() def iter_history(self, account): return self.browser.get_history(account) def transfer(self, account, to, amount, reason=None): return self.browser.do_transfer(account, to, amount, reason)
class PopolemploiBackend(BaseBackend, ICapJob): NAME = 'popolemploi' DESCRIPTION = u'Pole Emploi website' MAINTAINER = u'Bezleputh' EMAIL = '*****@*****.**' VERSION = '0.h' BROWSER = PopolemploiBrowser places_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ '100|FRANCE|FRANCE': u'France entière', '102|REGION|checkbox': u'Alsace', '103|DEPARTEMENT|checkbox_66': u'-- Rhin (Bas) (67)', '104|DEPARTEMENT|checkbox_67': u'-- Rhin (Haut) (68)', '105|REGION|checkbox_0': u'Aquitaine', '106|DEPARTEMENT|checkbox_21': u'-- Dordogne (24)', '107|DEPARTEMENT|checkbox_32': u'-- Gironde (33)', '108|DEPARTEMENT|checkbox_39': u'-- Landes (40)', '109|DEPARTEMENT|checkbox_46': u'-- Lot et Garonne (47)', '110|DEPARTEMENT|checkbox_63': u'-- Pyrénées Atlantiques (64)', '111|REGION|checkbox_1': u'Auvergne', '112|DEPARTEMENT|checkbox_1': u'-- Allier (03)', '113|DEPARTEMENT|checkbox_13': u'-- Cantal (15)', '114|DEPARTEMENT|checkbox_42': u'-- Loire (Haute) (43)', '115|DEPARTEMENT|checkbox_62': u'-- Puy de Dôme (63)', '116|REGION|checkbox_2': u'Bourgogne', '117|DEPARTEMENT|checkbox_18': u'-- Côte d\'Or (21)', '118|DEPARTEMENT|checkbox_57': u'-- Nièvre (58)', '119|DEPARTEMENT|checkbox_70': u'-- Saône et Loire (71)', '120|DEPARTEMENT|checkbox_88': u'-- Yonne (89)', '121|REGION|checkbox_3': u'Bretagne', '122|DEPARTEMENT|checkbox_19': u'-- Côtes d\'Armor (22)', '123|DEPARTEMENT|checkbox_26': u'-- Finistère (29)', '124|DEPARTEMENT|checkbox_34': u'-- Ille et Vilaine (35)', '125|DEPARTEMENT|checkbox_54': u'-- Morbihan (56)', '126|REGION|checkbox_4': u'Centre', '127|DEPARTEMENT|checkbox_16': u'-- Cher (18)', '128|DEPARTEMENT|checkbox_25': u'-- Eure et Loir (28)', '129|DEPARTEMENT|checkbox_35': u'-- Indre (36)', '130|DEPARTEMENT|checkbox_36': u'-- Indre et Loire (37)', '131|DEPARTEMENT|checkbox_40': u'-- Loir et Cher (41)', '132|DEPARTEMENT|checkbox_44': u'-- Loiret (45)', '133|REGION|checkbox_5': u'Champagne Ardenne', '134|DEPARTEMENT|checkbox_6': u'-- Ardennes (08)', '135|DEPARTEMENT|checkbox_8': u'-- Aube (10)', '136|DEPARTEMENT|checkbox_50': u'-- Marne (51)', '137|DEPARTEMENT|checkbox_51': u'-- Marne (Haute) (52)', '138|REGION|checkbox_6': u'Corse', '139|DEPARTEMENT|checkbox_26': u'-- Corse du Sud (2A)', '140|DEPARTEMENT|checkbox_27': u'-- Haute Corse (2B)', '141|REGION|checkbox_7': u'Franche Comté', '142|DEPARTEMENT|checkbox_89': u'-- Belfort (Territoire de) (90)', '143|DEPARTEMENT|checkbox_22': u'-- Doubs (25)', '144|DEPARTEMENT|checkbox_38': u'-- Jura (39)', '145|DEPARTEMENT|checkbox_69': u'-- Saône (Haute) (70)', '146|REGION|checkbox_8': u'Ile de France', '147|DEPARTEMENT|checkbox_90': u'-- Essonne (91)', '148|DEPARTEMENT|checkbox_91': u'-- Hauts de Seine (92)', '149|DEPARTEMENT|checkbox_74': u'-- Paris (Dept.) (75)', '150|DEPARTEMENT|checkbox_92': u'-- Seine Saint Denis (93)', '151|DEPARTEMENT|checkbox_76': u'-- Seine et Marne (77)', '152|DEPARTEMENT|checkbox_94': u'-- Val d\'Oise (95)', '153|DEPARTEMENT|checkbox_93': u'-- Val de Marne (94)', '154|DEPARTEMENT|checkbox_77': u'-- Yvelines (78)', '155|REGION|checkbox_9': u'Languedoc Roussillon', '156|DEPARTEMENT|checkbox_9': u'-- Aude (11)', '157|DEPARTEMENT|checkbox_39': u'-- Gard (30)', '158|DEPARTEMENT|checkbox_33': u'-- Hérault (34)', '159|DEPARTEMENT|checkbox_47': u'-- Lozère (48)', '161|DEPARTEMENT|checkbox_65': u'-- Pyrénées Orientales (66)', '162|REGION|checkbox_10': u'Limousin', '163|DEPARTEMENT|checkbox_17': u'-- Corrèze (19)', '164|DEPARTEMENT|checkbox_20': u'-- Creuse (23)', '165|DEPARTEMENT|checkbox_86': u'-- Vienne (Haute) (87)', '166|REGION|checkbox_11': u'Lorraine', '167|DEPARTEMENT|checkbox_53': u'-- Meurthe et Moselle (54)', '168|DEPARTEMENT|checkbox_54': u'-- Meuse (55)', '169|DEPARTEMENT|checkbox_56': u'-- Moselle (57)', '170|DEPARTEMENT|checkbox_87': u'-- Vosges (88)', '171|REGION|checkbox_12': u'Midi Pyrénées', '172|DEPARTEMENT|checkbox_7': u'-- Ariège (09)', '173|DEPARTEMENT|checkbox_10': u'-- Aveyron (12)', '174|DEPARTEMENT|checkbox_30': u'-- Garonne (Haute) (31)', '175|DEPARTEMENT|checkbox_31': u'-- Gers (32)', '176|DEPARTEMENT|checkbox_45': u'-- Lot (46)', '177|DEPARTEMENT|checkbox_64': u'-- Pyrénées (Hautes) (65)', '178|DEPARTEMENT|checkbox_80': u'-- Tarn (81)', '179|DEPARTEMENT|checkbox_81': u'-- Tarn et Garonne (82)', '180|REGION|checkbox_13': u'Nord Pas de Calais', '181|DEPARTEMENT|checkbox_58': u'-- Nord (59)', '182|DEPARTEMENT|checkbox_61': u'-- Pas de Calais (62)', '183|REGION|checkbox_14': u'Normandie (Basse)', '184|DEPARTEMENT|checkbox_12': u'-- Calvados (14)', '185|DEPARTEMENT|checkbox_49': u'-- Manche (50)', '186|DEPARTEMENT|checkbox_60': u'-- Orne (61)', '187|REGION|checkbox_15': u'Normandie (Haute)', '188|DEPARTEMENT|checkbox_24': u'-- Eure (27)', '189|DEPARTEMENT|checkbox_75': u'-- Seine Maritime (76)', '190|REGION|checkbox_16': u'Pays de la Loire', '191|DEPARTEMENT|checkbox_43': u'-- Loire Atlantique (44)', '192|DEPARTEMENT|checkbox_48': u'-- Maine et Loire (49)', '193|DEPARTEMENT|checkbox_52': u'-- Mayenne (53)', '194|DEPARTEMENT|checkbox_71': u'-- Sarthe (72)', '195|DEPARTEMENT|checkbox_84': u'-- Vendée (85)', '196|REGION|checkbox_17': u'Picardie', '197|DEPARTEMENT|checkbox_0': u'-- Aisne (02)', '198|DEPARTEMENT|checkbox_59': u'-- Oise (60)', '199|DEPARTEMENT|checkbox_79': u'-- Somme (80)', '200|REGION|checkbox_18': u'Poitou Charentes', '201|DEPARTEMENT|checkbox_14': u'-- Charente (16)', '202|DEPARTEMENT|checkbox_15': u'-- Charente Maritime (17)', '203|DEPARTEMENT|checkbox_78': u'-- Sèvres (Deux) (79)', '204|DEPARTEMENT|checkbox_85': u'-- Vienne (86)', '205|REGION|checkbox_19': u'Provence Alpes Côte d\'Azur', '206|DEPARTEMENT|checkbox_3': u'-- Alpes (Hautes) (05)', '207|DEPARTEMENT|checkbox_4': u'-- Alpes Maritimes (06)', '208|DEPARTEMENT|checkbox_2': u'-- Alpes de Haute Provence (04)', '209|DEPARTEMENT|checkbox_13': u'-- Bouches du Rhône (13)', '210|DEPARTEMENT|checkbox_82': u'-- Var (83)', '211|DEPARTEMENT|checkbox_83': u'-- Vaucluse (84)', '212|REGION|checkbox_20': u'Rhône Alpes', '213|DEPARTEMENT|checkbox': u'-- Ain (01)', '214|DEPARTEMENT|checkbox_5': u'-- Ardèche (07)', '215|DEPARTEMENT|checkbox_23': u'-- Drôme (26)', '216|DEPARTEMENT|checkbox_37': u'-- Isère (38)', '217|DEPARTEMENT|checkbox_41': u'-- Loire (42)', '218|DEPARTEMENT|checkbox_68': u'-- Rhône (69)', '219|DEPARTEMENT|checkbox_72': u'-- Savoie (73)', '220|DEPARTEMENT|checkbox_73': u'-- Savoie (Haute) (74)', '221|REGION|checkbox_21': u'Région Antilles / Guyane', '222|DEPARTEMENT|checkbox_95': u'-- Guadeloupe (971)', '223|DEPARTEMENT|checkbox_97': u'-- Guyane (973)', '224|DEPARTEMENT|checkbox_96': u'-- Martinique (972)', '225|DEPARTEMENT|checkbox_101': u'-- Saint Barthélémy (977)', '226|DEPARTEMENT|checkbox_102': u'-- Saint Martin (978)', '227|REGION|checkbox_22': u'Région Atlantique Nord', '228|DEPARTEMENT|checkbox_99': u'-- Saint Pierre et Miquelon (975)', '229|REGION|checkbox_23': u'Région Pacifique', '230|DEPARTEMENT|checkbox_107': u'-- Ile de Clipperton (989)', '231|DEPARTEMENT|checkbox_106': u'-- Nouvelle Calédonie (988)', '232|DEPARTEMENT|checkbox_105': u'-- Polynésie française (987)', '233|DEPARTEMENT|checkbox_103': u'-- Terres australes/antarctiques (984)', '234|DEPARTEMENT|checkbox_104': u'-- Wallis et Futuna (986)', '235|REGION|checkbox_24': u'Région Réunion / Mayotte', '236|DEPARTEMENT|checkbox_100': u'-- Mayotte (976)', '237|DEPARTEMENT|checkbox_98': u'-- Réunion (974)', }.iteritems()) ]) type_contrat_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ ' ': u'Tous types de contrats', '11': u'CDI tout public', '14': u'CDI alternance', '13': u'CDI insertion', '12': u'CDD tout public', '16': u'CDD alternance', '15': u'CDD insertion', '10': u'CDD Senior', '3': u'Mission d\'intérim', '4': u'Contrat de travail saisonnier', '5': u'Contrat de travail intermittent', '8': u'Franchise', '7': u'Profession libérale', '9': u'Reprise d\'entreprise', '6': u'Profession commerciale', }.iteritems()) ]) salary_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ ' ': u'Tout salaire annuel', 'FOURCHETTE1': u'Moins de 15000', 'FOURCHETTE2': u'Compris entre 15000 et 18000', 'FOURCHETTE3': u'Compris entre 18000 et 21000', 'FOURCHETTE4': u'Compris entre 21000 et 24000', 'FOURCHETTE5': u'Compris entre 24000 et 36000', 'FOURCHETTE6': u'Compris entre 36000 et 60000', 'FOURCHETTE7': u'Supérieur à 60000', }.iteritems()) ]) qualification_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ ' ': u'Toute Qualification', '1': u'Manoeuvre', '2': u'Ouvrier spécialisé', '3': u'Ouvrier qualifié (P1,P2)', '4': u'Ouvrier qualifié (P3,P4,OHQ)', '5': u'Employé non qualifié', '6': u'Employé qualifié', '7': u'Technicien', '8': u'Agent de maîtrise', '9': u'Cadre', }.iteritems()) ]) limit_date_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ '': u'Aucune limite', 'UN_JOUR': u'Hier', 'TROIS_JOUR': u'3 jours', 'UNE_SEMAINE': u'1 semaine', 'DEUX_SEMAINES': u'2 semaines', 'UN_MOIS': u'1 mois', 'TROIS_MOIS': u'3 mois', }.iteritems()) ]) domain_choices = OrderedDict([ (k, u'%s' % (v)) for k, v in sorted({ ' ': u'Tout secteur d\'activité', '88': u'Action sociale sans hebergt', '82': u'Activ.admin/soutien entreprise', '66': u'Activ. auxiliaire finance/assu', '90': u'Activ. crea/artistiq/spectacle', '77': u'Activ. de loc. et loc.-bail', '70': u'Activ. siege soc/conseil gest.', '93': u'Activ. sportive/recreat/loisir', '69': u'Activite juridique/comptable', '94': u'Activite organisations assoc.', '86': u'Activite pr la sante humaine', '53': u'Activites de poste/courrier', '64': u'Activite services financiers', '68': u'Activites immobilieres', '62': u'Activites informatiques', '78': u'Activites liees a l\'emploi', '75': u'Activites veterinaires', '84': u'Administration publiq/defense', '79': u'Agences voyage/activ. liees', '71': u'Archi/ing/control/analyse tech', '65': u'Assurance', '32': u'Autre industrie manufacturiere', '74': u'Autres activ.spe scientif/tech', '08': u'Autres industries extractives', '91': u'Biblio/ musée/ activ. culturel', '36': u'Captage/traitement/distrib.eau', '19': u'Cokefaction et raffinage', '37': u'Collecte/traitement eaux usees', '38': u'Collecte/traitnt/elimin dechet', '45': u'Commerce/reparation auto/moto', '47': u'Commerce detail sauf auto/moto', '46': u'Commerce gros sauf auto/moto', '41': u'Construction de batiments', '01': u'Cult./prod. animale, chasse', '39': u'Depollution/autre gest. dechet', '58': u'Edition', '80': u'Enquetes et securite', '85': u'Enseignement', '52': u'Entreposage/sce auxil. transp', '06': u'Extraction d\'hydrocarbures', '05': u'Extraction houille/ lignite', '07': u'Extraction minerais metalliq.', '26': u'Fab. prod. info/electro/optiq', '22': u'Fabr. prod. caoutchouc/plastiq', '30': u'Fabric. autre materiel transp.', '23': u'Fabric.autre produit non metal', '28': u'Fabric. autres machines/equip.', '27': u'Fabric. d\'equip. electriques', '31': u'Fabrication de meubles', '12': u'Fabrication produit base tabac', '25': u'Fabrication produits metalliq', '42': u'Genie civil', '55': u'Hebergement', '87': u'Hebergt médico-social/ social', '18': u'Imprimerie/reprod. enregistre.', '00': u'Indetermine', '29': u'Industrie automobile', '20': u'Industrie chimique', '14': u'Industrie de l\'habillement', '11': u'Industrie des boissons', '15': u'Industrie du cuir/la chaussure', '17': u'Industrie du papier/du carton', '21': u'Industrie pharmaceutique', '10': u'Industries alimentaires', '13': u'Industrie textile', '24': u'Metallurgie', '92': u'Orga. jeux hasard/argent', '99': u'Organisations et organismes', '03': u'Peche et aquaculture', '35': u'Prod./distrib.elec/gaz/vap/air', '59': u'Prod film cine/video/tv/musiq', '98': u'Production menage bien propre', '60': u'Programmation et diffusion', '73': u'Publicite et etudes de marche', '72': u'Rech.-dev. scientifique', '33': u'Repar./instal. machines/equip.', '95': u'Repar.pc/biens perso/domestiq', '56': u'Restauration', '97': u'Sce domestique pr particuliers', '81': u'Services bat/amenagnt paysager', '63': u'Services d\'information', '96': u'Services personnels', '09': u'Soutien industries extractives', '02': u'Sylvicult./exploit. forestiere', '61': u'Telecommunications', '51': u'Transports aeriens', '50': u'Transports par eau', '49': u'Transports terrestres', '16': u'Travail bois/fab. article bois', '43': u'Travaux constr.specialises', }.iteritems()) ]) CONFIG = BackendConfig( Value('metier', label='Job name', masked=False, default=''), Value('place', label=u'Place', choices=places_choices, default='100|FRANCE|FRANCE'), Value('contrat', label=u'Contract', choices=type_contrat_choices, default=''), Value('salary', label=u'Salary', choices=salary_choices, default=''), Value('qualification', label=u'Qualification', choices=qualification_choices, default=''), Value('limit_date', label=u'Date limite', choices=limit_date_choices, default=''), Value('domain', label=u'Domain', choices=domain_choices, default='')) def search_job(self, pattern=None): with self.browser: return self.browser.search_job(pattern=pattern) def advanced_search_job(self): return self.browser.advanced_search_job( metier=self.config['metier'].get(), place=self.config['place'].get(), contrat=self.config['contrat'].get(), salary=self.config['salary'].get(), qualification=self.config['qualification'].get(), limit_date=self.config['limit_date'].get(), domain=self.config['domain'].get()) def get_job_advert(self, _id, advert=None): with self.browser: return self.browser.get_job_advert(_id, advert) def fill_obj(self, advert, fields): self.get_job_advert(advert.id, advert) OBJECTS = {PopolemploiJobAdvert: fill_obj}
def registerEvent(self): selection = self.ui.modulesList.selectedItems() if not selection: return try: module = self.weboob.modules_loader.get_or_load_module( selection[0].text().lower()) except ModuleLoadError: module = None if not module: return dialog = QDialog(self) vbox = QVBoxLayout(dialog) if module.website: website = 'on the website <b>%s</b>' % module.website else: website = 'with the module <b>%s</b>' % module.name vbox.addWidget( QLabel( 'To create an account %s, please provide this information:' % website)) formlayout = QFormLayout() props_widgets = OrderedDict() for key, prop in module.klass.ACCOUNT_REGISTER_PROPERTIES.iteritems(): widget = QtValue(prop) formlayout.addRow(QLabel(u'%s:' % prop.label), widget) props_widgets[prop.id] = widget vbox.addLayout(formlayout) buttonBox = QDialogButtonBox(dialog) buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttonBox.accepted.connect(dialog.accept) buttonBox.rejected.connect(dialog.reject) vbox.addWidget(buttonBox) end = False while not end: end = True if dialog.exec_(): account = Account() account.properties = {} for key, widget in props_widgets.iteritems(): try: v = widget.get_value() except ValueError as e: QMessageBox.critical( self, self.tr('Invalid value'), self. tr('Invalid value for field "%s":<br /><br />%s') % (key, e)) end = False break else: account.properties[key] = v if end: try: module.klass.register_account(account) except AccountRegisterError as e: QMessageBox.critical( self, self.tr('Error during register'), self.tr( 'Unable to register account %s:<br /><br />%s') % (website, e)) end = False else: for key, value in account.properties.iteritems(): if key in self.config_widgets: self.config_widgets[key][1].set_value(value)
def ask(self, question, default=None, masked=None, regexp=None, choices=None, tiny=None): """ Ask a question to user. @param question text displayed (str) @param default optional default value (str) @param masked if True, do not show typed text (bool) @param regexp text must match this regexp (str) @param choices choices to do (list) @param tiny ask for the (small) value of the choice (bool) @return entered text by user (str) """ if isinstance(question, Value): v = copy(question) if default is not None: v.default = to_unicode(default) if isinstance(default, str) else default if masked is not None: v.masked = masked if regexp is not None: v.regexp = regexp if choices is not None: v.choices = choices if tiny is not None: v.tiny = tiny else: if isinstance(default, bool): klass = ValueBool elif isinstance(default, float): klass = ValueFloat elif isinstance(default, (int,long)): klass = ValueInt else: klass = Value v = klass(label=question, default=default, masked=masked, regexp=regexp, choices=choices, tiny=tiny) question = v.label if v.id: question = u'[%s] %s' % (v.id, question) if isinstance(v, ValueBackendPassword): print(question.encode(self.encoding) + ':') question = v.label choices = OrderedDict() choices['c'] = 'Run an external tool during backend load' if not v.noprompt: choices['p'] = 'Prompt value when needed (do not store it)' choices['s'] = 'Store value in config' if v.is_command(v.default): d = 'c' elif v.default == '' and not v.noprompt: d = 'p' else: d = 's' r = self.ask('*** How do you want to store it?', choices=choices, tiny=True, default=d) if r == 'p': return '' if r == 'c': print('Enter the shell command that will print the required value on the standard output') if v.is_command(v.default): print(': %s' % v.default[1:-1]) else: d = None while True: cmd = self.ask('') try: subprocess.check_output(cmd, shell=True) except subprocess.CalledProcessError as e: print('%s' % e) else: return '`%s`' % cmd aliases = {} if isinstance(v, ValueBool): question = u'%s (%s/%s)' % (question, 'Y' if v.default else 'y', 'n' if v.default else 'N') elif v.choices: if v.tiny is None: v.tiny = True for key in v.choices.iterkeys(): if len(key) > 5 or ' ' in key: v.tiny = False break if v.tiny: question = u'%s (%s)' % (question, '/'.join((s.upper() if s == v.default else s) for s in v.choices.iterkeys())) for s in v.choices.iterkeys(): if s == v.default: aliases[s.upper()] = s for key, value in v.choices.iteritems(): print(' %s%s%s: %s' % (self.BOLD, key, self.NC, value)) else: for n, (key, value) in enumerate(v.choices.iteritems()): print(' %s%2d)%s %s' % (self.BOLD, n + 1, self.NC, value.encode(self.encoding))) aliases[str(n + 1)] = key question = u'%s (choose in list)' % question if v.masked: question = u'%s (hidden input)' % question if not isinstance(v, ValueBool) and not v.tiny and v.default not in (None, ''): question = u'%s [%s]' % (question, '*******' if v.masked else v.default) question += ': ' while True: if v.masked: if sys.platform == 'win32': line = getpass.getpass(str(question)) else: line = getpass.getpass(question.encode(self.encoding)) else: self.stdout.write(question.encode(self.encoding)) self.stdout.flush() line = self.stdin.readline() if len(line) == 0: raise EOFError() else: line = line.rstrip('\r\n') if not line and v.default is not None: line = v.default if isinstance(line, str): line = line.decode('utf-8') if line in aliases: line = aliases[line] try: v.set(line) except ValueError as e: print(u'Error: %s' % e, file=self.stderr) else: break v.noprompt = True return v.get()
class IndeedModule(Module, CapJob): NAME = 'indeed' DESCRIPTION = u'indeed website' MAINTAINER = u'Bezleputh' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.2' BROWSER = IndeedBrowser type_contrat_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ 'all': u'Tous les emplois', 'fulltime': u'Temps plein', 'parttime': u'Temps partiel', 'contract': u'Durée indéterminée', 'internship': u'Stage / Apprentissage', 'temporary': u'Durée déterminée', }.iteritems())]) limit_date_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ 'any': u'à tout moment', '15': u'depuis 15 jours', '7': u'depuis 7 jours', '3': u'depuis 3 jours', '1': u'depuis hier', 'last': u'depuis ma dernière visite', }.iteritems())]) radius_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ '0': u'uniquement à cet endroit', '5': u'dans un rayon de 5 kilomètres', '10': u'dans un rayon de 10 kilomètres', '15': u'dans un rayon de 15 kilomètres', '25': u'dans un rayon de 25 kilomètres', '50': u'dans un rayon de 50 kilomètres', '100': u'dans un rayon de 100 kilomètres', }.iteritems())]) CONFIG = BackendConfig(Value('metier', label=u'Job name', masked=False, default=''), Value('limit_date', label=u'Date limite', choices=limit_date_choices, default=''), Value('contrat', label=u'Contract', choices=type_contrat_choices, default=''), Value('place', label=u'Place', masked=False, default=''), Value('radius', label=u'Radius', choices=radius_choices, default='')) def search_job(self, pattern=None): return self.browser.search_job(metier=pattern) def advanced_search_job(self): return self.browser.search_job(metier=self.config['metier'].get(), limit_date=self.config['limit_date'].get(), contrat=self.config['contrat'].get(), place=self.config['place'].get(), radius=self.config['radius'].get()) def get_job_advert(self, _id, advert=None): return self.browser.get_job_advert(_id, advert) def fill_obj(self, advert, fields): return self.get_job_advert(advert.id, advert) OBJECTS = {BaseJobAdvert: fill_obj}
class AdeccoModule(Module, CapJob): NAME = 'adecco' DESCRIPTION = u'adecco website' MAINTAINER = u'Bezleputh' EMAIL = '*****@*****.**' VERSION = '1.1' BROWSER = AdeccoBrowser publicationDate_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ '000000': u'-- Indifférent --', '1': u'Moins de 48 heures', '2': u'Moins de 1 semaine', '4': u'Moins de 2 semaines', '3': u'Moins de 5 semaines', }.iteritems())]) type_contract_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ '000000': u'--Indifferent--', '1': u'CDD', '2': u'CDI', '3': u'Intérim', '4': u'Emploi formation', '5': u'Emploi saisonnier', '6': u'Stage', '7': u'Autre', }.iteritems())]) places_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ '100|REGION_0|DEPARTEMENT_0': u'--Indifferent--', '101|REGION_1': u'Alsace', '102|REGION_1|DEPARTEMENT_1': u'-- Rhin (Bas) (67)', '103|REGION_1|DEPARTEMENT_2': u'-- Rhin (Haut) (68)', '104|REGION_2': u'Aquitaine', '105|REGION_2|DEPARTEMENT_3': u'-- Dordogne (24)', '106|REGION_2|DEPARTEMENT_4': u'-- Gironde (33)', '107|REGION_2|DEPARTEMENT_5': u'-- Landes (40)', '108|REGION_2|DEPARTEMENT_6': u'-- Lot et Garonne (47)', '109|REGION_2|DEPARTEMENT_7': u'-- Pyrénées Atlantiques (64)', '110|REGION_3': u'Auvergne', '111|REGION_3|DEPARTEMENT_8': u'-- Allier (03)', '112|REGION_3|DEPARTEMENT_9': u'-- Cantal (15)', '113|REGION_3|DEPARTEMENT_10': u'-- Loire (Haute) (43)', '114|REGION_3|DEPARTEMENT_11': u'-- Puy de Dôme (63)', '115|REGION_5': u'Bourgogne', '116|REGION_5|DEPARTEMENT_15': u'-- Côte d\'Or (21)', '117|REGION_5|DEPARTEMENT_16': u'-- Nièvre (58)', '118|REGION_5|DEPARTEMENT_17': u'-- Saône et Loire (71)', '119|REGION_5|DEPARTEMENT_18': u'-- Yonne (89)', '120|REGION_6': u'Bretagne', '121|REGION_6|DEPARTEMENT_19': u'-- Côtes d\'Armor (22)', '122|REGION_6|DEPARTEMENT_20': u'-- Finistère (29)', '123|REGION_6|DEPARTEMENT_21': u'-- Ille et Vilaine (35)', '124|REGION_6|DEPARTEMENT_22': u'-- Morbihan (56)', '125|REGION_7': u'Centre', '126|REGION_7|DEPARTEMENT_23': u'-- Cher (18)', '127|REGION_7|DEPARTEMENT_24': u'-- Eure et Loir (28)', '128|REGION_7|DEPARTEMENT_25': u'-- Indre (36)', '129|REGION_7|DEPARTEMENT_26': u'-- Indre et Loire (37)', '130|REGION_7|DEPARTEMENT_27': u'-- Loir et Cher (41)', '131|REGION_7|DEPARTEMENT_28': u'-- Loiret (45)', '132|REGION_8': u'Champagne Ardenne', '133|REGION_8|DEPARTEMENT_29': u'-- Ardennes (08)', '134|REGION_8|DEPARTEMENT_30': u'-- Aube (10)', '135|REGION_8|DEPARTEMENT_31': u'-- Marne (51)', '136|REGION_8|DEPARTEMENT_32': u'-- Marne (Haute) (52)', '137|REGION_9': u'Corse', '138|REGION_9|DEPARTEMENT_33': u'-- Corse du Sud (2A)', '139|REGION_9|DEPARTEMENT_34': u'-- Haute Corse (2B)', '140|REGION_11': u'Franche Comté', '141|REGION_11|DEPARTEMENT_43': u'-- Belfort (Territoire de) (90)', '142|REGION_11|DEPARTEMENT_40': u'-- Doubs (25)', '143|REGION_11|DEPARTEMENT_41': u'-- Jura (39)', '144|REGION_11|DEPARTEMENT_42': u'-- Saône (Haute) (70)', '145|REGION_13': u'Ile de France', '146|REGION_13|DEPARTEMENT_49': u'-- Essonne (91)', '147|REGION_13|DEPARTEMENT_50': u'-- Hauts de Seine (92)', '148|REGION_13|DEPARTEMENT_46': u'-- Paris (Dept.) (75)', '149|REGION_13|DEPARTEMENT_51': u'-- Seine Saint Denis (93)', '150|REGION_13|DEPARTEMENT_47': u'-- Seine et Marne (77)', '151|REGION_13|DEPARTEMENT_53': u'-- Val d\'Oise (95)', '152|REGION_13|DEPARTEMENT_52': u'-- Val de Marne (94)', '153|REGION_13|DEPARTEMENT_48': u'-- Yvelines (78)', '154|REGION_14': u'Languedoc Roussillon', '155|REGION_14|DEPARTEMENT_54': u'-- Aude (11)', '156|REGION_14|DEPARTEMENT_55': u'-- Gard (30)', '157|REGION_14|DEPARTEMENT_56': u'-- Hérault (34)', '158|REGION_14|DEPARTEMENT_57': u'-- Lozère (48)', '159|REGION_14|DEPARTEMENT_58': u'-- Pyrénées Orientales (66)', '160|REGION_15': u'Limousin', '161|REGION_15|DEPARTEMENT_59': u'-- Corrèze (19)', '162|REGION_15|DEPARTEMENT_60': u'-- Creuse (23)', '163|REGION_15|DEPARTEMENT_61': u'-- Vienne (Haute) (87)', '164|REGION_16': u'Lorraine', '165|REGION_16|DEPARTEMENT_62': u'-- Meurthe et Moselle (54)', '166|REGION_16|DEPARTEMENT_63': u'-- Meuse (55)', '167|REGION_16|DEPARTEMENT_64': u'-- Moselle (57)', '168|REGION_16|DEPARTEMENT_65': u'-- Vosges (88)', '169|REGION_17': u'Midi Pyrénées', '170|REGION_17|DEPARTEMENT_66': u'-- Ariège (09)', '171|REGION_17|DEPARTEMENT_67': u'-- Aveyron (12)', '172|REGION_17|DEPARTEMENT_68': u'-- Garonne (Haute) (31)', '173|REGION_17|DEPARTEMENT_69': u'-- Gers (32)', '174|REGION_17|DEPARTEMENT_70': u'-- Lot (46)', '175|REGION_17|DEPARTEMENT_71': u'-- Pyrénées (Hautes) (65)', '176|REGION_17|DEPARTEMENT_72': u'-- Tarn (81)', '177|REGION_17|DEPARTEMENT_73': u'-- Tarn et Garonne (82)', '178|REGION_18': u'Nord Pas de Calais', '179|REGION_18|DEPARTEMENT_74': u'-- Nord (59)', '180|REGION_18|DEPARTEMENT_75': u'-- Pas de Calais (62)', '181|REGION_4': u'Normandie (Basse)', '182|REGION_4|DEPARTEMENT_12': u'-- Calvados (14)', '183|REGION_4|DEPARTEMENT_13': u'-- Manche (50)', '184|REGION_4|DEPARTEMENT_14': u'-- Orne (61)', '185|REGION_12': u'Normandie (Haute)', '186|REGION_12|DEPARTEMENT_44': u'-- Eure (27)', '187|REGION_12|DEPARTEMENT_47': u'-- Seine Maritime (76)', '188|REGION_19': u'Pays de la Loire', '189|REGION_19|DEPARTEMENT_76': u'-- Loire Atlantique (44)', '190|REGION_19|DEPARTEMENT_77': u'-- Maine et Loire (49)', '191|REGION_19|DEPARTEMENT_78': u'-- Mayenne (53)', '192|REGION_19|DEPARTEMENT_79': u'-- Sarthe (72)', '193|REGION_19|DEPARTEMENT_80': u'-- Vendée (85)', '194|REGION_20': u'Picardie', '195|REGION_20|DEPARTEMENT_81': u'-- Aisne (02)', '196|REGION_20|DEPARTEMENT_83': u'-- Oise (60)', '197|REGION_20|DEPARTEMENT_84': u'-- Somme (80)', '198|REGION_21': u'Poitou Charentes', '199|REGION_21|DEPARTEMENT_85': u'-- Charente (16)', '200|REGION_21|DEPARTEMENT_86': u'-- Charente Maritime (17)', '201|REGION_21|DEPARTEMENT_87': u'-- Sèvres (Deux) (79)', '202|REGION_21|DEPARTEMENT_88': u'-- Vienne (86)', '203|REGION_22': u'Provence Alpes Côte d\'Azur', '204|REGION_22|DEPARTEMENT_90': u'-- Alpes (Hautes) (05)', '205|REGION_22|DEPARTEMENT_91': u'-- Alpes Maritimes (06)', '206|REGION_22|DEPARTEMENT_89': u'-- Alpes de Haute Provence (04)', '207|REGION_22|DEPARTEMENT_92': u'-- Bouches du Rhône (13)', '208|REGION_22|DEPARTEMENT_93': u'-- Var (83)', '209|REGION_22|DEPARTEMENT_94': u'-- Vaucluse (84)', '210|REGION_23': u'Rhône Alpes', '211|REGION_23|DEPARTEMENT_95': u'-- Ain (01)', '212|REGION_23|DEPARTEMENT_96': u'-- Ardèche (07)', '213|REGION_23|DEPARTEMENT_97': u'-- Drôme (26)', '214|REGION_23|DEPARTEMENT_98': u'-- Isère (38)', '215|REGION_23|DEPARTEMENT_99': u'-- Loire (42)', '216|REGION_23|DEPARTEMENT_100': u'-- Rhône (69)', '217|REGION_23|DEPARTEMENT_101': u'-- Savoie (73)', '218|REGION_23|DEPARTEMENT_102': u'-- Savoie (Haute) (74)', '219|REGION_10': u'DOM TOM', '220|REGION_10|DEPARTEMENT_35': u'-- Guadeloupe (971)', '221|REGION_10|DEPARTEMENT_37': u'-- Guyane (973)', '222|REGION_10|DEPARTEMENT_38': u'-- La Réunion (974)', '223|REGION_10|DEPARTEMENT_36': u'-- Martinique (972)', '224|REGION_10|DEPARTEMENT_108': u'-- Mayotte (976)', '225|REGION_10|DEPARTEMENT_109': u'-- Nouvelle Calédonie (988)', '226|REGION_10|DEPARTEMENT_108': u'-- Polynésie (987)', '227|REGION_10|DEPARTEMENT_107': u'-- Saint Pierre et Miquelon (975)', '228|REGION_24': u'International', '229|REGION_24|DEPARTEMENT_104': u'-- Andorre', '230|REGION_24|DEPARTEMENT_105': u'-- Monaco', '231|REGION_24|DEPARTEMENT_106': u'-- Suisse', }.iteritems())]) activityDomain_choices = OrderedDict([(k, u'%s' % (v)) for k, v in sorted({ '100|DOMAIN_0': u'Tous domaines d\'activité', '101|DOMAIN_1': u'Accueil - Secrétariat - Fonctions Administratives', '102|DOMAIN_1|ACTIVITY_1': u'-- Accueil', '103|DOMAIN_1|ACTIVITY_2': u'-- Secrétariat - Assistanat', '104|DOMAIN_1|ACTIVITY_3': u'-- Autres Fonctions Administratives', '105|DOMAIN_2': u'Achats - Juridique - Qualité - RH - Direction', '106|DOMAIN_2|ACTIVITY_4': u'-- Achats ', '107|DOMAIN_2|ACTIVITY_5': u'-- Juridique', '108|DOMAIN_2|ACTIVITY_6': u'-- Qualité', '109|DOMAIN_2|ACTIVITY_7': u'Ressources Humaines - Formation', '110|DOMAIN_2|ACTIVITY_8': u'-- Direction Générale', '111|DOMAIN_3': u'Agriculture - Viticulture - Pêche - Espaces Verts', '112|DOMAIN_3|ACTIVITY_9': u'-- Agriculture - Viticulture - Pêche ', '113|DOMAIN_3|ACTIVITY_10': u'-- Espaces Verts - Exploitation Forestière', '114|DOMAIN_4': u'Automobile', '115|DOMAIN_5': u'Banque - Finance - Gestion Comptabilité - Assurance', '116|DOMAIN_5|ACTIVITY_11': u'-- Banque - Finance ', '117|DOMAIN_5|ACTIVITY_12': u'-- Gestion - Comptabilité', '118|DOMAIN_5|ACTIVITY_13': u'-- Assurance', '119|DOMAIN_6': u'Bâtiment - Travaux Publics - Architecture - Immobilier', '120|DOMAIN_6|ACTIVITY_14': u'-- Bâtiment - Travaux Publics', '121|DOMAIN_6|ACTIVITY_15': u'-- Architecture - Immobilier ', '122|DOMAIN_13': u'Bureaux d\'Etudes - Méthodes', '123|DOMAIN_8': u'Commerce - Vente - Grande Distribution', '124|DOMAIN_8|ACTIVITY_20': u'-- Commerce - Vente', '125|DOMAIN_8|ACTIVITY_21': u'-- Grande et Moyenne Distribution', '126|DOMAIN_9': u'Environnement - Nettoyage - Sécurité', '127|DOMAIN_9|ACTIVITY_22': u'-- Environnement - HSE - Développement durable', '128|DOMAIN_9|ACTIVITY_23': u'-- Nettoyage - Assainissement - Pressing', '129|DOMAIN_9|ACTIVITY_24': u'-- Sécurité - Premiers secours', '130|DOMAIN_10': u'Hôtellerie - Restauration - Métiers de Bouche', '131|DOMAIN_10|ACTIVITY_25': u'-- Hôtellerie', '132|DOMAIN_10|ACTIVITY_27': u'-- Métiers de bouche', '133|DOMAIN_10|ACTIVITY_26': u'-- Restauration', '134|DOMAIN_11': u'Industrie', '135|DOMAIN_11|ACTIVITY_32': u'-- Aéronautique - Navale', '136|DOMAIN_11|ACTIVITY_33': u'-- Agroalimentaire', '137|DOMAIN_11|ACTIVITY_58': u'-- Chimie - Pétrochimie', '138|DOMAIN_11|ACTIVITY_28': u'-- Electricité - Electronique - Automatisme', '139|DOMAIN_11|ACTIVITY_29': u'-- Maintenance - Entretien - SAV ', '140|DOMAIN_11|ACTIVITY_30': u'-- Mécanique Générale', '141|DOMAIN_11|ACTIVITY_31': u'-- Production - Fabrication ', '142|DOMAIN_11|ACTIVITY_36': u'-- Sidérurgie - Métallurgie - Tuyauterie - Soudure', '143|DOMAIN_11|ACTIVITY_34': u'-- Nucléaire - Production d\'énergie', '144|DOMAIN_11|ACTIVITY_35': u'-- Plasturgie - Bois - Papier - Verre - Cuir - Textile', '145|DOMAIN_12': u'Informatique - Technologie de l\'Information', '146|DOMAIN_12|ACTIVITY_37': u'-- Direction informatique encadrement', '147|DOMAIN_12|ACTIVITY_38': u'-- Etude et développement', '148|DOMAIN_12|ACTIVITY_39': u'-- Exploitation, maintenance et support ', '149|DOMAIN_12|ACTIVITY_40': u'-- Systèmes et réseaux informatique et télécom', '150|DOMAIN_14': u'Logistique - Manutention - Transport', '151|DOMAIN_14|ACTIVITY_42': u'-- Conduite de véhicule', '152|DOMAIN_14|ACTIVITY_43': u'-- Exploitation de logistique - supply chain', '153|DOMAIN_14|ACTIVITY_44': u'-- Manutention', '154|DOMAIN_14|ACTIVITY_45': u'-- Transport', '155|DOMAIN_15': u'Marketing - Communication - Imprimerie - Edition', '156|DOMAIN_15|ACTIVITY_47': u'-- Imprimerie - Edition - Arts Graphiques', '157|DOMAIN_15|ACTIVITY_46': u'-- Marketing - Communication - Medias', '158|DOMAIN_16': u'Médical - Paramédical - Esthétique', '159|DOMAIN_16|ACTIVITY_59': u'-- Commerce Appareillage', '160|DOMAIN_16|ACTIVITY_50': u'-- Directions, Cadres et Enseignement', '161|DOMAIN_16|ACTIVITY_49': u'-- Rééducation, Radiologie, Appareillage, LAM', '162|DOMAIN_16|ACTIVITY_51': u'-- Secrétariat, Dentaire, Social, Esthétique et Autres', '163|DOMAIN_16|ACTIVITY_48': u'-- Soignants - Auxiliaires', '164|DOMAIN_7': u'Pharmacie (Industrie, Officine) - Recherche clinique', '165|DOMAIN_7|ACTIVITY_16': u'-- Industrie Pharmaceutique / Cosmétologique - Biotech', '166|DOMAIN_7|ACTIVITY_17': u'-- Recherche Clinique', '167|DOMAIN_7|ACTIVITY_18': u'-- Pharmacie Officine / Hospit / Para-pharmacie', '168|DOMAIN_7|ACTIVITY_19': u'-- Vente, information et promotion du médicament', '169|DOMAIN_17': u'Télémarketing - Téléservices', '170|DOMAIN_17|ACTIVITY_52': u'-- Téléconseil - Télévente - Autres', '171|DOMAIN_17|ACTIVITY_53': u'-- Direction, Encadrement', '172|DOMAIN_18': u'Tourisme - Loisirs - Spectacle - Audiovisuel', '173|DOMAIN_18|ACTIVITY_54': u'-- Tourisme - Loisirs', '174|DOMAIN_18|ACTIVITY_55': u'-- Spectacle - Audiovisuel', }.iteritems())]) CONFIG = BackendConfig(Value('publication_date', label=u'Publication Date', choices=publicationDate_choices), Value('place', label=u'Place', choices=places_choices), Value('contract', labe=u'Contract type', choices=type_contract_choices), Value('activity_domain', label=u'Activity Domain', choices=activityDomain_choices), ) def search_job(self, pattern=None): with self.browser: for advert in self.browser.search_job(pattern): yield advert def decode_choice(self, place): splitted_choice = place.split('|') part1 = splitted_choice[1].split('_')[1] if len(splitted_choice) == 3: part2 = splitted_choice[2].split('_')[1] return part1, part2 else: return part1, 0 def advanced_search_job(self): region, departement = self.decode_choice(self.config['place'].get()) domain, category = self.decode_choice(self.config['activity_domain'].get()) for advert in self.browser.advanced_search_job(publication_date=int(self.config['publication_date'].get()), contract_type=int(self.config['contract'].get()), conty=departement, region=region, job_category=category, activity_domain=domain ): yield advert def get_job_advert(self, _id, advert=None): with self.browser: return self.browser.get_job_advert(_id, advert) def fill_obj(self, advert, fields): self.get_job_advert(advert.id, advert) OBJECTS = {AdeccoJobAdvert: fill_obj}
def __init__(self, path): self.path = path self.values = OrderedDict() self.config = RawConfigParser()
def get_list(self): accounts = OrderedDict() for tr in self.document.getiterator('tr'): first_td = tr.getchildren()[0] if (first_td.attrib.get('class', '') == 'i g' or first_td.attrib.get('class', '') == 'p g') \ and first_td.find('a') is not None: a = first_td.find('a') link = a.get('href', '') if link.startswith('POR_SyntheseLst'): continue url = urlparse(link) p = parse_qs(url.query) if not 'rib' in p: continue for i in (2, 1): balance = FrenchTransaction.clean_amount( tr.getchildren()[i].text) currency = Account.get_currency(tr.getchildren()[i].text) if len(balance) > 0: break balance = Decimal(balance) id = p['rib'][0] if id in accounts: account = accounts[id] if not account.coming: account.coming = Decimal('0.0') account.coming += balance account._card_links.append(link) continue account = Account() account.id = id account.label = unicode( a.text).strip().lstrip(' 0123456789').title() account._link_id = link account._card_links = [] # Find accounting amount page = self.browser.get_document(self.browser.openurl(link)) coming = self.find_amount(page, u"Opérations à venir") accounting = self.find_amount(page, u"Solde comptable") if accounting is not None and accounting + ( coming or Decimal('0')) != balance: self.logger.warning('%s + %s != %s' % (accounting, coming, balance)) if accounting is not None: balance = accounting if coming is not None: account.coming = coming account.balance = balance account.currency = currency accounts[account.id] = account return accounts.itervalues()