diff --git a/modules/750g/backend.py b/modules/750g/backend.py index 7ead3b8f20ea58a223ed06245f3bbc503eefc3be..70afea3e60807561a6fc3bd0847a03a5b42ae101 100644 --- a/modules/750g/backend.py +++ b/modules/750g/backend.py @@ -46,7 +46,7 @@ def iter_recipes(self, pattern): return self.browser.iter_recipes(pattern.encode('utf-8')) def fill_recipe(self, recipe, fields): - if 'thumbnail_url' in fields or 'instructions' in fields: + if 'nb_person' in fields or 'instructions' in fields: rec = self.get_recipe(recipe.id) recipe.picture_url = rec.picture_url recipe.instructions = rec.instructions diff --git a/modules/cuisineaz/__init__.py b/modules/cuisineaz/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f8b90bc805cf4c5b6015bb0a3e207344abf8041b --- /dev/null +++ b/modules/cuisineaz/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Julien Veyssier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + +from .backend import CuisineazBackend + +__all__ = ['CuisineazBackend'] diff --git a/modules/cuisineaz/backend.py b/modules/cuisineaz/backend.py new file mode 100644 index 0000000000000000000000000000000000000000..a0c067e549946453913314683e5b735908338e0c --- /dev/null +++ b/modules/cuisineaz/backend.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Julien Veyssier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + +from weboob.capabilities.recipe import ICapRecipe,Recipe +from weboob.tools.backend import BaseBackend + +from .browser import CuisineazBrowser + +from urllib import quote_plus + +__all__ = ['CuisineazBackend'] + + +class CuisineazBackend(BaseBackend, ICapRecipe): + NAME = 'cuisineaz' + MAINTAINER = u'Julien Veyssier' + EMAIL = 'julien.veyssier@aiur.fr' + VERSION = '0.f' + DESCRIPTION = 'Cuisine AZ recipe website' + LICENSE = 'AGPLv3+' + BROWSER = CuisineazBrowser + + def create_default_browser(self): + return self.create_browser() + + def get_recipe(self, id): + return self.browser.get_recipe(id) + + def iter_recipes(self, pattern): + return self.browser.iter_recipes(pattern.encode('utf-8')) + + def fill_recipe(self, recipe, fields): + if 'nb_person' in fields or 'instructions' in fields: + rec = self.get_recipe(recipe.id) + recipe.picture_url = rec.picture_url + recipe.instructions = rec.instructions + recipe.ingredients = rec.ingredients + recipe.comments = rec.comments + recipe.nb_person = rec.nb_person + recipe.cooking_time = rec.cooking_time + recipe.preparation_time = rec.preparation_time + + return recipe + + OBJECTS = { + Recipe:fill_recipe, + } diff --git a/modules/cuisineaz/browser.py b/modules/cuisineaz/browser.py new file mode 100644 index 0000000000000000000000000000000000000000..35aa27943f64c0b4b0080e79ad61cedd8514b83c --- /dev/null +++ b/modules/cuisineaz/browser.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Julien Veyssier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + + +from weboob.tools.browser import BaseBrowser + +from .pages import RecipePage, ResultsPage + + +__all__ = ['CuisineazBrowser'] + +class CuisineazBrowser(BaseBrowser): + DOMAIN = 'www.cuisineaz.com' + PROTOCOL = 'http' + ENCODING = 'utf-8' + USER_AGENT = BaseBrowser.USER_AGENTS['wget'] + PAGES = { + 'http://www.cuisineaz.com/recettes/recherche_v2.aspx\?recherche=.*': ResultsPage, + 'http://www.cuisineaz.com/recettes/.*[0-9]*.aspx': RecipePage, + } + + def iter_recipes(self, pattern): + self.location('http://www.cuisineaz.com/recettes/recherche_v2.aspx?recherche=%s' % (pattern.replace(' ','-'))) + assert self.is_on_page(ResultsPage) + return self.page.iter_recipes() + + def get_recipe(self, id): + self.location('http://www.cuisineaz.com/recettes/%s.aspx' % id) + assert self.is_on_page(RecipePage) + return self.page.get_recipe(id) diff --git a/modules/cuisineaz/pages.py b/modules/cuisineaz/pages.py new file mode 100644 index 0000000000000000000000000000000000000000..ca115fed8e53c4e27bdfaf74cf77e3eea7e5304e --- /dev/null +++ b/modules/cuisineaz/pages.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Julien Veyssier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + + +from weboob.capabilities.recipe import Recipe +from weboob.capabilities.base import NotAvailable, NotLoaded +from weboob.tools.browser import BasePage + + +__all__ = ['RecipePage', 'ResultsPage'] + + +class ResultsPage(BasePage): + """ Page which contains results as a list of recipies + """ + def iter_recipes(self): + for div in self.parser.select(self.document.getroot(),'div.rechRecette'): + thumbnail_url = NotAvailable + short_description = NotAvailable + imgs = self.parser.select(div,'img.photo') + if len(imgs) > 0: + thumbnail_url = unicode(imgs[0].attrib.get('src','')) + + link = self.parser.select(div,'a.rechRecetTitle',1) + title = unicode(link.text) + id = unicode(link.attrib.get('href','').split('/')[-1].replace('.aspx','')) + + + short_description = u'' + ldivprix = self.parser.select(div,'div.prix') + if len(ldivprix) > 0: + divprix = ldivprix[0] + nbprixneg = 0 + spanprix = self.parser.select(divprix,'span') + if len(spanprix) > 0: + nbprixneg = unicode(spanprix[0].text).count(u'€') + nbprixtot = unicode(divprix.text_content()).count(u'€') + short_description += u'Cost: %s/%s ; '%(nbprixtot - nbprixneg, nbprixtot) + + short_description += unicode(' '.join(self.parser.select(div,'div.rechResume',1).text_content().split()).strip()).replace(u'€','') + short_description += u' ' + short_description += unicode(' '.join(self.parser.select(div,'div.rechIngredients',1).text_content().split()).strip()) + + recipe = Recipe(id,title) + recipe.thumbnail_url = thumbnail_url + recipe.short_description= short_description + recipe.instructions = NotLoaded + recipe.ingredients = NotLoaded + recipe.nb_person = NotLoaded + recipe.cooking_time = NotLoaded + recipe.preparation_time = NotLoaded + yield recipe + + +class RecipePage(BasePage): + """ Page which contains a recipe + """ + def get_recipe(self, id): + title = NotAvailable + preparation_time = NotAvailable + cooking_time = NotAvailable + nb_person = NotAvailable + ingredients = NotAvailable + picture_url = NotAvailable + instructions = NotAvailable + comments = [] + + title = unicode(self.parser.select(self.document.getroot(),'head > title',1).text.split(' - ')[1]) + main = self.parser.select(self.document.getroot(),'div.recette_description',1) + + rec_infos = self.parser.select(self.document.getroot(),'div.recette_infos div.infos_column strong') + for info_title in rec_infos: + if u'Temps de préparation' in unicode(info_title.text): + if info_title.tail.strip() != '': + preparation_time = int(info_title.tail.split()[0]) + if 'h' in info_title.tail: + preparation_time = 60*preparation_time + if 'Temps de cuisson' in info_title.text: + if info_title.tail.strip() != '': + cooking_time = int(info_title.tail.split()[0]) + if 'h' in info_title.tail: + cooking_time = 60*cooking_time + if 'Nombre de personnes' in info_title.text: + if info_title.tail.strip() != '': + nb_person = int(info_title.tail) + + ingredients = [] + p_ing = self.parser.select(main,'div.data.top.left > div.content p') + for ing in p_ing: + ingtxt = unicode(ing.text_content().strip()) + if ingtxt != '': + ingredients.append(ingtxt) + + lines_instr = self.parser.select(main,'div.data.top.right div.content li') + if len(lines_instr) > 0: + instructions = u'' + for line in lines_instr: + inst = ' '.join(line.text_content().strip().split()) + instructions += '%s\n'% inst + instructions = instructions.strip('\n') + + imgillu = self.parser.select(self.document.getroot(),'div.resume_recette_illustree img.photo') + if len(imgillu) > 0: + picture_url = unicode(imgillu[0].attrib.get('src','')) + + for divcom in self.parser.select(self.document.getroot(),'div.comment-outer'): + comtxt = unicode(' '.join(divcom.text_content().strip().split())) + if u'| Répondre' in comtxt: + comtxt = comtxt.strip('0123456789').replace(u' | Répondre','') + comments.append(comtxt) + + recipe = Recipe(id,title) + recipe.preparation_time = preparation_time + recipe.cooking_time = cooking_time + recipe.nb_person = nb_person + recipe.ingredients = ingredients + recipe.instructions = instructions + recipe.picture_url = picture_url + recipe.comments = comments + recipe.thumbnail_url = NotLoaded + return recipe diff --git a/modules/cuisineaz/test.py b/modules/cuisineaz/test.py new file mode 100644 index 0000000000000000000000000000000000000000..ff97427c4094586863689bbbf07d6e0ef16cf02b --- /dev/null +++ b/modules/cuisineaz/test.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Julien Veyssier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + +from weboob.tools.test import BackendTest + +class CuisineazTest(BackendTest): + BACKEND = 'cuisineaz' + + def test_recipe(self): + recipes = self.backend.iter_recipes('fondue') + for recipe in recipes: + full_recipe = self.backend.get_recipe(recipe.id) + assert full_recipe.instructions + assert full_recipe.ingredients + assert full_recipe.title + assert full_recipe.preparation_time + diff --git a/modules/marmiton/backend.py b/modules/marmiton/backend.py index 5cc0dcbd5c84cc4798523b6707b79db71deed2e7..965dd698212e0f7aadc63fccbef880665ea32508 100644 --- a/modules/marmiton/backend.py +++ b/modules/marmiton/backend.py @@ -46,7 +46,7 @@ def iter_recipes(self, pattern): return self.browser.iter_recipes(quote_plus(pattern.encode('utf-8'))) def fill_recipe(self, recipe, fields): - if 'thumbnail_url' in fields or 'instructions' in fields: + if 'nb_person' in fields or 'instructions' in fields: rec = self.get_recipe(recipe.id) recipe.picture_url = rec.picture_url recipe.instructions = rec.instructions