Skip to content

Commit

Permalink
Adds suport for nutritionfacts.org (#923)
Browse files Browse the repository at this point in the history
  • Loading branch information
jknndy authored Oct 29, 2023
1 parent bfe0c9e commit 969d4b2
Show file tree
Hide file tree
Showing 7 changed files with 2,530 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ Scrapers available for:
- `https://www.nrk.no/ <https://www.nrk.no/>`_
- `https://www.number-2-pencil.com/ <https://www.number-2-pencil.com/>`_
- `https://nutritionbynathalie.com/blog <https://nutritionbynathalie.com/blog>`_
- `https://nutritionfacts.org/ <https://nutritionfacts.org/>`_
- `https://cooking.nytimes.com/ <https://cooking.nytimes.com>`_
- `https://ohsheglows.com/ <https://ohsheglows.com>`_
- `https://omnivorescookbook.com <https://omnivorescookbook.com>`_
Expand Down
2 changes: 2 additions & 0 deletions recipe_scrapers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@
from .nrkmat import NRKMat
from .number2pencil import Number2Pencil
from .nutritionbynathalie import NutritionByNathalie
from .nutritionfacts import NutritionFacts
from .nytimes import NYTimes
from .ohsheglows import OhSheGlows
from .omnivorescookbook import OmnivoresCookbook
Expand Down Expand Up @@ -344,6 +345,7 @@
Delish.host(): Delish,
ElaVegan.host(): ElaVegan,
GrandFrais.host(): GrandFrais,
NutritionFacts.host(): NutritionFacts,
Thinlicious.host(): Thinlicious,
DomesticateMe.host(): DomesticateMe,
Downshiftology.host(): Downshiftology,
Expand Down
45 changes: 45 additions & 0 deletions recipe_scrapers/nutritionfacts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# mypy: allow-untyped-defs

from ._abstract import AbstractScraper
from ._grouping_utils import group_ingredients


class NutritionFacts(AbstractScraper):
@classmethod
def host(cls):
return "nutritionfacts.org"

def author(self):
return self.schema.author()

def title(self):
return self.schema.title()

def category(self):
return self.schema.category()

def yields(self):
return self.schema.yields()

def image(self):
return self.schema.image()

def ingredients(self):
return self.schema.ingredients()

def ingredient_groups(self):
return group_ingredients(
self.ingredients(),
self.soup,
".wprm-recipe-ingredient-group h4",
".wprm-recipe-ingredient",
)

def instructions(self):
return self.schema.instructions()

def ratings(self):
return self.schema.ratings()

def description(self):
return self.schema.description()
1,150 changes: 1,150 additions & 0 deletions tests/test_data/nutritionfacts_1.testhtml

Large diffs are not rendered by default.

1,151 changes: 1,151 additions & 0 deletions tests/test_data/nutritionfacts_2.testhtml

Large diffs are not rendered by default.

81 changes: 81 additions & 0 deletions tests/test_nutritionfacts_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# mypy: allow-untyped-defs

from recipe_scrapers.nutritionfacts import NutritionFacts
from tests import ScraperTest


class TestNutritionFactsScraper(ScraperTest):
scraper_class = NutritionFacts
test_file_name = "nutritionfacts_1"

def test_host(self):
self.assertEqual("nutritionfacts.org", self.harvester_class.host())

def test_canonical_url(self):
self.assertEqual(
"https://nutritionfacts.org/recipe/sweet-potato-taquitos/",
self.harvester_class.canonical_url(),
)

def test_author(self):
self.assertEqual("Michael Greger M.D. FACLM", self.harvester_class.author())

def test_title(self):
self.assertEqual("Sweet Potato Taquitos", self.harvester_class.title())

def test_category(self):
self.assertEqual("Main Course", self.harvester_class.category())

def test_yields(self):
self.assertEqual("4 servings", self.harvester_class.yields())

def test_image(self):
self.assertEqual(
"https://nutritionfacts.org/app/uploads/2022/05/potato-taquitos-2-scaled.jpg",
self.harvester_class.image(),
)

def test_ingredients(self):
self.assertEqual(
[
"2½ -3 cups chopped sweet potatoes (about 1 large or 2 medium sweet potatoes)",
"1 cup chopped carrots (about 3 medium carrots)",
"3 cloves garlic, minced",
"1 cup chopped red onion",
"1½ cups cooked black beans",
"1 teaspoon chili powder",
"½ teaspoon onion powder",
"½ teaspoon paprika or smoked paprika",
"½ teaspoon ground turmeric",
"¼ teaspoon black pepper",
"12-14 small corn tortillas",
"Cashew Cream (optional)",
"Avocado (optional)",
],
self.harvester_class.ingredients(),
)

def test_instructions(self):
self.assertEqual(
"\n".join(
[
"Boil the potatoes and carrots in 3-4 cups water until soft. Drain the water off. Mash the potatoes and carrots until reaches desired consistency. Feel free to add a splash of unsweetened soy milk or water for a smoother texture.",
"In a pan, sauté the garlic and onion with 2-3 tablespoons of water. Add the spices and cook until the onions are translucent. Stir in the cooked beans.",
"In a bowl, combine the potato and carrot mixture with the black beans mixture. Stir together.",
"Preheat the oven 425F or feel free to use an air fryer with a bake setting.",
"Place a small scoop of the potato and bean mixture on to a tortilla, spread it out, and then roll tightly. Place the seam-side of the tortilla down on a baking sheet lined with a silicon mat or parchment paper (or an air fryer basket). Repeat this process for the remaining tortillas.",
"Bake the tortillas for about 10-15 minutes.",
"Prepare the Cashew Cream, if desired. Thin it out a bit to drizzle on top of the Taquitos or use it as a dip. Optional to top with diced avocado. Enjoy!",
]
),
self.harvester_class.instructions(),
)

def test_ratings(self):
self.assertEqual(4.33, self.harvester_class.ratings())

def test_description(self):
self.assertEqual(
"Sweet Potato Taquitos are a delicious way to check-off a few Daily Dozen servings! This dish combines beans, whole grains, spices, and vegetables for a satisfying meal. Top with cashew cream and avocados, if desired. Pair with a green leafy salad to check even more Daily Dozen boxes off.",
self.harvester_class.description(),
)
100 changes: 100 additions & 0 deletions tests/test_nutritionfacts_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# mypy: allow-untyped-defs

from recipe_scrapers._grouping_utils import IngredientGroup
from recipe_scrapers.nutritionfacts import NutritionFacts
from tests import ScraperTest


class TestNutritionFactsScraper(ScraperTest):
scraper_class = NutritionFacts
test_file_name = "nutritionfacts_2"

def test_host(self):
self.assertEqual("nutritionfacts.org", self.harvester_class.host())

def test_canonical_url(self):
self.assertEqual(
"https://nutritionfacts.org/recipe/cinnamon-roll-oatmeal/",
self.harvester_class.canonical_url(),
)

def test_author(self):
self.assertEqual(
"Jill Dalton from the Whole Food Plant Based Cooking Show",
self.harvester_class.author(),
)

def test_title(self):
self.assertEqual("Cinnamon Roll Oatmeal", self.harvester_class.title())

def test_category(self):
self.assertEqual("Breakfast", self.harvester_class.category())

def test_yields(self):
self.assertEqual("4 servings", self.harvester_class.yields())

def test_image(self):
self.assertEqual(
"https://nutritionfacts.org/app/uploads/2023/08/jill-wfpb-cooking-cinnamon-roll-oats-scaled.jpg",
self.harvester_class.image(),
)

def test_ingredients(self):
expected_ingredients = [
"4 cups water",
"8 pitted dates",
"2 teaspoons cinnamon",
"2 teaspoons vanilla extract or powder",
"2 cups rolled oats",
"Raw pecans (optional garnish, as desired)",
"½ cup raw cashews",
"½ teaspoon vanilla extract",
"2 pitted dates",
"¾-1 cup water",
]
self.assertEqual(expected_ingredients, self.harvester_class.ingredients())

def test_ingredient_groups(self):
self.assertEqual(
[
IngredientGroup(
ingredients=[
"4 cups water",
"8 pitted dates",
"2 teaspoons cinnamon",
"2 teaspoons vanilla extract or powder",
"2 cups rolled oats",
"Raw pecans (optional garnish, as desired)",
],
purpose="For the Oatmeal",
),
IngredientGroup(
ingredients=[
"½ cup raw cashews",
"½ teaspoon vanilla extract",
"2 pitted dates",
"¾-1 cup water",
],
purpose="For the Drizzle",
),
],
self.harvester_class.ingredient_groups(),
)

def test_instructions(self):
self.assertEqual(
"\n".join(
[
"To make the oatmeal, in a high-speed blender, combine the water, dates, cinnamon, and vanilla. Blend until smooth and pour into a saucepan with the rolled oats. Cook until the oats reach your desired consistency.",
"To make the drizzle, combine all of the ingredients into a high-speed blender. Blend until smooth and creamy.",
"Divide the oatmeal into bowls, top with the drizzle, and garnish with pecans, as desired.",
]
),
self.harvester_class.instructions(),
)

def test_description(self):
self.assertEqual(
"This Cinnamon Roll Oatmeal is a naturally sweet and delicious way to start your day. It’s a date-sweetened oatmeal paired with a creamy cashew drizzle that makes for a fancy, yet simple breakfast. Less than 3 percent of Americans meet the daily recommended fiber intake, despite research suggesting that high-fiber foods, such as whole grains, can affect the progression of coronary heart disease. The soluble fiber of oatmeal forms a gel in the stomach, delaying stomach emptying, making one feel full for a longer period.",
self.harvester_class.description(),
)

0 comments on commit 969d4b2

Please sign in to comment.