diff --git a/README.md b/README.md index 5c3f7ead3..1c1d66330 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A simple web scraping tool for recipe sites I use in a project of mine that makes sense to live as a separate package. - pip install git+git://github.com/RyanNoelk/recipe-scraper.git@1.0.3 + pip install git+git://github.com/RyanNoelk/recipe-scraper.git@1.0.5 then: @@ -34,16 +34,6 @@ If you are programmer PRs with fixes are warmly welcomed and acknowledged with a ### Scrapers available for: - [http://allrecipes.com/](http://allrecipes.com/) -- [http://bonappetit.com/](http://bonappetit.com/) -- [http://cookstr.com/](http://cookstr.com/) -- [http://epicurious.com/](http://epicurious.com/) -- [http://finedininglovers.com/](https://www.finedininglovers.com/) -- [http://foodrepublic.com/](http://foodrepublic.com) -- [http://jamieoliver.com/](http://www.jamieoliver.com/) -- [http://mybakingaddiction.com/](http://mybakingaddiction.com/) -- [http://simplyrecipes.com/](http://www.simplyrecipes.com) -- [http://steamykitchen.com/](http://steamykitchen.com/) -- [http://tastykitchen.com/](http://tastykitchen.com/) -- [http://thevintagemixer.com/](http://www.thevintagemixer.com/) -- [http://twopeasandtheirpod.com/](http://twopeasandtheirpod.com/) -- [http://whatsgabycooking.com/](http://whatsgabycooking.com/) +- [http://budgetbytes.com/](http://budgetbytes.com/) +- [http://pamperedchef.com/](http://pamperedchef.com/) +- [http://tasteofhome.com/](http://tasteofhome.com/) diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index ef856b9d8..11b6c6541 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -1,10 +1,12 @@ #!/usr/bin/env python # encoding: utf-8 import re +import datetime from .allrecipes import AllRecipes from .bonappetit import BonAppetit from .budgetbytes import BudgetBytes +from .budgetbytesv2 import BudgetBytesv2 from .cookstr import Cookstr from .epicurious import Epicurious from .finedininglovers import FineDiningLovers @@ -23,6 +25,7 @@ AllRecipes.host(): AllRecipes, # BonAppetit.host(): BonAppetit, BudgetBytes.host(): BudgetBytes, + BudgetBytesv2.host(): BudgetBytesv2, # Cookstr.host(): Cookstr, # Epicurious.host(): Epicurious, # FineDiningLovers.host(): FineDiningLovers, @@ -55,9 +58,21 @@ def url_path_to_dict(path): return url_dict +def get_version(url_dict): + if url_dict['host'] == 'budgetbytes.com': + path = url_dict.get('path').split('/') + current_time = datetime.datetime.strptime(path[1] + '-' + path[2], '%Y-%m') + compare_time = datetime.datetime.strptime('2017-04', '%Y-%m') + if current_time > compare_time: + return url_dict['host'] + '-v2' + return url_dict['host'] + + def scrap_me(url_path): url_path = url_path.replace('://www.', '://') - return SCRAPERS[url_path_to_dict(url_path)['host']](url_path) + url_dict = url_path_to_dict(url_path) + url_dict['host'] = get_version(url_dict) + return SCRAPERS[url_dict['host']](url_path) __all__ = ['scrap_me'] diff --git a/recipe_scrapers/bonappetit.py b/recipe_scrapers/bonappetit.py deleted file mode 100644 index ff872860d..000000000 --- a/recipe_scrapers/bonappetit.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class BonAppetit(AbstractScraper): - - @classmethod - def host(self): - return 'bonappetit.com' - - def title(self): - return self.soup.find('h1', {'itemprop': 'name'}).get_text() - - def total_time(self): - return get_minutes(self.soup.find('span', {'itemprop': 'totalTime'})) - - def ingredients(self): - ingredients_html = self.soup.findAll('span', {'itemprop': "ingredients"}) - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html - ] - - def instructions(self): - instructions_html = self.soup.find('div', {'class': 'prep-steps'}).findAll('li') - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/recipe_scrapers/budgetbytes.py b/recipe_scrapers/budgetbytes.py index 3afb39948..d862c132e 100644 --- a/recipe_scrapers/budgetbytes.py +++ b/recipe_scrapers/budgetbytes.py @@ -57,7 +57,7 @@ def instructions(self): ] def description(self): - li = self.soup.find('div', {'class': 'entry-content'}).findAll('p') + li = self.soup.find('article', {'class': 'post'}).findAll('p') return li[0].get_text() def image(self): diff --git a/recipe_scrapers/budgetbytesv2.py b/recipe_scrapers/budgetbytesv2.py new file mode 100644 index 000000000..1cc6ee406 --- /dev/null +++ b/recipe_scrapers/budgetbytesv2.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from fractions import Fraction +from ._abstract import AbstractScraper +from ._utils import normalize_string + + +class BudgetBytesv2(AbstractScraper): + + @classmethod + def host(self): + return 'budgetbytes.com-v2' + + def title(self): + return self.soup.find('h1').get_text() + + def total_time(self): + return { + 'prep-time': self.soup.find( + 'span', + {'class': 'wprm-recipe-prep_time-minutes'} + ).get_text(), + 'cook-time': self.soup.find( + 'span', + {'class': 'wprm-recipe-cook_time-minutes'} + ).get_text() + } + + def servings(self): + return self.soup.find('span', {'itemprop': 'recipeYield'}).get_text().split(' ', 1)[0] + + def ingredients(self): + ingredients_html = self.soup.findAll('li', {'class': 'wprm-recipe-ingredient'}) + ingredients = [] + + for ingredient in ingredients_html: + try: + ingredient_dict = { + 'quantity': round(float(sum(Fraction(s) for s in ingredient.find( + 'span', + {'class': 'wprm-recipe-ingredient-amount'} + ).get_text().split())), 3), + 'measurement': ingredient.find( + 'span', + {'class': 'wprm-recipe-ingredient-unit'} + ).get_text(), + 'title': ingredient.find( + 'span', + {'class': 'wprm-recipe-ingredient-name'} + ).get_text() + } + except AttributeError: + ingredient_dict = { + 'title': ingredient.find( + 'span', + {'class': 'wprm-recipe-ingredient-name'} + ).get_text() + } + except: + ingredient_dict = { + 'title': ingredient + } + + ingredients.append(ingredient_dict) + + return ingredients + + def instructions(self): + instructions_html = self.soup.findAll('li', {'class': 'wprm-recipe-instruction'}) + + return [ + normalize_string(instruction.get_text()) + for instruction in instructions_html + ] + + def description(self): + li = self.soup.find('article', {'class': 'post'}).findAll('p') + return li[0].get_text() + + def image(self): + return self.soup.find('img', {'class': 'alignnone'})["src"] diff --git a/recipe_scrapers/cookstr.py b/recipe_scrapers/cookstr.py deleted file mode 100644 index 27f2c8f6a..000000000 --- a/recipe_scrapers/cookstr.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class Cookstr(AbstractScraper): - - @classmethod - def host(self): - return 'cookstr.com' - - def title(self): - return normalize_string(self.soup.find('h1', {'id': 'recipe_title'}).get_text()) - - def total_time(self): - recipe_info = self.soup.find('ul', {'id': 'recipe-info-attrs'}) - return sum([get_minutes(li) for li in recipe_info.findAll('li')]) - - def ingredients(self): - ingredients_html = self.soup.find('span', {'class': "recipe_structure_ingredients"}) - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html.findAll('li') - ] - - def instructions(self): - - instructions_html = self.soup.find('div', {'class': 'recipe_structure_directions'}) - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html.findAll('p') - ]) diff --git a/recipe_scrapers/epicurious.py b/recipe_scrapers/epicurious.py deleted file mode 100644 index 0b910ca33..000000000 --- a/recipe_scrapers/epicurious.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class Epicurious(AbstractScraper): - - @classmethod - def host(self): - return 'epicurious.com' - - def title(self): - return self.soup.find('h1', {'itemprop': 'name'}).get_text() - - def total_time(self): - return get_minutes(self.soup.findAll('p', {'class': 'summary_data'})[-1]) - - def ingredients(self): - ingredients_html = self.soup.findAll('li', {'itemprop': "ingredients"}) - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html - ] - - def instructions(self): - instructions_html = self.soup.find('div', {'id': 'preparation'}).find_all('p') - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/recipe_scrapers/finedininglovers.py b/recipe_scrapers/finedininglovers.py deleted file mode 100644 index 9d3a187dd..000000000 --- a/recipe_scrapers/finedininglovers.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class FineDiningLovers(AbstractScraper): - - @classmethod - def host(self): - return 'finedininglovers.com' - - def title(self): - return self.soup.find('h3', {'itemprop': 'name'}).get_text() - - def total_time(self): - return get_minutes(self.soup.find('time', {'itemprop': 'prepTime'})) - - def ingredients(self): - ingredients_html = self.soup.findAll('li', {'itemprop': "ingredients"}) - - return [ - normalize_string(ingredient.find('a').get_text()) - for ingredient in ingredients_html - ] - - def instructions(self): - instructions_html = self.soup.findAll('div', {'itemprop': 'recipeInstructions'}) - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/recipe_scrapers/foodrepublic.py b/recipe_scrapers/foodrepublic.py deleted file mode 100644 index c84db3ff4..000000000 --- a/recipe_scrapers/foodrepublic.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class FoodRepublic(AbstractScraper): - - @classmethod - def host(self): - return 'foodrepublic.com' - - def title(self): - return self.soup.find('h3', {'class': 'recipe-title'}).get_text() - - def total_time(self): - return get_minutes(self.soup.find('li', {'class': 'prep-time'})) +\ - get_minutes(self.soup.find('li', {'class': 'cook-time'})) - - def ingredients(self): - ingredients_html = self.soup.findAll('li', {'itemprop': "recipeIngredient"}) - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html - ] - - def instructions(self): - instructions_html = self.soup.find('div', {'class': 'directions'}).findAll('li') - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/recipe_scrapers/jamieoliver.py b/recipe_scrapers/jamieoliver.py deleted file mode 100644 index 8fbc8dfe6..000000000 --- a/recipe_scrapers/jamieoliver.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class JamieOliver(AbstractScraper): - - @classmethod - def host(self): - return 'jamieoliver.com' - - def title(self): - return self.soup.find('h1').get_text() - - def total_time(self): - return get_minutes(self.soup.find('div', {'class': 'time'})) - - def ingredients(self): - ul = self.soup.find('ul', {'class', 'ingred-list'}) - ingredients_html = ul.findAll('li') - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html - ] - - def instructions(self): - instructions_html = self.soup.find('div', {'class': 'instructions-wrapper'}) - return normalize_string(instructions_html.get_text()) diff --git a/recipe_scrapers/mybakingaddiction.py b/recipe_scrapers/mybakingaddiction.py deleted file mode 100644 index cfb27585f..000000000 --- a/recipe_scrapers/mybakingaddiction.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class MyBakingAddiction(AbstractScraper): - - @classmethod - def host(self): - return 'mybakingaddiction.com' - - def title(self): - return self.soup.find('h1').get_text() - - def total_time(self): - return get_minutes(self.soup.find('meta', {'itemprop': 'prepTime'})) +\ - get_minutes(self.soup.find('meta', {'itemprop': 'cookTime'})) - - def ingredients(self): - ingredients_html = self.soup.findAll('li', {'itemprop': "ingredients"}) - - if not len(ingredients_html): - ingredients_html = self.soup.find( - 'div', {'class': 'ingredients'}).get_text().split('\n') - - return [ - normalize_string(ingredient.get_text()) if type(ingredient) != str else ingredient - for ingredient in ingredients_html - if ingredient != '' - ] - - def instructions(self): - instructions_html = self.soup.find('span', {'itemprop': 'recipeInstructions'}).findAll(['li', 'p']) - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/recipe_scrapers/pamperedchef.py b/recipe_scrapers/pamperedchef.py new file mode 100644 index 000000000..15ae13a64 --- /dev/null +++ b/recipe_scrapers/pamperedchef.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import unicodedata +from ._abstract import AbstractScraper +from ._utils import get_minutes, normalize_string + + +class BudgetBytes(AbstractScraper): + + @classmethod + def host(self): + return 'pamperedchef.com' + + def title(self): + return self.soup.find('h1').get_text() + + def total_time(self): + return { + 'prep-time': get_minutes(self.soup.find('time', {'itemprop': 'prepTime'})), + 'cook-time': get_minutes(self.soup.find('time', {'itemprop': 'cookTime'})) + } + + def servings(self): + return self.soup.find('span', {'itemprop': 'recipeYield'}).get_text() + + def ingredients(self): + ingredients_html = self.soup.findAll('li', {'class': 'ingredient'}) + ingredients = [] + + for ingredient in ingredients_html: + ingredient = normalize_string(ingredient.get_text()) + ingredient = ingredient.split(' $', 1)[0] + + try: + array = ingredient.split(' ', 2) + ingredient_dict = { + 'quantity': round(unicodedata.numeric(array[0]), 3), + 'measurement': array[1], + 'title': array[2] + } + except: + ingredient_dict = { + 'title': ingredient + } + + ingredients.append(ingredient_dict) + + return ingredients + + def instructions(self): + instructions_html = self.soup.findAll('li', {'class': 'instruction'}) + + return [ + normalize_string(instruction.get_text()) + for instruction in instructions_html + ] + + def description(self): + li = self.soup.find('div', {'id': 'rpDirections'}).findAll('p') + return li[0].get_text() + + def image(self): + return self.soup.find('img', {'id': 'bigpic'})["src"] diff --git a/recipe_scrapers/simplyrecipes.py b/recipe_scrapers/simplyrecipes.py deleted file mode 100644 index 4bd45a303..000000000 --- a/recipe_scrapers/simplyrecipes.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class SimplyRecipes(AbstractScraper): - - @classmethod - def host(self): - return 'simplyrecipes.com' - - def title(self): - return self.soup.find('h1').get_text() - - def total_time(self): - return get_minutes(self.soup.find('span', {'class': 'preptime'})) +\ - get_minutes(self.soup.find('span', {'class': 'cooktime'})) - - def ingredients(self): - ingredients_html = self.soup.findAll('li', {'class': "ingredient"}) - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html - ] - - def instructions(self): - instructions_html = self.soup.find('div', {'itemprop': 'recipeInstructions'}).findAll('p') - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/recipe_scrapers/steamykitchen.py b/recipe_scrapers/steamykitchen.py deleted file mode 100644 index c37a3472a..000000000 --- a/recipe_scrapers/steamykitchen.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class SteamyKitchen(AbstractScraper): - - @classmethod - def host(self): - return 'steamykitchen.com' - - def title(self): - return self.soup.find('span', {'itemprop': 'name'}).get_text() - - def total_time(self): - return get_minutes(self.soup.find('meta', {'itemprop': 'prepTime'})) +\ - get_minutes(self.soup.find('meta', {'itemprop': 'cookTime'})) - - def ingredients(self): - ingredients_html = self.soup.findAll('span', {'itemprop': "ingredients"}) - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html - if len(normalize_string(ingredient.get_text())) > 0 - ] - - def instructions(self): - instructions_html = self.soup.findAll('span', {'itemprop': 'recipeInstructions'}) - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/recipe_scrapers/tasteofhome.py b/recipe_scrapers/tasteofhome.py new file mode 100644 index 000000000..8b98c6355 --- /dev/null +++ b/recipe_scrapers/tasteofhome.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from fractions import Fraction +from ._abstract import AbstractScraper +from ._utils import get_minutes, normalize_string + + +class AllRecipes(AbstractScraper): + + @classmethod + def host(self): + return 'tasteofhome.com' + + def title(self): + return self.soup.find('h1').get_text() + + def total_time(self): + return { + 'prep-time': get_minutes(self.soup.find('time', {'itemprop': 'prepTime'})), + 'cook-time': get_minutes(self.soup.find('time', {'itemprop': 'totalTime'})) + } + + def servings(self): + return self.soup.find('span', {'ng-bind': 'adjustedServings'}).get_text() + + def ingredients(self): + + ingredients_html = self.soup.findAll('span', {'class': "recipe-ingred_txt added"}) + ingredients = [] + + for ingredient in ingredients_html: + ingredient = normalize_string(ingredient.get_text()) + + try: + array = ingredient.split(' ', 2) + ingredient_dict = { + 'quantity': round(float(sum(Fraction(s) for s in array[0].split())), 3), + 'measurement': array[1], + 'title': array[2] + } + except: + ingredient_dict = { + 'title': ingredient + } + + ingredients.append(ingredient_dict) + return ingredients + + def instructions(self): + instructions_html = self.soup.findAll('span', {'class': 'recipe-directions__list--item'}) + + return [ + normalize_string(instruction.get_text()) + for instruction in instructions_html + ] + + def description(self): + return normalize_string( + self.soup.find('div', {'class': 'submitter__description'}).get_text() + ) + + def image(self): + return self.soup.find('img', {'class': 'rec-photo'})["src"] diff --git a/recipe_scrapers/tastykitchen.py b/recipe_scrapers/tastykitchen.py deleted file mode 100644 index 5e8c6a099..000000000 --- a/recipe_scrapers/tastykitchen.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class TastyKitchen(AbstractScraper): - - @classmethod - def host(self): - return 'tastykitchen.com' - - def title(self): - return self.soup.find('h1', {'itemprop': 'name'}).get_text() - - def total_time(self): - return get_minutes(self.soup.find('time', {'itemprop': 'prepTime'})) +\ - get_minutes(self.soup.find('time', {'itemprop': 'cookTime'})) - - def ingredients(self): - ingredients_html = self.soup.find('ul', {'class': "ingredients"}).findAll('li') - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html - ] - - def instructions(self): - directions_html = self.soup.find('span', {'itemprop': 'instructions'}).findAll('p') - - return '\n'.join([ - normalize_string(direction.get_text()) - for direction in directions_html - ]) diff --git a/recipe_scrapers/tests/test_bonappetit.py b/recipe_scrapers/tests/test_bonappetit.py deleted file mode 100644 index 85a22ea4f..000000000 --- a/recipe_scrapers/tests/test_bonappetit.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.bonappetit import BonAppetit - - -class TestBonAppetitScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'bonappetit.html' - )) as file_opened: - self.harvester_class = BonAppetit(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'bonappetit.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Red Wine-Braised Short Ribs' - ) - - def test_total_time(self): - self.assertEqual( - 0, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '5 pounds bone-in beef short ribs, cut crosswise into 2-inch pieces', - 'Kosher salt and freshly ground black pepper', - '3 tablespoons vegetable oil', - '3 medium onions, chopped', - '3 medium carrots, peeled, chopped', - '2 celery stalks, chopped', - '3 tablespoons all-purpose flour', - '1 tablespoon tomato paste', - '1 750 ml bottle dry red wine (preferably Cabernet Sauvignon)', - '10 sprigs flat-leaf parsley', - '8 sprigs thyme', - '4 sprigs oregano', - '2 sprigs rosemary', - '2 fresh or dried bay leaves', - '1 head of garlic, halved crosswise', - '4 cups low-salt beef stock' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - 'Preheat oven to 350°. Season short ribs with salt and pepper. Heat oil in a large Dutch oven over medium-high. Working in 2 batches, brown short ribs on all sides, about 8 minutes per batch. Transfer short ribs to a plate. Pour off all but 3 Tbsp. drippings from pot.\nAdd onions, carrots, and celery to pot and cook over medium-high heat, stirring often, until onions are browned, about 5 minutes. Add flour and tomato paste; cook, stirring constantly, until well combined and deep red, 2-3 minutes. Stir in wine, then add short ribs with any accumulated juices. Bring to a boil; lower heat to medium and simmer until wine is reduced by half, about 25 minutes. Add all herbs to pot along with garlic. Stir in stock. Bring to a boil, cover, and transfer to oven.\nCook until short ribs are tender, 2–2½ hours. Transfer short ribs to a platter. Strain sauce from pot into a measuring cup. Spoon fat from surface of sauce and discard; season sauce to taste with salt and pepper. Serve in shallow bowls over mashed potatoes with sauce spooned over.', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_cookstr.py b/recipe_scrapers/tests/test_cookstr.py deleted file mode 100644 index 233a882b0..000000000 --- a/recipe_scrapers/tests/test_cookstr.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.cookstr import Cookstr - - -class TestCookstrScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'cookstr.html' - )) as file_opened: - self.harvester_class = Cookstr(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'cookstr.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Mozzarella-Tomato-Basil Frittata' - ) - - def test_total_time(self): - self.assertEqual( - 30, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '12 large eggs', - '½ cup whole milk', - '2 tablespoons extra virgin olive oil', - '4 large ripe tomatoes, peeled and sliced', - '1 pound fresh or smoked mozzarella, diced', - '2 tablespoons slivered basil leaves', - 'Salt and freshly ground black pepper' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - 'Preheat the broiler.\nIn a large bowl, beat the eggs with the milk.\nPour 1 tablespoon of the oil into a very large ovenproof skillet, or use 2 skillets with half the ingredients in each. Place over medium heat on the stovetop and pour in the egg mixture. Scatter the tomatoes, cheese, and basil over the eggs. Season with salt and pepper to taste.\nWhen the bottom just begins to brown, place the skillet under the broiler just until the top is set, a minute or less. Remove from the oven and use a large spatula to transfer the frittata to a serving platter. Cool about 10 minutes, cut into wedges, and serve.\n', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_epicurious.py b/recipe_scrapers/tests/test_epicurious.py deleted file mode 100644 index 5669fdffe..000000000 --- a/recipe_scrapers/tests/test_epicurious.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.epicurious import Epicurious - - -class TestEpicurious(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'epicurious.html' - )) as file_opened: - self.harvester_class = Epicurious(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'epicurious.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Poached Eggs in Tomato Sauce with Chickpeas and Feta' - ) - - def test_total_time(self): - self.assertEqual( - 35, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '1/4 cup olive oil', - '1 medium onion, finely chopped', - '4 garlic cloves, coarsely chopped', - '2 jalapeños, seeded, finely chopped', - '1 15-ounce can chickpeas, drained', - '2 teaspoons Hungarian sweet paprika', - '1 teaspoon ground cumin', - '1 28-ounce can whole peeled tomatoes, crushed by hand, juices reserved', - 'Kosher salt and freshly ground black pepper', - '1 cup coarsely crumbled feta', - '8 large eggs', - '1 tablespoon chopped flat-leaf parsley', - '1 tablespoon chopped fresh cilantro', - 'Warm pita bread' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - 'Preheat oven to 425°F. Heat oil in a large ovenproof skillet over medium-high heat. Add onion, garlic, and jalapeños; cook, stirring occasionally, until onion is soft, about 8 minutes. Add chickpeas, paprika, and cumin and cook for 2 minutes longer.\nAdd crushed tomatoes and their juices. Bring to a boil, reduce heat to medium-low, and simmer, stirring occasionally, until sauce thickens slightly, about 15 minutes. Season to taste with salt and pepper. Sprinkle feta evenly over sauce. Crack eggs one at a time and place over sauce, spacing evenly apart. Transfer skillet to oven and bake until whites are just set but yolks are still runny, 5-8 minutes. Garnish with parsley and cilantro. Serve with pita for dipping.\nPer serving: 358 calories, 22 g fat, 22 g carbohydrates\nNutritional analysis provided by Bon Appétit', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_finedininglovers.py b/recipe_scrapers/tests/test_finedininglovers.py deleted file mode 100644 index c6cdd0393..000000000 --- a/recipe_scrapers/tests/test_finedininglovers.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.finedininglovers import FineDiningLovers - - -class TestFineDiningLoversScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'finedininglovers.html' - )) as file_opened: - self.harvester_class = FineDiningLovers(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'finedininglovers.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Zucchini Raw Vegan Lasagna' - ) - - def test_total_time(self): - self.assertEqual( - 50, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - 'Zucchini', - 'Basil', - 'Pine nuts', - 'Extra-virgin olive oil', - 'Yeast flakes', - 'Garlic', - 'Salt', - 'Tomato', - 'Sundried tomato', - 'Extra-virgin olive oil', - 'Salt', - 'Pepper', - 'Brown sugar', - 'Dried oregano', - 'Macadamia nuts', - 'Yeast flakes', - 'Salt', - 'Lime', - 'Water' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - 'For the macadamia cheese Pour all ingredients in a blender and mix until a thick cream. Set aside. For the tomato cream Pour all ingredients into a blender and mix until creamy. Set aside. For the basil pesto Pour all ingredients into a blender and mix until creamy. Set aside. Wash zucchini and cut them into very thin slices. Make the raw vegan lasagna alternating a layer of zucchini, a layer of macadamia cheese, a layer of zucchini, a layer of tomato sauce, a layer of zucchini, a layer of basil pesto. Keep the lasagna in the fridge and serve decorated with fresh basil and pine nuts.', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_foodrepublic.py b/recipe_scrapers/tests/test_foodrepublic.py deleted file mode 100644 index f13178eb9..000000000 --- a/recipe_scrapers/tests/test_foodrepublic.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.foodrepublic import FoodRepublic - - -class TestFoodRepublicScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'foodrepublic.html' - )) as file_opened: - self.harvester_class = FoodRepublic(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'foodrepublic.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Dutch White Asparagus Recipe' - ) - - def test_total_time(self): - self.assertEqual( - 60, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '12 spears Dutch white asparagus', - '1/2 each Meyer lemon, orange and grapefruit', - '2 cups water, for steaming', - '1 cup grated Parmesan cheese', - '1/2 cup Chardonnay', - '1/2 cup white wine vinegar', - '2 sprigs fresh thyme', - '1/2 cup shallots, minced', - 'small chunk of Parmesan rind', - '4 tablespoons unsalted butter, chilled and cut into small cubes', - '4 fresh eggs, poached (see instructions)', - '4 slices prosciutto' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - 'After peeling and trimming the asparagus, steam it in citrus water — water with Meyer lemon, orange and grapefruit slices — until fork tender.\nIn a pot add the Chardonnay, white wine vinegar, thyme, shallots and chunk of Parmesan rind; reduce about a quarter.\nRemove from heat and slowly whisk in cubes of butter until sauce is thick and glossy.\nPour 2 tablespoons of beurre blanc on a plate, top it with a poached egg, steamed white asparagus, prosciutto and grated Parmesan.\nSpring Asparagus Soup Recipe\nGoat Cheese And Asparagus Macaroni Salad Recipe\nRoasted Asparagus & Scrambled Eggs Recipe', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_jamieoliver.py b/recipe_scrapers/tests/test_jamieoliver.py deleted file mode 100644 index 75dbb0694..000000000 --- a/recipe_scrapers/tests/test_jamieoliver.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.jamieoliver import JamieOliver - - -class TestJamieOliverScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'jamieoliver.html' - )) as file_opened: - self.harvester_class = JamieOliver(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'jamieoliver.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - "Bloomin' brilliant brownies" - ) - - def test_total_time(self): - self.assertEqual( - 40, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '250 g unsalted butter', - '200 g good-quality dark chocolate (70% cocoa solids) , broken up', - '75 g dried sour cherries , optional', - '50 g chopped nuts , optional', - '80 g cocoa powder , sifted', - '65 g plain flour , sifted', - '1 teaspoon baking powder', - '360 g caster sugar', - '4 large free-range eggs', - 'zest of 1 orange , optional', - '250 ml crème fraîche , optional' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - self.assertEqual( - 'Preheat your oven to 180°C/350°F/gas 4. Line a 24cm square baking tin with greaseproof paper. In a large bowl over some simmering water, melt the butter and the chocolate and mix until smooth. Add the cherries and nuts, if you’re using them, and stir together. In a separate bowl, mix together the cocoa powder, flour, baking powder and sugar, then add this to the chocolate, cherry and nut mixture. Stir together well. Beat the eggs and mix in until you have a silky consistency. Pour your brownie mix into the baking tray, and place in the oven for around 25 minutes. You don’t want to overcook them so, unlike cakes, you don’t want a skewer to come out all clean. The brownies should be slightly springy on the outside but still gooey in the middle. Allow to cool in the tray, then carefully transfer to a large chopping board and cut into chunky squares. These make a fantastic dessert served with a dollop of crème fraîche mixed with some orange zest.', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_mybakingaddiction.py b/recipe_scrapers/tests/test_mybakingaddiction.py deleted file mode 100644 index 0b718ea9f..000000000 --- a/recipe_scrapers/tests/test_mybakingaddiction.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.mybakingaddiction import MyBakingAddiction - - -class TestMyBakingAddictionScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'mybakingaddiction.html' - )) as file_opened: - self.harvester_class = MyBakingAddiction(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'mybakingaddiction.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Cheesecake in a Jar' - ) - - def test_total_time(self): - self.assertEqual( - 0, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '½ cup plus 2 tablespoons granulated sugar', - 'zest of one lemon', - '2 packages cream cheese, 8 oz each; room temperature', - '2 large eggs; room temperature', - '¼ cup heavy cream', - '1 ½ teaspoons pure vanilla extract', - '1 cup fresh berries' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - 'Preheat oven to 350°F.\nBegin to boil a large pot of water for the water bath.\nIn the bowl of your stand mixer fitted with your paddle attachment, combine the sugar and lemon zest and mix until the sugar is moistened and fragrant.\nAdd in the cream cheese and cream together until smooth.\nAdd eggs, one at a time, fully incorporating each before adding the next. Make sure to scrape down the bowl in between each egg.\nAdd heavy cream and vanilla and mix until smooth.\nPour batter into canning jars until about ¾ of the way full.\nPlace jars into a larger pan and pour boiling water into the larger pan until halfway up the sides of the jars.\nBake 25 to 30 minutes, the edges will appear to be set, but the center will still have a little jiggle to it.\nCarefully remove the cheesecake jars from the water bath and place on a cooling rack to cool completely.\nOnce the cheesecakes are completely cooled, place them into the refrigerator for at least 5 hours.\nTop will fresh berries and serve.', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_simplyrecipes.py b/recipe_scrapers/tests/test_simplyrecipes.py deleted file mode 100644 index 73b5c26e1..000000000 --- a/recipe_scrapers/tests/test_simplyrecipes.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.simplyrecipes import SimplyRecipes - - -class TestSimplyRecipesScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'simpyrecipes.html' - )) as file_opened: - self.harvester_class = SimplyRecipes(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'simplyrecipes.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Cheesy Bread' - ) - - def test_total_time(self): - self.assertEqual( - 20, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '4 oz shredded Mozzarella cheese (1 cup)', - '8 oz shredded sharp cheddar cheese (about 2 cups)', - '1/4 to 1/2 cup chopped green onion (to taste)', - '1/4 cup mayonnaise', - '1 Tbsp sour cream (optional)', - '1-2 cloves garlic, minced', - '1/2 stick unsalted butter (1/4 cup, 2 ounces), softened to the point of being slightly melted', - '1 loaf of French or Italian bread (I used Ciabatta)' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - '1 In a large bowl, mix together the cheeses and the green onion. Stir in the mayonnaise and sour cream. In a separate small bowl blend the butter and garlic until smooth. Add the butter mixture to the cheese mixture.\n\n2 Preheat broiler. Slice loaf of bread in half horizontally, lay crust side down on a foil-lined baking sheet. Spread cheese mixture over the bread.\n\n3 Place under the broiler until nicely browned, about 3 to 5 minutes.\n\n4 Remove from broiler and let sit for 5 minutes until cool enough to handle. Slice the bread with a bread knife. Serve.\nVariations:\nTry mixing in other ingredients with the topping mixture, such as chopped black olives, chopped canned artichoke hearts, minced shrimp, or crab meat.', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_steamykitchen.py b/recipe_scrapers/tests/test_steamykitchen.py deleted file mode 100644 index 433607de0..000000000 --- a/recipe_scrapers/tests/test_steamykitchen.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.steamykitchen import SteamyKitchen - - -class TestSteamyKitchenScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'streamykitchen.html' - )) as file_opened: - self.harvester_class = SteamyKitchen(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'steamykitchen.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Vietnamese Pho: Beef Noodle Soup Recipe' - ) - - def test_total_time(self): - self.assertEqual( - 270, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - 'THE BROTH', - '2 onions, halved', - '4" nub of ginger, halved lengthwise', - '5-6 pounds of good beef bones, preferably leg and knuckle', - '1 pound of beef meat - chuck, brisket, rump, cut into large slices [optional]', - '6 quarts of water', - '1 package of Pho Spices [1 cinnamon stick, 1 tbl coriander seeds, 1 tbl fennel seeds, 5 whole star anise, 1 cardamom pod, 6 whole cloves - in mesh bag]', - '1 1/2 tablespoons kosher salt (halve if using regular table salt)', - '1/4 cup fish sauce', - '1 inch chunk of yellow rock sugar (about 1 oz) - or 1oz of regular sugar', - '2 pounds rice noodles (dried or fresh)', - 'Cooked beef from the broth (shredded or thinly sliced)', - '1/2 pound flank, london broil, sirloin or eye of round, sliced as thinly as possible.', - 'big handful of each: mint, cilantro, basil', - '2 limes, cut into wedges', - '2-3 chili peppers, sliced', - '2 big handfuls of fresh bean sprouts', - 'Hoisin sauce', 'Sriracha hot sauce' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - 'Char: Turn your broiler on high and move rack to the highest spot. Place ginger and onions on baking sheet. Brush just a bit of cooking oil on the cut side of each. Broil on high until ginger and onions begin to char. Turn over and continue to char. This should take a total of 10-15 minutes. Parboil the bones: Fill large pot (12-qt capacity) with cool water. Boil water, and then add the bones, keeping the heat on high. Boil vigorously for 10 minutes. Drain, rinse the bones and rinse out the pot. If you have a lot of marrow in the bones, use a small spoon to scoop out and discard some of the marrow. Refill pot with bones and 6 qts of cool water. Bring to boil over high heat and lower to simmer. Using a ladle or a fine mesh strainer, remove any scum that rises to the top. Boil broth: Add ginger, onion, spice packet, beef, sugar, fish sauce, salt and simmer uncovered for 1 1/2 hours. Remove the beef meat and set aside (you\'ll be eating this meat later in the bowls) Continue simmering for another 1 1/2 hours. Strain broth and return the broth to the pot. Taste broth and adjust seasoning - this is a crucial step. If the broth\'s flavor doesn\'t quite shine yet, add 2 teaspoons more of fish sauce, large pinch of salt and a small nugget of rock sugar (or 1 teaspoon of regular sugar). Keep doing this until the broth tastes perfect. Prepare noodles & meat: Slice your flank/london broil/sirloin as thin as possible - try freezing for 15 minutes prior to slicing to make it easier. Remember the cooked beef meat that was part of your broth? Cut or shred the meat and set aside. Arrange all other ingredients on a platter for the table. Your guests will "assemble" their own bowls. Follow the directions on your package of noodles - there are many different sizes and widths of rice noodles, so make sure you read the directions. For some fresh rice noodles, just a quick 5 second blanch in hot water is all that\'s needed. The package that I purchased (above) - needed about 45 seconds in boiling water. Ladling: Bring your broth back to a boil. Line up your soup bowls next to the stove. Fill each bowl with rice noodles, shredded cooked beef and raw meat slices. As soon as the broth comes back to a boil, ladle into each bowl. the hot broth will cook your raw beef slices. Serve immediately. Guests can garnish their own bowls as they wish.', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_tastykitchen.py b/recipe_scrapers/tests/test_tastykitchen.py deleted file mode 100644 index cb109c923..000000000 --- a/recipe_scrapers/tests/test_tastykitchen.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.tastykitchen import TastyKitchen - - -class TestTastyKitchenScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'tasty_kitchen.html' - )) as file_opened: - self.harvester_class = TastyKitchen(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'tastykitchen.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Cheddar and Garlic Scape Biscuits' - ) - - def test_total_time(self): - self.assertEqual( - 30, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '2 cups All-purpose Flour', - '1 teaspoon Kosher Salt', - '1 Tablespoon Baking Powder', - '1 teaspoon Baking Soda', - '5 Tablespoons Cold Unsalted Butter', - '1 cup Buttermilk', - '4 Garlic Scapes, Finely Chopped', - '2 Tablespoons Fresh Chives', - '½ cups Shredded Cheddar Cheese, Sharp' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - 'Preheat oven to 450ºF.\nCombine dry ingredients together in bowl. Cut butter into small pea-sized pieces and fold into dry ingredients. Combine thoroughly, smashing butter into mixture until blended. Stir in buttermilk and stir by hand until roughly blended.\nAdd scapes, chives and cheddar cheese, setting aside a small amount of cheese and chives to top biscuits with before baking. Combine to form a ball.\nTurn dough out onto floured surface and knead lightly (dough should have slightly sticky consistency). Roll out dough so that it is 3/4 inch thick. Using a glass or a biscuit cutter, cut out 2-inch round shapes. Place the rounds on an ungreased baking sheet. Gather dough scraps, and gently roll out again and repeat.\nSprinkle top of rounds with a pinch of cheddar cheese and chives. Bake biscuits for 8–10 minutes until golden brown. Serve warm with a pat of butter.', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_thevintagemixer.py b/recipe_scrapers/tests/test_thevintagemixer.py deleted file mode 100644 index ffca3a5aa..000000000 --- a/recipe_scrapers/tests/test_thevintagemixer.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.thevintagemixer import TheVintageMixer - - -class TestTheVintageMixerScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'thevintagemixer.html' - )) as file_opened: - self.harvester_class = TheVintageMixer(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'thevintagemixer.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Cauliflower Pizza Crust Recipe' - ) - - def test_total_time(self): - self.assertEqual( - 0, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '1 small head of cauliflower, leaves and stems removed', - '1 teaspoon basil', - '1 teaspoon oregano', - '1 teaspoon parsley', - '1 teaspoon salt', - '1/2 cup Manchengo sheep milk cheese (or Mozzarella)', - '2 eggs', 'cornmeal, to dust the pizza stone', - '1 jar marinara or pizza sauce', - '1/2 cup sheep milk cheese', - '5-8 basil leaves' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - "Preheat oven to 350 degrees.\nChop cauliflower florets into chunks. Pulse the cauliflower in a food processor until it resembles a fine grain, like rice or couscous. Pour cauliflower into a large bowl. Add herbs, and salt, then cheese and eggs.\nSpread a tablespoon or so of cornmeal all over a pizza stone. Place the cauliflower mixture (note- this won't resemble a ball of dough) on the middle of the stone and use your hands to press it into a circle about 1/4 inch thick.\nBake for 20 minutes at 350 then an additional 10 minutes at 400 degrees. Crust will be done when it turns golden brown in color.\nRemove crust from oven. Change oven temperature to 450 degrees. Add pizza sauce, cheese and whatever toppings you would like, then bake again for about 5 minutes or until cheese on top is melted.", - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_twopeasandtheirpod.py b/recipe_scrapers/tests/test_twopeasandtheirpod.py deleted file mode 100644 index 9c1618ee9..000000000 --- a/recipe_scrapers/tests/test_twopeasandtheirpod.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.twopeasandtheirpod import TwoPeasAndTheirPod - - -class TestTwoPeasAndTheirPodScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'twopeasandtheirpod.html' - )) as file_opened: - self.harvester_class = TwoPeasAndTheirPod(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'twopeasandtheirpod.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Red Velvet Cheesecake Cookies' - ) - - def test_total_time(self): - # as it is written '12-15 minutes in our test case' - self.assertEqual( - 13, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '1 box red velvet cake mix (I used Duncan Hines)', - '2 tablespoons all-purpose flour', - '2 large eggs', - '1/2 cup canola oil', - '1 teaspoon vanilla extract', - '4 oz cream cheese, at room temperature', - '2 cups powdered sugar', - '1 teaspoon vanilla extract', - '1 1/2 cups white chocolate chips, melted' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - "1. To make cookies, in a large bowl combine cake mix and flour. Whisk until clumps disappear. In the bowl of a stand mixer, mix together cake mix, flour, eggs, oil and vanilla extract. Mix until smooth. Wrap the dough in plastic wrap. The dough will be oily. Refrigerate for at least two hours.\n2. To make the cheesecake filling, using a mixer, combine cream cheese, powdered sugar, and vanilla extract. Mix until smooth. Using a teaspoon, scoop out cheesecake filling and place on a plate. Continue scooping out cheesecake filling into teaspoon balls until you have 10. Place plate in the freezer and freeze for at least two hours.\n3. Preheat oven to 350 degrees F. Line a large baking sheet with parchment paper or a silicone baking mat. To assemble the cookies, take about 1/4 cup of red velvet cookie dough and flatten in your hands. Place a teaspoon of cheesecake filling in the center and wrap the cookie dough around the filling. Gently roll into a ball and place on prepared baking sheet. Scoop onto lightly greased or parchment lined baking sheets. Only bake 3 cookies at a time. The cookies are large and will spread. Bake for 11-13 minutes or until the cookies begin to crackle. Let the cookies cool on the baking sheet for 5 minutes. Remove from baking sheet to a wire cooling rack and cool completely.\n4. Melt the white chocolate chips in a microwave safe bowl or over a double-boiler. Drizzle the white chocolate over the cooled cookies. Let the cookies set until the chocolate hardens. Serve and enjoy!\nNote: if you are going to store the cookies for more than a day, you may want to keep them in the refrigerator. You can make the cookies smaller. Just use less dough and filling. You want to make sure you completely wrap the cookie dough around the filling before baking-so it doesn't leak. Enjoy!", - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/tests/test_whatsgabycooking.py b/recipe_scrapers/tests/test_whatsgabycooking.py deleted file mode 100644 index d9a9dac69..000000000 --- a/recipe_scrapers/tests/test_whatsgabycooking.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -import os -import unittest - -from recipe_scrapers.whatsgabycooking import WhatsGabyCooking - - -class TestWhatsGabyCookingScraper(unittest.TestCase): - def setUp(self): - # tests are run from tests.py - with open(os.path.join( - os.getcwd(), - 'recipe_scrapers', - 'tests', - 'test_data', - 'whatsgabycooking.html' - )) as file_opened: - self.harvester_class = WhatsGabyCooking(file_opened, test=True) - - def test_host(self): - self.assertEqual( - 'whatsgabycooking.com', - self.harvester_class.host() - ) - - def test_title(self): - self.assertEqual( - self.harvester_class.title(), - 'Strawberry Basil Lemonade' - ) - - def test_total_time(self): - self.assertEqual( - 0, - self.harvester_class.total_time() - ) - - def test_ingredients(self): - self.assertListEqual( - [ - '10 lemons, juiced, about 1 cup of fresh lemon juice', - '3/4 cup super fine sugar', - '4 cups water', - '8-10 strawberries, tops removed', - '1/3 cup fresh basil', - '1/2 cup gin or vodka (optional)' - ], - self.harvester_class.ingredients() - ) - - def test_instructions(self): - return self.assertEqual( - 'Juice the lemons and transfer the juice into a large pitcher.\nAdd the sugar and the water and stir to combine and dissolve the sugar.\nAdd the strawberries and basil.\nUsing an immersion blender, blend the mixture for about 20 seconds just until the mixture turns pink and the basil is finely chopped.\nAdd alcohol if desired. Serve over crushed ice and enjoy!', - self.harvester_class.instructions() - ) diff --git a/recipe_scrapers/thevintagemixer.py b/recipe_scrapers/thevintagemixer.py deleted file mode 100644 index b2284a671..000000000 --- a/recipe_scrapers/thevintagemixer.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class TheVintageMixer(AbstractScraper): - - @classmethod - def host(self): - return 'thevintagemixer.com' - - def title(self): - return self.soup.find('div', {'id': 'zlrecipe-title'}).get_text() - - def total_time(self): - return get_minutes(self.soup.find('span', {'itemprop': 'totalTime'})) - - def ingredients(self): - ingredients_html = self.soup.findAll('li', {'itemprop': "ingredients"}) - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html - if len(normalize_string(ingredient.get_text())) > 0 - ] - - def instructions(self): - instructions_html = self.soup.findAll('li', {'itemprop': 'recipeInstructions'}) - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/recipe_scrapers/twopeasandtheirpod.py b/recipe_scrapers/twopeasandtheirpod.py deleted file mode 100644 index 6c6c56063..000000000 --- a/recipe_scrapers/twopeasandtheirpod.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class TwoPeasAndTheirPod(AbstractScraper): - - @classmethod - def host(self): - return 'twopeasandtheirpod.com' - - def title(self): - return self.soup.find('h2').get_text() - - def total_time(self): - return get_minutes(self.soup.find('span', {'class': 'cooktime'})) - - def ingredients(self): - ingredients_html = self.soup.find('div', {'class': 'ingredient'}).findAll('p') - ingredients_flatten = [] - for ingredient in ingredients_html: - ingredients_flatten.extend(ingredient.get_text().split('\n')) - - return [ - normalize_string(ingredient) - for ingredient in ingredients_flatten - if ingredient[0].isdigit() - ] - - def instructions(self): - instructions_html = self.soup.find('div', {'class': 'instructions'}).findAll(['p', 'li']) - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/recipe_scrapers/whatsgabycooking.py b/recipe_scrapers/whatsgabycooking.py deleted file mode 100644 index 188cc4840..000000000 --- a/recipe_scrapers/whatsgabycooking.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -from ._abstract import AbstractScraper -from ._utils import get_minutes, normalize_string - - -class WhatsGabyCooking(AbstractScraper): - - @classmethod - def host(self): - return 'whatsgabycooking.com' - - def title(self): - return self.soup.find('h1', {'class': 'entry-title'}).get_text() - - def total_time(self): - return get_minutes(self.soup.find('span', {'class': 'ready-in-time'})) - - def ingredients(self): - ingredients_html = self.soup.findAll('li', {'itemprop': "ingredients"}) - - return [ - normalize_string(ingredient.get_text()) - for ingredient in ingredients_html - if len(ingredient) > 0 - ] - - def instructions(self): - instructions_html = self.soup.findAll('li', {'itemprop': 'recipeInstructions'}) - - return '\n'.join([ - normalize_string(instruction.get_text()) - for instruction in instructions_html - ]) diff --git a/setup.py b/setup.py index edf7ea216..590fe214f 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name='openeats-recipe-scraper', url='https://github.com/RyanNoelk/recipe-scraper/', - version='1.0.4', + version='1.0.5', description='Python package, scraping recipes from all over the internet', keywords='python recipes scraper harvest', long_description=README,