From fed55c6e2fe0b9a6ddfe49e0d3fa9edffed05f73 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sun, 1 Dec 2024 15:02:27 -0800 Subject: [PATCH 01/94] Adds support for kitchendivas (#1386) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/kitchendivas.py | 31 + .../kitchendivas.com/kitchendivas_1.json | 65 + .../kitchendivas.com/kitchendivas_1.testhtml | 3105 ++++++++++++++++ .../kitchendivas.com/kitchendivas_2.json | 118 + .../kitchendivas.com/kitchendivas_2.testhtml | 3285 +++++++++++++++++ 7 files changed, 6607 insertions(+) create mode 100644 recipe_scrapers/kitchendivas.py create mode 100644 tests/test_data/kitchendivas.com/kitchendivas_1.json create mode 100644 tests/test_data/kitchendivas.com/kitchendivas_1.testhtml create mode 100644 tests/test_data/kitchendivas.com/kitchendivas_2.json create mode 100644 tests/test_data/kitchendivas.com/kitchendivas_2.testhtml diff --git a/README.rst b/README.rst index d521ace33..1d281ea3b 100644 --- a/README.rst +++ b/README.rst @@ -265,6 +265,7 @@ Scrapers available for: - `https://keukenliefde.nl/ `_ - `https://www.kingarthurbaking.com `_ - `https://kitchenaid.com.au/ `_ +- `https://kitchendivas.com `_ - `https://www.kitchendreaming.com `_ - `https://www.kitchensanctuary.com/ `_ - `https://www.kitchenstories.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 3739e60eb..f5a1b35d9 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -213,6 +213,7 @@ from .keukenliefdenl import KeukenLiefdeNL from .kingarthur import KingArthur from .kitchenaidaustralia import KitchenAidAustralia +from .kitchendivas import KitchenDivas from .kitchendreaming import KitchenDreaming from .kitchensanctuary import KitchenSanctuary from .kitchenstories import KitchenStories @@ -537,6 +538,7 @@ JoyTheBaker.host(): JoyTheBaker, KaleJunkie.host(): KaleJunkie, KitchenAidAustralia.host(): KitchenAidAustralia, + KitchenDivas.host(): KitchenDivas, KitchenDreaming.host(): KitchenDreaming, KristinesKitchenBlog.host(): KristinesKitchenBlog, KrollsKorner.host(): KrollsKorner, diff --git a/recipe_scrapers/kitchendivas.py b/recipe_scrapers/kitchendivas.py new file mode 100644 index 000000000..d5c308064 --- /dev/null +++ b/recipe_scrapers/kitchendivas.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class KitchenDivas(AbstractScraper): + @classmethod + def host(cls): + return "kitchendivas.com" + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/tests/test_data/kitchendivas.com/kitchendivas_1.json b/tests/test_data/kitchendivas.com/kitchendivas_1.json new file mode 100644 index 000000000..9f69ab44b --- /dev/null +++ b/tests/test_data/kitchendivas.com/kitchendivas_1.json @@ -0,0 +1,65 @@ +{ + "author": "Karin and Ken", + "canonical_url": "https://kitchendivas.com/our-favorite-banana-bread/", + "site_name": "Kitchen Divas", + "host": "kitchendivas.com", + "language": "en-US", + "title": "Best Banana Bread with Chocolate Chips", + "ingredients": [ + "2 cups bananas, very ripe, mashed (about four bananas)", + "2 cups all-purpose flour", + "¾ cup sugar", + "¾ teaspoon baking soda", + "½ teaspoon salt", + "¼ cup sour cream", + "2 large eggs", + "6 tablespoons unsalted butter (melted and cooled)", + "2 teaspoons vanilla extract", + "4 ounces semi-sweet chocolate (chopped, to taste)" + ], + "instructions_list": [ + "Preheat oven to 350 degrees.", + "Grease and flour bottom and sides of nonstick loaf pan. Set aside.", + "Combine flour, sugar, baking soda and salt in large bowl. Set aside.", + "In another bowl combine mashed bananas, sour cream, eggs, butter, and vanilla with a wooden spoon.", + "Gently fold banana mixture into flour mixture until just combined and batter looks thick and chunky.", + "Using a spatula pour batter into prepared loaf pan.", + "Bake until loaf is golden brown on top and a toothpick inserted in the middle comes out clean, about 60-65 minutes.", + "Cool in pan for at least 5 minutes, then transfer to wire rack. Enjoy!" + ], + "category": "Breakfast,Dessert,Snack", + "yields": "8 servings", + "description": "Soft, decadent, sweet and perfectly moist, this chocolate chip banana bread is sure to become your next favorite way to put those overripe bananas to use!", + "total_time": 80, + "cook_time": 65, + "prep_time": 10, + "cuisine": "American", + "ratings": 5.0, + "ratings_count": 1, + "equipment": [ + "9 x 5 inch loaf panor bread pan", + "whisk", + "mixing bowl", + "wooden spoon", + "Rubber spatula", + "wire rack" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "412 kcal", + "fatContent": "17 g", + "saturatedFatContent": "10 g", + "unsaturatedFatContent": "6 g", + "transFatContent": "0.4 g", + "carbohydrateContent": "59 g", + "sugarContent": "29 g", + "proteinContent": "6 g", + "sodiumContent": "272 mg", + "fiberContent": "3 g", + "cholesterolContent": "74 mg" + }, + "image": "https://kitchendivas.com/wp-content/uploads/2019/05/Banana-Bread-cc.jpg", + "keywords": [ + "chocolate chip banana bread" + ] +} diff --git a/tests/test_data/kitchendivas.com/kitchendivas_1.testhtml b/tests/test_data/kitchendivas.com/kitchendivas_1.testhtml new file mode 100644 index 000000000..ec6b45135 --- /dev/null +++ b/tests/test_data/kitchendivas.com/kitchendivas_1.testhtml @@ -0,0 +1,3105 @@ + + + + + + + + + + + + + + + + + + + + + Chocolate Chip Banana Bread - Kitchen Divas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/kitchendivas.com/kitchendivas_2.json b/tests/test_data/kitchendivas.com/kitchendivas_2.json new file mode 100644 index 000000000..f0870e33a --- /dev/null +++ b/tests/test_data/kitchendivas.com/kitchendivas_2.json @@ -0,0 +1,118 @@ +{ + "author": "Karin and Ken", + "canonical_url": "https://kitchendivas.com/taco-bell-cheesy-gordita-crunch/", + "site_name": "Kitchen Divas", + "host": "kitchendivas.com", + "language": "en-US", + "title": "Cheesy Gordita Crunch Copycat", + "ingredients": [ + "1 lb ground beef", + "6 Hard Taco Shells", + "6 Gordita Flour Tortillas", + "1 cup shredded cheddar cheese (or 8 oz)", + "1 cup shredded iceberg lettuce", + "1 tomato (diced)", + "1 tsp chili powder", + "1 tsp cumin", + "½ tsp smoked paprika", + "½ tsp coriander", + "½ tsp garlic powder", + "½ tsp minced onion", + "¼ tsp sugar", + "½ cup sour cream", + "¼ cup mayonnaise", + "1 tbsp hot sauce", + "½ tsp garlic powder", + "1 tsp dried dill weed", + "¼ tsp black pepper", + "¼ tsp onion powder", + "¼ tsp dried parsley", + "¼ tsp kosher salt" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 lb ground beef", + "6 Hard Taco Shells", + "6 Gordita Flour Tortillas", + "1 cup shredded cheddar cheese (or 8 oz)", + "1 cup shredded iceberg lettuce", + "1 tomato (diced)" + ], + "purpose": null + }, + { + "ingredients": [ + "1 tsp chili powder", + "1 tsp cumin", + "½ tsp smoked paprika", + "½ tsp coriander", + "½ tsp garlic powder", + "½ tsp minced onion", + "¼ tsp sugar" + ], + "purpose": "Copycat Taco Bell Taco Seasoning" + }, + { + "ingredients": [ + "½ cup sour cream", + "¼ cup mayonnaise", + "1 tbsp hot sauce", + "½ tsp garlic powder", + "1 tsp dried dill weed", + "¼ tsp black pepper", + "¼ tsp onion powder", + "¼ tsp dried parsley", + "¼ tsp kosher salt" + ], + "purpose": "Jalapeno Ranch Sauce Ingredients" + } + ], + "instructions_list": [ + "Preheat the oven to 375*", + "Heat a skillet over medium high heat. Add olive oil and swirl to coat the pan. Add the ground beef and break apart. Once halfway cooked, stir in the taco seasoning. Remove from heat and place into a bowl.", + "Lay gorditas out on a rimmed baking sheet. Cover each evenly with shredded cheddar cheese and place into the oven to melt for 4 minutes.", + "Prepare the spicy ranch while the cheese is melting. Add all ingredients to a mixing bowl and whisk well to combine.", + "Once cheese has melted on the gorditas, remove them from the oven and place onto a taco stand to help hold the shape. Add the hard shell tortilla over the cheese. Scoop taco meat into the center of the hardshell tortilla. Top with spicy ranch, shredded lettuce, tomato, and cheese.", + "Serve immediately and enjoy!" + ], + "category": "Main Course", + "yields": "6 servings", + "description": "Follow this copycat Taco Bell cheesy Gordita crunch recipe for a version that's better than Taco Bell's. Like the original, it's loaded with beef, cheese, and seasonings and has an outside that packs a crunch; only it's homemade!", + "total_time": 30, + "cook_time": 20, + "prep_time": 10, + "cuisine": "Mexican", + "ratings": 5.0, + "ratings_count": 1, + "equipment": [ + "Measuring cups and spoons", + "Sharp knife", + "cutting board", + "large skillet", + "wooden spoon", + "mixing bowl", + "Cheese grater", + "rimmed baking sheet", + "whisk" + ], + "nutrients": { + "servingSize": "1 Gordita", + "calories": "456 kcal", + "fatContent": "39 g", + "saturatedFatContent": "17 g", + "unsaturatedFatContent": "18 g", + "transFatContent": "1 g", + "carbohydrateContent": "3 g", + "sugarContent": "2 g", + "proteinContent": "23 g", + "sodiumContent": "523 mg", + "fiberContent": "1 g", + "cholesterolContent": "107 mg" + }, + "image": "https://kitchendivas.com/wp-content/uploads/2021/10/Cheesy-Gordita-Crunch-Copycat-17-of-39.jpg", + "keywords": [ + "cheesy gordita crunch", + "taco bell copycat" + ] +} diff --git a/tests/test_data/kitchendivas.com/kitchendivas_2.testhtml b/tests/test_data/kitchendivas.com/kitchendivas_2.testhtml new file mode 100644 index 000000000..ed1856f86 --- /dev/null +++ b/tests/test_data/kitchendivas.com/kitchendivas_2.testhtml @@ -0,0 +1,3285 @@ + + + + + + + + + + + + + + + + + + + + + + Taco Bell Cheesy Gordita Crunch Copycat - Kitchen Divas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + From 43dbeb53875fae78908da09da752822546bd8c44 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sun, 1 Dec 2024 18:02:36 -0800 Subject: [PATCH 02/94] Adds support for cookomix (#1393) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/cookomix.py | 13 ++ tests/test_data/cookomix.com/cookomix.json | 48 +++++ .../test_data/cookomix.com/cookomix.testhtml | 189 ++++++++++++++++++ 5 files changed, 253 insertions(+) create mode 100644 recipe_scrapers/cookomix.py create mode 100644 tests/test_data/cookomix.com/cookomix.json create mode 100644 tests/test_data/cookomix.com/cookomix.testhtml diff --git a/README.rst b/README.rst index 1d281ea3b..97fd69af4 100644 --- a/README.rst +++ b/README.rst @@ -158,6 +158,7 @@ Scrapers available for: - `https://cooking.nytimes.com/ `_ - `https://cookingcircle.com/ `_ - `https://cookinglight.com/ `_ +- `https://cookomix.com/ `_ - `https://cookpad.com/ `_ - `https://cookscountry.com/ `_ (*) - `https://cooksillustrated.com/ `_ (*) diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index f5a1b35d9..2ea62eaf0 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -105,6 +105,7 @@ from .cookiesandcups import CookiesAndCups from .cookingcircle import CookingCircle from .cookinglight import CookingLight +from .cookomix import Cookomix from .cookpad import CookPad from .cookscountry import CooksCountry from .cooksillustrated import CooksIllustrated @@ -502,6 +503,7 @@ CookiesAndCups.host(): CookiesAndCups, CookingCircle.host(): CookingCircle, CookingLight.host(): CookingLight, + Cookomix.host(): Cookomix, CooksCountry.host(): CooksCountry, CooksIllustrated.host(): CooksIllustrated, CopyKat.host(): CopyKat, diff --git a/recipe_scrapers/cookomix.py b/recipe_scrapers/cookomix.py new file mode 100644 index 000000000..cb4260d47 --- /dev/null +++ b/recipe_scrapers/cookomix.py @@ -0,0 +1,13 @@ +from ._abstract import AbstractScraper + + +class Cookomix(AbstractScraper): + @classmethod + def host(cls): + return "cookomix.com" + + def instructions(self): + instructions_html = self.soup.select_one(".instructions.dsb-select ol") + + instructions = instructions_html.find_all("li") + return "\n".join(li.get_text() for li in instructions) diff --git a/tests/test_data/cookomix.com/cookomix.json b/tests/test_data/cookomix.com/cookomix.json new file mode 100644 index 000000000..d252ee0e0 --- /dev/null +++ b/tests/test_data/cookomix.com/cookomix.json @@ -0,0 +1,48 @@ +{ + "author": "rbormi", + "canonical_url": "https://www.cookomix.com/recettes/risotto-champignons-et-courgettes-thermomix/", + "site_name": "Cookomix", + "host": "cookomix.com", + "language": "fr-FR", + "title": "Risotto champignons et courgettes au thermomix", + "ingredients": [ + "Échalote - 1", + "Beurre - 20 grammes", + "Champignons de Paris blancs - 100 grammes", + "Courgette - 1", + "Riz spécial risotto - 250 grammes", + "Vin blanc - 60 grammes", + "Eau - 590 grammes", + "Fond de légumes - 1 cuillère à soupe", + "Sel - 1 cuillère à café", + "Poivre - 1 pincée", + "Crème fraîche épaisse - 2 cuillères à soupe", + "Parmesan - 2 cuillères à soupe" + ], + "instructions_list": [ + "Mettre 1 échalote, 20 grammes de beurre, 100 grammes de champignons de paris blancs et 1 courgette coupée en morceaux dans le Thermomix. Mélanger 10 sec/vitesse 4. Racler ensuite les parois du bol avec la spatule.", + "Rissoler 3 min 30 sec/120°C/vitesse 1.", + "Ajouter 250 grammes de riz spécial risotto et 60 grammes de vin blanc dans le Thermomix. Rissoler 3 min/120°C/vitesse 1.", + "Ajouter 590 grammes d'eau, 1 cuillère à soupe de fond de légumes, 1 cuillère à café de sel et 1 pincée de poivre dans le Thermomix. Cuire 15 min/100°C//vitesse 1 avec le panier de cuisson à la place du gobelet doseur sur le couvercle du bol pour éviter les projections.", + "Ajouter 2 cuillères à soupe de crème fraîche épaisse et 2 cuillères à soupe de parmesan dans le Thermomix. Remuer 30 sec//.", + "Réserver pendant 10 min avant de servir." + ], + "category": "Plat principal", + "yields": "4 servings", + "description": "Le risotto est l’un des plats les plus emblématique de la cuisine italienne. D'un point de vue purement technique il s’agit d’une réduction de bouillon de riz cuit avec divers ingrédients qui varient selon les recettes. Le riz va cuire en absorbant le bouillon chau, on l'aura fait au préablable revenir dans du beurre ou de l’huile d’olive. Le premier mouillage se fait généralement avec du vin blanc. En fin de cuisson, un généreux morceau de beurre, de parmesan ou une grosse cuillère de mascarpone y est ajouté afin de faire la liaison dans le risotto et le rendre encore plus onctueux. Les italiens appellent ça “mantecare”. Traditionnellement sa préparation demande de l’huile de coude, beaucoup de patience et un certain savoir-faire. Du coup est-il possible de réaliser un bon risotto au Thermomix ? La réponse est bien évidemment oui et il sera tout aussi crémeux et savoureux que si vous l’aviez réalisé de manière traditionnelle. La bonne nouvelle c’est que vous ne serez plus obligé de rester devant la casserole pour remuer régulièrement et surveiller la cuisson ;) Grâce à votre Thermomix réaliser un risotto n’aura jamais été aussi simple ! Je vous propose ici une recette de risotto aux champignons et courgettes bien gourmande. Les quantités données ici vous garantissent une consistance parfaite. Les courgettes et les champignons apportant encore plus de fondant au plat, le tout notamment assaisonné avec un fond de légumes que l'on vous conseille évidement de faire maison. Si jamais vous consultiez cette recette alors que ce n'est pas la saison de la courgette, vous pouvez simplement augmenter la quantité de champignon (jusqu'à 250 grammes). En plat unique ou en accompagnement, vous serez certain de régaler tout le monde, petits et grands :)", + "total_time": 51, + "cook_time": 41, + "prep_time": 10, + "cuisine": "Méditerranéenne", + "ratings": 4.89, + "ratings_count": 2110, + "nutrients": { + "calories": "331 kcal" + }, + "image": "https://www.cookomix.com/wp-content/uploads/2016/01/risotto-courgettes-champignons.jpg", + "keywords": [ + "Riz", + "Végétarien", + "Été" + ] +} diff --git a/tests/test_data/cookomix.com/cookomix.testhtml b/tests/test_data/cookomix.com/cookomix.testhtml new file mode 100644 index 000000000..1602c5066 --- /dev/null +++ b/tests/test_data/cookomix.com/cookomix.testhtml @@ -0,0 +1,189 @@ + Risotto champignons et courgettes au Thermomix - Cookomix
R

Risotto champignons et courgettes

publié par rbormi

Risotto champignons et courgettes au Thermomix
Préparation
10 min
Repos
10 min
Durée totale
41 min
Difficulté
facile
Nombre de parts
4 portions
Coût pour 1 portion
0.69 €
Coût de la recette
2.77 €
Calories par portion (331 g)
331 kcal
Lipides
8.9 g
Acides gras saturés
5.2 g
Glucides
53.5 g
Sucres
3.1 g
Fibres
1.9 g
Protéines
8.1 g
Charge Glycémique
élevée
Calories pour 100g
100 kcal
Points WW par portion
10
Recette pour
Thermomix TM5 et Thermomix TM6
Note
4.89 / 5 (2110 notes)
1
Échalote
20 grammes
Beurre
100 grammes
Champignons de Paris blancs
1
Courgette
250 grammes
Riz spécial risotto
60 grammes
Vin blanc
590 grammes
Eau
1 cuillère à soupe
Fond de légumes
1 cuillère à café
Sel
1 pincée
Poivre
2 cuillères à soupe
Crème fraîche épaisse
2 cuillères à soupe
Parmesan
Plat principalRizVégétarienMéditerranéenneÉté

Le risotto est l’un des plats les plus emblématique de la cuisine italienne. D’un point de vue purement technique il s’agit d’une réduction de bouillon de riz cuit avec divers ingrédients qui varient selon les recettes. Le riz va cuire en absorbant le bouillon chau, on l’aura fait au préablable revenir dans du beurre ou de l’huile d’olive. Le premier mouillage se fait généralement avec du vin blanc. En fin de cuisson, un généreux morceau de beurre, de parmesan ou une grosse cuillère de mascarpone y est ajouté afin de faire la liaison dans le risotto et le rendre encore plus onctueux. Les italiens appellent ça “mantecare”.

Traditionnellement sa préparation demande de l’huile de coude, beaucoup de patience et un certain savoir-faire. Du coup est-il possible de réaliser un bon risotto au Thermomix ? La réponse est bien évidemment oui et il sera tout aussi crémeux et savoureux que si vous l’aviez réalisé de manière traditionnelle. La bonne nouvelle c’est que vous ne serez plus obligé de rester devant la casserole pour remuer régulièrement et surveiller la cuisson 😉 Grâce à votre Thermomix réaliser un risotto n’aura jamais été aussi simple !

Je vous propose ici une recette de risotto aux champignons et courgettes bien gourmande. Les quantités données ici vous garantissent une consistance parfaite. Les courgettes et les champignons apportant encore plus de fondant au plat, le tout notamment assaisonné avec un fond de légumes que l’on vous conseille évidement de faire maison. Si jamais vous consultiez cette recette alors que ce n’est pas la saison de la courgette, vous pouvez simplement augmenter la quantité de champignon (jusqu’à 250 grammes).

En plat unique ou en accompagnement, vous serez certain de régaler tout le monde, petits et grands 🙂

Astuce
Il est impératif d’utiliser du riz spécial risotto qui a une plus grande capacité d’absorption que tout autre sorte de riz. En effet, les riz comme le Carnaroli, le Vialone Nano ou encore l’Arborio, ont une teneur en amidon plus élevée, ce qui donnera à votre risotto une texture moelleuse et fondante. (Ne rincez pas le riz avant cuisson, vous risqueriez d’enlever cet amidon).
Astuce
Quel vin blanc choisir pour mon risotto ? Privilégiez un vin de qualité puisque ce dernier aura forcément un impact sur les arômes donnés au plat, c'est pourquoi il faut le choisir avec un minimum de soin :)
On conseille généralement du Chardonnay ou un Blanc du Rhône (Viognier ou Grenache blanc) ou du Sud-Ouest (Bergerac ou Gaillac). Ces derniers étant les plus doux, nous vous le recommandons pour cette recette de risotto au Thermomix avec des champignons et des courgettes.
Variante
Vous pouvez remplacer les champignons de Paris par d’autres variétés de champignons comme des cèpes, des girolles, des chanterelles ou des pleurotes.
  1. Mettre 1 échalote, 20 grammes de beurre, 100 grammes de champignons de paris blancs et 1 courgette coupée en morceaux dans le Thermomix. Mélanger 10 sec/vitesse 4. Racler ensuite les parois du bol avec la spatule.
  2. Rissoler 3 min 30 sec/120°C/vitesse 1.
  3. Ajouter 250 grammes de riz spécial risotto et 60 grammes de vin blanc dans le Thermomix. Rissoler 3 min/120°C/vitesse 1.
  4. Ajouter 590 grammes d'eau, 1 cuillère à soupe de fond de légumes, 1 cuillère à café de sel et 1 pincée de poivre dans le Thermomix. Cuire 15 min/100°C//vitesse 1 avec le panier de cuisson à la place du gobelet doseur sur le couvercle du bol pour éviter les projections.
  5. Ajouter 2 cuillères à soupe de crème fraîche épaisse et 2 cuillères à soupe de parmesan dans le Thermomix. Remuer 30 sec//.
  6. Réserver pendant 10 min avant de servir.

Vous devez vous connecter pour réagir à cette recette.

  • Illustration du profil de Mokaroyal

    Mokaroyal a noté 5/5 cette recette, il y a 7 ans

    très bon. je fais revenir à la poêle avec un peu d’huile d’olive quelques champignons et de la courgette en dés afin d’avoir des morceaux intacts. je trouve cela plus joli.
    seul défaut pour moi avec un risotto c’est qu’on ne puisse malheureusement pas le préparer à l’avance!

    Risotto champignons et courgettes Thermomix par Mokaroyal
    Risotto champignons et courgettes Thermomix par Mokaroyal
    J'aimeMiamMerciLove82
  • Illustration du profil de aurelie_isabel

    aurelie_isabel a noté 5/5 cette recette, il y a 2 ans et 4 mois

    E X C E L L E N T I S S I M E 🤤
    Consistance parfaite 👌

    ⚠️ mes modifs : j’ai doublé la quantité de courgettes, j’ai aussi fait revenir les champignons à la poêle et ajouté des allumettes de bacon pour en faire un plat complet 🍽

    Risotto champignons et courgettes Thermomix par aurelie_isabel
    J'aimeMiamLove60
  • Illustration du profil de courantdair

    courantdair a noté 5/5 cette recette, il y a 3 ans et 5 mois

    Le risotto au Thermomix c’est le top et quand le pti chat se régale c’est royal 😍 Un grand merci pour la recette 😘

    Risotto champignons et courgettes Thermomix par courantdair
    J'aimeMiamLove51
  • Illustration du profil de Nanie🍫

    Nanie🍫 a noté 5/5 cette recette, il y a 3 ans et 2 mois

    Ex-ce- llent !!! 🤪 je me prive souvent de champi »gn »on mon mari les déteste… mais la franchement j’ai pris mon pied avec ce risotto !!! Extra !!! 😋👌

    Risotto champignons et courgettes Thermomix par Nanie🍫
    MiamJ'aimeWowLoveHaha45
  • Illustration du profil de Oliju87-

    Oliju87- a noté 5/5 cette recette, il y a 5 ans et 7 mois

    Miam 😋
    Recette suivie à la lettre avec des chanterelles cueillies dans les bois 😊

    Risotto champignons et courgettes Thermomix par Oliju87-
    J'aimeLove44
  • Illustration du profil de Coconini

    Coconini a noté 5/5 cette recette, il y a 2 ans et 6 mois

    Merci rbormi pour cette chouette recette. J’ai mixé 60 gr de parmesan. Puis j’ai mixé l’échalote 5s vit 5, rajouté la courgette, les champignons de Paris ( ce qu’il me restait de la recette des friands aux champignons, jambon ), un reste de lardons, 4s vit 4 pour ne pas avoir un hachis. Je n’ai pas mis de vin blanc mais le même volume d’eau à la place, les fameuses épices Italiennes qui donnent un goût incomparable !!!!!! Si si 😂😂😂J’ai fait cuire avec le mode sens inverse, cuillère à la place de la vit 1. J’ai mis du Skyr à la place de la crème fraîche, un régal ♥️♥️♥️

    Risotto champignons et courgettes Thermomix par Coconini
    Risotto champignons et courgettes Thermomix par Coconini
    J'aimeMiamLoveMerciWow35
  • M

    Mateli a noté 5/5 cette recette, il y a 5 ans et 8 mois

    Très bon et simple comme tout à réaliser

    Risotto champignons et courgettes Thermomix par Mateli
    J'aimeMiamLove28
  • Illustration du profil de Cricri-25

    Cricri-25 a noté 5/5 cette recette, il y a 1 an et 2 mois

    Aujourd’hui j’avais prévu une croziflette pour le repas ! 🙂 Sauf que je ne suis pas allée en courses depuis plusieurs jours et qu’en regardant de plus près, en dehors du vin blanc et de la crème fraîche je n’avais rien pour la préparer 🙄🙉🙈 Heureusement cookomix était là pour me donner une idée et me sauver la mise 😉 J’ai sorti un paquet de chanterelles (300 grs) 🍄 et un pot de bouillon de légumes maison (345 grs) du congélateur.
    Pour la préparation de ce magnifique risotto, j’ai mis l’échalote et le beurre dans le bol, pulvérisé et rajouté
    environ 100 grs de courgette 🥒 coupée en petits morceaux au couteau et les champignons rincés et bien égouttés avant de faire rissoler le tout.
    Je n’ai pas mis de fond de légumes mais mon bouillon que j’ai complété avec de l’eau pour avoir le poids de liquide préconisé. Pas d’ajout de sel. Il me restait également du jambon de Parme que j’ai coupé en lanières et mis dans le bol en même temps que la crème et le parmesan.
    Finalement je m’en suis bien sortie et c’était très bon ! 😋👌

    Risotto champignons et courgettes Thermomix par Cricri-25
    HahaJ'aimeMiamWowLove25
  • C

    cecilemg a noté 5/5 cette recette, il y a 5 ans et 6 mois

    Délicieux! Elaboré dans mon Monsieur Cuisine + en suivant scrupuleusement la recette. J’ai juste mis un cube de bouillon de légumes au lieu de fond de légumes en poudre. Très bonne texture et beaucoup de goût.

    Risotto champignons et courgettes Thermomix par cecilemg
    J'aimeMerci25
  • karine_nette a noté 5/5 cette recette, il y a 9 mois

    Excellent !!! Recette très facile et rapide à réaliser. Le risotto est vraiment onctueux et servi avec des noix de St Jacques , le plat a fait l’unanimité…

    Risotto champignons et courgettes Thermomix par karine_nette
    MiamJ'aimeLove20
  • Khadikoi a noté 5/5 cette recette, il y a 5 ans et 5 mois

    Succulent. Remplacé le vin par de l’eau. Merciiii

    Risotto champignons et courgettes Thermomix par Khadikoi
    J'aime19
  • Illustration du profil de Cricri7172

    Cricri7172 a noté 5/5 cette recette, il y a 3 ans et 5 mois

    Excellente recette de risotto très onctueux… j adore 🥰 🍽🍽

    Risotto champignons et courgettes Thermomix par Cricri7172
    J'aimeMiam18
  • Illustration du profil de adego

    adego a noté 5/5 cette recette, il y a 3 ans et 6 mois

    Excellent risotto, nous sommes 2, j’ai donc divisé les quantités par 2 (sauf les champignons) et mis 250g d’eau. 😋

    Risotto champignons et courgettes Thermomix par adego
    J'aime18
  • Illustration du profil de Sofia

    Sofia a noté 5/5 cette recette, il y a 5 ans et 3 mois

    Recette au top, j ai mixé la courgette et le beurre ensemble, j ai ensuite ajouté les échalotes surgelées et les champignons émincés (je voulais qu ils restent « entiers »). Pour le reste, j ai suivi à la lettre 😊

    Risotto champignons et courgettes Thermomix par Sofia
    J'aimeMiamLove14
  • maurinehrz a noté 5/5 cette recette, il y a 2 mois et 1 semaine

    Alors……!

    Suite à la recette des farfalles à la crème de courgette d’hier il me restait 1 quart de l’enooooorme courgette du jardin qui devait bien pesé 1 kg 🥲 du coup je me suis dis que pour ne pas gâcher ce serait soit gâteau chocolat courgette soit un repas…. Le choix a vite été fait ! Je me muni de mes champignons bruns conserves sagement au frigo (trop sagement) et à l’ouverture une odeeeeeeur pestilentielle !! Une horreur. Vous l’aurez compris les champignons ont moisi. Génial ! (Et c’est pas fini) je réfléchis rapidement et vois une aubergine tapi dans le l’ombre. Ni une ni deux je m’en muni et commence à la préparer. Pas d’échalote, pas de champignon, pas de vin blanc… et sinon c’est pas drôle… pas de riz à risotto non plus ! Quelle galère. Du coup je l’ai fait à ma sauce, un oignon coupé grossièrement une aubergine, mon reste de courgette, 1 bouillon légume, aromates à souhait, 200g de riz long et 450g d’eau (je crois). Au fil des étapes j’étais toujours aussi dubitative, les légumes qui rendent bcp d’eau ne m’ont pas rassuré non plus. Et pourtant, après 28min de cuisson (18min en premier puis 10min pour évaporer un peu plus l’eau) j’ai obtenu ce superbe risotto aubergine courgette ! Je peux vous dire qu’on s’est régalé. Saupoudré de parmesan et accompagné de filet de rouget pour moi et poulet pour monsieur et notre petit ange. Je referais cette recette, autant l’originale que cette version fond de frigo 🤪 après tout une photo vaut mieux que 1000 mots, jugez par vous même 🥳 (dit-elle après avoir écrit un pavé) bon appétit !

    Risotto champignons et courgettes Thermomix par maurinehrz
    MiamJ'aimeLoveWowHaha15
  • Illustration du profil de nadinemarie

    nadinemarie a noté 5/5 cette recette, il y a 1 an et 4 mois

    merci rbormi pour ce très bon risotto.

    Risotto champignons et courgettes Thermomix par nadinemarie
    MiamMerciLoveJ'aime13
  • Illustration du profil de lilytomamel

    lilytomamel a noté 5/5 cette recette, il y a 1 an et 3 mois

    Super recette merci beaucoup rien changé à la recette. Fait avec une courgette du jardin 🤗 par contre pas de champignons frais,mis avec 1 boîte de champignons. Mon grand de 12ans à dit mélange courgettes/parmesan pas top🤣 les 2 petits 4ans et 20 mois) ont adoré🥰 recette à refaire 🤗

    Risotto champignons et courgettes Thermomix par lilytomamel
    Risotto champignons et courgettes Thermomix par lilytomamel
    J'aimeMiamLove13
  • Illustration du profil de lowmy95

    lowmy95 a noté 5/5 cette recette, il y a 1 an et 11 mois

    Excellente recette 😁.
    Faite sans champignon pour ma part, avec 2 courgettes.

    Risotto champignons et courgettes Thermomix par lowmy95
    J'aimeMiam13
  • Afficher plus de commentaires
Rejoignez la communauté !

Enregistrez vos meilleures recettes Thermomix et partagez-les !

© cookomix.com Tous droits réservés © 2024 - Mentions Légales - Paramétrer les cookies - Aide

+ \ No newline at end of file From d706c218e82f2639f5032d95b3d708dc1ad1763f Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 2 Dec 2024 02:33:43 +0000 Subject: [PATCH 03/94] Bump version to 15.3.0: Adds support for: - abeautifulmess.com - aldi-nord (multiple) - aldi-sued (multiple) - barefootinthepines.com - betterfoodguru.com - beyondfrosting.com - bitsofcarey.com - brokenovenbaking.com - cakemehometonight.com - cambreabakes.com - colleenchristensennutrition.com - cookiesandcups.com - cookomix.com - cookwell.com - hungryhappens.net - kitchendivas.com - krollskorner.com - quitoque.fr - rewe.de - spainonafork.com - thefoodietakesflight.com Extends fields supported by: - reciperunner - recipetineats - sallysblog - saltpepperskillet - simplycookit - simplyquinoa - skinnytaste - spendwithpennies - staysnatched - sundpaabudget - sunset - sweetpeasandsaffron - tastesoflizzyt - tasty - thehappyfoodie - thekitchenmagpie - thekitchn - therecipecritic - thevintagemixer - thewoksoflife - themodernproper - thinlicious - timesofindia - tineno - tudogostoso - usapears - vegrecipesofindia - wellplated - womensweekly - zenbelly Bugfixes: - maangchi: ingredient header regex fixup - mccormick: filter-out redundant step-number instructions - modernproper, usapears: filter redundant nutrient names from value output - thekitchn: fixup for site name output - timesofindia: search for ingredients only within ingredient-data container - usapears: fixups for `ratings`/`author` retrieval - (library) utils: reject empty input to `get_yields` function - (library) schema.org: don't return zero servings for empty-string `recipeYield` Removals: - sundpaabudget: removal nutritional information - thexpertguides: remove scraper Misc: - python: declare Python3.13 support - test data: add `LICENSE` notice - ci: upgrade to Ubuntu 24.04 for most GitHub Actions workflows - ci: upgrade MacOS version for unittest GitHub Actions workflow - ci: enable `pip` caching in unittest, linters GitHub Actions workflows - ci: restore `unittest-parallel` for unittest GitHub Actions workflow - ci: suppress noisy static-value exception messaging during unittest GitHub Actions workflow - ci: remove dependency on `tox` from GitHub Actions unittest and linters worklows - tests: improve robustness of `DeprecationWarning` test cases - project: update authorship and copyright details - release: GitHub Actions: confirm release commit is found on release branch --- recipe_scrapers/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe_scrapers/__version__.py b/recipe_scrapers/__version__.py index f59bc580d..1609d49b5 100644 --- a/recipe_scrapers/__version__.py +++ b/recipe_scrapers/__version__.py @@ -1 +1 @@ -__version__ = "15.2.1" +__version__ = "15.3.0" From 846d9e759c21eaa88ee95ba03df4114ac0a79f97 Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 2 Dec 2024 03:04:20 +0000 Subject: [PATCH 04/94] Revert "GitHub Actions: releases: confirm commit exists on release branch (#1312)" This reverts commit 07bc48eddb0d78d3e9f57f0f02090ab8ee879977. --- .github/workflows/publish.yaml | 2 -- .github/workflows/test_publish.yaml | 2 -- 2 files changed, 4 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 4fc6fe373..7f10e4b63 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -9,8 +9,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Check that the release commit can be found in a release branch - run: git branch main v14 --contains ${{ github.sha }} | egrep '.+' - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/test_publish.yaml b/.github/workflows/test_publish.yaml index eed9d72db..8e03ef01d 100644 --- a/.github/workflows/test_publish.yaml +++ b/.github/workflows/test_publish.yaml @@ -14,8 +14,6 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 - - name: Check that the release commit can be found in a release branch - run: git branch main v14 --contains ${{ github.sha }} | egrep '.+' - name: Set up Python uses: actions/setup-python@v4 with: From 42310149eedf268239dad8a6f0136b57f842eac7 Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 2 Dec 2024 03:04:34 +0000 Subject: [PATCH 05/94] Bump version to 15.3.1: - release: fixup: temporarily revert #1312. --- recipe_scrapers/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe_scrapers/__version__.py b/recipe_scrapers/__version__.py index 1609d49b5..63b4c27f3 100644 --- a/recipe_scrapers/__version__.py +++ b/recipe_scrapers/__version__.py @@ -1 +1 @@ -__version__ = "15.3.0" +__version__ = "15.3.1" From de6dc334934925b258b3e19d0b2a2f0b33f2812a Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 2 Dec 2024 03:10:10 +0000 Subject: [PATCH 06/94] README: Fixup: justification of section heading underline markup --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 97fd69af4..43b48050a 100644 --- a/README.rst +++ b/README.rst @@ -586,7 +586,7 @@ All the `contributors that helped improving Date: Mon, 2 Dec 2024 03:10:20 +0000 Subject: [PATCH 07/94] Bump version to 15.3.2: - README: Fixup for section heading markup justification --- recipe_scrapers/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe_scrapers/__version__.py b/recipe_scrapers/__version__.py index 63b4c27f3..85829d2f9 100644 --- a/recipe_scrapers/__version__.py +++ b/recipe_scrapers/__version__.py @@ -1 +1 @@ -__version__ = "15.3.1" +__version__ = "15.3.2" From e49df1a278c5f2504ccdbc4124411ae419003f20 Mon Sep 17 00:00:00 2001 From: Julian <108492240+Gamekohl@users.noreply.github.com> Date: Wed, 4 Dec 2024 17:59:48 +0100 Subject: [PATCH 08/94] Add support for madamecuisine.de (#1405) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/madamecuisine.py | 60 + .../madamecuisine.de/madamecuisine_1.json | 51 + .../madamecuisine.de/madamecuisine_1.testhtml | 859 +++ .../madamecuisine.de/madamecuisine_2.json | 40 + .../madamecuisine.de/madamecuisine_2.testhtml | 4984 +++++++++++++++++ 7 files changed, 5997 insertions(+) create mode 100644 recipe_scrapers/madamecuisine.py create mode 100644 tests/test_data/madamecuisine.de/madamecuisine_1.json create mode 100644 tests/test_data/madamecuisine.de/madamecuisine_1.testhtml create mode 100644 tests/test_data/madamecuisine.de/madamecuisine_2.json create mode 100644 tests/test_data/madamecuisine.de/madamecuisine_2.testhtml diff --git a/README.rst b/README.rst index 43b48050a..200fd370c 100644 --- a/README.rst +++ b/README.rst @@ -291,6 +291,7 @@ Scrapers available for: - `http://livelytable.com/ `_ - `https://lovingitvegan.com/ `_ - `https://www.maangchi.com `_ +- `https://www.madamecuisine.de `_ - `https://madensverden.dk/ `_ - `https://madsvin.com/ `_ - `https://marmiton.org/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 2ea62eaf0..74b031f0b 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -239,6 +239,7 @@ from .livelytable import LivelyTable from .lovingitvegan import Lovingitvegan from .maangchi import Maangchi +from .madamecuisine import MadameCuisine from .madensverden import MadensVerden from .madsvin import Madsvin from .marmiton import Marmiton @@ -547,6 +548,7 @@ KuchynaLidla.host(): KuchynaLidla, LittleSunnyKitchen.host(): LittleSunnyKitchen, LeitesCulinaria.host(): LeitesCulinaria, + MadameCuisine.host(): MadameCuisine, McCormick.host(): McCormick, Miljuschka.host(): Miljuschka, ModernHoney.host(): ModernHoney, diff --git a/recipe_scrapers/madamecuisine.py b/recipe_scrapers/madamecuisine.py new file mode 100644 index 000000000..911f353cb --- /dev/null +++ b/recipe_scrapers/madamecuisine.py @@ -0,0 +1,60 @@ +from ._abstract import AbstractScraper +from ._utils import get_yields + + +class MadameCuisine(AbstractScraper): + @classmethod + def host(cls): + return "madamecuisine.de" + + def author(self): + return self.soup.find("meta", {"name": "author"})["content"] + + def title(self): + return self.soup.find("h2", {"class": "wprm-recipe-name"}).get_text() + + def category(self): + return self.soup.find("span", {"class": "wprm-recipe-keyword"}).get_text() + + def total_time(self): + time_elements = self.soup.select( + ".wprm-recipe-details.wprm-recipe-details-minutes" + ) + total_time = 0 + + for time_element in time_elements: + total_time += int(time_element.contents[0].strip()) + + return f"{total_time}" + + def yields(self): + return get_yields(self.soup.find("span", {"class": "wprm-recipe-servings"})) + + def image(self): + return self.soup.select_one(".wp-block-image img")["src"] + + def ingredients(self): + ingredients = self.soup.find_all("li", {"class": "wprm-recipe-ingredient"}) + ingredient_list = [] + + for ingredient in ingredients: + ingredient_list.append(ingredient.get_text().strip()) + + return ingredient_list + + def instructions(self): + instructions = self.soup.find_all( + "div", {"class": "wprm-recipe-instruction-text"} + ) + instruction_list = [] + + for instruction in instructions: + instruction_list.append(instruction.get_text().strip()) + + return "\n".join(instruction_list) + + def cuisine(self): + return self.soup.find("span", {"class": "wprm-recipe-cuisine"}).get_text() + + def description(self): + return self.soup.find("div", {"class": "wprm-recipe-summary"}).get_text() diff --git a/tests/test_data/madamecuisine.de/madamecuisine_1.json b/tests/test_data/madamecuisine.de/madamecuisine_1.json new file mode 100644 index 000000000..52aacf39f --- /dev/null +++ b/tests/test_data/madamecuisine.de/madamecuisine_1.json @@ -0,0 +1,51 @@ +{ + "author": "Sonja", + "canonical_url": "https://www.madamecuisine.de/gemueseeintopf-mit-wintergemuese/", + "site_name": "Madame Cuisine Foodblog", + "host": "madamecuisine.de", + "language": "de", + "title": "Gemüseeintopf mit Wintergemüse", + "ingredients": [ + "1 Stange Lauch", + "2 Karotten", + "3 Stangen Sellerie + das Grün für die Gremolata", + "1 Süßkartoffel ca. 200 g", + "2 Zehen Knoblauch", + "1 Stück Ingwer ca. 2 cm", + "2 EL Olivenöl", + "1 TL getrocknete italienische Kräuter", + "½ TL Kreuzkümmel", + "200 g passierte Tomaten", + "500-600 ml Gemüsebrühe", + "400 g gemischte Bohnen aus der Dose", + "125 g Baby-Spinat oder Schwarzkohl oder ein anderes grünes Blattgemüse", + "Salz, Pfeffer, Piment d'Espelette", + "saure Sahne oder Crème fraîche zum Servieren", + "1 Bio-Zitrone", + "Selleriegrün alternativ glatte Petersilie", + "1 handvoll Walnusskerne", + "1 Zehe Knoblauch", + "4 EL Olivenöl", + "grobes Meersalz" + ], + "instructions_list": [ + "Die äußeren Blätter vom Lauch ggf. entfernen, das untere Ende abschneiden. Anschließend den Lauch der Länge nach halbieren, dann quer in ca. 0,5 cm dicke Stück schneiden. In ein Sieb geben und unter fließendem Wasser gründlich waschen. Gut abtropfen lassen.", + "Die Karotten und die Süßkartoffel schälen, waschen und in nicht zu große Würfel schneiden. Den Sellerie waschen und putzen. Dickere Stangen der Länge nach halbieren, dann quer in kleine Stücke schneiden.", + "Knoblauch und Ingwer schälen und fein hacken.", + "Das Olivenöl in einem großen Topf erhitzen.Lauch, Karotten, Süßkartoffel und Sellerie bei mittlerer Hitze 4-5 Min. anschwitzen. Gelegentlich umrühren. Knoblauch und Ingwer hinzufügen und für 1-2 Min. mit anschwitzen.", + "Getrocknete italienische Kräuter und Kreuzkümmel für 1 Min. einrühren, dann die passierten Tomaten, sowie 500 ml der Gemüsebrühe dazugeben. Den Deckel auf den Topf legen und alles ca. 20 Min. köcheln lassen. Ab und zu umrühren.", + "In der Zwischenzeit das Blattgemüse waschen und etwas trocken tupfen. Falls ihr Schwarzkohl oder Grünkohl verwendet, den harten Stielansatz entfernen. Grob hacken.", + "Die gemischten Bohnen in ein Sieb füllen und unter fließend kaltem Wasser waschen. Gut abtropfen lassen.", + "Blattgemüse und Bohnen für die letzten 5 Min. zum Eintopf geben und gut untermischen. Falls ihr das Gefühl habt, das noch Flüssigkeit fehlt, noch etwas von der Gemüsebrühe hinzufügen. Kräftig mit Salz, Pfeffer und Piment d'Espelette würzen und abschmecken. Bei ausgeschaltetem Herd noch ein paar Min. ziehen lassen.", + "Die Zitrone heiß waschen, dann trocken reiben. Schale fein abreiben und in ein hohes Gefäß geben.", + "Das Selleriegrün (alternativ glatte Petersilie) waschen und trocken tupfen. Grob hacken und zur Zitronenschale geben.", + "Walnusskerne ebenfalls grob hacken. Knoblauch schälen und hacken. Beides zusammen mit 4 EL Olivenöl und etwas grobem Meersalz zum Sellerie und der Zitronenschale geben. Mit dem Stabmixer zu einer Art Paste mixen. Es soll nicht zu fein und cremig sein.", + "Den Eintopf auf Teller verteilen und mit etwas Gremolata und einem Klecks saurer Sahne oder Crème fraîche servieren." + ], + "category": "Eintopf, Gemüseeintopf", + "yields": "4 servings", + "description": "Dieser leckere Eintopf wird mit viel Gemüse, Bohnen, Gewürzen und Kräutern zubereitet. Die Gemüse-Sorten lassen sich - je nach Geschmack und Saison - beliebig variieren. Ein einfaches Essen, das sich wunderbar vorbereiten lässt und durchaus auch Gäste tauglich ist. ", + "total_time": "60", + "cuisine": "Amerikanisch, Deutsch", + "image": "https://www.madamecuisine.de/wp-content/uploads/2024/10/gemueseeintopf-mit-wintergemuese04.jpg" +} diff --git a/tests/test_data/madamecuisine.de/madamecuisine_1.testhtml b/tests/test_data/madamecuisine.de/madamecuisine_1.testhtml new file mode 100644 index 000000000..3e440809b --- /dev/null +++ b/tests/test_data/madamecuisine.de/madamecuisine_1.testhtml @@ -0,0 +1,859 @@ + + + + + + + + + + + + + Gemüseeintopf mit Wintergemüse - Madame Cuisine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Inspiration für ein weiteres Rezept

+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/madamecuisine.de/madamecuisine_2.json b/tests/test_data/madamecuisine.de/madamecuisine_2.json new file mode 100644 index 000000000..8f304b538 --- /dev/null +++ b/tests/test_data/madamecuisine.de/madamecuisine_2.json @@ -0,0 +1,40 @@ +{ + "author": "Sonja", + "canonical_url": "https://www.madamecuisine.de/shakshuka-schakschuka/", + "site_name": "Madame Cuisine Foodblog", + "host": "madamecuisine.de", + "language": "de", + "title": "Shakshuka (Schakschuka) - Israelische Köstlichkeit", + "ingredients": [ + "1 Zwiebel", + "1 Zehe Knoblauch", + "1 rote Paprika", + "2-3 EL Olivenöl", + "½ Teel. Kreuzkümmel", + "½ Teel. süßes Paprikapulver", + "¼ Teel. Cayennepfeffer oder gemahlenes Chilipulver", + "1 Dose ganze geschälte Tomaten (380g)", + "Salz und Pfeffer", + "100 g Schafskäse", + "4 Eier", + "2-3 EL frischer Koriander", + "Brot zum Servieren" + ], + "instructions_list": [ + "Zwiebel schälen, halbieren und in sehr dünne Scheiben schneiden. Knoblauch ebenfalls schälen und fein hacken. Paprika waschen, vierteln, entkernen und quer in feine Streifen schneiden.", + "In einer großen, am besten gusseisernen, Pfanne (die Pfanne darf keinen Plastikgriff haben, da sie später noch in den Ofen gestellt wird!) das Olivenöl erhitzen. Zwiebel und Paprika darin bei kleiner Hitze für ca. 20 Minuten schmoren, bis sie schön weich sind. Dabei gelegentlich umrühren. Für die letzten 2-3 Minuten den Knoblauch hinzufügen.", + "Den Backofen auf 190 Grad Ober-/Unterhitze vorheizen.", + "Kreuzkümmel, Paprikapulver und Cayennepfeffer oder Chilipulver dazugeben und für eine Minuten rösten.", + "Tomaten aus der Dose zum Gemüse geben und die Tomaten mit dem Pfannenwender vorsichtig zerdrücken. Alles mit Salz und Pfeffer würzen und in ca. 10-15 Minuten einkochen lassen.", + "Den Schafskäse zerbröckeln und unter die Soße rühren.", + "Nun die Eier vorsichtig am Pfannenrand aufschlagen und auf die Tomatensoße gleiten lassen, vorher ggf. mit einem Löffel kleine Mulden in die Soße formen. Etwas Salz und Pfeffer über die Eier geben.", + "Die Pfanne in den Ofen schieben und für ca. 8-10 Minuten backen, bis die Eier gestockt sind.", + "Vor dem Servieren mit frischem Koriander bestreuen und dann einfach dicke Scheiben Brot in die Soße tunken. Köstlich!!" + ], + "category": "Paprika, Schakschuka, Shakshuka, Tomaten, Versunkene Eier", + "yields": "2 servings", + "description": "Shakshuka, das sind versunkene Eier in einer Tomatensoße mit Paprika und Zwiebeln. Die Soße in einer Pfanne langsam einköcheln, dann die Eier im Ofen stocken lassen.", + "total_time": "60", + "cuisine": "Israelisch / Arabisch", + "image": "https://www.madamecuisine.de/wp-content/uploads/2019/11/shakshuka02-720x480.jpg" +} diff --git a/tests/test_data/madamecuisine.de/madamecuisine_2.testhtml b/tests/test_data/madamecuisine.de/madamecuisine_2.testhtml new file mode 100644 index 000000000..dee127f84 --- /dev/null +++ b/tests/test_data/madamecuisine.de/madamecuisine_2.testhtml @@ -0,0 +1,4984 @@ + + + + + + + + + + + + + + Shakshuka (Schakschuka) - Israelische Köstlichkeit - Madame Cuisine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Inspiration für ein weiteres Rezept

+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 5093d2b437d9104a51ca2419507a58ac8b135a04 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 4 Dec 2024 17:02:00 +0000 Subject: [PATCH 09/94] madamecuisine: nitpick/consistency fixup: return integer values from `total_time` field --- recipe_scrapers/madamecuisine.py | 2 +- tests/test_data/madamecuisine.de/madamecuisine_1.json | 2 +- tests/test_data/madamecuisine.de/madamecuisine_2.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/recipe_scrapers/madamecuisine.py b/recipe_scrapers/madamecuisine.py index 911f353cb..ad56367d0 100644 --- a/recipe_scrapers/madamecuisine.py +++ b/recipe_scrapers/madamecuisine.py @@ -25,7 +25,7 @@ def total_time(self): for time_element in time_elements: total_time += int(time_element.contents[0].strip()) - return f"{total_time}" + return total_time def yields(self): return get_yields(self.soup.find("span", {"class": "wprm-recipe-servings"})) diff --git a/tests/test_data/madamecuisine.de/madamecuisine_1.json b/tests/test_data/madamecuisine.de/madamecuisine_1.json index 52aacf39f..4646f6507 100644 --- a/tests/test_data/madamecuisine.de/madamecuisine_1.json +++ b/tests/test_data/madamecuisine.de/madamecuisine_1.json @@ -45,7 +45,7 @@ "category": "Eintopf, Gemüseeintopf", "yields": "4 servings", "description": "Dieser leckere Eintopf wird mit viel Gemüse, Bohnen, Gewürzen und Kräutern zubereitet. Die Gemüse-Sorten lassen sich - je nach Geschmack und Saison - beliebig variieren. Ein einfaches Essen, das sich wunderbar vorbereiten lässt und durchaus auch Gäste tauglich ist. ", - "total_time": "60", + "total_time": 60, "cuisine": "Amerikanisch, Deutsch", "image": "https://www.madamecuisine.de/wp-content/uploads/2024/10/gemueseeintopf-mit-wintergemuese04.jpg" } diff --git a/tests/test_data/madamecuisine.de/madamecuisine_2.json b/tests/test_data/madamecuisine.de/madamecuisine_2.json index 8f304b538..97af5c1b7 100644 --- a/tests/test_data/madamecuisine.de/madamecuisine_2.json +++ b/tests/test_data/madamecuisine.de/madamecuisine_2.json @@ -34,7 +34,7 @@ "category": "Paprika, Schakschuka, Shakshuka, Tomaten, Versunkene Eier", "yields": "2 servings", "description": "Shakshuka, das sind versunkene Eier in einer Tomatensoße mit Paprika und Zwiebeln. Die Soße in einer Pfanne langsam einköcheln, dann die Eier im Ofen stocken lassen.", - "total_time": "60", + "total_time": 60, "cuisine": "Israelisch / Arabisch", "image": "https://www.madamecuisine.de/wp-content/uploads/2019/11/shakshuka02-720x480.jpg" } From e3c7ee929555ef348836a4c2513dc2488329683b Mon Sep 17 00:00:00 2001 From: bencondemi <105668786+bencondemi@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:04:58 -0500 Subject: [PATCH 10/94] Added scraper for 40aprons.com (#1408) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/fortyaprons.py | 72 + .../test_data/40aprons.com/fortyaprons_1.json | 104 + .../40aprons.com/fortyaprons_1.testhtml | 2305 ++++++++++++++++ .../test_data/40aprons.com/fortyaprons_2.json | 48 + .../40aprons.com/fortyaprons_2.testhtml | 2327 +++++++++++++++++ 7 files changed, 4859 insertions(+) create mode 100644 recipe_scrapers/fortyaprons.py create mode 100644 tests/test_data/40aprons.com/fortyaprons_1.json create mode 100644 tests/test_data/40aprons.com/fortyaprons_1.testhtml create mode 100644 tests/test_data/40aprons.com/fortyaprons_2.json create mode 100644 tests/test_data/40aprons.com/fortyaprons_2.testhtml diff --git a/README.rst b/README.rst index 200fd370c..b8c4ca1ec 100644 --- a/README.rst +++ b/README.rst @@ -78,6 +78,7 @@ Scrapers available for: - `https://101cookbooks.com/ `_ - `https://15gram.be `_ +- `https://40aprons.com/ `_ - `https://www.750g.com `_ - `https://abeautifulmess.com/ `_ - `https://aberlehome.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 74b031f0b..128fff043 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -161,6 +161,7 @@ from .foodrepublic import FoodRepublic from .forksoverknives import ForksOverKnives from .forktospoon import ForkToSpoon +from .fortyaprons import FortyAprons from .franzoesischkochen import FranzoesischKochen from .g750g import G750g from .gesundaktiv import GesundAktiv @@ -529,6 +530,7 @@ FamilyfoodOnTheTable.host(): FamilyfoodOnTheTable, FifteenGram.host(): FifteenGram, FitSlowCookerQueen.host(): FitSlowCookerQueen, + FortyAprons.host(): FortyAprons, GlutenFreeOnAShoeString.host(): GlutenFreeOnAShoeString, GourmetTraveller.host(): GourmetTraveller, GrandFrais.host(): GrandFrais, diff --git a/recipe_scrapers/fortyaprons.py b/recipe_scrapers/fortyaprons.py new file mode 100644 index 000000000..76ac209f4 --- /dev/null +++ b/recipe_scrapers/fortyaprons.py @@ -0,0 +1,72 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class FortyAprons(AbstractScraper): + @classmethod + def host(cls): + return "40aprons.com" + + def author(self): + return self.schema.author() + + def description(self): + return self.schema.description() + + def image(self): + return self.schema.image() + + def ingredients(self): + return self.schema.ingredients() + + def instructions(self): + return self.schema.instructions() + + def title(self): + return self.schema.title() + + def total_time(self): + return self.schema.total_time() + + def yields(self): + return self.schema.yields() + + def category(self): + return self.schema.category() + + def cook_time(self): + return self.schema.cook_time() + + def cuisine(self): + return self.schema.cuisine() + + def nutrients(self): + return self.schema.nutrients() + + def prep_time(self): + return self.schema.prep_time() + + def ratings(self): + return self.schema.ratings() + + def ratings_count(self): + return self.schema.ratings_count() + + def equipment(self): + equipment_elements = self.soup.select(".wprm-recipe-equipment-name") + return ( + [element.get_text() for element in equipment_elements] + if equipment_elements + else None + ) + + def keywords(self): + return self.schema.keywords() + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + "h4.wprm-recipe-group-name", + "li.wprm-recipe-ingredient", + ) diff --git a/tests/test_data/40aprons.com/fortyaprons_1.json b/tests/test_data/40aprons.com/fortyaprons_1.json new file mode 100644 index 000000000..3bcb46694 --- /dev/null +++ b/tests/test_data/40aprons.com/fortyaprons_1.json @@ -0,0 +1,104 @@ +{ + "author": "Cheryl Malik", + "canonical_url": "https://40aprons.com/rosemary-raspberry-vodka-fizz/", + "site_name": "40 Aprons", + "host": "40aprons.com", + "language": "en-US", + "title": "Raspberry Cocktails with Rosemary", + "ingredients": [ + "1 tablespoon rosemary needles", + "1 ½ cups frozen raspberries (defrosted)", + "juice of 1 lemon (approximately 2 tablespoons)", + "5 tablespoons sugar (¼ cup + 1 tablespoon)", + "¾ cup water", + "1 tablespoon cornstarch", + "1 ½ ounces vodka (or gin)", + "½ ounce St. Germaine elderflower liqueur", + "1 ½ ounces raspberry-rosemary syrup (made from ingredients above)", + "ice", + "1 tablespoon soda water", + "1 tablespoon champagne", + "ice", + "rosemary sprigs", + "raspberries" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 tablespoon rosemary needles", + "1 ½ cups frozen raspberries (defrosted)", + "juice of 1 lemon (approximately 2 tablespoons)", + "5 tablespoons sugar (¼ cup + 1 tablespoon)", + "¾ cup water", + "1 tablespoon cornstarch" + ], + "purpose": "For the Raspberry-Rosemary Syrup (Makes Enough for 6–8 Cocktails)" + }, + { + "ingredients": [ + "1 ½ ounces vodka (or gin)", + "½ ounce St. Germaine elderflower liqueur", + "1 ½ ounces raspberry-rosemary syrup (made from ingredients above)", + "ice", + "1 tablespoon soda water", + "1 tablespoon champagne" + ], + "purpose": "For the Cocktail (Makes Enough for 1 Cocktail)" + }, + { + "ingredients": [ + "ice", + "rosemary sprigs", + "raspberries" + ], + "purpose": "Serving Suggestions (All Optional)" + } + ], + "instructions_list": [ + "For the Syrup (Makes Enough for 6-8 Cocktails)", + "Add 1 tablespoon rosemary needles to small bowl. Muddle rosemary needles with muddler or back of wooden spoon to release oils.", + "Place small saucepan on stovetop over high heat. Add muddled rosemary needles, 1 ½ cups frozen raspberries, juice of lemon, 5 tablespoons sugar, ¾ cup water, and 1 tablespoon cornstarch to saucepan. Stir to incorporate, then bring mixture to rolling boil.", + "When mixture begins to boil, immediately reduce heat under saucepan to low.", + "Use potato masher to mash raspberries completely, then stir mixture and simmer 10 minutes.", + "After 10 minutes, remove saucepan from heat and set aside. Let mixture cool completely.", + "Once cooled, pour mixture through fine-mesh strainer or nut-milk bag and into airtight container. Use immediately or refrigerate until ready to use.", + "For the Cocktail (Makes Enough for 1 Cocktail)", + "Add 1 ½ ounces vodka (or gin), ½ ounce St. Germaine elderflower liqueur, 1 ½ ounces raspberry-rosemary syrup, and ice to cocktail shaker. Shake vigorously.", + "Strain cocktail into glass, with or without ice. Add 1 tablespoon soda water and stir to incorporate into drink. Top cocktail with 1 tablespoon champagnethen garnish with rosemary sprigs and raspberries if desired. Serve immediately." + ], + "category": "Drinks", + "yields": "1 serving", + "description": "A flavorful, vibrant cocktail blending fruity raspberry, woodsy rosemary, floral St. Germaine, and bubbly champagne.", + "total_time": 25, + "cook_time": 15, + "prep_time": 10, + "cuisine": "American", + "ratings": 5.0, + "ratings_count": 1.0, + "equipment": [ + "Small bowl", + "Muddler", + "Small saucepan", + "Potato masher", + "Fine mesh sieve or nut-milk bag", + "Cocktail shaker" + ], + "nutrients": { + "servingSize": "1 cocktail", + "calories": "357 kcal", + "fatContent": "1 g", + "saturatedFatContent": "1 g", + "unsaturatedFatContent": "2 g", + "carbohydrateContent": "36 g", + "sugarContent": "30 g", + "proteinContent": "1 g", + "sodiumContent": "18 mg", + "fiberContent": "4 g" + }, + "image": "https://40aprons.com/wp-content/uploads/2015/12/raspberry-cocktails-rosemary-01.jpg", + "keywords": [ + "christmas dinner", + "holiday drink", + "winter flavors" + ] +} diff --git a/tests/test_data/40aprons.com/fortyaprons_1.testhtml b/tests/test_data/40aprons.com/fortyaprons_1.testhtml new file mode 100644 index 000000000..a7a4977cc --- /dev/null +++ b/tests/test_data/40aprons.com/fortyaprons_1.testhtml @@ -0,0 +1,2305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Raspberry Cocktails with Rosemary - 40 Aprons + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ +
+ + 40 Aprons Premium (Ad free!) +
+ +
+
+ + +
+ +
+
+
+
+
+
+ +
+
+

This Post May Contain Affiliate Links. Please Read Our Disclosure Policy.

+
+ +

This vibrant, refreshing, and festive raspberry cocktail is perfect for the holiday season! Sweetened with a homemade syrup made from mashed raspberries, elderflower liqueur, and muddled rosemary, this vodka (or gin!) drink is topped off with a champagne floater. Great for Thanksgiving dinner or your next Christmas party!

+ + + +
A bright red raspberry cocktail in a glass, garnished with a raspberry and sprig of rosemary.
+ + + + + +
+

Before You Get Started

+ + + +
    +
  • For mixed drinks like this raspberry cocktail, you don’t need to reach for any top shelf vodka or gin. Save those pricy boozes for drinks where they’re the star and not supporting cast! I’d recommend Fords Gin or Ketel One vodka here, but as long as you use something you enjoy the flavor of, you’ll be fine.
  • +
+
+ + + +

How to Make This Recipe

+ + + +

See recipe card below for full list of measurements, ingredients, and instructions.

+ + + +

Muddle the rosemary.

+ + + +

Place the rosemary needles in a small bowl and use a muddler to press the herbs against the bottom or side of the bowl. Twist the muddler in one direction and repeat, pressing the herbs just until they release fragrant oil. Be gentle, though – too much pressure will make them release a bitter-tasting chlorophyll.

+ + + +
+

If you don’t have an actual muddler tool, you can use the back or the end of a wooden spoon, or a pestle from a mortar and pestle.

+
+ + + +

Make the Syrup.

+ + + +

Transfer the muddled rosemary needles and the oil they released to the saucepan, then add the rest of syrup ingredients. Stir everything together and bring the mixture to a boil, then immediately reduce the heat to low and mash the raspberries with a potato masher.

+ + + +

Simmer & Strain.

+ + + +

After you’ve mashed the raspberries, let the mixture simmer for 10 minutes, then move the saucepan from the heat and let the syrup mixture cool completely. Once it’s cooled, pour the mixture through a fine-mesh strainer, catching all of the raspberry seeds and rosemary needles. You don’t want those in your syrup!

+ + + +

Mix Your Drink.

+ + + +

Combine gin or vodka, elderflower liqueur, some of that fresh raspberry-rosemary syrup, and ice in a cocktail shaker. Shake everything really well, then strain the liquid into a glass. With or without fresh ice, up to you! Add a floater of champagne and a floater of soda water, then garnish and enjoy!

+ + + + + + + +

What I Love About This Recipe

+ + + +
    +
  • This raspberry cocktail is so easy to make, even with the homemade syrup! Plus, the prepared syrup will keep for a couple of weeks in the fridge, so you can have some on hand to make an evening cocktail even more easily.
  • + + + +
  • There’s a ton of delicious flavor in this cocktail. Woodsy rosemary, fruity raspberry, floral elderflower, the sweetness of the syrup. Everything is balanced perfectly, and the drink beautifully festive, too.
  • + + + +
  • Frozen raspberries work so well here – no need to track down some out-of-season fresh ones. Just defrost the frozen berries overnight in the fridge first!
  • +
+ + +
+ +
+
+
Recipe By: Cheryl Malik
+ +
+ +
+
5 from 1 vote
+

Raspberry Cocktails with Rosemary

+ +
Prep 10 minutes
Cook 15 minutes
Total 25 minutes
+
+ + +
A flavorful, vibrant cocktail blending fruity raspberry, woodsy rosemary, floral St. Germaine, and bubbly champagne.
+
+ +
+ +
+ + +
+
+
+
+
1 cocktail
+ +
+ + +
+ +

Equipment

  • Small bowl
  • Muddler
  • Small saucepan
  • Potato masher
  • Fine mesh sieve or nut-milk bag
  • Cocktail shaker
+

Ingredients

For the Raspberry-Rosemary Syrup (Makes Enough for 68 Cocktails)

  • 1 tablespoon rosemary needles
  • 1 ½ cups frozen raspberries defrosted
  • juice of 1 lemon approximately 2 tablespoons
  • 5 tablespoons sugar ¼ cup + 1 tablespoon
  • ¾ cup water
  • 1 tablespoon cornstarch

For the Cocktail (Makes Enough for 1 Cocktail)

  • 1 ½ ounces vodka or gin
  • ½ ounce St. Germaine elderflower liqueur
  • 1 ½ ounces raspberry-rosemary syrup made from ingredients above
  • ice
  • 1 tablespoon soda water
  • 1 tablespoon champagne

Serving Suggestions (All Optional)

  • ice
  • rosemary sprigs
  • raspberries
+
+
+ +

Instructions

For the Syrup (Makes Enough for 68 Cocktails)

  • Add 1 tablespoon rosemary needles to small bowl. Muddle rosemary needles with muddler or back of wooden spoon to release oils.
  • Place small saucepan on stovetop over high heat. Add muddled rosemary needles, 1 ½ cups frozen raspberries, juice of 1 lemon, 5 tablespoons sugar, ¾ cup water, and 1 tablespoon cornstarch to saucepan. Stir to incorporate, then bring mixture to rolling boil.
  • When mixture begins to boil, immediately reduce heat under saucepan to low.
  • Use potato masher to mash raspberries completely, then stir mixture and simmer 10 minutes.
  • After 10 minutes, remove saucepan from heat and set aside. Let mixture cool completely.
  • Once cooled, pour mixture through fine-mesh strainer or nut-milk bag and into airtight container. Use immediately or refrigerate until ready to use.

For the Cocktail (Makes Enough for 1 Cocktail)

  • Add 1 ½ ounces vodka (or gin), ½ ounce St. Germaine elderflower liqueur, 1 ½ ounces raspberry-rosemary syrup, and ice to cocktail shaker. Shake vigorously.
  • Strain cocktail into glass, with or without ice. Add 1 tablespoon soda water and stir to incorporate into drink. Top cocktail with 1 tablespoon champagnethen garnish with rosemary sprigs and raspberries if desired. Serve immediately.
+
+ +
+
+ +
+ + + + +
+

Approximate Information for One Serving

Serving Size: 1cocktailCalories: 357calProtein: 1gFat: 1gSaturated Fat: 1gSodium: 18mgPotassium: 130mgTotal Carbs: 36gFiber: 4gSugar: 30gNet Carbs: 32gVitamin A: 78IUVitamin C: 16mgCalcium: 29mgIron: 1mg
+
+
Nutrition Disclaimers
Number of total servings shown is approximate. Actual number of servings will depend on your preferred portion sizes.
+ +
+
Nutritional values shown are general guidelines and reflect information for 1 serving using the ingredients listed, not including any optional ingredients. Actual macros may vary slightly depending on specific brands and types of ingredients used.
+
+
To determine the weight of one serving, prepare the recipe as instructed. Weigh the finished recipe, then divide the weight of the finished recipe (not including the weight of the container the food is in) by the desired number of servings. Result will be the weight of one serving.
+ +
+
+ +
+ +
+

Did You Make This Recipe?

+

Tag @40aprons on Instagram and be sure to leave a review on the blog post!

+
+ + +

More Holiday Recipes We Love

+ + + + +
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+

Leave A Review

Your email address will not be published. Required fields are marked *

+ +
+ Recipe Rating +




+
+
+

+ +
+
+

+ +

+

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments

    +
  1. + +
      +
    1. +
      + + +
      +

      The amounts are listed in the recipe card. It’s just above the comment box!

      +
      + +
      +
    2. +
    +
  2. +
  3. + +
  4. +
  5. +
    + + +
    +

    These look amazing! I can’t wait to make them. Great looking photo’s. Happy New Year!5 stars

    +
    + +
    +
  6. +
+
+
+
+
+

Where To Next?

+ +
+
+
+
+
+
+ +
+
+
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ +
+ +
+

our promise

+ + + +

At 40 Aprons our goal is simple. To serve up delicious, approachable recipes the whole family can enjoy

+ + + +
+ + + +
+
join the list!
+ + + +

A curated selection of our most recent recipes, delivered straight to your inbox once a week.

+ + + + +
+ + + +
+ + + +
+ +
+ +
+ + +
+ + + + + + + + + + +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/40aprons.com/fortyaprons_2.json b/tests/test_data/40aprons.com/fortyaprons_2.json new file mode 100644 index 000000000..01c715e5a --- /dev/null +++ b/tests/test_data/40aprons.com/fortyaprons_2.json @@ -0,0 +1,48 @@ +{ + "author": "Cheryl Malik", + "canonical_url": "https://40aprons.com/easy-perfect-caramel-sauce/", + "site_name": "40 Aprons", + "host": "40aprons.com", + "language": "en-US", + "title": "Easy Homemade Caramel Sauce", + "ingredients": [ + "½ cup water", + "1 ½ cups granulated sugar", + "3 tablespoons unsalted butter (at room temperature)", + "1 cup whipping cream (at room temperature)" + ], + "instructions_list": [ + "Place large saucepan on stovetop over medium-low heat. Add ½ cup water and 1 ½ cups granulated sugar to saucepan, then slowly whisk ingredients together until sugar has dissolved completely, approximately 5 minutes.", + "Once sugar has dissolved, increase heat under saucepan to medium-high. Let syrup come to boil, then boil syrup just until golden, approximately 10 to 12 minutes. Occasionally, brush down sides of pan with pastry brush dipped into water to prevent or stop any crystallization. Swirl pan as needed if sugar clumps.", + "When syrup is golden, reduce heat under saucepan to low and remove saucepan from heat. Add 3 tablespoons unsalted butter to saucepan and whisk to incorporate.", + "Once butter is incorporated, gradually add 1 cup whipping cream in small increments while whisking constantly. Mixture will bubble vigorously with each addition. Repeat until all cream has been added and incorporated.", + "After whipping cream is added, return saucepan to low heat. Gently stir mixture until sauce is completely smooth.", + "Carefully transfer caramel sauce to jar or serving container. Allow sauce to cool to lukewarm temperature before serving." + ], + "category": "Dessert,Sauce", + "yields": "8 servings", + "description": "Sweet, sticky, rich caramel sauce - made quick and easy in your own kitchen!", + "total_time": 20, + "cook_time": 15, + "prep_time": 5, + "cuisine": "American", + "nutrients": { + "servingSize": "1 serving", + "calories": "283 kcal", + "fatContent": "15 g", + "saturatedFatContent": "10 g", + "unsaturatedFatContent": "7 g", + "transFatContent": "0.2 g", + "carbohydrateContent": "38 g", + "sugarContent": "38 g", + "proteinContent": "1 g", + "sodiumContent": "10 mg", + "cholesterolContent": "45 mg" + }, + "image": "https://40aprons.com/wp-content/uploads/2012/12/easy-caramel-sauce-2.jpg", + "keywords": [ + "autumn recipe", + "easy to make", + "holiday" + ] +} diff --git a/tests/test_data/40aprons.com/fortyaprons_2.testhtml b/tests/test_data/40aprons.com/fortyaprons_2.testhtml new file mode 100644 index 000000000..4abd0660d --- /dev/null +++ b/tests/test_data/40aprons.com/fortyaprons_2.testhtml @@ -0,0 +1,2327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Easy Homemade Caramel Sauce - 40 Aprons + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ +
+ + 40 Aprons Premium (Ad free!) +
+ +
+
+ + +
+ +
+
+
+
+
+
+ +
+
+

This Post May Contain Affiliate Links. Please Read Our Disclosure Policy.

+
+ +

Meet the simple, 4-ingredient recipe for homemade caramel sauce will replace your store-bought jars for good. It’s sweet, sticky, and deliciously rich, with that beautifully amber color that screams “caramel”. Use it on top of fruit or ice cream, drizzled onto cheesecake, stirred into a latte, or drink it straight out of the bowl – I won’t judge!

+ + + +
A spoonful of caramel sauce being lifted out of a glass jar of caramel sauce.
+ + + +
+ + +
+

Before You Get Started

+ + + +
    +
  • Use a light-colored saucepan if you have one! A saucepan that’s black or dark grey on the inside can be a little misleading, making the caramel look darker than it actually is. Since the color of the sauce is a key component in the timing, you want to see it as accurately as possible!
  • + + + +
  • This recipe calls for whipping cream, not heavy whipping cream. The difference between the two is slight, with HWC simply having a higher fat content. We didn’t test this recipe with HWC, though, so your results may vary slightly if you use it instead of regular whipping cream.
  • + + + +
  • To prevent curdling or separation, your butter and whipping cream must be at room temperature before adding them to the hot syrup. Don’t skip this!
  • +
+
+
+ + + +
+

How to Make This Recipe

+ + + +

See recipe card below for full list of measurements, ingredients, and instructions.

+ + + +

All About That Base.

+ + + +

To make the base of your caramel sauce, add the sugar and water to a large saucepan and simmer the mixture over medium-low heat, stirring until the sugar is completely dissolved. The mixture will look a little cloudy at first, but that’s ok – it’ll clear up after a few minutes.

Once it does, raise the heat under the saucepan to medium-high and bring the mixture to a boil. Don’t stir the syrup again. Instead, carefully pick up the saucepan and swirl it a little to break up any clumps of sugar, and use a pastry brush dipped in water to wipe down the insides of the pan if you see crystals start to form.

+ + + +
+

A Note from Cheryl: Do this just until the syrup is a pretty golden color. I find that, once it’s dark enough to be considered “amber”, it’s likely burnt.

+
+ + + +

Butter it up.

+ + + +

Take the saucepan off the heat and let it cool just slightly. Add room temperature butter and whisk the mixture well until the butter’s melted and mixed in.

+ + + +

The Big Finish.

+ + + +

Pour in the room-temperature whipping cream in small increments (say, ¼ cup at a time) and whisk everything together before adding more. The caramel will bubble each time you add the cream, so don’t let that startle you. Once all the cream’s added and mixed in, return the saucepan to low heat and simmer it just a few minutes, stirring until it’s completely smooth. It may seem too thin right now, but it will thicken up as it cools!

Once the sauce is smooth, transfer it to a jar or serving container and let it cool until it’s lukewarm or so, then serve it however you like!

+ + + + +
+ + + +
+

What I Love About This Recipe

+ + + +
    +
  • I’ve tried my hand at many a caramel recipe over the years, and without fail I always come back to this one! It’s just so simple and the results are everything you could ever want from a caramel sauce. Sweet, rich, thick, gooey – not to mention that gorgeous caramel color!
  • + + + +
  • It only takes FOUR INGREDIENTS! Water, sugar, butter, and whipping cream. If you’re a baker or general dessert lover, you probably have all of those on hand already.
  • + + + +
  • What’s better than a recipe you don’t need any special ingredients to make? I don’t know, maybe one that’s ready in roughly 15 minutes?! Yup, you can whip up a caramel sauce in basically no time at all if you use this easy recipe. Perfect for a low-effort holiday dessert or a sudden sweet tooth craving.
  • +
+
+ + + +
+

Recipe Variations

+ + + +
    +
  • Sweetener: For a richer, deeper, more butterscotch-like flavor, you can replace the white sugar with light or dark brown sugar. If you need to go sugar-free, try our recipe for 3-Ingredient Keto Caramel Sauce.
  • + + + +
  • Salted Caramel: A pinch of salt, sea salt, or flake salt is all you need to transform this easy caramel sauce into a salted caramel sauce! Salt plays off the sweetness of the sugar beautifully – just be careful not to overdo it.
  • +
+ + + +
+

Making changes to a recipe can result in recipe failure. Any substitutions or variations listed are simple changes that I believe will work in this recipe, but results are not guaranteed.

+
+
+ + +
+ +
+
+
Recipe By: Cheryl Malik
+ +
+ +
+ +

Easy Homemade Caramel Sauce

+ +
Prep 5 minutes
Cook 15 minutes
Total 20 minutes
+
+ + +
Sweet, sticky, rich caramel sauce – made quick and easy in your own kitchen!
+
+ +
+ +
+ + +
+
+
+
+
8 servings
+ +
+ + +
+ +

Equipment

  • Large saucepan light-colored saucepan recommended
  • whisk
  • Pastry brush
+

Ingredients

  • ½ cup water
  • 1 ½ cups granulated sugar
  • 3 tablespoons unsalted butter at room temperature
  • 1 cup whipping cream at room temperature
+
+
+ +

Instructions

  • Place large saucepan on stovetop over medium-low heat. Add ½ cup water and 1 ½ cups granulated sugar to saucepan, then slowly whisk ingredients together until sugar has dissolved completely, approximately 5 minutes.
  • Once sugar has dissolved, increase heat under saucepan to medium-high. Let syrup come to boil, then boil syrup just until golden, approximately 10 to 12 minutes. Occasionally, brush down sides of pan with pastry brush dipped into water to prevent or stop any crystallization. Swirl pan as needed if sugar clumps.
  • When syrup is golden, reduce heat under saucepan to low and remove saucepan from heat. Add 3 tablespoons unsalted butter to saucepan and whisk to incorporate.
  • Once butter is incorporated, gradually add 1 cup whipping cream in small increments while whisking constantly. Mixture will bubble vigorously with each addition. Repeat until all cream has been added and incorporated.
  • After whipping cream is added, return saucepan to low heat. Gently stir mixture until sauce is completely smooth.
  • Carefully transfer caramel sauce to jar or serving container. Allow sauce to cool to lukewarm temperature before serving.
+
+ +
    +
  • Whipping Cream: This recipe calls for whipping cream, which has a lower fat content than heavy whipping cream. We didn’t test this recipe with heavy whipping cream and can’t say what adjustments might be needed to accomodate the higher fat content.
  • +
  • Leftovers: Cool any remaining caramel sauce completely, then refrigerate sauce in an airtight container up to 1 week. Reheat sauce on stovetop over low heat or in the microwave.
  • +
+
+ +
+ + + + +
+

Approximate Information for One Serving

Serving Size: 1servingCalories: 283calProtein: 1gFat: 15gSaturated Fat: 10gTrans Fat: 0.2gCholesterol: 45mgSodium: 10mgPotassium: 30mgTotal Carbs: 38gSugar: 38gNet Carbs: 38gVitamin A: 569IUVitamin C: 0.2mgCalcium: 22mgIron: 0.1mg
+
+
Nutrition Disclaimers
Number of total servings shown is approximate. Actual number of servings will depend on your preferred portion sizes.
+ +
+
Nutritional values shown are general guidelines and reflect information for 1 serving using the ingredients listed, not including any optional ingredients. Actual macros may vary slightly depending on specific brands and types of ingredients used.
+
+
To determine the weight of one serving, prepare the recipe as instructed. Weigh the finished recipe, then divide the weight of the finished recipe (not including the weight of the container the food is in) by the desired number of servings. Result will be the weight of one serving.
+ +
+
+ +
+ +
+

Did You Make This Recipe?

+

Tag @40aprons on Instagram and be sure to leave a review on the blog post!

+
+ + +

Frequently Asked Questions

+ + + +
Why is my caramel sauce grainy?

If you stir the mixture as while it’s boiling, you’ll cause crystals to form, and those crystals will give your sauce a grainy texture. That also happens if the sauce goes up the sides of the saucepan and starts to crystallize, so make sure you’re keeping an eye on it and wiping down the saucepan as needed.

How do I store my caramel sauce?

Let it cool completely, then refrigerate it in an airtight container! It’ll keep for 1-2 weeks if stored properly. Reheat it as needed on the stovetop or in the microwave.

Can I fix my caramel sauce if it’s grainy?

Yes! Add 2-3 tablespoons warm water, bring the mixture to a boil, then whisk the ingredients together until the sugar crystals have fully dissolved and the sauce is smooth again. You can add a little more water if you need to, just be careful not to overdo it.

+ + + +

More Delectably Sweet Recipes You’ll Love

+ + + + +
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+

Leave A Review

Your email address will not be published. Required fields are marked *

+ +
+ Recipe Rating +




+
+
+

+ +
+
+

+ +

+

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments

    +
  1. + +
      +
    1. + +
    2. +
    +
  2. +
  3. + +
      +
    1. + +
    2. +
    +
  4. +
+
+
+
+
+

Where To Next?

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ +
+ +
+

our promise

+ + + +

At 40 Aprons our goal is simple. To serve up delicious, approachable recipes the whole family can enjoy

+ + + +
+ + + +
+
join the list!
+ + + +

A curated selection of our most recent recipes, delivered straight to your inbox once a week.

+ + + + +
+ + + +
+ + + +
+ +
+ +
+ + +
+ + + + + + + + + + +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 1a1e014a72d83d68d34ce8651b100d91eb14e913 Mon Sep 17 00:00:00 2001 From: bencondemi <105668786+bencondemi@users.noreply.github.com> Date: Thu, 5 Dec 2024 23:42:03 -0500 Subject: [PATCH 11/94] Added scraper for IrishCentral (#1416) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/irishcentral.py | 101 ++ .../irishcentral.com/irishcentral.json | 36 + .../irishcentral.com/irishcentral.testhtml | 1371 +++++++++++++++++ 5 files changed, 1511 insertions(+) create mode 100644 recipe_scrapers/irishcentral.py create mode 100644 tests/test_data/irishcentral.com/irishcentral.json create mode 100644 tests/test_data/irishcentral.com/irishcentral.testhtml diff --git a/README.rst b/README.rst index b8c4ca1ec..f73fd907d 100644 --- a/README.rst +++ b/README.rst @@ -251,6 +251,7 @@ Scrapers available for: - `https://www.innit.com/ `_ - `https://insanelygoodrecipes.com `_ - `https://inspiralized.com/ `_ +- `https://irishcentral.com/ `_ - `https://izzycooking.com/ `_ - `https://jamieoliver.com/ `_ - `https://jimcooksfoodgood.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 128fff043..566272f31 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -199,6 +199,7 @@ from .innit import Innit from .insanelygoodrecipes import InsanelyGoodRecipes from .inspiralized import Inspiralized +from .irishcentral import IrishCentral from .izzycooking import IzzyCooking from .jamieoliver import JamieOliver from .jimcooksfoodgood import JimCooksFoodGood @@ -538,6 +539,7 @@ HungryHappens.host(): HungryHappens, InBloomBakery.host(): InBloomBakery, InGoodFlavor.host(): InGoodFlavor, + IrishCentral.host(): IrishCentral, JoCooks.host(): JoCooks, JoshuaWeissman.host(): JoshuaWeissman, JoyTheBaker.host(): JoyTheBaker, diff --git a/recipe_scrapers/irishcentral.py b/recipe_scrapers/irishcentral.py new file mode 100644 index 000000000..daeaf0b94 --- /dev/null +++ b/recipe_scrapers/irishcentral.py @@ -0,0 +1,101 @@ +import re + +from ._abstract import AbstractScraper +from ._exceptions import FieldNotProvidedByWebsiteException +from ._utils import get_yields, normalize_string + + +class IrishCentral(AbstractScraper): + @classmethod + def host(cls): + return "irishcentral.com" + + def author(self): + author_element = self.soup.find("div", class_="article-header-byline-author") + return author_element.get_text(strip=True) + + def description(self): + description = self.soup.find("meta", {"property": "og:description"})["content"] + return description + + def image(self): + return self.schema.image() + + def ingredients(self): + # Check if the ingredients are in a

structure (https://www.irishcentral.com/culture/food-drink/apple-jameson-tart-recipe) + ingredients_label = self.soup.find("p", string=re.compile(r"Ingredients:")) + + if ingredients_label: + ingredients_list = [] + ingredients_paragraphs = ingredients_label.find_next_siblings("p") + + for paragraph in ingredients_paragraphs: + text = normalize_string(paragraph.get_text()) + + if not text or text.lower() in ["most read", "popular"]: + continue + + if not text.startswith("-") and not any( + char.isdigit() for char in text + ): + break + + ingredients_list.append(text.lstrip("-").strip()) + + if ingredients_list: + return ingredients_list + + # Check if the ingredients are in a

    structure (https://www.irishcentral.com/culture/food-drink/shepherds-pie-recipe) + ingredients_list = ingredients_label.find_next("ul") + if ingredients_list: + ingredients_list = [ + normalize_string(li.get_text()) + for li in ingredients_list.find_all("li") + if li.get_text(strip=True) + and li.get_text(strip=True).lower() not in ["most read", "popular"] + ] + if ingredients_list: + return ingredients_list + + def instructions(self): + instructions_label = self.soup.find("p", string=re.compile(r"Method")) + instructions_list = [] + + if instructions_label: + instructions_list = [] + instructions_steps = instructions_label.find_next_siblings("p") + + for step in instructions_steps: + instruction_text = normalize_string(step.get_text()) + if instruction_text and not instruction_text.startswith("*"): + instructions_list.append(instruction_text) + else: + break + + return "\n".join(instructions_list) + + def title(self): + title = self.soup.find("meta", {"property": "og:title"})["content"] + return title + + def total_time(self): + raise FieldNotProvidedByWebsiteException(return_value=None) + + def yields(self): + serves_label = self.soup.find("strong", text=lambda t: t and "Serves:" in t) + + # serves_label = self.soup.find("p", string=re.compile(r"Serves\s+\d+")) + + if serves_label: + serves_text = normalize_string(serves_label.get_text()) + serves_value = serves_text.replace("Serves:", "").strip() + return get_yields(serves_value) + + # if serves_label: + # serves_text = normalize_string(serves_label.get_text()) + # serves_value = re.search(r"Serves\s+(\d+)", serves_text).group(1) + # return get_yields(serves_value) + + def keywords(self): + keywords = self.soup.find("meta", {"name": "keywords"})["content"] + return [keyword.strip() for keyword in keywords.split(",")] if keywords else [] diff --git a/tests/test_data/irishcentral.com/irishcentral.json b/tests/test_data/irishcentral.com/irishcentral.json new file mode 100644 index 000000000..e623b1872 --- /dev/null +++ b/tests/test_data/irishcentral.com/irishcentral.json @@ -0,0 +1,36 @@ +{ + "author": "Bord Bia", + "canonical_url": "https://www.irishcentral.com/culture/food-drink/apple-jameson-tart-recipe", + "site_name": "IrishCentral.com", + "host": "irishcentral.com", + "language": "en", + "title": "Two Irish favorites combine in this delicious apple and Jameson tart recipe", + "ingredients": [ + "250g shortcrust pastry", + "50g ground almonds", + "4 large Bramley apples, peeled and diced", + "2 tablespoons sugar", + "250ml cream", + "3 egg yolks", + "50g caster sugar", + "Dash of whiskey" + ], + "instructions_list": [ + "Set oven Gas Mark 6, 200°C (400°F).", + "Line four individual tart tins with the pastry. Sprinkle some ground almonds on the base of each one. Then add the apple and enough sugar to sweeten. Heat the cream. Beat the egg yolks and sugar together. Stir in the cream and a dash of whiskey. Spoon a little of the cream mixture into each tart. Keep remaining cream. Bake tarts for 25-35 minutes.", + "Pour the remaining cream into a bowl. Place over simmering water. Stirring constantly, and continue to cook until the custard thickens. Set aside - keep warm", + "Serving suggestions", + "Serve the tart, dusted with icing sugar, with the warm custard. Vanilla ice cream, thin almond biscuits, raspberries, etc. are optional.", + "John Howard was quite possibly Ireland's first celebrity chef. For 25 years he and his wife, Catherine, ran Le Coq Hardi restaurant, in Dublin 4, in 1977. It was one of the best-known dining locations in the country. Le Coq Hardi was known for its great food, expensive wine and for being where the captains of industry dined on lavish expense accounts mixed in with a little hanky panky.", + "In early 2000, he retired, sold the premises to a wine company, and moved to Spain to consult with Bord Bia." + ], + "yields": "4 servings", + "description": "Irish celebrity chef John Howard's apple and Jameson tart recipe marries two Irish favorites.", + "total_time": null, + "image": "https://www.irishcentral.com/uploads/article/5031/Apple_and_jameson_tart_via_Bord_bia.png?t=1727079191", + "keywords": [ + "IrishCentral", + "Irish news", + "Irish entertainment" + ] +} diff --git a/tests/test_data/irishcentral.com/irishcentral.testhtml b/tests/test_data/irishcentral.com/irishcentral.testhtml new file mode 100644 index 000000000..9b1bcda04 --- /dev/null +++ b/tests/test_data/irishcentral.com/irishcentral.testhtml @@ -0,0 +1,1371 @@ + + + + + Apple and Jameson tart recipe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    + +
    +

    Two Irish favorites combine in this delicious apple and Jameson tart recipe

    +

    Irish celebrity chef John Howard's apple tart really takes a beloved Irish classic to the next level.

    + +
    + +
    + John Howard\'s apple and Jameson tart. +
    John Howard's apple and Jameson tart.
    +
    + +
    +
    +
    + + +
    +
    +
    +

    Irish celebrity chef John Howard's apple and Jameson tart recipe marries two Irish favorites.

    +

    The Irish love an apple pie! There's nothing better than the traditional short-crust pastry apple pie with a dollop of ice cream on the side, just like Mammy made it. However, Irish celebrity chef John Howard's apple and Jameson tart really takes it to the next level.

    +

    What a treat!

    +

    Apple and Jameson tart recipe

    +
    +

    Serves: 4

    +

    Ingredients:

    +

    - 250g shortcrust pastry

    +

    - 50g ground almonds

    +

    - 4 large Bramley apples, peeled and diced

    +

    - 2 tablespoons sugar

    +

    - 250ml cream

    +

    - 3 egg yolks

    +

    - 50g caster sugar

    +

    - Dash of whiskey

    +
    + +
    +

    Method:

    +

    Set oven Gas Mark 6, 200°C (400°F).

    +

    Line four individual tart tins with the pastry. Sprinkle some ground almonds on the base of each one. Then add the apple and enough sugar to sweeten. Heat the cream. Beat the egg yolks and sugar together. Stir in the cream and a dash of whiskey. Spoon a little of the cream mixture into each tart. Keep remaining cream. Bake tarts for 25-35 minutes.

    +

    Pour the remaining cream into a bowl. Place over simmering water. Stirring constantly, and continue to cook until the custard thickens. Set aside - keep warm

    +

    Serving suggestions

    +
    +

    Serve the tart, dusted with icing sugar, with the warm custard. Vanilla ice cream, thin almond biscuits, raspberries, etc. are optional.

    +

    Chef John Howard

    +

    John Howard was quite possibly Ireland's first celebrity chef. For 25 years he and his wife, Catherine, ran Le Coq Hardi restaurant, in Dublin 4, in 1977. It was one of the best-known dining locations in the country. Le Coq Hardi was known for its great food, expensive wine and for being where the captains of industry dined on lavish expense accounts mixed in with a little hanky panky.

    +
    +

    In early 2000, he retired, sold the premises to a wine company, and moved to Spain to consult with Bord Bia.

    +

    * Originally published in 2015, updated in September 2024.

    +
    + + + +
    +
    +
    + + + + + + + +
    +

    Read Next

    +
    + + + + +
    +
    + + +
    + + + +
    +
    +
    + +
    +

    Comments

    +
    +
    + + + +
    +
    + + + + + +
    +
    +
    + + + + + + + +
    + + + + + + + + + + + + + From a0fdda2c24efba8869515c93abce4f280d5ec2c1 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 6 Dec 2024 22:10:05 -0500 Subject: [PATCH 12/94] Adds support for shelikesfood (#1388) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/shelikesfood.py | 16 + .../shelikesfood.com/shelikesfood_1.json | 52 + .../shelikesfood.com/shelikesfood_1.testhtml | 1839 +++++++++++++++++ .../shelikesfood.com/shelikesfood_2.json | 106 + .../shelikesfood.com/shelikesfood_2.testhtml | 1582 ++++++++++++++ 7 files changed, 3598 insertions(+) create mode 100644 recipe_scrapers/shelikesfood.py create mode 100644 tests/test_data/shelikesfood.com/shelikesfood_1.json create mode 100644 tests/test_data/shelikesfood.com/shelikesfood_1.testhtml create mode 100644 tests/test_data/shelikesfood.com/shelikesfood_2.json create mode 100644 tests/test_data/shelikesfood.com/shelikesfood_2.testhtml diff --git a/README.rst b/README.rst index f73fd907d..78f8cc221 100644 --- a/README.rst +++ b/README.rst @@ -390,6 +390,7 @@ Scrapers available for: - `https://www.saveur.com/ `_ - `https://www.savorynothings.com/ `_ - `https://seriouseats.com/ `_ +- `https://shelikesfood.com/ `_ - `https://simple-veganista.com/ `_ - `https://simply-cookit.com/ `_ - `https://simplyquinoa.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 566272f31..d87a4ead3 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -336,6 +336,7 @@ from .saveur import Saveur from .savorynothings import SavoryNothings from .seriouseats import SeriousEats +from .shelikesfood import SheLikesFood from .simpleveganista import SimpleVeganista from .simplycookit import SimplyCookit from .simplyquinoa import SimplyQuinoa @@ -577,6 +578,7 @@ RicettePerBimby.host(): RicettePerBimby, SandwhichTribunal.host(): SandwhichTribunal, SavoryNothings.host(): SavoryNothings, + SheLikesFood.host(): SheLikesFood, SpainOnAFork.host(): SpainOnAFork, StrongrFastr.host(): StrongrFastr, TasteAtlas.host(): TasteAtlas, diff --git a/recipe_scrapers/shelikesfood.py b/recipe_scrapers/shelikesfood.py new file mode 100644 index 000000000..abfebc44f --- /dev/null +++ b/recipe_scrapers/shelikesfood.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class SheLikesFood(AbstractScraper): + @classmethod + def host(cls): + return "shelikesfood.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".tasty-recipes-ingredients p", + ".tasty-recipes-ingredients ul li", + ) diff --git a/tests/test_data/shelikesfood.com/shelikesfood_1.json b/tests/test_data/shelikesfood.com/shelikesfood_1.json new file mode 100644 index 000000000..3389e874d --- /dev/null +++ b/tests/test_data/shelikesfood.com/shelikesfood_1.json @@ -0,0 +1,52 @@ +{ + "author": "She Likes Food", + "canonical_url": "https://www.shelikesfood.com/copycat-taco-bell-bean-burrito-recipe/", + "site_name": "She Likes Food", + "host": "shelikesfood.com", + "language": "en-US", + "title": "Copycat Taco Bell Bean Burrito Recipe", + "ingredients": [ + "2/3 cup refried beans", + "4 heaping tablespoons finely shredded cheese, I like to use a bagged fiesta or Mexican style mix", + "2 tablespoons finely chopped yellow or white onion", + "4 tablespoons Taco sauce, I like to use the Taco Bell mild sauce that I buy from Walmart", + "2 burrito sized flour tortillas" + ], + "instructions_list": [ + "Add your refried beans to a small saucepan along with a couple tablespoons of water. Canned refried beans are usually pretty thick, so I like to thin mine out with a little water to make them more spreadable. How much water you use will depend on the consistency of your refried beans.", + "Mix the beans and water together well and place over medium heat. Cook beans until piping hot, turn the heat off and let sit with the lid on while you are preparing your flour tortillas.", + "Heat a large pan over medium heat and add your flour tortilla. You don’t need to use any cooking spray for this, you just want to heat the tortilla. Heat tortilla on both sides until hot. Remove tortilla from the pan and place on a plate or cutting board.", + "If you want your cheese to be more melty, it’s important to move quickly while assembling your bean and cheese burrito so there isn’t much time for the refried beans or the tortilla to cool down.", + "Spread the middle of the tortilla with about 1/3 cup of the heated refried beans. Top with a handful of cheese, about 1 tablespoon of chopped onion and 1-2 tablespoons of the taco sauce. Fold the sides of your burrito in and carefully roll up. You can either enjoy immediately or let burrito cool for a few minutes, which will give the cheese a little more time to get melty. Enjoy with extra taco sauce, if desired!" + ], + "category": "Dinner", + "yields": "2 servings", + "description": "These Copycat Taco Bell Bean Burritos only require 5 simple ingredients and they taste so much like the real thing! If you're craving Taco Bell, but don't want to leave the house, make these delicious bean burritos right at home.", + "total_time": 10, + "cook_time": 5, + "prep_time": 5, + "cuisine": "Mexican inspired", + "cooking_method": "stovetop", + "ratings": 5.0, + "ratings_count": 1, + "nutrients": { + "servingSize": "1 Burrito", + "calories": "619 calories", + "fatContent": "10.1 g", + "saturatedFatContent": "4.2 g", + "transFatContent": "0.2 g", + "carbohydrateContent": "109.1 g", + "sugarContent": "3.2 g", + "proteinContent": "20.2 g", + "sodiumContent": "556.4 mg", + "fiberContent": "7.5 g", + "cholesterolContent": "18.8 mg" + }, + "dietary_restrictions": [ + "Vegetarian Diet" + ], + "image": "https://www.shelikesfood.com/wp-content/uploads/2023/09/copycat-taco-bell-bean-burritos-8842-225x225.jpg", + "keywords": [ + "Copycat Taco Bell Bean Burrito" + ] +} diff --git a/tests/test_data/shelikesfood.com/shelikesfood_1.testhtml b/tests/test_data/shelikesfood.com/shelikesfood_1.testhtml new file mode 100644 index 000000000..c142ba606 --- /dev/null +++ b/tests/test_data/shelikesfood.com/shelikesfood_1.testhtml @@ -0,0 +1,1839 @@ + + + + + + + + + Copycat Taco Bell Bean Burrito Recipe - She Likes Food + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + +
    +
      +
    • +
    • +
    • +
    • +
    +
    + + + +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/shelikesfood.com/shelikesfood_2.json b/tests/test_data/shelikesfood.com/shelikesfood_2.json new file mode 100644 index 000000000..974ddcc38 --- /dev/null +++ b/tests/test_data/shelikesfood.com/shelikesfood_2.json @@ -0,0 +1,106 @@ +{ + "author": "She Likes Food", + "canonical_url": "https://www.shelikesfood.com/roasted-rainbow-veggie-bowls-with-citrus-tahini-sauce/", + "site_name": "She Likes Food", + "host": "shelikesfood.com", + "language": "en-US", + "title": "Roasted Rainbow Veggie Bowls", + "ingredients": [ + "7-8 cups diced rainbow colored vegetables of choice OR", + "1 large red bell pepper, diced", + "1 1/2 cups diced butternut squash, I like to use frozen", + "1/2 cup diced carrot", + "1 large yellow bell pepper, diced", + "1 cup small broccoli florets", + "1 cup quartered brussels sprouts", + "1 cup diced rutabaga", + "1/2 small red onion, diced", + "3 tablespoons olive oil, or oil of choice", + "1 1/2 teaspoons salt", + "1 teaspoon garlic powder", + "1/2 teaspoon black pepper", + "2 cups chickpeas", + "Quinoa for serving, or other grain of choice", + "Fresh herbs for garnish", + "1/2 cup tahini", + "3 tablespoons fresh lemon juice", + "4 tablespoons fresh orange juice", + "1/2 teaspoon lemon zest", + "1/2 teaspoon orange zest", + "1-2 clove garlic, minced", + "1 teaspoon pure maple syrup", + "3–6 tablespoons water, depending on how thick you would like the dressing", + "1/2 teaspoon salt, or more if needed" + ], + "ingredient_groups": [ + { + "ingredients": [ + "7-8 cups diced rainbow colored vegetables of choice OR", + "1 large red bell pepper, diced", + "1 1/2 cups diced butternut squash, I like to use frozen", + "1/2 cup diced carrot", + "1 large yellow bell pepper, diced", + "1 cup small broccoli florets", + "1 cup quartered brussels sprouts", + "1 cup diced rutabaga", + "1/2 small red onion, diced", + "3 tablespoons olive oil, or oil of choice", + "1 1/2 teaspoons salt", + "1 teaspoon garlic powder", + "1/2 teaspoon black pepper", + "2 cups chickpeas", + "Quinoa for serving, or other grain of choice", + "Fresh herbs for garnish" + ], + "purpose": null + }, + { + "ingredients": [ + "1/2 cup tahini", + "3 tablespoons fresh lemon juice", + "4 tablespoons fresh orange juice", + "1/2 teaspoon lemon zest", + "1/2 teaspoon orange zest", + "1-2 clove garlic, minced", + "1 teaspoon pure maple syrup", + "3–6 tablespoons water, depending on how thick you would like the dressing", + "1/2 teaspoon salt, or more if needed" + ], + "purpose": "Citrus Tahini Sauce" + } + ], + "instructions_list": [ + "Pre-heat oven to 425 degrees F. Add all of your diced vegetables to an extra large sheet pan and drizzle them with olive oil. Add garlic powder, salt and pepper (and any other seasonings you may want) and use your hands to toss everything together until vegetables are fully coated and arrange them in a single layer on the baking sheet.", + "Place veggies in the oven and roast until fork tender and beginning to caramelize, about 30-35 minutes, flipping once. Remove from the oven and let cool for a couple of minutes.", + "Make the tahini sauce while the vegetables are roasting. Add all sauce ingredients, except for the water, to a medium sized bowl, or jar, and mix until combined. Once the sauce gets thick, add a couple tablespoons of water at a time and mix until desired thickness is reached. You could also add in extra citrus juice instead of water, if you like.", + "Assemble you’re bowls. To each one, add about 3/4 cup quinoa, 1/2 cup chickpeas and 1/4 of the roasted veggies. Drizzle with desired amount of dressing and add extra salt or fresh herbs, if desired." + ], + "category": "Dinner", + "yields": "4 servings", + "description": "If you're looking to add more vegetables into your diet this year, these easy Roasted Rainbow Veggie Bowls with Citrus Tahini Sauce are the perfect way! These healthy, plant based bowls are customizable to your taste and great served with, protein packed, quinoa and chickpeas. The citrus tahini dressing brightens everything up adds creaminess.", + "total_time": 55, + "cook_time": 35, + "prep_time": 20, + "cuisine": "American", + "cooking_method": "Oven", + "nutrients": { + "servingSize": "1/4", + "calories": "564 calories", + "fatContent": "30.7 g", + "saturatedFatContent": "4.2 g", + "transFatContent": "0 g", + "carbohydrateContent": "62.4 g", + "sugarContent": "9.7 g", + "proteinContent": "17.9 g", + "sodiumContent": "1255.4 mg", + "fiberContent": "14.1 g", + "cholesterolContent": "0 mg" + }, + "dietary_restrictions": [ + "Vegan Diet" + ], + "image": "https://www.shelikesfood.com/wp-content/uploads/2024/01/Roasted-Rainbow-Veggie-Bowls-1764-225x225.jpg", + "keywords": [ + "Rainbow Veggie Bowls" + ] +} diff --git a/tests/test_data/shelikesfood.com/shelikesfood_2.testhtml b/tests/test_data/shelikesfood.com/shelikesfood_2.testhtml new file mode 100644 index 000000000..0afac1c70 --- /dev/null +++ b/tests/test_data/shelikesfood.com/shelikesfood_2.testhtml @@ -0,0 +1,1582 @@ + + + + + + + + + + Roasted Rainbow Veggie Bowls with Citrus Tahini Sauce - She Likes Food + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + +
    +
      +
    • +
    • +
    • +
    • +
    +
    + + + +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 071c617a9087db566a50c90e51dceea4d735102d Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 6 Dec 2024 22:13:07 -0500 Subject: [PATCH 13/94] Adds support for wedishitup (#1389) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/wedishitup.py | 31 + .../wedishitup.com/wedishitup_1.json | 65 + .../wedishitup.com/wedishitup_1.testhtml | 1933 +++++++++++++++++ .../wedishitup.com/wedishitup_2.json | 82 + .../wedishitup.com/wedishitup_2.testhtml | 1709 +++++++++++++++ 7 files changed, 3823 insertions(+) create mode 100644 recipe_scrapers/wedishitup.py create mode 100644 tests/test_data/wedishitup.com/wedishitup_1.json create mode 100644 tests/test_data/wedishitup.com/wedishitup_1.testhtml create mode 100644 tests/test_data/wedishitup.com/wedishitup_2.json create mode 100644 tests/test_data/wedishitup.com/wedishitup_2.testhtml diff --git a/README.rst b/README.rst index 78f8cc221..5216e7325 100644 --- a/README.rst +++ b/README.rst @@ -457,6 +457,7 @@ Scrapers available for: - `https://www.waitrose.com/ `_ - `https://watchwhatueat.com/ `_ - `https://wearenotmartha.com/ `_ +- `https://wedishitup.com/ `_ - `https://www.weightwatchers.com/ `_ (*) - `https://www.wellplated.com/ `_ - `https://whatsgabycooking.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index d87a4ead3..b50ae61cd 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -405,6 +405,7 @@ from .waitrose import Waitrose from .watchwhatueat import WatchWhatUEat from .wearenotmartha import WeAreNotMartha +from .wedishitup import WeDishItUp from .weightwatchers import WeightWatchers from .weightwatcherspublic import WeightWatchersPublic from .wellplated import WellPlated @@ -823,6 +824,7 @@ Waitrose.host(): Waitrose, WatchWhatUEat.host(): WatchWhatUEat, WeAreNotMartha.host(): WeAreNotMartha, + WeDishItUp.host(): WeDishItUp, WeightWatchers.host(): WeightWatchers, WeightWatchersPublic.host(): WeightWatchersPublic, WellPlated.host(): WellPlated, diff --git a/recipe_scrapers/wedishitup.py b/recipe_scrapers/wedishitup.py new file mode 100644 index 000000000..fcebfce89 --- /dev/null +++ b/recipe_scrapers/wedishitup.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class WeDishItUp(AbstractScraper): + @classmethod + def host(cls): + return "wedishitup.com" + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/tests/test_data/wedishitup.com/wedishitup_1.json b/tests/test_data/wedishitup.com/wedishitup_1.json new file mode 100644 index 000000000..03b64350e --- /dev/null +++ b/tests/test_data/wedishitup.com/wedishitup_1.json @@ -0,0 +1,65 @@ +{ + "author": "Stacy Roman", + "canonical_url": "https://wedishitup.com/2530/copy-cat-nacho-bell-grande/", + "site_name": "We Dish It Up", + "host": "wedishitup.com", + "language": "en-US", + "title": "Copy Cat Nacho Bell Grande", + "ingredients": [ + "1 10-13 oz Bag Tortilla Chips", + "1 lb Ground Beef", + "1 13 oz Can Refried Beans", + "1 12 oz Jar Nacho Cheese (Store-Bought )", + "6-8 oz Sour Cream", + "1 medium Tomato (Diced)", + "Green Onions (Optional)", + "Jalapenos (Optional)", + "Salsa or Hot Sauce (Optional)", + "Guacamole (Optional)" + ], + "instructions_list": [ + "Dump Tortilla Chips out on a Platter", + "In a Medium Fry Pan -Cook and break up the ground Beef-add Taco Seasoning and water as directed on seasoning", + "Heat Beans and Nacho Cheese in Microwave", + "Scoop beans on to chips using an ice cream scoop works best but go with what you have", + "Spread ground beef over chips and beans", + "Pour hot nacho cheese over chips , beans, and beef", + "Sprinkle tomatoes over nachos", + "Top with sour cream and other optional garnishes Serve and Enjoy" + ], + "category": "Appetizer", + "yields": "6 servings", + "description": "Chips with Beans , Ground Beef, Nacho Cheese, Sour Cream and Tomatoes", + "total_time": 10, + "cook_time": 5, + "prep_time": 5, + "cuisine": "Mexican", + "ratings": 3.17, + "ratings_count": 6, + "equipment": [ + "stove, large pan, knife, cutting board", + "Microwave" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "212 kcal", + "fatContent": "17 g", + "saturatedFatContent": "6 g", + "unsaturatedFatContent": "9 g", + "transFatContent": "1 g", + "carbohydrateContent": "2 g", + "sugarContent": "1 g", + "proteinContent": "13 g", + "sodiumContent": "55 mg", + "fiberContent": "1 g", + "cholesterolContent": "54 mg" + }, + "image": "https://wedishitup.com/wp-content/uploads/2019/12/Copy-Cat-Nacho-Bell-2.jpg", + "keywords": [ + "Appetizer", + "Bell", + "Grande", + "Nachos", + "Taco Bell" + ] +} diff --git a/tests/test_data/wedishitup.com/wedishitup_1.testhtml b/tests/test_data/wedishitup.com/wedishitup_1.testhtml new file mode 100644 index 000000000..91616430f --- /dev/null +++ b/tests/test_data/wedishitup.com/wedishitup_1.testhtml @@ -0,0 +1,1933 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The Best Copycat Taco Bell Nacho Bell Grande The Best Copycat Taco Be + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Footer

    Copyright © 2024 We Dish It Up on the Foodie Pro Theme

    +
    + +
    +

    Sharing is Caring

    Help spread the word. You're awesome for doing it!

    +
    +
    +
    +
    +
    +
    + +
    + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Verified by MonsterInsights
    + + \ No newline at end of file diff --git a/tests/test_data/wedishitup.com/wedishitup_2.json b/tests/test_data/wedishitup.com/wedishitup_2.json new file mode 100644 index 000000000..100819a64 --- /dev/null +++ b/tests/test_data/wedishitup.com/wedishitup_2.json @@ -0,0 +1,82 @@ +{ + "author": "Stacy Roman", + "canonical_url": "https://wedishitup.com/14176/sheet-pan-ranch-chicken-thighs/", + "site_name": "We Dish It Up", + "host": "wedishitup.com", + "language": "en-US", + "title": "Sheet Pan Ranch Chicken Thighs", + "ingredients": [ + "1 pkt Ranch Seasoning", + "1/2 cup Olive Oil", + "2 tbsp Garlic Herb Seasoning", + "4-6 Chicken Thighs (Bone in Skin On)", + "4 Apples (Peeled, Cored and Sliced)", + "2 cups Baby Carrots", + "2 Red Onions (Thinly Sliced)", + "6-8 Red Potatoes (Sliced in Half)", + "Chopped Parsley" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 pkt Ranch Seasoning", + "1/2 cup Olive Oil", + "2 tbsp Garlic Herb Seasoning" + ], + "purpose": "Chicken Marinade" + }, + { + "ingredients": [ + "4-6 Chicken Thighs (Bone in Skin On)", + "4 Apples (Peeled, Cored and Sliced)", + "2 cups Baby Carrots", + "2 Red Onions (Thinly Sliced)", + "6-8 Red Potatoes (Sliced in Half)", + "Chopped Parsley" + ], + "purpose": "Chicken and Vegetables" + } + ], + "instructions_list": [ + "Pre-heat oven to 400 °", + "In a small mixing bowl , combine ranch seasoning , garlic herb seasoning and olive oil, Whisk together.", + "In a large bowl place chicken thighs and pour half of the marinade over the chicken and toss to coat well.", + "Next, refrigerate marinated chicken for 20-30 minutes well doing the other prepping of veggies.", + "Chop and slice apples and veggies.", + "Spray a baking pan with nonstick spray , arrange vegetables on baking sheet pour remaining marinade on veggies.", + "Add chicken to pan and bake for 35-40 minutes until internal temperature of chicken reaches 165°", + "Serve hot" + ], + "category": "dinner", + "yields": "4 servings", + "description": "Sheet Pan Ranch Chicken Thighs are the perfect weeknight dinner. Chicken Thighs, baby carrots, red potatoes, apples, red onion, and seasonings. It can all be thrown together on one pan and ready in less than an hour. You can't beat that am I right?", + "total_time": 85, + "cook_time": 40, + "prep_time": 15, + "cuisine": "American", + "equipment": [ + "OVEN", + "Sheet Pan", + "Mixing Bowl" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "730 kcal", + "fatContent": "33 g", + "saturatedFatContent": "7 g", + "unsaturatedFatContent": "24 g", + "transFatContent": "0.1 g", + "carbohydrateContent": "87 g", + "sugarContent": "28 g", + "proteinContent": "26 g", + "sodiumContent": "217 mg", + "fiberContent": "13 g", + "cholesterolContent": "111 mg" + }, + "image": "https://wedishitup.com/wp-content/uploads/2022/09/Ranch-Chicken-Sheet-Pan-2-1-2.jpg", + "keywords": [ + "Chicken Thighs", + "Dinner", + "Sheet Pan" + ] +} diff --git a/tests/test_data/wedishitup.com/wedishitup_2.testhtml b/tests/test_data/wedishitup.com/wedishitup_2.testhtml new file mode 100644 index 000000000..ced6be185 --- /dev/null +++ b/tests/test_data/wedishitup.com/wedishitup_2.testhtml @@ -0,0 +1,1709 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sheet Pan Ranch Chicken Thighs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Footer

    Copyright © 2024 We Dish It Up on the Foodie Pro Theme

    +
    + +
    +

    Sharing is Caring

    Help spread the word. You're awesome for doing it!

    +
    +
    +
    +
    +
    +
    + +
    + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Verified by MonsterInsights
    + + \ No newline at end of file From d0ad303a43785eaeb35a6040de603406bd556401 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 6 Dec 2024 22:23:03 -0500 Subject: [PATCH 14/94] Adds support for amessavorykitchen (#1390) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/ameessavorydish.py | 46 + .../ameessavorydish_1.json | 63 + .../ameessavorydish_1.testhtml | 1490 +++++++++++++++++ .../ameessavorydish_2.json | 84 + .../ameessavorydish_2.testhtml | 1432 ++++++++++++++++ 7 files changed, 3118 insertions(+) create mode 100644 recipe_scrapers/ameessavorydish.py create mode 100644 tests/test_data/ameessavorydish.com/ameessavorydish_1.json create mode 100644 tests/test_data/ameessavorydish.com/ameessavorydish_1.testhtml create mode 100644 tests/test_data/ameessavorydish.com/ameessavorydish_2.json create mode 100644 tests/test_data/ameessavorydish.com/ameessavorydish_2.testhtml diff --git a/README.rst b/README.rst index 5216e7325..7212c9190 100644 --- a/README.rst +++ b/README.rst @@ -103,6 +103,7 @@ Scrapers available for: - `https://altonbrown.com/ `_ - `https://amazingribs.com/ `_ - `https://ambitiouskitchen.com/ `_ +- `https://ameessavorydish.com/ `_ - `https://americastestkitchen.com/ `_ (*) - `https://archanaskitchen.com/ `_ - `https://www.argiro.gr/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index b50ae61cd..7a45306e5 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -55,6 +55,7 @@ from .altonbrown import AltonBrown from .amazingribs import AmazingRibs from .ambitiouskitchen import AmbitiousKitchen +from .ameessavorydish import AmeesSavoryDish from .americastestkitchen import AmericasTestKitchen from .archanaskitchen import ArchanasKitchen from .argiro import Argiro @@ -454,6 +455,7 @@ AmazingRibs.host(): AmazingRibs, AmbitiousKitchen.host(): AmbitiousKitchen, AmericasTestKitchen.host(): AmericasTestKitchen, + AmeesSavoryDish.host(): AmeesSavoryDish, ArchanasKitchen.host(): ArchanasKitchen, Argiro.host(): Argiro, Arla.host(): Arla, diff --git a/recipe_scrapers/ameessavorydish.py b/recipe_scrapers/ameessavorydish.py new file mode 100644 index 000000000..e940e8511 --- /dev/null +++ b/recipe_scrapers/ameessavorydish.py @@ -0,0 +1,46 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment, normalize_string + + +class AmeesSavoryDish(AbstractScraper): + @classmethod + def host(cls): + return "ameessavorydish.com" + + def ingredients(self): + ingredients_list = [] + for element in self.soup.select(".wprm-recipe-ingredient:not(:has(strong))"): + ingredient_text = " ".join( + span.get_text(strip=True) + for span in element.select( + ".wprm-recipe-ingredient-amount, " + ".wprm-recipe-ingredient-unit, " + ".wprm-recipe-ingredient-name, " + ".wprm-recipe-ingredient-notes" + ) + ) + ingredients_list.append(ingredient_text) + return ingredients_list + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group .wprm-recipe-ingredient-name strong", + ".wprm-recipe-ingredient:not(:has(strong))", + ) + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + normalize_string(item.get_text()) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) diff --git a/tests/test_data/ameessavorydish.com/ameessavorydish_1.json b/tests/test_data/ameessavorydish.com/ameessavorydish_1.json new file mode 100644 index 000000000..d6e8a0e4c --- /dev/null +++ b/tests/test_data/ameessavorydish.com/ameessavorydish_1.json @@ -0,0 +1,63 @@ +{ + "author": "Amee Livingston", + "canonical_url": "https://ameessavorydish.com/pumpkin-chocolate-cake/", + "site_name": "Amee's Savory Dish", + "host": "ameessavorydish.com", + "language": "en-US", + "title": "Gluten-Free Pumpkin Chocolate Cake", + "ingredients": [ + "1 cup King Arthur measure for measure all-purpose gluten-free flour sifted. You can also use cake flour if gluten is not a concern.", + "1/3 cup cocoa powder", + "1 1/2 teaspoons cinnamon", + "1/2 tsp pumpkin pie spice", + "1 teaspoon baking powder", + "1/2 teaspoon baking soda", + "1/4 teaspoon salt", + "1/4 cup butter melted", + "3/4 cup coconut sugar *see notes for sweetener swaps", + "1/4 cup pure maple syrup room temperature", + "2 eggs room temperature", + "1/4 cup Kefir plain unsweetened (or buttermilk)", + "15 oz can pumpkin purée", + "1 teaspoon vanilla extract", + "Powdered sugar for dusting (optional)" + ], + "instructions_list": [ + "Preheat oven to 350°F. Grease an (8-inch) square baking pan with butter or cooking oil spray and set aside.", + "In a large bowl, whisk together flour, cocoa powder, cinnamon, pumpkin pie spice, baking powder, baking soda and salt.", + "In a separate bowl, whisk together melted butter, coconut sugar, maple syrup, kefir, eggs, pumpkin and vanilla.", + "Whisk flour mixture into pumpkin mixture until well combined then transfer batter to prepared pan. Bake 40-50 minutes or until the cakes pulls away from the sides of the pan and a toothpick or cake tester inserted in the center comes out clean.", + "Set aside to let cool then cut into squares and dust with powdered sugar, or top with whipped cream or frosting." + ], + "category": "Dessert", + "yields": "12 servings", + "description": "This Gluten-free Pumpkin Chocolate Cake has the perfect balance of cocoa and pumpkin spice -and is nothing short of amazing!", + "total_time": 50, + "cook_time": 40, + "prep_time": 10, + "cuisine": "American", + "ratings": 4.72, + "ratings_count": 7, + "nutrients": { + "servingSize": "1 serving", + "calories": "151 kcal", + "fatContent": "5 g", + "saturatedFatContent": "1 g", + "unsaturatedFatContent": "3 g", + "transFatContent": "1 g", + "carbohydrateContent": "25 g", + "sugarContent": "12 g", + "proteinContent": "3 g", + "sodiumContent": "210 mg", + "fiberContent": "3 g", + "cholesterolContent": "28 mg" + }, + "image": "https://ameessavorydish.com/wp-content/uploads/2017/11/Pumpkin-choc-cake-feature-.jpg", + "keywords": [ + "cake", + "chocolate", + "fall", + "glutenfree", + "pumpkin" + ] +} diff --git a/tests/test_data/ameessavorydish.com/ameessavorydish_1.testhtml b/tests/test_data/ameessavorydish.com/ameessavorydish_1.testhtml new file mode 100644 index 000000000..baeccdd0b --- /dev/null +++ b/tests/test_data/ameessavorydish.com/ameessavorydish_1.testhtml @@ -0,0 +1,1490 @@ + + + + + + + + + + + + + + + + + + + + + + + Gluten-Free Pumpkin Chocolate Cake- Amee's Savory Dish + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + | | +
    +

    Gluten-Free Pumpkin Chocolate Cake

    +
    + +
    + +

    This Gluten-free Pumpkin Chocolate Cake has the perfect balance of cocoa and pumpkin spice -and is nothing short of amazing! Made with pumpkin puree and cleaned-up ingredients, this is the perfect healthy dessert for fall.

    + + + +
    a slice of pumpkin chocolate cake on a plate topped with powdered sugar and whipped cream with pumpkins in the background
    + + + +

    Is it just me or does everyone have a go-to dessert they make during the holidays -and is it just me, or does that dessert always involve chocolate? It’s hard to go wrong with chocolate-flavored desserts because chocolate is life, but do you know what else is life? Pumpkin spice. This chocolate cake made with pumpkin puree combines the best of both worlds!

    + + + +

    The inspiration for this cozy pumpkin chocolate cake came from a recipe I stumbled upon on the Whole Foods website. I modified the ingredients so my husband could indulge. He has a gluten sensitivity, so I adapted what I needed to in order to make a moist and tender pumpkin chocolate cake just as amazing as the original.

    + + + +

    Flavored with rich cocoa and warm and cozy cinnamon and pumpkin spice, this homemade gluten-free pumpkin chocolate cake is the perfect way to and an amazing holiday meal.

    + + + +
    +

    Why You’ll Love This Recipe

    + + + +
      +
    • This recipe makes a moist and tender chocolate cake with gluten-free ingredients.
    • + + + +
    • It’s super easy to make!
    • + + + +
    • Perfect for Thanksgiving and the holiday season!
    • + + + +
    • You can decorate this simple sheet pan pumpkin cake as simply or as festively as you like.
    • +
    +
    + + + +
    a platter of slices of pumpkin chocolate cake with a slice of cake on a plate with a fork next to it
    + + + +
    +

    Ingredients You’ll Need For Gluten-Free Pumpkin Chocolate Cake

    + + + +
      +
    • Land O’ Lakes Olive Oil Butter Blend Stick (melted): adds richness and moisture. You can also use regular butter.
    • + + + +
    • All-purpose Gluten-free Flour: Measure for Measure King Arther brand recommended. If gluten is of no concern, you can swap the gluten-free flour with regular unbleached all-purpose flour. *Using a different gluten-free flour blend can affect the results.
    • + + + +
    • Cocoa Powder: adds deep dark chocolate flavor.
    • + + + +
    • Cinnamon & Pumpkin Pie Spice: bring the perfect balance of warming fall flavors to this cake.
    • + + + +
    • Leavening Agents: You will need both baking powder and baking soda to help the cake rise and become soft and tender.
    • + + + +
    • Salt: enhances the sweet and spiced flavors.
    • + + + +
    • Sweetener: Instead of granulated sugar, this cake is made with coconut sugar and pure maple syrup. Feel free to swap the coconut sugar maple syrup blend with 1 cup of sugar if that’s what you have on hand.
    • + + + +
    • Eggs: add moisture and density to the cake.
    • + + + +
    • Kefir (plain unsweetened): Using kefir in baked goods is a great way to make moist gluten-free baked goods without adding heavy oils or shortening.
    • + + + +
    • Canned Pumpkin Puree: makes this gluten-free cake dangerously rich and delicious. Not to mention, the nutrients it adds.
    • + + + +
    • Vanilla Extract: enhances the pleasantly sweet flavors.
    • + + + +
    • Optional: Powdered sugar for dusting.
    • +
    +
    + + + +
    +

    How To Make Gluten-Free Chocolate Cake with Canned Pumpkin

    + + + +

    Step 1: Preheat oven and prepare pan:

    + + + +

    Preheat the oven to 350°F and grease an 8″ square baking pan with oil. Dust with a sprinkle of gluten-free flour and set aside.

    + + + +

    Step 2: Mix dry ingredients:

    + + + +

    In a large mixing bowl, add flour, cocoa powder, cinnamon, pumpkin pie spice, baking powder, baking soda, and salt. Whisk well to combine.

    + + + +

    Step 3: Mix wet ingredients:

    + + + +

    In a separate large mixing bowl, add melted butter, coconut sugar, maple syrup, kefir, eggs, canned pumpkin, and vanilla. Whisk well to combine.

    + + + +

    Step 4: Mix everything together:

    + + + +

    Whisk the flour mixture into the pumpkin mixture until a smooth cake batter forms. Do not overmix.

    + + + +

    Step 5: Bake:

    + + + +

    Pour the batter into the prepared baking pan and bake in a preheated oven for 40-50 minutes or until the cake begins to pull away from the sides of the pan and a toothpick inserted in the center comes out clean.

    + + + +

    Step 6: Let cool and decorate:

    + + + +

    Set the cake aside to let cool completely before cutting into squares. Optional; dust each square with powdered sugar or top with whipped cream or frosting.

    +
    + + + +
    close up photo of a slice of pumpkin chocolate cake topped with whipped cream with a mini pumpkin in the background
    + + + +
    +

    Recipe Tips

    + + + +
      +
    • There is a difference between pumpkin puree and pumpkin pie filling. Make sure you’re using puree as it is just pumpkin. Pumpkin pie filling has added flavor and sweeteners.
    • + + + +
    • Be sure to measure the ingredients carefully and use room-temperature eggs to get the flavor and texture of this gluten-free cake just right.
    • + + + +
    • Feel free to add more cinnamon and pumpkin pie spice to the batter for a stronger warm and spiced flavor.
    • +
    +
    + + + +
    +

    Serving Ideas

    + + + +
      +
    • Make this gluten-free pumpkin chocolate cake even more amazing by topping each square with a dollop of homemade whipped cream.
    • + + + +
    • I love to add a little vanilla, sugar, and cinnamon when whipping the heavy cream for whipped cream.
    • + + + +
    • Another tasty option is frosting the cake with maple cream cheese frosting. Simply heaven.
    • + + + +
    • If you want to keep things simple, I promise you this cake is amazing all by itself with just a light dusting of powdered sugar.
    • + + + +
    • Or how about a cup of fresh brewed coffee to go with a warm slice of this moist gluten-free cake?
    • +
    +
    + + + +
    overhead photo of pumpkin chocolate cake with a fork
    + + + +
    +

    Storing & Freezing

    + + + +

    Storing: To keep the cake from drying out, it’s best it be stored covered at room temperature and enjoyed within 2 to 3 days.

    + + + +

    Freezing: A gluten-free chocolate cake can be frozen just like a regular cake. Make sure the cake has cooled completely to room temperature and then wrap the sheet cake in several layers of plastic wrap and store in a sealed bag in the freezer for up to 2 months. You can freeze single slices the same way.

    +
    + + + +
    +

    Recipe FAQ

    + + + +
    Are all cocoa powders gluten-free?

    All pure cocoa powders should inherently be gluten-free but always double-check the label.

    Do gluten-free chocolate cakes take longer to bake?

    Generally, yes. Gluten-free baked goods brown quicker so for the best results gluten-free cakes should be baked at a lower temper temperature for a longer period of time.

    Can I use pumpkin pie filling instead of pumpkin puree?

    No. Pumpkin pie filling contains added flavors and sugars. The two can not be used interchangeably.

    +
    + + + + + + + +
    +

    If you love this recipe I would be so grateful if you could leave a 5-star 🌟rating in the recipe card below. I love reading your comments and feedback!

    + + + +

    Stay posted on my latest cooking adventures through social media @ Instagram, Pinterest, and Facebook. Don’t forget to tag me when you try one of my recipes!

    +
    + + +
    close up photo of slice of pumpkin chocolate cake with whipped cream on top
    +
    +
    +

    Gluten-Free Pumpkin Chocolate Cake

    +
    +
     This Gluten-free Pumpkin Chocolate Cake has the perfect balance of cocoa and pumpkin spice -and is nothing short of amazing!
    +
    +
    4.72 from 7 votes
    +
    + Print + Pin + Rate + +
    +
    Course: Dessert
    Cuisine: American
    +
    Prep Time: 10 minutes
    Cook Time: 40 minutes
    Total Time: 50 minutes
    +
    Servings: 12
    +
    Calories: 151kcal
    +
    Author: Amee
    + +
    + +

    Ingredients

    • 1 cup King Arthur measure for measure all-purpose gluten-free flour sifted. You can also use cake flour if gluten is not a concern.
    • 1/3 cup cocoa powder
    • 1 1/2 teaspoons cinnamon
    • 1/2 tsp pumpkin pie spice
    • 1 teaspoon baking powder
    • 1/2 teaspoon baking soda
    • 1/4 teaspoon salt
    • 1/4 cup butter melted
    • 3/4 cup coconut sugar *see notes for sweetener swaps
    • 1/4 cup pure maple syrup room temperature
    • 2 eggs room temperature
    • 1/4 cup Kefir plain unsweetened (or buttermilk)
    • 15 oz can pumpkin purée
    • 1 teaspoon vanilla extract
    • Powdered sugar for dusting (optional)
    +

    Instructions

    • Preheat oven to 350°F. Grease an (8-inch) square baking pan with butter or cooking oil spray and set aside.
    • In a large bowl, whisk together flour, cocoa powder, cinnamon, pumpkin pie spice, baking powder, baking soda and salt.
    • In a separate bowl, whisk together melted butter, coconut sugar, maple syrup, kefir, eggs, pumpkin and vanilla.
    • Whisk flour mixture into pumpkin mixture until well combined then transfer batter to prepared pan. Bake 40-50 minutes or until the cakes pulls away from the sides of the pan and a toothpick or cake tester inserted in the center comes out clean.
    • Set aside to let cool then cut into squares and dust with powdered sugar, or top with whipped cream or frosting.
    +
    +

    Notes

    *You can swap the coconut sugar maple syrup blend with 1 cup of regular sugar or brown sugar, if desired.
    +

    Nutrition

    Calories: 151kcal | Carbohydrates: 25g | Protein: 3g | Fat: 5g | Saturated Fat: 1g | Polyunsaturated Fat: 1g | Monounsaturated Fat: 2g | Trans Fat: 1g | Cholesterol: 28mg | Sodium: 210mg | Potassium: 139mg | Fiber: 3g | Sugar: 12g | Vitamin A: 5735IU | Vitamin C: 2mg | Calcium: 61mg | Iron: 1mg
    +
    +
    Tried this recipe?Mention @ameecooks or tag #ameecooks!
    +
    + + +

    *This post was originally published November 9, 2017 and has been updated throughout.

    + +
    Amee Livingston
    Follow me
    Latest posts by Amee Livingston (see all)
    +
    +
    +
    + + + + + +
    +

    5 Comments

      +
    1. +
      + + +
      +

      This chocolate pumpkin cake looks delicious! I was just talking with my boys about what kind of pumpkin treats we should bake this holiday weekend!

      +
      + +
      +
        +
      1. + +
      2. +
      +
    2. +
    3. +
      + + +
      +

      5 stars
      +I used to have pumpkin pie or carrot cake on my birthday but since this recipe was first posted it became my favorite cake to have on my birthday. It is moist and so yummy.

      +
      + +
      +
    4. +
    5. +
      + + +
      +

      3 stars
      +This recipe is listed as requiring only one cup of flour. Could this be a typo?

      +
      + +
      +
        +
      1. + +
      2. +
      +
    6. +
    +
    +
    +
    + 4.72 from 7 votes (5 ratings without comment) +
    +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +

    +

    + +

    +
    +
    +
    + + +
    +
    +
    + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/ameessavorydish.com/ameessavorydish_2.json b/tests/test_data/ameessavorydish.com/ameessavorydish_2.json new file mode 100644 index 000000000..c6c38a958 --- /dev/null +++ b/tests/test_data/ameessavorydish.com/ameessavorydish_2.json @@ -0,0 +1,84 @@ +{ + "author": "Amee Livingston", + "canonical_url": "https://ameessavorydish.com/roasted-vegetable-power-bowl-with-creamy-avocado-dressing-thereciperedux/", + "site_name": "Amee's Savory Dish", + "host": "ameessavorydish.com", + "language": "en-US", + "title": "Taco Bell Veggie Power Bowl {Copycat Recipe}", + "ingredients": [ + "1 cup canned black beans in seasoned sauce", + "1 cup Spanish style ready rice", + "4 cups lettuce finely chopped", + "2 Roma tomatoes seeded and chopped", + "2 oz cheddar cheese shredded-or try a three-cheese blend similar to the one Taco Bell uses, made with mozzarella, cheddar, and pepper jack cheese", + "½ avocado sliced", + "2 tbsp sour cream", + "½ ripe avocado", + "½ cup plain non-fat Greek yogurt", + "3 tbsp fresh lime juice", + "1 tbsp ranch seasoning *in the packet", + "Optional bowl add-ins: onions, pickled jalapeños, salsa, pico de gallo" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 cup canned black beans in seasoned sauce", + "1 cup Spanish style ready rice", + "4 cups lettuce finely chopped", + "2 Roma tomatoes seeded and chopped", + "2 oz cheddar cheese shredded-or try a three-cheese blend similar to the one Taco Bell uses, made with mozzarella, cheddar, and pepper jack cheese", + "½ avocado sliced", + "2 tbsp sour cream" + ], + "purpose": "For the bowls:" + }, + { + "ingredients": [ + "½ ripe avocado", + "½ cup plain non-fat Greek yogurt", + "3 tbsp fresh lime juice", + "1 tbsp ranch seasoning *in the packet", + "Optional bowl add-ins: onions, pickled jalapeños, salsa, pico de gallo" + ], + "purpose": "For the avocado lime ranch dressing:" + } + ], + "instructions_list": [ + "Place the black beans in a small saucepan and heat on medium-low. Heat beans until simmering, while stirring.", + "While the beans are simmering, cook the seasoned rice in the microwave according to package directions, typically 90 seconds.", + "Divide the ingredients between 2 medium-size bowls.", + "Place the dressing ingredients into a small blender or food processor and blend until smooth.", + "Drizzle the dressing on top of the bowls and serve." + ], + "category": "Main Course", + "yields": "2 servings", + "description": "An easy Mexican-inspired vegetable power bowl recipe ready in 10 minutes or less.", + "total_time": 10, + "cook_time": 5, + "prep_time": 5, + "cuisine": "Mexican", + "equipment": [ + "Microwave", + "small saucepan" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "484 kcal", + "fatContent": "21 g", + "saturatedFatContent": "7 g", + "unsaturatedFatContent": "11 g", + "transFatContent": "0.01 g", + "carbohydrateContent": "55 g", + "sugarContent": "8 g", + "proteinContent": "22 g", + "sodiumContent": "1343 mg", + "fiberContent": "12 g", + "cholesterolContent": "35 mg" + }, + "image": "https://ameessavorydish.com/wp-content/uploads/2016/10/Veggie-taco-bowl-feature.jpg", + "keywords": [ + "beans", + "rice", + "vegetables" + ] +} diff --git a/tests/test_data/ameessavorydish.com/ameessavorydish_2.testhtml b/tests/test_data/ameessavorydish.com/ameessavorydish_2.testhtml new file mode 100644 index 000000000..15bd3dc88 --- /dev/null +++ b/tests/test_data/ameessavorydish.com/ameessavorydish_2.testhtml @@ -0,0 +1,1432 @@ + + + + + + + + + + + + + + + + + + + + + + + Taco Bell Veggie Power Bowl {Copycat Recipe} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + | | +
    +

    Taco Bell Veggie Power Bowl {Copycat Recipe}

    +
    + +
    + +

    This copycat Taco Bell Veggie Power Bowl recipe offers the same satisfaction as the original with nearly double the protein! With a shortlist of quick and convenient plant-based ingredients, you can have these bowls on the table in 10 minutes or less!

    + + + +
    veggie power bowl with sliced avocado
    + + + +

    Though I eat a lot of eggs, lean beef, chicken, and fish for lean protein, I also love a good, high-protein, plant-based meal on occasion. The veggie power bowl from Taco Bell is one of my fast food favorites.

    + + + +

    Fortunately, Taco Bell’s power bowl menu is pretty simple, so recreating the vegetarian option was a breeze. The difference? This recipe boasts nearly double the protein content of the Taco Bell version to keep you satisfied and energized throughout the day!

    + + + +

    And the best part? It comes together in just 10 minutes – so why settle for the drive-thru when you can enjoy a healthier, equally delicious power bowl in no time? 

    + + + +

    Why you’ll love this recipe

    + + + +
      +
    • Healthier version of a fast food favorite. With a whopping 22 grams of protein per serving (dressing included), it leaves the Taco Bell version in the dust, which offers only 12 grams.
    • + + + +
    • Quick and easy. In just 10 minutes, you’ll have a restaurant-quality plant-based power bowl ready to dig into from the comfort of your kitchen.
    • + + + +
    • The power of plants! Thanks to all the plant-based goodness, these vegetarian power bowls are loaded with good fiber, lean muscle-building protein, and micronutrients. 
    • + + + +
    • Balanced nutrition. These bowls are a significant source of protein from black beans and Greek yogurt, healthy fats from avocado, and fiber from grains and fresh veggies. 
    • + + + +
    • Power bowl sauce. This recipe includes a Greek yogurt-based avocado lime ranch dressing for an added protein kick. Not to mention, it tastes so good I could almost drink it!
    • +
    + + + +

    Ingredients you’ll need

    + + + +
    taco bell veggie bowl ingredients measured on a counter
    + + + +

    For the bowls: 

    + + + +
      +
    • Canned black beans. Grab a can labeled “seasoned.” They are a convenient way to add cooked, flavorful black beans with very little preparation. 
    • + + + +
    • Spanish-style ready rice. These bowls are all about ease and accessibility, so I popped a pouch of Spanish-style ready rice in the microwave, but you can always make your rice from scratch if you prefer. 
    • + + + +
    • Lettuce. Taco Bell uses shredded iceberg lettuce. Substitute romaine for a similar crunch and mild, slightly sweet flavor.
    • + + + +
    • Tomatoes. I used seeded and chopped Roma tomatoes, but you can use any firm but not overly juicy variety like beefsteak, plum, cherry, or grape.  
    • + + + +
    • Cheddar cheese. Or try a three-cheese blend similar to the one Taco Bell uses, made with mozzarella, cheddar, and pepper jack cheese.
    • + + + +
    • Avocado. For a boost of healthy fats, fiber, vitamins, and minerals. Guacamole is also excellent here.  
    • + + + +
    • Sour cream. It adds a creamy, tangy element to complement the zesty flavors.
    • +
    + + + +

    For the avocado ranch dressing:

    + + + +
      +
    • Avocado. Be sure to use an avocado that is ripe but not overly soft so it blends smoothly and contributes a creamy consistency. 
    • + + + +
    • Greek yogurt. The exact protein content can vary slightly, but using plain, non-fat Greek yogurt as the sauce base can contribute 5-6 grams of protein per serving! 
    • + + + +
    • Fresh lime juice. It adds an acidic, citrusy tang that brightens the flavors of the other ingredients.   
    • + + + +
    • Ranch seasoning. Use a packet of dry ranch seasoning here. 
    • +
    + + + +

    How to make a copycat Taco Bell veggie power bowl

    + + + +

    Step 1: Warm black beans. Heat the black on medium-low until simmering while stirring.

    + + + +
    black beans simmering in a pot on the stove
    + + + +

    Step 2: Heat ready rice. While the beans are simmering, cook the ready rice in the microwave according to package directions. These are two great quick options for making these bowls.

    + + + +
    packets of ready rice on a counter
    + + + +

    Step 3: Assemble bowls. Divide the ingredients between 2 medium-sized bowls.

    + + + +
    veggie bowls assembled with a container of salsa
    + + + +

    Step 4: Make dressing. Place the dressing ingredients in a small blender or food processor and blend until smooth.

    + + + +
    avocado lime ranch dressing ingrediens in a mini blender container
    + + + +

    Step 5: Serve. Drizzle the dressing on top of the bowls, and enjoy!

    + + + +
    avocado lime ranch dressing drizzled on top of veggie bowls
    + + + +

    Recipe Tips

    + + + +
      +
    • To layer the ingredients in the bowls, start with the rice, then add your beans, raw veggies, cheese, avocado, and sour cream, and finally, drizzle the avocado ranch sauce on top for an irresistible presentation. 
    • + + + +
    • To make homemade black beans, soak dried black beans in water overnight. Then, drain, rinse, and simmer them in a pot of water with Taco seasonings like onion, garlic, cumin, paprika, and bay leaves until they’re tender. Add salt to taste.
    • + + + +
    • To make Spanish rice from scratch, sauté onions and garlic in olive oil, then add uncooked rice and cook until lightly toasted. Then, add diced tomatoes, broth, and a blend of Spanish seasonings. Bring the mixture to a boil, reduce the heat, cover, and simmer until the rice is tender. Fluff with a fork and serve.
    • +
    + + + +

    Variations

    + + + +
      +
    • Vegetarian protein – If you don’t like black beans, try other plant-based protein sources in your power bowls, like chickpeas, lentils, crispy tofu, tempeh, or edamame. Try half beans and half lentils for more iron and protein. 
    • + + + +
    • Rice – Instead of rice, you can opt for protein-rich grains like quinoa, farro, or bulgur. Or opt for a low-carb power bowl base like cauliflower rice or spiralized zucchini. 
    • + + + +
    • Sour cream – Several healthier alternatives, like Greek yogurt, coconut yogurt, or hummus, can add a similarly rich, creamy flavor. 
    • + + + +
    • Fresh toppings – Besides lettuce, tomato, and avocado, try topping your bowl with pickled red onions, chopped cilantro, pickled jalapeño, pico de gallo, thinly sliced radish, salsa, grilled peppers and onions, a squeeze of lime juice, etc. 
    • + + + +
    • Dressing – If you’re looking for a non-creamy dressing for your Taco Bell veggie power bowl, the Avocado Ranch Vinaigrette (from my burger bowls) is a must-make!
    • +
    + + + +

    Storing

    + + + +

    Transfer bowl ingredients to individual airtight containers and store the containers in the refrigerator for 3-4 days. If possible, keep the power bowl sauce separate until you’re ready to eat. 

    + + + +

    FAQ

    + + + +
    What is in the Taco Bell veggie power bowl?

    According to the menu, the Taco Bell veggie power bowl includes seasoned rice, black beans, tomatoes, guacamole, lettuce, cheddar cheese, and an avocado ranch sauce.

    Is the veggie power bowl from Taco Bell healthy?

    I consider it a healthier option, as it includes some protein and fiber from vegetables and beans and healthy fats from guacamole. However, it is low on protein for my personal goals. This higher protein copycat recipe made with fresh vegetables and a Greek yogurt dressing is definitely a solid healthy choice!

    Can I make the Greek yogurt avocado dressing in advance?

    Yes! You can make the dressing in advance. It keeps up to 5 days in a sealed container in the fridge -just give it a good stir before serving with the veggie bowls.

    + + + +

    More grain and rice bowl recipes

    + + + + + + + +

    If you love this copycat Taco Bell recipe, I would be so grateful if you could leave a 5-star 🌟 rating in the recipe card below. I love reading your comments and feedback!

    + + + +

    Stay posted on my latest cooking adventures through social media @ Instagram, Pinterest, and Facebook. Also, don’t forget to tag me when you try one of my recipes!

    + + + +
    veggie bowl with rice, beans, tomatoes, cheese, avocado and sour cream with avocado dressing drizzle
    + + +
    veggie bowl with rice, beans, tomatoes, cheese, avocado and sour cream with avocado dressing drizzle
    +
    +
    +

    Taco Bell Veggie Power Bowl {Copycat Recipe}

    +
    +
    An easy Mexican-inspired vegetable power bowl recipe ready in 10 minutes or less.
    +
    +
    No ratings yet
    +
    + Print + Pin + Rate + +
    +
    Course: Main Course
    Cuisine: Mexican
    +
    Prep Time: 5 minutes
    Cook Time: 5 minutes
    Total Time: 10 minutes
    +
    Servings: 2 servings
    +
    Calories: 484kcal
    +
    Author: Amee
    + +
    +

    Equipment

    • Microwave
    • small saucepan
    +

    Ingredients

    • For the bowls:
    • 1 cup canned black beans in seasoned sauce
    • 1 cup Spanish style ready rice
    • 4 cups lettuce finely chopped
    • 2 Roma tomatoes seeded and chopped
    • 2 oz cheddar cheese shredded-or try a three-cheese blend similar to the one Taco Bell uses, made with mozzarella, cheddar, and pepper jack cheese
    • ½ avocado sliced
    • 2 tbsp sour cream
    • For the avocado lime ranch dressing:
    • ½ ripe avocado
    • ½ cup plain non-fat Greek yogurt
    • 3 tbsp fresh lime juice
    • 1 tbsp ranch seasoning *in the packet
    • Optional bowl add-ins: onions, pickled jalapeños, salsa, pico de gallo
    +

    Instructions

    • Place the black beans in a small saucepan and heat on medium-low. Heat beans until simmering, while stirring.
    • While the beans are simmering, cook the seasoned rice in the microwave according to package directions, typically 90 seconds.
    • Divide the ingredients between 2 medium-size bowls.
    • Place the dressing ingredients into a small blender or food processor and blend until smooth.
    • Drizzle the dressing on top of the bowls and serve.
    +
    +

    Notes

    +
      +
    • To make homemade black beans, soak dried black beans in water overnight. Then, drain, rinse, and simmer them in a pot of water with Taco seasonings like onion, garlic, cumin, paprika, and bay leaves until they’re tender. Add salt to taste.
    • +
      +
    • To make Spanish rice from scratch, sauté onions and garlic in olive oil, then add uncooked rice and cook until lightly toasted. Then, add diced tomatoes, broth, and a blend of Spanish seasonings. Bring the mixture to a boil, reduce the heat, cover, and simmer until the rice is tender. Fluff with a fork and serve.
    • +
    +
    +

    Nutrition

    Calories: 484kcal | Carbohydrates: 55g | Protein: 22g | Fat: 21g | Saturated Fat: 7g | Polyunsaturated Fat: 2g | Monounsaturated Fat: 9g | Trans Fat: 0.01g | Cholesterol: 35mg | Sodium: 1343mg | Potassium: 1104mg | Fiber: 12g | Sugar: 8g | Vitamin A: 1653IU | Vitamin C: 27mg | Calcium: 369mg | Iron: 4mg
    +
    +
    Tried this recipe?Mention @ameecooks or tag #ameecooks!
    +
    +
    Amee Livingston
    Follow me
    Latest posts by Amee Livingston (see all)
    +
    +
    +
    + + + + + +
    +

    4 Comments

      +
    1. + +
    2. +
    3. + +
        +
      1. + +
          +
        1. +
          + + +
          +

          You can plug the recipe ingredients into an app, like My Fitness Pal, if you need calorie counts. I don’t do calorie counts on my recipes. I try to focus more on nutrient density and portion size.

          +
          + +
          +
        2. +
        +
      2. +
      +
    4. +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +

    +

    + +

    +
    +
    +
    + + +
    +
    +
    + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 5b7abc9f75e4c150da9d13306a91e50053b9c416 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 6 Dec 2024 22:56:26 -0500 Subject: [PATCH 15/94] Adds support for meganvskitchen (#1391) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/meganvskitchen.py | 16 + .../meganvskitchen.com/meganvskitchen_1.json | 48 + .../meganvskitchen_1.testhtml | 973 ++++++++++++++++++ .../meganvskitchen.com/meganvskitchen_2.json | 77 ++ .../meganvskitchen_2.testhtml | 957 +++++++++++++++++ 7 files changed, 2074 insertions(+) create mode 100644 recipe_scrapers/meganvskitchen.py create mode 100644 tests/test_data/meganvskitchen.com/meganvskitchen_1.json create mode 100644 tests/test_data/meganvskitchen.com/meganvskitchen_1.testhtml create mode 100644 tests/test_data/meganvskitchen.com/meganvskitchen_2.json create mode 100644 tests/test_data/meganvskitchen.com/meganvskitchen_2.testhtml diff --git a/README.rst b/README.rst index 7212c9190..643405673 100644 --- a/README.rst +++ b/README.rst @@ -301,6 +301,7 @@ Scrapers available for: - `https://www.marthastewart.com/ `_ - `https://matprat.no/ `_ - `https://www.mccormick.com/ `_ +- `https://meganvskitchen.com/ `_ - `https://meljoulwan.com/ `_ - `https://www.melskitchencafe.com/ `_ - `https://www.miljuschka.nl/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 7a45306e5..135ffd823 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -249,6 +249,7 @@ from .marthastewart import MarthaStewart from .matprat import Matprat from .mccormick import McCormick +from .meganvskitchen import MeganVsKitchen from .meljoulwan import Meljoulwan from .melskitchencafe import MelsKitchenCafe from .miljuschka import Miljuschka @@ -558,6 +559,7 @@ LeitesCulinaria.host(): LeitesCulinaria, MadameCuisine.host(): MadameCuisine, McCormick.host(): McCormick, + MeganVsKitchen.host(): MeganVsKitchen, Miljuschka.host(): Miljuschka, ModernHoney.host(): ModernHoney, MomOnTimeout.host(): MomOnTimeout, diff --git a/recipe_scrapers/meganvskitchen.py b/recipe_scrapers/meganvskitchen.py new file mode 100644 index 000000000..bffde6c6c --- /dev/null +++ b/recipe_scrapers/meganvskitchen.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class MeganVsKitchen(AbstractScraper): + @classmethod + def host(cls): + return "meganvskitchen.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/tests/test_data/meganvskitchen.com/meganvskitchen_1.json b/tests/test_data/meganvskitchen.com/meganvskitchen_1.json new file mode 100644 index 000000000..529f9a43b --- /dev/null +++ b/tests/test_data/meganvskitchen.com/meganvskitchen_1.json @@ -0,0 +1,48 @@ +{ + "author": "Megan", + "canonical_url": "https://meganvskitchen.com/crispy-ground-beef-tacos/", + "site_name": "Megan vs Kitchen", + "host": "meganvskitchen.com", + "language": "en-US", + "title": "Crispy Beef Tacos", + "ingredients": [ + "1 pound ground beef (lean, 90%)", + "1 packet of taco seasoning", + "¾ cup enchilada sauce", + "2.5 cups Oaxaca cheese (or Mexican cheese or Monterey Jack )", + "10 corn tortillas", + "1 tbs olive oil", + "Toppings: (hot sauce, guacamole, salsa, pickled onions, sour cream, lime wedge)" + ], + "instructions_list": [ + "Preheat oven to 450F.", + "Brown beef in a skillet over medium-high high heat. Mix in taco seasoning and enchilada sauce. Bring to a simmer, then remove pan from the heat.", + "Wrap corn tortillas in a damp paper towel and microwave for 30-60 seconds or until they are pliable.", + "Brush one side of a tortilla with olive oil. Flip it so the oiled side is on the pan. Add 2 tablespoons of shredded cheese to half of the tortilla, top with 1/4 cup of ground beef, and 2 more tablespoons of shredded cheese. Fold the tortilla over the filling*.", + "Repeat with the remaining tortillas and range the tacos in a single layer on your baking sheet.", + "Bake for 16 minutes, or until the tortillas are crispy and the cheese has melted. Let them cool for 3 minutes before serving." + ], + "category": "Main Course", + "yields": "10 servings", + "description": "These Crispy Ground Beef Tacos are an easy weeknight win. They only take 35 minutes to make, and everyone will love dipping them in salsa, queso, and guacamole!", + "total_time": 35, + "cook_time": 35, + "cuisine": "Mexican", + "ratings": 4.67, + "ratings_count": 9, + "nutrients": { + "servingSize": "2 taco", + "calories": "524 kcal", + "fatContent": "30 g", + "saturatedFatContent": "16 g", + "transFatContent": "0.6 g", + "carbohydrateContent": "28 g", + "sugarContent": "4 g", + "proteinContent": "36 g", + "fiberContent": "4 g" + }, + "image": "https://meganvskitchen.com/wp-content/uploads/2023/07/Crispy-Beef-Tacos-Sheet-Pan.jpg", + "keywords": [ + "Crispy Beef Tacos" + ] +} diff --git a/tests/test_data/meganvskitchen.com/meganvskitchen_1.testhtml b/tests/test_data/meganvskitchen.com/meganvskitchen_1.testhtml new file mode 100644 index 000000000..247d5dc9a --- /dev/null +++ b/tests/test_data/meganvskitchen.com/meganvskitchen_1.testhtml @@ -0,0 +1,973 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Crispy Ground Beef Tacos (Baked) - Megan vs Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/meganvskitchen.com/meganvskitchen_2.json b/tests/test_data/meganvskitchen.com/meganvskitchen_2.json new file mode 100644 index 000000000..612a467aa --- /dev/null +++ b/tests/test_data/meganvskitchen.com/meganvskitchen_2.json @@ -0,0 +1,77 @@ +{ + "author": "Megan", + "canonical_url": "https://meganvskitchen.com/cheesy-bean-and-rice-burrito/", + "site_name": "Megan vs Kitchen", + "host": "meganvskitchen.com", + "language": "en-US", + "title": "Cheesy Bean and Rice Burrito", + "ingredients": [ + "¼ cup sour cream", + "¼ cup mayonnaise", + "2 tablespoons pickled jalapenos diced (optional)", + "2 tablespoons pickled jalapeno juice (optional)", + "1 teaspoon paprika", + "1 teaspoon cumin", + "½ teaspoon garlic powder", + "½ teaspoon onion powder", + "½ teaspoon chipotle chili powder or regular chili powder", + "8 9-inch flour tortillas", + "1 16-oz can of refried beans", + "2 2/3 cups Spanish rice (I used a box of New East’s Spanish rice which makes about 3 cups)", + "2 cups Mexican cheese blend" + ], + "ingredient_groups": [ + { + "ingredients": [ + "¼ cup sour cream", + "¼ cup mayonnaise", + "2 tablespoons pickled jalapenos diced (optional)", + "2 tablespoons pickled jalapeno juice (optional)", + "1 teaspoon paprika", + "1 teaspoon cumin", + "½ teaspoon garlic powder", + "½ teaspoon onion powder", + "½ teaspoon chipotle chili powder or regular chili powder" + ], + "purpose": "Creamy Jalapeno Sauce" + }, + { + "ingredients": [ + "8 9-inch flour tortillas", + "1 16-oz can of refried beans", + "2 2/3 cups Spanish rice (I used a box of New East’s Spanish rice which makes about 3 cups)", + "2 cups Mexican cheese blend" + ], + "purpose": "Cheesy Bean and Rice Burrito" + } + ], + "instructions_list": [ + "In a small bowl, mix together the creamy jalapeno sauce ingredients.", + "Lay a tortilla flat, spread 1/4 cup of refried beans, 1/3 cup of Spanish rice, 1/4 cup of Mexican cheese, and 1/2 tablespoon* of jalapeno sauce down the middle. Roll into a burrito.", + "Fold the burrito.", + "Place a skillet over medium heat. Add burrito seam side down. Toast on both sides till brown." + ], + "category": "Dinner", + "yields": "8 servings", + "description": "Inspired by Taco Bell, this copycat Cheesy Bean and Rice Burrito is easy to make, cheap, and so much better than the original.", + "total_time": 35, + "cook_time": 15, + "prep_time": 20, + "cuisine": "American", + "ratings": 4.79, + "ratings_count": 37, + "nutrients": { + "servingSize": "1 Burrito", + "calories": "385 kcal", + "fatContent": "15.1 g", + "saturatedFatContent": "6.9 g", + "carbohydrateContent": "51 g", + "sugarContent": "2.1 g", + "proteinContent": "13.4 g", + "fiberContent": "3.2 g" + }, + "image": "https://meganvskitchen.com/wp-content/uploads/2022/11/IMG_5024-scaled.jpg", + "keywords": [ + "cheesy bean and rice burrito" + ] +} diff --git a/tests/test_data/meganvskitchen.com/meganvskitchen_2.testhtml b/tests/test_data/meganvskitchen.com/meganvskitchen_2.testhtml new file mode 100644 index 000000000..73a7aa718 --- /dev/null +++ b/tests/test_data/meganvskitchen.com/meganvskitchen_2.testhtml @@ -0,0 +1,957 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cheesy Bean and Rice Burrito - Megan vs Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + \ No newline at end of file From be18baf29dd041aa4e4a49df6012d92c4048b07c Mon Sep 17 00:00:00 2001 From: Brandon Sprague Date: Fri, 6 Dec 2024 20:13:16 -0800 Subject: [PATCH 16/94] Add "A Healthy Slice of Life" site (#1413) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/ahealthysliceoflife.py | 38 + .../ahealthysliceoflife.json | 31 + .../ahealthysliceoflife.testhtml | 2272 +++++++++++++++++ 5 files changed, 2344 insertions(+) create mode 100644 recipe_scrapers/ahealthysliceoflife.py create mode 100644 tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json create mode 100644 tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.testhtml diff --git a/README.rst b/README.rst index 643405673..507dc2f1f 100644 --- a/README.rst +++ b/README.rst @@ -88,6 +88,7 @@ Scrapers available for: - `http://www.afghankitchenrecipes.com/ `_ - `https://aflavorjournal.com/ `_ - `https://ah.nl/ `_ +- `https://www.ahealthysliceoflife.com/ `_ - `https://akispetretzikis.com/ `_ - `https://aldi-nord.de/ `_ - `.es `__, `.fr `__, `.lu `__, `.nl `__, `.pl `__, `.pt `__ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 135ffd823..0cbe9e990 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -41,6 +41,7 @@ from .addapinch import AddAPinch from .afghankitchenrecipes import AfghanKitchenRecipes from .aflavorjournal import AFlavorJournal +from .ahealthysliceoflife import AHealthySliceOfLife from .akispetretzikis import AkisPetretzikis from .albertheijn import AlbertHeijn from .aldi import Aldi @@ -428,6 +429,7 @@ ABeautifulMess.host(): ABeautifulMess, ACoupleCooks.host(): ACoupleCooks, AFlavorJournal.host(): AFlavorJournal, + AHealthySliceOfLife.host(): AHealthySliceOfLife, ALittleBitYummy.host(): ALittleBitYummy, AberleHome.host(): AberleHome, Abril.host(): Abril, diff --git a/recipe_scrapers/ahealthysliceoflife.py b/recipe_scrapers/ahealthysliceoflife.py new file mode 100644 index 000000000..25ef58fb4 --- /dev/null +++ b/recipe_scrapers/ahealthysliceoflife.py @@ -0,0 +1,38 @@ +from ._abstract import AbstractScraper +from ._utils import normalize_string + + +class AHealthySliceOfLife(AbstractScraper): + @classmethod + def host(cls): + return "ahealthysliceoflife.com" + + def author(self): + return self.schema.author() + + def title(self): + return self.schema.title() + + def category(self): + return self.schema.category() + + def image(self): + return self.schema.image() + + def ingredients(self): + ingredients = self.soup.find( + "div", {"class": "tasty-recipes-ingredients-body"} + ).findAll("p") + return [normalize_string(ing.get_text().strip()) for ing in ingredients] + + def instructions(self): + return self.schema.instructions() + + def ratings(self): + return self.schema.ratings() + + def cuisine(self): + return self.schema.cuisine() + + def description(self): + return self.schema.description() diff --git a/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json new file mode 100644 index 000000000..aebc7e85e --- /dev/null +++ b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json @@ -0,0 +1,31 @@ +{ + "author": "Brittany Dixon", + "canonical_url": "https://www.ahealthysliceoflife.com/red-lentil-carrot-curry-recipe/", + "site_name": "A Healthy Slice of Life", + "host": "ahealthysliceoflife.com", + "language": "en-US", + "title": "Red Lentil and Carrot Curry Recipe", + "ingredients": [ + "3 Tbsp olive oil", + "3 garlic cloves, minced", + "1.5 tsp grated ginger", + "1 small onion, small diced (about 1 c)", + "2 large carrots, small diced (about 1 c)", + "1.5 Tbsp curry powder", + "1 tsp turmeric", + "1.5 c red lentils", + "1.5 tsp salt", + "1 c vegetable broth", + "1 can full fat coconut milk", + "3 oz chopped baby spinach", + "Juice of half a lime" + ], + "instructions_list": [ + "In a large pan, heat oil over medium heat.", + "Add onion and carrots. Sauté 4 minutes until onions are beginning to soften. Add garlic, ginger, curry powder, and turmeric to the pan and sauté for 1-2 minutes more, until fragrant.", + "Add lentils, salt, broth, and coconut milk to the pan. Bring to a boil while mixing well, then cover and reduce heat to a gentle simmer. Let simmer for 20 minutes, then remove from heat.", + "Take off the lid, add spinach and lime juice and stir to combine. Serve over hot buttered rice." + ], + "description": "This nourishing curry recipe is perfect for when you need something comforting and delicious on the dinner table quickly!", + "image": "https://www.ahealthysliceoflife.com/wp-content/uploads/2021/08/A-Healthy-Slice_Lentil-Curry-9-scaled-225x225.jpg" +} diff --git a/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.testhtml b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.testhtml new file mode 100644 index 000000000..6e0037116 --- /dev/null +++ b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.testhtml @@ -0,0 +1,2272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Red Lentil & Carrot Curry Recipe - A Healthy Slice of Life + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Red Lentil & Carrot Curry Recipe

    +
    This curry recipe is perfect for when you need something nourishing and delicious on the dinner table quickly!

    This post may contain affiliate links to products I use and love! More about privacy here.

    +
    + +
      +
    • +
    • +
    + +
      +
    • +
    • +
    + +

    Looking for something specific?

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From acff74511b4ed6b694b84bbe41d6cf6a2a2a2221 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sat, 7 Dec 2024 09:37:55 -0500 Subject: [PATCH 17/94] recetteplus (#1414) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/recetteplus.py | 22 + tests/test_data/recette.plus/recetteplus.json | 47 + .../recette.plus/recetteplus.testhtml | 2011 +++++++++++++++++ 5 files changed, 2083 insertions(+) create mode 100644 recipe_scrapers/recetteplus.py create mode 100644 tests/test_data/recette.plus/recetteplus.json create mode 100644 tests/test_data/recette.plus/recetteplus.testhtml diff --git a/README.rst b/README.rst index 507dc2f1f..5c5b2b80e 100644 --- a/README.rst +++ b/README.rst @@ -371,6 +371,7 @@ Scrapers available for: - `https://www.receitasnestle.com.br `_ - `https://recept.se/ `_ - `https://receptyprevas.sk/ `_ +- `https://recette.plus/ `_ - `https://www.recipegirl.com/ `_ - `https://reciperunner.com/ `_ - `https://recipes.farmhousedelivery.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 0cbe9e990..c796c9b58 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -320,6 +320,7 @@ from .receitasnestlebr import ReceitasNestleBR from .recept import Recept from .receptyprevas import ReceptyPreVas +from .recetteplus import RecettePlus from .recipegirl import RecipeGirl from .reciperunner import RecipeRunner from .recipetineats import RecipeTinEats @@ -580,6 +581,7 @@ QuiToque.host(): QuiToque, Recept.host(): Recept, ReceptyPreVas.host(): ReceptyPreVas, + RecettePlus.host(): RecettePlus, RecipeGirl.host(): RecipeGirl, Rewe.host(): Rewe, RicettePerBimby.host(): RicettePerBimby, diff --git a/recipe_scrapers/recetteplus.py b/recipe_scrapers/recetteplus.py new file mode 100644 index 000000000..9369cd069 --- /dev/null +++ b/recipe_scrapers/recetteplus.py @@ -0,0 +1,22 @@ +from ._abstract import AbstractScraper +from ._utils import get_equipment + + +class RecettePlus(AbstractScraper): + @classmethod + def host(cls): + return "recette.plus" + + def equipment(self): + equipment_container = self.soup.find("ul", class_="ustensiles-list") + if not equipment_container: + return None + + equipment_items = [] + for item in equipment_container.find_all("li", class_="ustensiles-item"): + equipment_info = item.find("span", class_="ustensiles-info") + if equipment_info: + equipment_text = equipment_info.get_text().replace(" ", " ") + equipment_items.append(equipment_text) + + return get_equipment(equipment_items) diff --git a/tests/test_data/recette.plus/recetteplus.json b/tests/test_data/recette.plus/recetteplus.json new file mode 100644 index 000000000..d33355883 --- /dev/null +++ b/tests/test_data/recette.plus/recetteplus.json @@ -0,0 +1,47 @@ +{ + "author": "sofie", + "canonical_url": "https://www.recette.plus/recettes/plat-principal/2330-pignons-de-poulet-a-la-creme.html", + "site_name": "Recette Plus : Découvrez toutes les recettes de cuisine française et du monde", + "host": "recette.plus", + "language": "fr", + "title": "Pignons de poulet à la crème", + "ingredients": [ + "1 Oignon jaune", + "2 Tomate", + "10 g Beurre", + "1 cuillère à soupe Huile d'olive", + "4 Pignons", + "20 cl Crème liquide" + ], + "instructions_list": [ + "Faites rôtir les pignons au four dans du beurre pendant 1 h.", + "Émincez l'oignon et faites-le revenir dans une poêle avec un peu d'huile d'olive et mettre de côté.", + "Une fois cuit, mettre les pignons de poulet dans la poêle avec le beurre, et les pignons qui sortent du four.", + "Ensuite ajoutez la crème, les tomates coupées en dés et les oignons cuits auparavant. Laissez mijoter 15 min le temps que les tomates se ramollissent.", + "Servir chaud accompagné par exemple de pommes de terre sautées." + ], + "category": "Plat principal", + "yields": "2 servings", + "total_time": 95, + "cook_time": 75, + "prep_time": 20, + "equipment": [ + "1 Four", + "1 Set 3 poêles", + "1 Dénoyauteur", + "1 Balance de cuisine" + ], + "image": "https://www.recette.plus/uploads/posts/2023-08/urecipes_d00e2528110cb18d8c3b33b0e0cf0b6a.webp", + "keywords": [ + "Pignons de poulet à la crème", + "oignon jaune", + "tomate", + "beurre", + "huile dolive", + "pignons", + "crème liquide", + "poulet en sauce", + "facile", + "bon marché" + ] +} diff --git a/tests/test_data/recette.plus/recetteplus.testhtml b/tests/test_data/recette.plus/recetteplus.testhtml new file mode 100644 index 000000000..2b098b989 --- /dev/null +++ b/tests/test_data/recette.plus/recetteplus.testhtml @@ -0,0 +1,2011 @@ + + + + Pignons de poulet à la crème + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + +
    + + + + + +
    +
    + + + + + + + + +
    + + + + + + + + + + +
    + + + + + + + + +
    + +
    + + + + + + + +
    + + + + +
    +
    + +
    + + +
    + + +
    +

    Ingrédients

    +
    + + +
    +
    + + +
    2 Personnes
    + + + +
    + +
    + + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + + + + + +
    + +
    + +
    +

    Ustensiles

    +
    + + +
      +
    • Four
      1 Four
    • + + +
    • Set 3 poêles
      1 Set 3 poêles
    • + + +
    • Dénoyauteur
      1 Dénoyauteur
    • + + +
    • Balance de cuisine
      1 Balance de cuisine
    • + +
    + + +
    + +
    +
    +

    Préparation

    +
    + + + + + + +
      +
    • +
      + +
      +
      + Temps de Preparation +
      +
      +
      20 min
      + +
      +
      + +
      +
    • +
    • +
      + +
      +
      + Repos +
      +
      +
      -
      + +
      +
      + +
      +
    • + +
    • +
      +
      +
      + Cuisson +
      +
      +
      75 min
      + +
      +
      +
      +
    • +
    + + + + + + + + + + + + +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + + + + + + + + + + +
    +
    +
    + + + + + + + +

    Recettes Suggérées

    +
    + + +
    + Recette +
    +
    +
    Méli-mélo dorzo et de verdure
    + +
    +
    + +
    + Recette +
    +
    +
    Pastèque pizza salée
    + +
    +
    + +
    + Recette +
    +
    +
    Tarte aux pignons et sa frangipane
    + +
    +
    + +
    + Recette +
    +
    +
    Tarte aux pommes, pignons et noisette
    + +
    +
    + +
    + Recette +
    +
    +
    Pennes au poulet, tomates séchées et pignons
    + +
    +
    + +
    + Recette +
    +
    +
    Poulet aigre-doux au four
    + +
    +
    + +
    + Recette +
    +
    +
    Poulet mariné façon Cricri
    + +
    +
    + +
    + Recette +
    +
    +
    Sauté de veau aux raisins et pignons
    + +
    +
    + +
    + Recette +
    +
    +
    spaghetti aux asperges, artichauts et pignons
    + +
    +
    + +
    + Recette +
    +
    +
    Velouté de courgettes aux pignons de pin
    + +
    +
    +
    +
    +
    + + +
    +
    Commentaires (0)
    +
    + +
    + + +
    +
    +
    +
    + + + +
    + + +
    +
    + + +
    +
    + +
    +
    +
    Il n'y a pas encore de commentaires. Vous pouvez être le premier!
    + +
    + +
    +
    + +
    + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From e715ef5bc63a4014f9ffee968da8f9a010f81a8e Mon Sep 17 00:00:00 2001 From: melody hu <40373356+shinyumh@users.noreply.github.com> Date: Sat, 7 Dec 2024 11:50:17 -0500 Subject: [PATCH 18/94] Added scraper for schoolofwok.co.uk (#1415) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/schoolofwok.py | 136 +++ .../schoolofwok.co.uk/schoolofwok.json | 76 ++ .../schoolofwok.co.uk/schoolofwok.testhtml | 947 ++++++++++++++++++ 5 files changed, 1162 insertions(+) create mode 100644 recipe_scrapers/schoolofwok.py create mode 100644 tests/test_data/schoolofwok.co.uk/schoolofwok.json create mode 100644 tests/test_data/schoolofwok.co.uk/schoolofwok.testhtml diff --git a/README.rst b/README.rst index 5c5b2b80e..886332e77 100644 --- a/README.rst +++ b/README.rst @@ -393,6 +393,7 @@ Scrapers available for: - `https://sandwichtribunal.com/ `_ - `https://www.saveur.com/ `_ - `https://www.savorynothings.com/ `_ +- `https://schoolofwok.co.uk/ `_ - `https://seriouseats.com/ `_ - `https://shelikesfood.com/ `_ - `https://simple-veganista.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index c796c9b58..351a4df77 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -339,6 +339,7 @@ from .sandwhichtribunal import SandwhichTribunal from .saveur import Saveur from .savorynothings import SavoryNothings +from .schoolofwok import SchoolOfWok from .seriouseats import SeriousEats from .shelikesfood import SheLikesFood from .simpleveganista import SimpleVeganista @@ -775,6 +776,7 @@ SallysBlog.host(): SallysBlog, SaltPepperSkillet.host(): SaltPepperSkillet, Saveur.host(): Saveur, + SchoolOfWok.host(): SchoolOfWok, SeriousEats.host(): SeriousEats, SimpleVeganista.host(): SimpleVeganista, SimplyCookit.host(): SimplyCookit, diff --git a/recipe_scrapers/schoolofwok.py b/recipe_scrapers/schoolofwok.py new file mode 100644 index 000000000..e590af7fd --- /dev/null +++ b/recipe_scrapers/schoolofwok.py @@ -0,0 +1,136 @@ +from collections import defaultdict + +from ._abstract import AbstractScraper +from ._grouping_utils import IngredientGroup +from ._utils import get_minutes, get_yields, normalize_string + + +class SchoolOfWok(AbstractScraper): + @classmethod + def host(cls): + return "schoolofwok.co.uk" + + def author(self): + return "School of Wok" + + def site_name(self): + return "School of Wok" + + def title(self): + return self.soup.find("h1").get_text() + + def cuisine(self): + categoryheader = self.soup.find( + string=lambda text: text and text.lower() == "cuisine" + ) + + return categoryheader.find_next("p").get_text() if categoryheader else None + + def total_time(self): + timeheader = self.soup.find(string=lambda text: text and text.lower() == "time") + + return get_minutes(timeheader.find_next("p").get_text()) if timeheader else None + + def yields(self): + servingheader = self.soup.find( + string=lambda text: text and text.lower() == "servings" + ) + + return ( + get_yields(servingheader.find_next("p").get_text()) + if servingheader + else None + ) + + def image(self): + return self.soup.find("img", {"alt": "recipe"}).get("src") + + def ingredients(self): + section = self.soup.find("section", {"id": "recipe-ingredients"}) + div_class = "flex flex-col gap-y-4 font-medium md:basis-1/2 xl:basis-2/5" + divs = section.findChildren("div", {"class": div_class}) + + if not divs: + return [] + + paragraphs = divs[0].find_all("p") + ingredients_list = [] + + if paragraphs: + for paragraph in paragraphs: + text = normalize_string(paragraph.get_text()) + if text and not paragraph.find("strong"): + ingredients_list.append(text) + else: + list_items = divs[0].find_all("li") + ingredients_list = [ + normalize_string(item.get_text()) for item in list_items + ] + + return ingredients_list + + def ingredient_groups(self): + section = self.soup.find("section", {"id": "recipe-ingredients"}) + div_class = "flex flex-col gap-y-4 font-medium md:basis-1/2 xl:basis-2/5" + divs = section.findChildren("div", {"class": div_class}) + + if not divs: + return [] + + paragraphs = divs[0].find_all("p") + groupings = defaultdict(list) + current_heading = None + + if paragraphs: + for paragraph in paragraphs: + normalized_ingredient = normalize_string(paragraph.get_text()) + if normalized_ingredient: + if paragraph.find("strong"): + current_heading = normalized_ingredient + else: + groupings[current_heading].append(normalized_ingredient) + else: + list_items = divs[0].find_all() + for item in list_items: + if ( + item.name == "h3" + and normalize_string(item.get_text()).lower() != "ingredients" + ): + current_heading = normalize_string(item.get_text()) + elif item.name == "li": + normalized_ingredient = normalize_string(item.get_text()) + if normalized_ingredient: + groupings[current_heading].append(normalized_ingredient) + + return [ + IngredientGroup(purpose=heading, ingredients=items) + for heading, items in groupings.items() + ] + + def instructions(self): + section = self.soup.find("section", {"id": "recipe-ingredients"}) + div_class = "flex flex-col gap-y-4 font-medium md:basis-1/2 xl:basis-2/5" + divs = section.findChildren("div", {"class": div_class}) + + if len(divs) < 2: + return "" + + instructions = divs[1].find_all("p") + instructionslist = [] + + for instruction in instructions: + normalizedinstruction = normalize_string(instruction.get_text()) + if normalizedinstruction: + if normalizedinstruction[0].isdigit(): + instructionslist.append(normalizedinstruction[3:]) + elif normalizedinstruction[0] == "•": + instructionslist.append(normalizedinstruction[2:]) + else: + instructionslist.append(normalizedinstruction) + + return "\n".join(instructionslist) + + def description(self): + return self.soup.find( + "p", {"class": "mb-2 pb-4 border-b border-b-white xl:text-lg"} + ).get_text() diff --git a/tests/test_data/schoolofwok.co.uk/schoolofwok.json b/tests/test_data/schoolofwok.co.uk/schoolofwok.json new file mode 100644 index 000000000..29bc796bf --- /dev/null +++ b/tests/test_data/schoolofwok.co.uk/schoolofwok.json @@ -0,0 +1,76 @@ +{ + "author": "School of Wok", + "canonical_url": "https://schoolofwok.co.uk/tips-and-recipes/simple-chicken-and-rice", + "site_name": "School of Wok", + "host": "schoolofwok.co.uk", + "language": "en", + "title": "Simple Chicken and Rice", + "ingredients": [ + "400g boned, skinless chicken thighs", + "280g jasmine rice", + "340ml chicken stock", + "½ onion", + "1 thumb-sized piece of ginger (roughly chopped)", + "2 spring onions (sliced in half", + "2 teaspoons sesame oil", + "2 tablespoons light soy sauce", + "2 tablespoons Shaoxing rice wine", + "1 teaspoon granulated sugar", + "1 thumb size piece of ginger grated", + "3 garlic cloves grated", + "1 thumb-sized piece of ginger", + "2 cloves garlic", + "1 tsp sugar", + "5 birds eye chillies", + "Juice of a lime" + ], + "ingredient_groups": [ + { + "ingredients": [ + "400g boned, skinless chicken thighs", + "280g jasmine rice", + "340ml chicken stock", + "½ onion", + "1 thumb-sized piece of ginger (roughly chopped)", + "2 spring onions (sliced in half" + ], + "purpose": null + }, + { + "ingredients": [ + "2 teaspoons sesame oil", + "2 tablespoons light soy sauce", + "2 tablespoons Shaoxing rice wine", + "1 teaspoon granulated sugar", + "1 thumb size piece of ginger grated", + "3 garlic cloves grated" + ], + "purpose": "The Marinade" + }, + { + "ingredients": [ + "1 thumb-sized piece of ginger", + "2 cloves garlic", + "1 tsp sugar", + "5 birds eye chillies", + "Juice of a lime" + ], + "purpose": "Chilli Paste" + } + ], + "instructions_list": [ + "Trim all the fat and bone from the chicken and place in a pot with the chicken stock. Add the spring onions and ginger and allow that broth to simmer on the side.", + "Cut the chicken thighs into 5mm slices and put in a bowl. Add the marinade ingredients to the bowl and, using your hands, rub them together until all the marinade has been absorbed.", + "Rinse the rice 2–3 times to get rid of any excess starch, then drain the rice through a sieve.", + "Heat the vegetable oil to a medium heat in a heavy-bottomed saucepan.", + "Finely dice the onion and place in the pan to fry until golden.", + "Add the washed rice to the pan and fry it for 1 minute, stirring to coat the grains evenly, then pour over the broth. Bring to the boil, then reduce to a simmer, add the chicken, cover with a lid and cook over a low heat for 15-20 minutes.", + "Remove the lid and check that the chicken is cooked (it should be light brown or white in colour, with no pink), and that the rice has formed a crisp, golden-brown layer on the bottom of the pan. If it needs it, leave it to cook for a few minutes longer. Make a quick chilli sauce from the juice of a lime, red chillies, ginger, sugar and garlic. Pop that into a pestle and mortar and break down into a chiili paste.", + "Once cooked, spoon the chicken rice into bowls and garnish with the chilli." + ], + "yields": "2 servings", + "description": "We all love Hainanese chicken rice, but we don't always have the time to make the full thing. Here's a quicker and easier way to get similar results that will leave your cravings satisfied!", + "total_time": 45, + "cuisine": "Singaporean", + "image": "https://school-of-wok.s3.eu-west-2.amazonaws.com/recipes/show_images/7287b461711c044521422a0a246757fe.jpg" +} diff --git a/tests/test_data/schoolofwok.co.uk/schoolofwok.testhtml b/tests/test_data/schoolofwok.co.uk/schoolofwok.testhtml new file mode 100644 index 000000000..0a7c18de8 --- /dev/null +++ b/tests/test_data/schoolofwok.co.uk/schoolofwok.testhtml @@ -0,0 +1,947 @@ + + + + + + + + Simple Chicken and Rice Recipe! | School of Wok + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    + +
    + +
    + + school of wok + +
    +
    + + + + + + + + + + + + + + + + +
    + + + + + + +
    + +
    + + + +
    + + + +
    + + + + +
    + +
    +
    + + + +
    +
    +
    +
    + +
    + +
    +
    + +

    Posted on Wed 13th March 2024

    +

    Simple Chicken and Rice

    +

    We all love Hainanese chicken rice, but we don't always have the time to make the full thing. Here's a quicker and easier way to get similar results that will leave your cravings satisfied!

    + +
    +
    +

    Cuisine

    +

    Singaporean

    +
    +
    +

    Time

    +

    45 mins

    +
    +
    +

    Servings

    +

    2

    +
    +
    + + + +
    + Most popular + Latest +
    + +
    +
    + +
    + recipe +
    + +
    + +
    + +
    +
    + +
    +

    Ingredients

    +
    +

    400g boned, skinless chicken thighs

    + +

    280g jasmine rice

    + +

    340ml chicken stock

    + +

    ½ onion

    + +

    1 thumb-sized piece of ginger (roughly chopped) 

    + +

    2 spring onions (sliced in half  

    + +

     

    + +

    The Marinade

    + +

    2 teaspoons sesame oil

    + +

    2 tablespoons light soy sauce

    + +

    2 tablespoons Shaoxing rice wine

    + +

    1 teaspoon granulated sugar

    + +

    1 thumb size piece of ginger grated

    + +

    3 garlic cloves grated

    + +

     

    + +

    Chilli Paste

    + +

    1 thumb-sized piece of ginger 

    + +

    2 cloves garlic 

    + +

    1 tsp sugar 

    + +

    5 birds eye chillies 

    + +

    Juice of a lime

    +
    +
    + +
    +

    Method

    +

    Preparation

    +
    +

    Trim all the fat and bone from the chicken and place in a pot with the chicken stock.  Add the spring onions and ginger and allow that broth to simmer on the side. 

    + +

    Cut the chicken thighs into 5mm slices and put in a bowl. Add the marinade ingredients to the bowl and, using your hands, rub them together until all the marinade has been absorbed.

    + +

    Rinse the rice 2–3 times to get rid of any excess starch, then drain the rice through a sieve.

    +
    +

    Cooking

    +
    +

    Heat the vegetable oil to a medium heat in a heavy-bottomed saucepan.

    + +

    Finely dice the onion and place in the pan to fry until golden. 

    + +

    Add the washed rice to the pan and fry it for 1 minute, stirring to coat the grains evenly, then pour over the broth. Bring to the boil, then reduce to a simmer, add the chicken,  cover with a lid and cook over a low heat for 15-20 minutes. 

    + +

    Remove the lid and check that the chicken is cooked (it should be light brown or white in colour, with no pink), and that the rice has formed a crisp, golden-brown layer on the bottom of the pan. If it needs it, leave it to cook for a few minutes longer. Make a quick chilli sauce from the juice of a lime, red chillies, ginger, sugar and garlic. Pop that into a pestle and mortar and break down into a chiili paste. 

    + +

    Once cooked, spoon the chicken rice into bowls and garnish with the chilli.  

    +
    +
    + +
    +
    + +
    + +
    +

    Explore our award-winning cookware range today!

    + +
    +
    +
    +
    + +
    + +
    +
    +
    + + + + STAINLESS STEEL WOK RING (12322012) + + + + STAINLESS STEEL WOK RING (12322012) +

    £12.00

    + +
    +
    +
    +
    + + + + School of Wok Wok Clock (12373365) + + + + School of Wok Wok Clock (12373365) +

    £15.00

    + +
    +
    +
    +
    + + + + Supreme 24cm Non-Stick Frying Pan (12101823) + + + + Supreme 24cm Non-Stick Frying Pan (12101823) +

    £82.00

    + +
    +
    +
    +
    + + + + Stainless Steel Sieve 15cm (17830311) + + + + Stainless Steel Sieve 15cm (17830311) +

    £10.00

    + +
    +
    +
    +
    + + + + Wooden Lemon Reamer (17841485) + + + + Wooden Lemon Reamer (17841485) +

    £4.75

    + +
    +
    + +
    +
    +
    +
    + + +
    + Go Shopping +
    +
    +
    + +
    + +
    +
    + +
    +

    How to cook Simple Chicken and Rice

    + +
    + +
    + +
    + +
    + + +
    + + + + + + + + + + \ No newline at end of file From f81f53a6b706834a59a93d8a14eeb17c82eaa6ce Mon Sep 17 00:00:00 2001 From: melody hu <40373356+shinyumh@users.noreply.github.com> Date: Sat, 7 Dec 2024 11:50:46 -0500 Subject: [PATCH 19/94] Added scraper for veroniquecloutier.com (#1411) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/veroniquecloutier.py | 129 ++ .../veroniquecloutier.json | 63 + .../veroniquecloutier.testhtml | 1506 +++++++++++++++++ 5 files changed, 1701 insertions(+) create mode 100644 recipe_scrapers/veroniquecloutier.py create mode 100644 tests/test_data/veroniquecloutier.com/veroniquecloutier.json create mode 100644 tests/test_data/veroniquecloutier.com/veroniquecloutier.testhtml diff --git a/README.rst b/README.rst index 886332e77..314b15fd9 100644 --- a/README.rst +++ b/README.rst @@ -459,6 +459,7 @@ Scrapers available for: - `https://www.vegetarbloggen.no/ `_ - `https://vegolosi.it/ `_ - `https://vegrecipesofindia.com/ `_ +- `https://veroniquecloutier.com `_ - `https://www.waitrose.com/ `_ - `https://watchwhatueat.com/ `_ - `https://wearenotmartha.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 351a4df77..b250ed489 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -407,6 +407,7 @@ from .vegetarbloggen import Vegetarbloggen from .vegolosi import Vegolosi from .vegrecipesofindia import VegRecipesOfIndia +from .veroniquecloutier import VeroniqueCloutier from .waitrose import Waitrose from .watchwhatueat import WatchWhatUEat from .wearenotmartha import WeAreNotMartha @@ -831,6 +832,7 @@ VegRecipesOfIndia.host(): VegRecipesOfIndia, Vegetarbloggen.host(): Vegetarbloggen, Vegolosi.host(): Vegolosi, + VeroniqueCloutier.host(): VeroniqueCloutier, Waitrose.host(): Waitrose, WatchWhatUEat.host(): WatchWhatUEat, WeAreNotMartha.host(): WeAreNotMartha, diff --git a/recipe_scrapers/veroniquecloutier.py b/recipe_scrapers/veroniquecloutier.py new file mode 100644 index 000000000..025a5b2fd --- /dev/null +++ b/recipe_scrapers/veroniquecloutier.py @@ -0,0 +1,129 @@ +from collections import defaultdict + +from ._abstract import AbstractScraper +from ._exceptions import FieldNotProvidedByWebsiteException +from ._grouping_utils import IngredientGroup +from ._utils import normalize_string + + +class VeroniqueCloutier(AbstractScraper): + @classmethod + def host(cls): + return "veroniquecloutier.com" + + def author(self): + return self.soup.find("strong").get_text() + + def title(self): + return self.soup.find("h1", {"class": "title -main -page-title"}).get_text() + + def total_time(self): + raise FieldNotProvidedByWebsiteException(return_value=None) + + def yields(self): + potion_line = self.soup.find( + string=lambda text: text + and ("portions" in text.lower() or "donne " in text.lower()) + ) + + if not potion_line: + return None + + parent_text = potion_line.parent.get_text() if potion_line.parent else None + french_numbers = { + "un": 1, + "deux": 2, + "trois": 3, + "quatre": 4, + "cinq": 5, + "six": 6, + "sept": 7, + "huit": 8, + "neuf": 9, + "dix": 10, + "onze": 11, + "douze": 12, + "treize": 13, + "quatorze": 14, + "quinze": 15, + } + special_cases = {"dizaine": 10, "douzaine": 12} + + for word in parent_text.split(): + word_lower = word.lower() + if word.isdigit(): + return f"{word} serving" if int(word) == 1 else f"{word} servings" + if word_lower in french_numbers: + number = french_numbers[word_lower] + return f"{number} serving" if number == 1 else f"{number} servings" + if word_lower in special_cases: + number = special_cases[word_lower] + return f"{number} serving" if number == 1 else f"{number} servings" + + return None + + def ingredients(self): + start = self.soup.find( + string=lambda text: text and text.lower() == "ingrédients" + ) + + ingredient_list = [] + for sibling in start.find_all_next(): + if sibling.string and "préparation" in sibling.string.lower(): + break + if sibling.name == "ul": + ingredient_list.extend(li.text for li in sibling.find_all("li")) + + return ingredient_list + + def ingredient_groups(self): + start = self.soup.find( + string=lambda text: text and text.lower() == "ingrédients" + ) + + found_ingredients = [] + groupings = defaultdict(list) + current_heading = None + for sibling in start.find_all_next(): + if sibling.string and "préparation" in sibling.string.lower(): + break + + if sibling.name == "p" and sibling.text.strip(): + current_heading = sibling.text.strip() + + if sibling.name == "ul" and current_heading: + groupings[current_heading].extend( + li.text for li in sibling.find_all("li") + ) + found_ingredients.extend(li.text for li in sibling.find_all("li")) + elif sibling.name == "ul": + found_ingredients.extend(li.text for li in sibling.find_all("li")) + + if not groupings: + return [IngredientGroup(ingredients=found_ingredients)] + + return [ + IngredientGroup(purpose=heading, ingredients=items) + for heading, items in groupings.items() + ] + + def instructions(self): + start = self.soup.find( + string=lambda text: text and text.lower() == "préparation" + ) + + instruction_list = [] + for sibling in start.find_all_next(): + if sibling.name == "div": + break + if sibling.name == "ol": + instruction_list.extend(li.text for li in sibling.find_all("li")) + elif sibling.name == "p" and sibling.text[0].isdigit(): + instruction_list.append(sibling.text[3:]) + + return "\n".join(instruction_list) + + def description(self): + return normalize_string( + self.soup.find("div", {"class": "post-excerpt"}).get_text() + ) diff --git a/tests/test_data/veroniquecloutier.com/veroniquecloutier.json b/tests/test_data/veroniquecloutier.com/veroniquecloutier.json new file mode 100644 index 000000000..17df6c4a1 --- /dev/null +++ b/tests/test_data/veroniquecloutier.com/veroniquecloutier.json @@ -0,0 +1,63 @@ +{ + "author": "Marilou", + "canonical_url": "https://veroniquecloutier.com/cuisine/boeuf-braise-a-loignon-et-puree-de-pommes-de-terre-au-bacon", + "site_name": "Véronique Cloutier", + "host": "veroniquecloutier.com", + "language": "fr-CA", + "title": "Boeuf braisé à l’oignon et purée de pommes de terre au bacon", + "ingredients": [ + "30 ml (2 c. à soupe) de beurre et 30 ml (2 c. à soupe) de beurre supplémentaire au besoin", + "225 g (1/2 lb) de champignons tranchés", + "250 ml (1 t) d’oignons hachés", + "2 gousses d’ail entières pelées", + "900 g (2 lb) de rôti de palette de boeuf désossé", + "1 sachet de 50 g (2 oz) de soupe à l’oignon déshydratée du commerce", + "500 ml (2 t) d’eau", + "6 pommes de terre Yukon Gold, pelées et coupées en dés", + "30 ml (2 c. à soupe) de beurre", + "30 ml (2 c. à soupe) de crème 35 %", + "65 ml (1/4 t) de bacon croustillant émietté", + "Sel et poivre du moulin" + ], + "ingredient_groups": [ + { + "ingredients": [ + "30 ml (2 c. à soupe) de beurre et 30 ml (2 c. à soupe) de beurre supplémentaire au besoin", + "225 g (1/2 lb) de champignons tranchés", + "250 ml (1 t) d’oignons hachés", + "2 gousses d’ail entières pelées", + "900 g (2 lb) de rôti de palette de boeuf désossé", + "1 sachet de 50 g (2 oz) de soupe à l’oignon déshydratée du commerce", + "500 ml (2 t) d’eau" + ], + "purpose": "Boeuf braisé" + }, + { + "ingredients": [ + "6 pommes de terre Yukon Gold, pelées et coupées en dés", + "30 ml (2 c. à soupe) de beurre", + "30 ml (2 c. à soupe) de crème 35 %", + "65 ml (1/4 t) de bacon croustillant émietté", + "Sel et poivre du moulin" + ], + "purpose": "Purée de pommes de terre au bacon" + } + ], + "instructions_list": [ + "Préchauffer le four à 150 °C (300 °F).", + "Dans une braisière ou une casserole pouvant aller au four, faire fondre le beurre et y faire dorer les champignons. Ajouter les oignons et l’ail, puis poursuivre la cuisson de 2 à 3 minutes.", + "Déposer le rôti sur les champignons et les oignons. Verser dessus le sachet de soupe à l’oignon.", + "Ajouter l’eau, mettre le couvercle, puis enfourner 3 1/2 heures.", + "Transférer la viande dans une grande assiette. Réserver.", + "Passer la sauce au mélangeur jusqu’à ce que qu’elle soit homogène. J’aime bien ajouter 2 c. à soupe de beurre, mais c’est optionnel.", + "Verser la sauce dans la braisière, remettre la viande dans la sauce, puis réserver jusqu’au moment de servir.", + "Faire bouillir les pommes de terre dans une casserole remplie d’eau salée jusqu’à ce qu’elles soient tendres.", + "Égoutter, puis passer au presse-purée. Bien assaisonner.", + "Ajouter le beurre et la crème avant de bien mélanger.", + "Ajouter le bacon et bien mélanger à nouveau." + ], + "yields": "4 servings", + "description": "Enfin une recette simple pour nourrir de grandes tablées sans trop d’efforts! Les restes font d’excellents sandwiches à l’effilochée de boeuf.", + "total_time": null, + "image": "https://s3.amazonaws.com/rose.vero/wp-content/uploads/2015/01/12154413/boeuf-braise-1.jpg" +} diff --git a/tests/test_data/veroniquecloutier.com/veroniquecloutier.testhtml b/tests/test_data/veroniquecloutier.com/veroniquecloutier.testhtml new file mode 100644 index 000000000..86082b5ab --- /dev/null +++ b/tests/test_data/veroniquecloutier.com/veroniquecloutier.testhtml @@ -0,0 +1,1506 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Boeuf braisé à l’oignon et purée de pommes de terre au bacon - Véronique Cloutier + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + + +
    +
    +
    + + + + +
    + + + + + +
    + + + +
    + + + +
    + + + + +
    + +
    + + + +
    + +

    Boeuf braisé à l’oignon et purée de pommes de terre au bacon

    +
    + boeuf-braise
    + +
    + 15 Jan 2015 par Marilou +
    +
    +
    + Catégories : Cuisine / Recette +
    +
    + + + + + Icon +
    +
    +
    + +
    +

    Enfin une recette simple pour nourrir de grandes tablées sans trop d’efforts! Les restes font d’excellents sandwiches à l’effilochée de boeuf.

    +
    + +
    +
    +
    + + +
    +

    +

    Boeuf braisé à l’oignon et purée de pommes de terre au bacon

    +

    Portions : 4 à 6

    +

    INGRÉDIENTS

    +

    Boeuf braisé

    +
      +
    • 30 ml (2 c. à soupe) de beurre et 30 ml (2 c. à soupe) de beurre supplémentaire au besoin
    • +
    • 225 g (1/2 lb) de champignons tranchés
    • +
    • 250 ml (1 t) d’oignons hachés
    • +
    • 2 gousses d’ail entières pelées
    • +
    • 900 g (2 lb) de rôti de palette de boeuf désossé
    • +
    • 1 sachet de 50 g (2 oz) de soupe à l’oignon déshydratée du commerce
    • +
    • 500 ml (2 t) d’eau
    • +
    +

    Purée de pommes de terre au bacon

    +
      +
    • 6 pommes de terre Yukon Gold, pelées et coupées en dés
    • +
    • 30 ml (2 c. à soupe) de beurre
    • +
    • 30 ml (2 c. à soupe) de crème 35 %
    • +
    • 65 ml (1/4 t) de bacon croustillant émietté
    • +
    • Sel et poivre du moulin
    • +
    +

    PRÉPARATION

    +

    Boeuf braisé

    +
      +
    1. Préchauffer le four à 150 °C (300 °F).
    2. +
    3. Dans une braisière ou une casserole pouvant aller au four, faire fondre le beurre et y faire dorer les champignons. Ajouter les oignons et l’ail, puis poursuivre la cuisson de 2 à 3 minutes.
    4. +
    5. Déposer le rôti sur les champignons et les oignons. Verser dessus le sachet de soupe à l’oignon.
    6. +
    7. Ajouter l’eau, mettre le couvercle, puis enfourner 3 1/2 heures.
    8. +
    9. Transférer la viande dans une grande assiette. Réserver.
    10. +
    11. Passer la sauce au mélangeur jusqu’à ce que qu’elle soit homogène. J’aime bien ajouter 2 c. à soupe de beurre, mais c’est optionnel.
    12. +
    13. Verser la sauce dans la braisière, remettre la viande dans la sauce, puis réserver jusqu’au moment de servir.
    14. +
    +

    Purée de pommes de terre au bacon

    +
      +
    1. Faire bouillir les pommes de terre dans une casserole remplie d’eau salée jusqu’à ce qu’elles soient tendres.
    2. +
    3. Égoutter, puis passer au presse-purée. Bien assaisonner.
    4. +
    5. Ajouter le beurre et la crème avant de bien mélanger.
    6. +
    7. Ajouter le bacon et bien mélanger à nouveau.
    8. +
    +

    Photo : Alexandre Champagne

    +

    Recette extraite du Magazine VÉRO No2 Hiver 2013-2014.
    +

    +

    +

    Voir aussi: 

    + +
    + +
    +
    +
    +

    +
    +
    +
    + + + +
    +
    +
    + Catégories : Cuisine / Recette +
    +
    + + + + +
    +
    +
    + +
    +
    + +
    +
    +
    + 36 + Masquer les commentaires +
    + +
    + +
    +
    +

    Laisser un commentaire

    Votre adresse de courriel ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    + + +

    + +

    +
    + +
      +
    1. +
      +
      + Jocelyne Coulombe dit :
      + + + +

      Bonjour, est-ce que le rôti peut être fait à l’autocuiseur ou à la mijoteuse. Si oui, combien de temps?

      + + +
      +
    2. +
    3. +
      +
      + Annie Savard dit :
      + + + +

      Bonjour peut-on remplacer les champignons?

      + + +
      + +
    4. +
    5. +
      +
      + Denise Plante dit :
      + + + +

      Très bonne recette, facile à faire et tout le monde apprécie beaucoup. Super!
      +Merci Denise

      + + +
      +
    6. +
    7. +
      +
      + marie dit :
      + + + +

      Délicieux, la sauce est très très bonnes!

      + + +
      +
    8. +
    9. +
      +
      + France Ponton dit :
      + + + +

      Est ce que vous faite revenir la viande avant ?

      + + +
      + +
    10. +
    11. +
      +
      + phoebe dit :
      + + + +

      Bonne cuisine!

      + + +
      +
    12. +
    13. +
      +
      + Michel Laurin dit :
      + + + +

      Recette de bœuf braisé: excellent. Les commentaires étaient tous pareils : tout le monde a vraiment apprécié.

      + + +
      +
    14. +
    15. +
      +
      + Gigi dit :
      + + + +

      C’est absolument divin! Merci pour toutes ces recettes et la vinaigrette cesar de vero est très bonne aussi – vite fait et goûteux

      + + +
      +
    16. +
    17. +
      +
      + Sylvie monastesse dit :
      + + + +

      bonjour j aimerais savoir si ont peux le faire à la mijoteuse au lieux du fourneau merci

      + + +
      +
    18. +
    19. +
      +
      + Maryse Brisson dit :
      + + + +

      Merci Madame Cloutier pour la publication de cette recette très goûteuse et si délicieuse. Je l’ai servi ce midi à mes trois petites-filles et j’ai eu droit à: « c’est très très bon grand-maman »

      + + +
      +
    20. +
    21. +
      +
      + Micheline St-Laurent dit :
      + + + +

      Je viens de servir le boeuf braisé ! c’est tout à fait délicieux ca fond dans la bouche et la sauce est succulente…

      + + +
      +
    22. +
    23. +
      +
      + Solange Godbout dit :
      + + + +

      J’en n’ai manger chez ma fille j’ai adorer ca me rappelais chez ma mère quant jetais jeune je n’avais pas manger depuis merci pour cette recette Solange

      + + +
      +
    24. +
    25. +
      +
      + sylvain robitaille dit :
      + + + +

      Écoeurant Véro ,j aurais meme pas penser que ce mélange la aurait fait une si bonne sauce,c était exquis, le seul HIC c est en transférant ma viande dans l assiette, me suis apercue que j avais oublié d enlever le plastic qui ressemble a un kotex en dessous de la viandelolllll,mais bon cela était tres bon pareille …merci Véro xxxx

      + + +
      +
    26. +
    27. +
      +
      + Martine dit :
      + + + +

      Délicieux! Ça restera dans nos recettes familiales préférées! Pas super pour la ligne, mais une fois de temps en temps! 🙂

      + + +
      +
    28. +
    29. +
      +
      + France dit :
      + + + +

      je viens de faire ta recette. On s’est régalé!!

      + + +
      +
    30. +
    31. +
      +
      + Béatrice Frate dit :
      + + + +

      Je viens d’avoir du succès auprès de ma petite famille avec cette belle recette réconfortante. Merci !

      + + +
      +
    32. +
    33. +
      +
      + Micheline dit :
      + + + +

      Délicieux et réconfortant!

      + + +
      +
    34. +
    35. +
      +
      + valérie pagé dit :
      + + + +

      Au menu ce soir..tres tres délicieux!!

      + + +
      +
    36. +
    37. +
      +
      + Julie Weldon dit :
      + + + +

      Est-ce que je peux utiliser un rôti de palette avec os???

      + + +
      +
        +
      • +
        +
        + Francine Racine dit :
        + + + +

        Pouruoi les os?
        +Moi je le fais avec un roti de palette sans os.
        +C’est telement bon, c’est du bonbon!,

        + + +
        +
      • +
      +
    38. +
    39. +
      +
      + line dubé dit :
      + + + +

      très bonne recette moi je met des carottes et navet délicieux

      + + +
      +
    40. +
    41. +
      +
      + Denise Forest dit :
      + + + +

      hacher les reste de la viande et faire un pâté chinois la viande donne beaucoup de goût vous ne voudrez plus en faire d’autre

      + + +
      +
    42. +
    43. +
      +
      + Julie dit :
      + + + +

      La recette doit-elle se faire uniquement avec un rôti de palette désossé ou je pourrais utiliser un avec os???

      + + +
      +
    44. +
    45. +
      +
      + Francescca dit :
      + + + +

      Est-ce que le boeuf pourrait se faire à la mijoteuse?

      + + +
      +
    46. +
    47. +
      +
      + Silvy Tousignant dit :
      + + + +

      Moi aussi, je fais cette recette depuis longtemps et j’ajoute aussi des légumes qui cuisent en même temps. Merci de partager Marilou et merci à Alexandre pour la photo car on mange d’abord avec les yeux! 😉

      + + +
      +
    48. +
    49. +
      +
      + delicieux dit :
      + + + +

      J adore les braisers…. le bacon ds les pomme de terre miam divon

      + + +
      +
    50. +
    51. +
      +
      + Jocelyne Forest dit :
      + + + +

      Je fais cette recette depuis des années. En plus j’y ajoute des carottes, ça fait de la couleur et c’est très bon. Vraiment simple. Jeannette Bertrand faisait ça à la télé il y a très longtemps. Si tu veux une viande encore plus tendre, tu peux prendre un rôti de pointe de surlonge. C’est ce que je fais.

      + + +
      +
    52. +
    53. +
      +
      + claudette avon dit :
      + + + +

      tres belles recettes merci marilou

      + + +
      +
    54. +
    55. +
      +
      + Lyne Dubé dit :
      + + + +

      Bière brune au lieu de l’eau, miam miam

      + + +
      +
    56. +
    57. +
      +
      + Constance Dubreuil dit :
      + + + +

      J aime tes recettes et elles sont économique

      + + +
      +
    58. +
    59. +
      +
      + christiane dit :
      + + + +

      Merci

      + + +
      +
    60. +
    61. +
      +
      + Mélanie dit :
      + + + +

      Bonjour, est-ce que ce sont des recettes qui se retrouvent uniquement sur ton site ou bien également sur le site de trois fois par jour? Je ne la retrouve pas ailleurs jusqu’à maintenant sauf sur le site de Véro…
      +Merci!

      + + +
      +
    62. +
    63. +
      +
      + monique dit :
      + + + +

      Ça l air tout simplement merveilleux cette recettes…je vais l essayer….Merci Véro…

      + + +
      +
    64. +
    65. +
      +
      + Evelyne dit :
      + + + +

      Est-ce que tu saurais comment faire cette recette à la mijoteuse?

      + + +
      +
    66. +
    + +
    + + Ajouter un commentaire +
    + +
    +
    +
    +
    +
    +
    +
    + +
    + +
    + + + +
    +
    +
    +
    + +
    +
    +

    Magazine Véro

    + S'abonner au magazine +
    +
    + +
    +
    + + +
    + + +
    + + + + + + + + + + + \ No newline at end of file From 7c21a6fe73bad139bee36beea3e24f2143c693a6 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sat, 7 Dec 2024 11:51:19 -0500 Subject: [PATCH 20/94] chefjeanpierre (#1422) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/chefjeanpierre.py | 31 + .../chefjeanpierre.com/chefjeanpierre_1.json | 47 + .../chefjeanpierre_1.testhtml | 2103 +++++++++++++++++ .../chefjeanpierre.com/chefjeanpierre_2.json | 123 + .../chefjeanpierre_2.testhtml | 1652 +++++++++++++ 7 files changed, 3959 insertions(+) create mode 100644 recipe_scrapers/chefjeanpierre.py create mode 100644 tests/test_data/chefjeanpierre.com/chefjeanpierre_1.json create mode 100644 tests/test_data/chefjeanpierre.com/chefjeanpierre_1.testhtml create mode 100644 tests/test_data/chefjeanpierre.com/chefjeanpierre_2.json create mode 100644 tests/test_data/chefjeanpierre.com/chefjeanpierre_2.testhtml diff --git a/README.rst b/README.rst index 314b15fd9..2e371c272 100644 --- a/README.rst +++ b/README.rst @@ -147,6 +147,7 @@ Scrapers available for: - `https://castironketo.net/ `_ - `https://cdkitchen.com/ `_ - `https://celebratingsweets.com/ `_ +- `https://chefjeanpierre.com/ `_ - `https://chefkoch.de/ `_ - `https://www.chefnini.com/ `_ - `https://chefsavvy.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index b250ed489..62541bc82 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -96,6 +96,7 @@ from .castironketo import CastIronKeto from .cdkitchen import CdKitchen from .celebratingsweets import CelebratingSweets +from .chefjeanpierre import ChefJeanPierre from .chefkoch import Chefkoch from .chefnini import Chefnini from .chefsavvy import ChefSavvy @@ -502,6 +503,7 @@ CastIronKeto.host(): CastIronKeto, CdKitchen.host(): CdKitchen, CelebratingSweets.host(): CelebratingSweets, + ChefJeanPierre.host(): ChefJeanPierre, ChefSavvy.host(): ChefSavvy, Chefkoch.host(): Chefkoch, Chefnini.host(): Chefnini, diff --git a/recipe_scrapers/chefjeanpierre.py b/recipe_scrapers/chefjeanpierre.py new file mode 100644 index 000000000..7a8450dd4 --- /dev/null +++ b/recipe_scrapers/chefjeanpierre.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class ChefJeanPierre(AbstractScraper): + @classmethod + def host(cls): + return "chefjeanpierre.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) diff --git a/tests/test_data/chefjeanpierre.com/chefjeanpierre_1.json b/tests/test_data/chefjeanpierre.com/chefjeanpierre_1.json new file mode 100644 index 000000000..fa0f4c1ce --- /dev/null +++ b/tests/test_data/chefjeanpierre.com/chefjeanpierre_1.json @@ -0,0 +1,47 @@ +{ + "author": "Chef Jean-Pierre", + "canonical_url": "https://chefjeanpierre.com/recipes/beef-bourguignon-recipe/", + "site_name": "Chef Jean-Pierre", + "host": "chefjeanpierre.com", + "language": "en-US", + "title": "Awesome Beef Bourguignon Recipe!", + "ingredients": [ + "2 to 3 tablespoons Clarified Butter or Extra Virgin Butter Olive Oil", + "8 ounces thick sliced Bacon cut into ¼ inch pieces", + "4 pounds Beef Chuck Roast, well trimmed, cut into approx. 1 ½ inch cubes", + "1 cup Flour sifter", + "2 cups Onions diced or Pearl Onions", + "1 cup Pearl Onion, optional the chef used Aunt Nellie’s", + "2 cups Mushrooms quartered", + "2 cups Carrots sliced into ¼ inch slices", + "2 tablespoons fresh Garlic minced", + "1 bottle 750ML of a good Red Wine (Bordeaux, Shiraz or Burgundy)", + "2 tablespoons fresh Thyme minced", + "2 cups Beef Stock", + "2 to 3 dozen of very small Raw Potatoes, if they are big slice them in half", + "Salt and Pepper to taste", + "¼ cup Parsley finely chopped" + ], + "instructions_list": [ + "The Chef does in two separate pots in the video to save some time but you can do it all in one pot. This is how….", + "In a Dutch oven, heat clarified butter or the olive oil when hot, add the bacon. Cook at low heat for a few minutes to release some of the fat from the bacon. Add as many meat cubes as you can without crowding (if the skillet is too crowded, the meat won't brown properly) Brown the meat well on all sides, remove each batch as it browns and set them aside. Add the onions and cook them until golden brown. It may be necessary to add a little Clarified butter or Butter olive oil.", + "When all the onions are golden brown add the mushrooms, add salt on top of the mushrooms and cook until they have release most of their water. Add the carrots, reserved beef cubes, garlic and when fragrant, add the wine, bring to boil and let reduce by half. This could take about 3 to 5 minutes depending on your pot and your heat source. Add the potatoes, fresh thyme and salt and pepper to taste.", + "To thicken, use the chef’s technique with the flour or if you have use a roux and thicken to your liking. Add half of the chopped parsley, bring to boil, reduce to VERY LOW heat, cook for about 2 ½ to 3 hours or until the beef is fork tender.", + "When finished, add the Cognac, the rest of the chopped parsley and adjust salt and pepper to your liking." + ], + "yields": "8 servings", + "description": "Hello there friends today I'm very excited to share with you my Beef Bourguignon Recipe. It is essentially a Beef Stew with the addition of a beautiful red wine. If you haven't watched my Beef Stew video yet I highly recommend you do as its one of the most popular videos on the Channel! I hope you enjoy this Delicious Beef Bourguignon!", + "ratings": 4.34, + "ratings_count": 355, + "equipment": [ + "Butter Olive Oil", + "Woll Non-Stick Fry Pan", + "Staub Dutch Oven", + "Laser Thermometer", + "Wusthof Chef's Knife", + "Chopper - Scrapper", + "Cutting Board", + "Signed Cooking 101" + ], + "image": "https://eadn-wc02-12309146.nxedge.io/wp-content/uploads/2021/11/How-To-Make-Beef-Bourguignon-_-Chef-Jean-Pierre.jpg" +} diff --git a/tests/test_data/chefjeanpierre.com/chefjeanpierre_1.testhtml b/tests/test_data/chefjeanpierre.com/chefjeanpierre_1.testhtml new file mode 100644 index 000000000..fb12c9b0e --- /dev/null +++ b/tests/test_data/chefjeanpierre.com/chefjeanpierre_1.testhtml @@ -0,0 +1,2103 @@ + + + + + + + + + + + +My Best Beef Bourguignon Recipe! | Chef Jean-Pierre + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    + + + + + + +
    +
    + + + + +
    + + + + + chef-jean-pierre-logo +
    +
    + + + + + +
    + + + + +
    + + +
    + + + + + + +
    + + + + + +
    + + +
    +
    +
    + +
    +
    +
    +
    +
    + + +
    + + + +

     

    +
    +
    How To Make Beef Bourguignon _ Chef Jean-Pierre
    +
    + +

    Awesome Beef Bourguignon Recipe!

    +
    +chef jean pierre 200x200 1Chef Jean-Pierre +
    +
    Hello there friends today I'm very excited to share with you my Beef Bourguignon Recipe. It is essentially a Beef Stew with the addition of a beautiful red wine. If you haven't watched my Beef Stew video yet I highly recommend you do as its one of the most popular videos on the Channel!
    I hope you enjoy this Delicious Beef Bourguignon!
    +
    +
    4.34 from 355 votes
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    Servings 8
    Calories
    +
    +
    +

    Recipe Video

    +
    + + +
    + +
    + +
    +
    +
    +
    + +

    Recipe Ingredients
      

    • 2 to 3 tablespoons Clarified Butter or Extra Virgin Butter Olive Oil
    • 8 ounces thick sliced Bacon cut into ¼ inch pieces
    • 4 pounds Beef Chuck Roast, well trimmed, cut into approx. 1 ½ inch cubes
    • 1 cup Flour sifter
    • 2 cups Onions diced or Pearl Onions
    • 1 cup Pearl Onion, optional the chef used Aunt Nellie’s
    • 2 cups Mushrooms quartered
    • 2 cups Carrots sliced into ¼ inch slices
    • 2 tablespoons fresh Garlic minced
    • 1 bottle 750ML of a good Red Wine (Bordeaux, Shiraz or Burgundy)
    • 2 tablespoons fresh Thyme minced
    • 2 cups Beef Stock
    • 2 to 3 dozen of very small Raw Potatoes, if they are big slice them in half
    • Salt and Pepper to taste
    • ¼ cup Parsley finely chopped
    +
    + + + + + + +

    Recipe Instructions
     

    • The Chef does in two separate pots in the video to save some time but you can do it all in one pot.  This is how….
    • In a Dutch oven, heat clarified butter or the olive oil when hot, add the bacon.  Cook at low heat for a few minutes to release some of the fat from the bacon.  Add as many meat cubes as you can without crowding (if the skillet is too crowded, the meat won't brown properly)  Brown the meat well on all sides, remove each batch as it browns and set them aside.  Add the onions and cook them until golden brown.  It may be necessary to add a little Clarified butter or Butter olive oil.
    • When all the onions are golden brown add the mushrooms, add salt on top of the mushrooms and cook until they have release most of their water.  Add the carrots, reserved beef cubes, garlic and when fragrant, add the wine, bring to boil and let reduce by half.  This could take about 3 to 5 minutes depending on your pot and your heat source.  Add the potatoes, fresh thyme and salt and pepper to taste.
    • To thicken, use the chef’s technique with the flour or if you have use a roux and thicken to your liking.  Add half of the chopped parsley, bring to boil, reduce to VERY LOW heat, cook for about 2 ½ to 3 hours or until the beef is fork tender.
    • When finished, add the Cognac, the rest of the chopped parsley and adjust salt and pepper to your liking.
    + +
    +

    You can find the items below used in making this dish at our online store!

    +
    + + + + + + + +
    + + + + + + + + + +
    +

    Private Notes

    +
    + +
    + +
    + +
    + + +
    +
    +
    + + +
    + + +
    +
    + + +
    +
    +

    Pin It on Pinterest

    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/chefjeanpierre.com/chefjeanpierre_2.json b/tests/test_data/chefjeanpierre.com/chefjeanpierre_2.json new file mode 100644 index 000000000..ab9c736eb --- /dev/null +++ b/tests/test_data/chefjeanpierre.com/chefjeanpierre_2.json @@ -0,0 +1,123 @@ +{ + "author": "Chef Jean-Pierre", + "canonical_url": "https://chefjeanpierre.com/dinner-ideas/duck-a-lorange/", + "site_name": "Chef Jean-Pierre", + "host": "chefjeanpierre.com", + "language": "en-US", + "title": "Duck A L'Orange Recipe", + "ingredients": [ + "1 Whole Duck (approximately 4 - 5 pounds )", + "3 tablespoons Salt", + "1 large Onion, roughly chopped", + "4 Carrots, chopped (about 2 cups)", + "4 Celery Stalks, chopped (about 1.5 cups)", + "1 large Leek, sliced (about 1 cup)", + "2 Star Anise", + "4 Garlic Cloves, peeled", + "1 tablespoon Black Peppercorns", + "1/2 cup Acacia Honey", + "2 tablespoons Soy Sauce", + "1 Star Anise", + "1/2 cup Sugar", + "1/2 cup Red Wine Vinegar", + "2 cups Duck Stock (see instructions)", + "2 tablespoons Orange Juice Concentrate", + "2 tablespoons Fresh Orange Juice", + "1 tablespoons Cornstarch mixed with 2 tablespoons (30ml) Water", + "Zest of 1 Orange", + "2 tablespoon Butter", + "Orange Segments" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 Whole Duck (approximately 4 - 5 pounds )", + "3 tablespoons Salt", + "1 large Onion, roughly chopped", + "4 Carrots, chopped (about 2 cups)", + "4 Celery Stalks, chopped (about 1.5 cups)", + "1 large Leek, sliced (about 1 cup)", + "2 Star Anise", + "4 Garlic Cloves, peeled", + "1 tablespoon Black Peppercorns" + ], + "purpose": "For the Duck and Stock:" + }, + { + "ingredients": [ + "1/2 cup Acacia Honey", + "2 tablespoons Soy Sauce", + "1 Star Anise" + ], + "purpose": "For the Glaze:" + }, + { + "ingredients": [ + "1/2 cup Sugar", + "1/2 cup Red Wine Vinegar", + "2 cups Duck Stock (see instructions)", + "2 tablespoons Orange Juice Concentrate", + "2 tablespoons Fresh Orange Juice", + "1 tablespoons Cornstarch mixed with 2 tablespoons (30ml) Water", + "Zest of 1 Orange", + "2 tablespoon Butter" + ], + "purpose": "For the Orange Sauce:" + }, + { + "ingredients": [ + "Orange Segments" + ], + "purpose": "For the Garnish:" + } + ], + "instructions_list": [ + "Prepare the duck by trimming excess skin, removing giblets, and patting it dry. Poke small holes in the skin to help render fat during cooking. Dry-brine the duck by generously salting the skin and inside cavity, then place it uncovered in the refrigerator for 24 hours.", + "While the duck brines, prepare the duck stock. In a large pot, combine chopped duck neck, wings, onion, carrots, celery, leek, star anise, garlic, and peppercorns. Add water to cover, bring to a boil, reduce the heat and simmer for 3-4 hours. Strain the stock and set reserve.", + "Preheat Oven to 375°F (190°C)", + "Rinse the duck in ice water to remove excess salt, pat it dry, and score the skin without cutting into the meat. Place it in a roasting pan or a drying rack on a bed of onion. Roast for 2 hours or until the internal temperature reaches 155°F (68°C).", + "While the duck roasts, make the glaze. Combine honey, soy sauce, and star anise in a small saucepan and simmer until slightly thickened. Brush the glaze over the duck during the last 10 minutes of roasting and increase the oven temperature to 500°F (260°C) to achieve a golden brown finish.", + "For the Orange Sauce, combine sugar and vinegar in a saucepan over medium heat to create a caramel. Carefully add the duck stock, orange juices, and orange zest. Simmer until reduced, then thicken with cornstarch slurry. Stir in butter off heat until smooth and glossy.", + "Carve the duck by removing the legs and slicing the breast meat. Serve with orange sauce drizzled on top or on the side. Garnish with orange segments if desired." + ], + "category": "Dinner,Main Course", + "yields": "4 servings", + "description": "A Classic French dish Duck A L'Orange combines the rich, savory flavor of roasted duck with a bright, tangy orange sauce. This elegant recipe is perfect for festive occasions or a gourmet dinner at home. Follow these step-by-step instructions to create a beautiful and delicious meal that will impress your guests.", + "cuisine": "French", + "equipment": [ + "Wusthof Chef's Knife", + "Cooking Twine", + "Wusthof Boning Knife", + "Acacia Honey", + "Demeyere Stainless Steel Fry Pan", + "Silicone Brush", + "Citrus Zester", + "Demeyere Reduction Pan", + "Wusthof Slicing Knife", + "Digital In-Oven Thermometer", + "Instant Read Thermometer", + "Laser Thermometer", + "Silicone Baking Mat", + "Silicone Spatulas", + "Chopper - Scrapper" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "1190.98 kcal", + "fatContent": "82.86 g", + "saturatedFatContent": "29.33 g", + "unsaturatedFatContent": "48.33 g", + "transFatContent": "0.23 g", + "carbohydrateContent": "85.55 g", + "sugarContent": "70.15 g", + "proteinContent": "28.28 g", + "sodiumContent": "6129.5 mg", + "fiberContent": "3.88 g", + "cholesterolContent": "163.81 mg" + }, + "image": "https://eadn-wc02-12309146.nxedge.io/wp-content/uploads/2023/11/Duck-a-l-Orange-Recipe-Chef-Jean-Pierre.jpg", + "keywords": [ + "Duck A L'Orange", + "Duck A L'Orange Recipe" + ] +} diff --git a/tests/test_data/chefjeanpierre.com/chefjeanpierre_2.testhtml b/tests/test_data/chefjeanpierre.com/chefjeanpierre_2.testhtml new file mode 100644 index 000000000..ed9fda577 --- /dev/null +++ b/tests/test_data/chefjeanpierre.com/chefjeanpierre_2.testhtml @@ -0,0 +1,1652 @@ + + + + + + + + + + + +The Secret To Perfect Duck à L'Orange Every Time + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    + + + + + + +
    +
    + + + + +
    + + + + + chef-jean-pierre-logo +
    +
    + + + + + +
    + + + + +
    + + +
    + + + + + + +
    + + + + + +
    + + +
    +
    +
    + +
    +
    +
    +
    +
    + + +
    + + + +

     

    +
    +
    +

    Table of Contents

    +
    +
    +

    Duck à l’Orange Recipe: A Classic French Delight

    +

     
    +Duck A L'Orange - Chef Jean-PierrreHello, friends! Let’s dive into the flavors of the 1970s with one of the most celebrated dishes in French cuisine—Duck à l’Orange. This classic recipe features a beautifully roasted duck paired with a rich, caramelized orange sauce that dances between sweet and tangy. It’s a dish that has graced fine dining tables for decades, and today, I’ll guide you through everything you need to know to make this at home. From the crispy skin to the spectacular sauce, you’ll discover why this recipe has remained a favorite among food enthusiasts.

    +

     

    +

    A Brief Historical Context and Cultural Significance

    +

     

    +

    Duck à l’Orange, often synonymous with classic French cuisine, actually has roots that span far beyond France. Early iterations of roasted duck with orange sauce can be traced back to medieval Europe, where citrus fruits symbolized wealth and elegance. Over centuries, the dish evolved, with the French perfecting it into the luxurious version we know today. Its combination of savory duck and vibrant orange sauce makes it a testament to French culinary artistry, bridging tradition and timeless appeal.

    +

     

    +

    Essential Tools for Duck à l’Orange Success

    +

     

    +

    To ensure your Duck à l’Orange is a masterpiece, you’ll need the following tools:

    +
      +
    • Sharp Chef’s Knife: For scoring the duck skin and segmenting oranges.
    • +
    • Thermometer: To guarantee the perfect internal temperature for moist, tender meat.
    • +
    • Roasting Pan: Ideal for even cooking and collecting those flavorful drippings.
    • +
    • Fine Mesh Strainer: Essential for achieving a smooth, velvety sauce.
    • +
    • Prickly Tool or Paring Knife: To poke small holes in the skin, allowing fat to render and the skin to crisp.
    • +
    • Heavy-Bottomed Saucepan: Perfect for creating the rich orange sauce.
    • +
    +

     

    +

    Common Mistakes to Avoid

    +

     
    +Cooking Duck à l’Orange can seem intimidating, but avoiding these pitfalls will keep you on track:

    +
      +
    1. Skipping the Dry Brine: Salting the duck and letting it rest uncovered in the fridge ensures the skin crisps up beautifully.
    2. +
    3. Overcooking the Duck: A thermometer is your best friend. Aim for an internal temperature of 155°F to 160°F for perfectly cooked meat.
    4. +
    5. Not Properly Scoring the Skin: Make shallow cuts to allow fat to render. Cutting too deep can damage the meat and affect presentation.
    6. +
    7. Ignoring the Sauce Balance: Duck à l’Orange is all about harmony—too sweet or too sour ruins the dish. Use equal parts sugar and vinegar for the gastrique base.
    8. +
    +

     

    +

    Flavor Profiles: Regional Duck à l’Orange Styles

    +

     
    +While the French version reigns supreme, different regions put their own twist on this dish:

    +
      +
    • Classic French Duck à l’Orange: Features a caramelized orange sauce with a delicate balance of sweetness and acidity.
    • +
    • Italian Influence: Some variations include balsamic vinegar and rosemary for a more herbaceous touch.
    • +
    • Asian Fusion: A hint of soy sauce and ginger introduces savory depth and umami to the orange sauce.
    • +
    +

    Each style showcases the versatility of this iconic dish, proving its universal appeal.

    +

     

    +

    How to Best Serve Duck à l’Orange

    +

     
    +Duck à l’Orange pairs wonderfully with:

    +

     
    +Sweet Potato SouffleSweet Potato Soufflé: The light and fluffy texture of sweet potato soufflé beautifully complements the richness of Duck à l’Orange. Its natural sweetness subtly echoes the citrusy orange sauce, creating a harmonious balance on the plate. The creaminess of the soufflé contrasts with the crispy duck skin, offering a well-rounded dining experience. This dish also adds a warm, earthy flavor that enhances the overall meal.

    +

     
    +How to Make Pommes Anna RecipePommes Anna: Pommes Anna is a classic French potato dish that layers thinly sliced potatoes with butter, baked until crisp and golden. Its buttery richness and delicate texture provide the perfect foil to the tangy orange sauce of Duck à l’Orange. The mild, savory flavor of the potatoes lets the duck shine while adding a satisfying element to each bite.

    +

     
    +Honey Glazed Carrots in a ceramic bowlHoney Glazed Carrots with Orange Zest: The sweet and tangy glaze on these tender carrots complements the flavors of the duck’s orange sauce. The fresh orange zest ties the side dish directly to the main course, creating a cohesive flavor profile. Meanwhile, the carrots’ natural sweetness enhances the dish’s overall balance, making it feel fresh and vibrant.

    +

     

    +

    Storage and Reheating Tips

    +

     

    +

    Duck à l’Orange is just as delightful the next day when stored properly:

    +
      +
    • Refrigeration: Store leftovers in an airtight container for up to 3 days.
    • +
    • Freezing: Duck can be frozen for up to 3 months. Wrap individual portions in plastic wrap and place in a freezer-safe bag.
    • +
    • Reheating: Reheat duck in the oven at 300°F to retain its crispy skin. For the sauce, reheat gently on the stovetop, whisking to restore its texture.
    • +
    +

     
    +Friends, Duck à l’Orange is more than just a recipe—it’s an experience that blends culinary tradition with irresistible flavor. Whether it’s the crispy skin, the savory meat, or the caramelized orange sauce, every bite is a celebration.

    +

    So, what are we waiting for? Let’s get cooking!

    +

    +
    Duck-a-l-Orange-Recipe-Chef Jean-Pierre
    +
    +

    Duck A L’Orange Recipe

    +
    +chef jean pierre 200x200 2Chef Jean-Pierre +
    +
    A Classic French dish Duck A L'Orange combines the rich, savory flavor of roasted duck with a bright, tangy orange sauce. This elegant recipe is perfect for festive occasions or a gourmet dinner at home. Follow these step-by-step instructions to create a beautiful and delicious meal that will impress your guests.
    +
    +
    No ratings yet
    +
    + +
    +
    + +
    +
    +
    +
    +
    Course Dinner, Main Course
    Cuisine French
    +
    +
    +
    +
    Servings 4 servings
    Calories 1190.98 kcal
    +
    +
    +

    Recipe Video

    +
    + + +
    + +
    + +
    +
    +
    +
    + +

    Recipe Ingredients
     
     

    For the Duck and Stock:

    • 1 Whole Duck (approximately 4 - 5 pounds )
    • 3 tablespoons Salt
    • 1 large Onion, roughly chopped
    • 4 Carrots, chopped (about 2 cups)
    • 4 Celery Stalks, chopped (about 1.5 cups)
    • 1 large Leek, sliced (about 1 cup)
    • 2 Star Anise
    • 4 Garlic Cloves, peeled
    • 1 tablespoon Black Peppercorns

    For the Glaze:

    • 1/2 cup Acacia Honey
    • 2 tablespoons Soy Sauce
    • 1 Star Anise

    For the Orange Sauce:

    • 1/2 cup Sugar
    • 1/2 cup Red Wine Vinegar
    • 2 cups Duck Stock (see instructions)
    • 2 tablespoons Orange Juice Concentrate
    • 2 tablespoons Fresh Orange Juice
    • 1 tablespoons Cornstarch mixed with 2 tablespoons (30ml) Water
    • Zest of 1 Orange
    • 2 tablespoon Butter

    For the Garnish:

    • Orange Segments
    +
    + + + + + + +

    Recipe Instructions
     

    • Prepare the duck by trimming excess skin, removing giblets, and patting it dry. Poke small holes in the skin to help render fat during cooking. Dry-brine the duck by generously salting the skin and inside cavity, then place it uncovered in the refrigerator for 24 hours.
    • While the duck brines, prepare the duck stock. In a large pot, combine chopped duck neck, wings, onion, carrots, celery, leek, star anise, garlic, and peppercorns. Add water to cover, bring to a boil, reduce the heat and simmer for 3-4 hours. Strain the stock and set reserve.

    Preheat Oven to 375°F (190°C)

    • Rinse the duck in ice water to remove excess salt, pat it dry, and score the skin without cutting into the meat. Place it in a roasting pan or a drying rack on a bed of onion. Roast for 2 hours or until the internal temperature reaches 155°F (68°C).
    • While the duck roasts, make the glaze. Combine honey, soy sauce, and star anise in a small saucepan and simmer until slightly thickened. Brush the glaze over the duck during the last 10 minutes of roasting and increase the oven temperature to 500°F (260°C) to achieve a golden brown finish.
    • For the Orange Sauce, combine sugar and vinegar in a saucepan over medium heat to create a caramel. Carefully add the duck stock, orange juices, and orange zest. Simmer until reduced, then thicken with cornstarch slurry. Stir in butter off heat until smooth and glossy.
    • Carve the duck by removing the legs and slicing the breast meat. Serve with orange sauce drizzled on top or on the side. Garnish with orange segments if desired.
    +

    Pro-Tips

    Cooking Time:
    +For a defrosted 5 pound Duck, cook for about 2 hours for an internal temperature of 160; for a 6 pound duck, cook for another 20 minutes (total cooking time should be about 20 minutes per pound.
    + 
    +

    Pro-Tip: Achieving Crispy Skin Every Time

    +For irresistibly crispy duck skin:
    +
      +
    1. Dry Brine Overnight: Salting the duck and leaving it uncovered in the fridge for 24 hours dries out the skin.
    2. +
    3. Score Thoughtfully: Shallow cuts allow fat to render while keeping the meat intact.
    4. +
    5. Roast Smartly: Start at a higher temperature for an initial crisp, then lower it to finish cooking evenly.
    6. +
    7. Use a Rack: Elevating the duck prevents it from sitting in its rendered fat, ensuring every bit of the skin stays crisp.
    8. +
    + 
    +

    Bonus Pro-Tip: Mastering the Orange Sauce

    + 
    +The sauce is the soul of Duck à l'Orange. Here’s how to elevate it:
    +
      +
    1. Gastrique Balance: Start with equal parts sugar and red wine vinegar to achieve a base that’s neither too sweet nor too acidic. Let it caramelize to a golden amber before adding stock and orange components.
    2. +
    3. Use Concentrate Sparingly: Orange concentrate enhances sweetness, but too much can overwhelm. Blend with freshly squeezed juice for a bright, natural flavor.
    4. +
    5. Finish with Butter: Whisk in cold butter off the heat for a glossy, rich finish. This step transforms the sauce into a silky masterpiece.
    6. +
    + 
    +
    + +
    + + + + + + + +
    + + + + + +

    Nutrition

    Calories: 1190.98kcalCarbohydrates: 85.55gProtein: 28.28gFat: 82.86gSaturated Fat: 29.33gPolyunsaturated Fat: 10.35gMonounsaturated Fat: 37.98gTrans Fat: 0.23gCholesterol: 163.81mgSodium: 6129.5mgPotassium: 1001.24mgFiber: 3.88gSugar: 70.15gVitamin A: 11140.98IUVitamin C: 31.18mgCalcium: 104.53mgIron: 6.78mg
    + + + +
    +

    Private Notes

    +

    +
    +

     

    +

    Frequently Asked Questions About Duck à l’Orange

    +

     

    +

    1. What is Duck à l’Orange Recipe?

    +

    Duck à l’Orange Recipe is a French dish featuring roasted duck paired with a tangy orange sauce. It combines the rich flavors of duck with a sweet and sour orange glaze, creating a perfect balance of savory and citrus.

    +
    +

     

    +

    2. What type of duck is best for Duck à l’Orange Recipe?

    +

    Choose a whole duck with good fat content, such as Pekin or Mallard. These varieties render enough fat during cooking to achieve a tender, flavorful result and help make the skin crispy.

    +
    +

     

    +

    3. How do I make the skin crispy?

    +

    To achieve crispy skin, dry the duck thoroughly with paper towels, poke small holes in the skin to help fat render, and dry-brine it overnight in the fridge with kosher salt. Roasting at the correct temperature will also help crisp up the skin.

    +
    +

     

    +

    4. What temperature should Duck à l’Orange Recipe be cooked to?

    +

    Duck is best cooked to an internal temperature of 155°F to 160°F. Use a thermometer to check the thickest part of the duck for accurate results and avoid overcooking.

    +
    +

     

    +

    5. What is the secret to a perfect orange sauce?

    +

    The orange sauce starts with a balanced gastrique made from equal parts sugar and vinegar. Add orange zest, freshly squeezed orange juice, and a bit of orange concentrate for depth. Finish with butter to achieve a smooth, rich consistency.

    +
    +

     

    +

    6. How long does it take to make Duck à l’Orange Recipe?

    +

    Cooking a whole duck takes about 2 hours, including preparation time. The sauce can be made while the duck roasts, ensuring a cohesive cooking process.

    +
    +

     

    +

    7. Can Duck à l’Orange Recipe be made with duck breasts instead of a whole duck?

    +

    Yes, duck breasts can be used for a quicker version of the recipe. Sear the breasts skin-side down until crispy, then finish cooking in the oven and serve with the orange sauce.

    +
    +

     

    +

    8. How can I avoid making the sauce too sweet or too sour?

    +

    Balance is key in the sauce. Use equal parts sugar and vinegar for the base and adjust sweetness with orange concentrate. Adding orange zest will enhance the citrus flavor without overwhelming the sauce.

    +
    +

     

    +

    9. What side dishes pair well with Duck à l’Orange Recipe?

    +

    Pair this dish with buttery Pommes Anna, sweet potato mash, or roasted vegetables like carrots and Brussels sprouts. These sides complement the rich duck and tangy orange sauce.

    +
    +

     

    +

    10. Can I prepare Duck à l’Orange Recipe ahead of time?

    +

    Yes, you can prepare the duck and sauce a day in advance. Store the duck uncovered in the fridge to maintain crispy skin, and reheat in the oven before serving. Reheat the sauce gently on the stovetop.

    +
    +

     

    +

    11. What tools do I need for Duck à l’Orange Recipe?

    +

    Essential tools include a roasting pan, a sharp knife for scoring the skin, a meat thermometer, and a saucepan for the sauce. A prickly tool or paring knife is also helpful for creating small holes in the skin.

    +
    +

     

    +

    12. What wine pairs best with Duck à l’Orange Recipe?

    +

    Pair Duck à l’Orange Recipe with a medium-bodied red wine like Pinot Noir or a slightly sweet white wine such as Gewürztraminer. Both balance the dish’s rich and tangy elements.

    +
    +

     

    +

    13. Can Duck à l’Orange Recipe be frozen?

    +

    Yes, it can be frozen. Wrap the duck in plastic wrap and store in a freezer-safe bag for up to 3 months. The sauce should be stored separately in an airtight container.

    +
    +

     

    +

    14. How do I reheat Duck à l’Orange Recipe?

    +

    Reheat the duck in the oven at 300°F to preserve its crispy skin. The sauce should be reheated gently on the stovetop and whisked to restore its texture.

    +
    +

     

    +

    15. What is the difference between Duck à l’Orange Recipe and Duck Confit?

    +

    Duck à l’Orange Recipe is roasted duck served with orange sauce, while Duck Confit is duck slowly cooked in its own fat. The latter has a richer, more concentrated flavor and is prepared differently.

    +
    +

     

    +

    16. Is it possible to make Duck à l’Orange Recipe healthier?

    +

    To make the dish healthier, use less sugar in the sauce and trim excess fat from the duck before cooking. Opt for fresh orange juice over concentrate for a more natural sweetness.

    +
    +

     

    +

    17. What are common mistakes to avoid when making Duck à l’Orange Recipe?

    +

    Common mistakes include not drying the duck thoroughly, overcooking the meat, and making the sauce overly sweet or sour. Using a thermometer and following proper sauce ratios can prevent these errors.

    +
    +

     

    +

    18. Can I use other citrus fruits in Duck à l’Orange Recipe?

    +

    Yes, you can experiment with other citrus fruits like blood oranges, mandarins, or grapefruit for a unique twist on the traditional orange sauce.

    +
    +

     

    +

    19. How do I know when the duck is done?

    +

    Check the internal temperature with a meat thermometer. The duck is done when it reaches 155°F to 160°F. Look for golden brown, crispy skin as an additional visual cue.

    +
    +

     

    +

    20. What makes Duck à l’Orange Recipe a classic French dish?

    +

    Duck à l’Orange Recipe exemplifies French cuisine’s emphasis on balance and technique. Its combination of rich duck and vibrant citrus sauce showcases the elegance and complexity of French cooking traditions.

    +
    +

     

    + +
    Latest posts by Chef Jean-Pierre (see all)
    + +
    + +
    + + +
    +
    +
    + + +
    + + +
    +
    + + +
    +
    +

    Pin It on Pinterest

    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 3f669ff4fb06a80bdbd1282257b49005b9261458 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sat, 7 Dec 2024 11:51:38 -0500 Subject: [PATCH 21/94] themediterraneandish (#1402) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/themediterranedish.py | 16 + .../themediterranedish_1.json | 54 + .../themediterranedish_1.testhtml | 1694 ++++++++++++++ .../themediterranedish_2.json | 89 + .../themediterranedish_2.testhtml | 2046 +++++++++++++++++ 7 files changed, 3902 insertions(+) create mode 100644 recipe_scrapers/themediterranedish.py create mode 100644 tests/test_data/themediterraneandish.com/themediterranedish_1.json create mode 100644 tests/test_data/themediterraneandish.com/themediterranedish_1.testhtml create mode 100644 tests/test_data/themediterraneandish.com/themediterranedish_2.json create mode 100644 tests/test_data/themediterraneandish.com/themediterranedish_2.testhtml diff --git a/README.rst b/README.rst index 2e371c272..2f053aec0 100644 --- a/README.rst +++ b/README.rst @@ -437,6 +437,7 @@ Scrapers available for: - `https://thekitchn.com/ `_ - `https://theloopywhisk.com/ `_ - `https://www.themagicalslowcooker.com/ `_ +- `https://themediterraneandish.com/ `_ - `https://themodernproper.com/ `_ - `https://www.thepalatablelife.com `_ - `https://thepioneerwoman.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 62541bc82..0228728eb 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -383,6 +383,7 @@ from .thekitchn import TheKitchn from .theloopywhisk import TheLoopyWhisk from .themagicalslowcooker import TheMagicalSlowCooker +from .themediterranedish import TheMediterraneDish from .themodernproper import TheModernProper from .thepalatablelife import ThePalatableLife from .thepioneerwoman import ThePioneerWoman @@ -600,6 +601,7 @@ TheFoodieTakesFlight.host(): TheFoodieTakesFlight, TheGlutenFreeAustrian.host(): TheGlutenFreeAustrian, TheLoopyWhisk.host(): TheLoopyWhisk, + TheMediterraneDish.host(): TheMediterraneDish, ThePalatableLife.host(): ThePalatableLife, TheSaltyMarshmallow.host(): TheSaltyMarshmallow, Thinlicious.host(): Thinlicious, diff --git a/recipe_scrapers/themediterranedish.py b/recipe_scrapers/themediterranedish.py new file mode 100644 index 000000000..583d9d45a --- /dev/null +++ b/recipe_scrapers/themediterranedish.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class TheMediterraneDish(AbstractScraper): + @classmethod + def host(cls): + return "themediterraneandish.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/tests/test_data/themediterraneandish.com/themediterranedish_1.json b/tests/test_data/themediterraneandish.com/themediterranedish_1.json new file mode 100644 index 000000000..a8682a12c --- /dev/null +++ b/tests/test_data/themediterraneandish.com/themediterranedish_1.json @@ -0,0 +1,54 @@ +{ + "author": "Suzy Karadsheh", + "canonical_url": "https://www.themediterraneandish.com/savory-yogurt-bowl/", + "site_name": "The Mediterranean Dish", + "host": "themediterraneandish.com", + "language": "en-US", + "title": "Savory Yogurt Bowls", + "ingredients": [ + "1 cup Greek yogurt", + "1/2 cup cooked chickpeas ((cooked from scratch or drained and rinsed canned chickpeas), patted dry)", + "2 hard boiled eggs, (grated)", + "2 Persian cucumbers, (chopped)", + "2 Roma tomatoes, (chopped)", + "Extra virgin olive oil", + "Kosher salt", + "Za’atar (and/or Dukkah, for serving)" + ], + "instructions_list": [ + "Build the breakfast bowl. Divide the yogurt into the bottom of two serving bowls. Top with the chickpeas, egg, and veggies.", + "Finish and serve. Add a drizzle of good extra virgin olive oil, pinch of salt, and a good sprinkle of za’atar or dukkah. Serve or cover and refrigerate for up to 1 night." + ], + "category": "Breakfast", + "yields": "2 servings", + "description": "This savory breakfast bowl is everything I want for busy weekdays: healthy, easy, keeps me satisfied until lunchtime, and I can prep the night before. Make on repeat all year round! Swap with seasonal vegetables and what you have on hand, and trade out the yogurt for hummus if you're looking for a dairy-free option.", + "total_time": 10, + "prep_time": 10, + "cuisine": "Mediterranean", + "ratings": 5.0, + "ratings_count": 2, + "nutrients": { + "servingSize": "1 serving", + "calories": "255.1 kcal", + "fatContent": "7.4 g", + "saturatedFatContent": "1.9 g", + "unsaturatedFatContent": "4 g", + "transFatContent": "0.01 g", + "carbohydrateContent": "24.9 g", + "sugarContent": "9.2 g", + "proteinContent": "22.7 g", + "sodiumContent": "106.4 mg", + "fiberContent": "5.5 g", + "cholesterolContent": "191.5 mg" + }, + "dietary_restrictions": [ + "Gluten Free Diet", + "Vegetarian Diet" + ], + "image": "https://www.themediterraneandish.com/wp-content/uploads/2024/10/SAVORY-YOG-BOWL-20208.jpg", + "keywords": [ + "breakfast recipe", + "greek yogurt", + "savory yogurt" + ] +} diff --git a/tests/test_data/themediterraneandish.com/themediterranedish_1.testhtml b/tests/test_data/themediterraneandish.com/themediterranedish_1.testhtml new file mode 100644 index 000000000..81b8dc211 --- /dev/null +++ b/tests/test_data/themediterraneandish.com/themediterranedish_1.testhtml @@ -0,0 +1,1694 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Savory Yogurt Bowl Recipe | The Mediterranean Dish + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Savory Yogurt Bowls are the Secret to Easy and Healthy Breakfasts

    Jump to Recipe
    PrintComment

    This post may contain affiliate links.

    +
    + + +

    Skip the mid-morning sugar crash and make this savory yogurt bowl loaded with vegetarian protein! Make the night before for a healthy breakfast you’ll love waking up to. 

    + + + +
    A close up of a savory yogurt bowl.
    Photo Credits: Miriam Novoa
    + + + +

    When I first started the Mediterranean Dish about 10 years ago, the concept of the Mediterranean diet had not quite taken off yet. Nowadays people have a better understanding of what it means to eat the Mediterranean way: Incorporating seasonal produce, healthy fats, whole grains, and lean protein with delicious, joyful meals. But what I still get asked about more than anything is this: What should I eat for a healthy Mediterranean breakfast?

    + + + +

    The short–and maybe not so catchy–answer is there is no one way to enjoy a Mediterranean breakfast, and I have so many healthy breakfast recipes to choose from. But generally speaking, we tend to go for savory and fresh instead of sweet. We fill our tables with color like we do every meal. We even enjoy salad and Hummus at breakfast! 

    + + + +

    So while this savory yogurt bowl is not a traditional recipe by any means, it certainly has a Mediterranean spirit. I load it with healthy protein, including omega-rich hard-boiled eggs and mineral-packed chickpeas. Then I layer on the flavor and texture with some of my favorite Middle Eastern herb blends, fresh veggies, and a drizzle of extra virgin olive oil. 

    + + + +

    It’s everything I want in a breakfast: perfectly simple and healthy, comes together quickly, keeps me satisfied until lunchtime, and I can prep the night before. You’re going to love it!

    + + +
    Table of Contents
    1. What You Need to Make Savory Greek Yogurt Bowls
    2. Ingredient Spotlight
    3. Swaps and Substitutions
    4. How to Make Savory Greek Yogurt Bowls
    5. Ways to Mix it Up
    6. What to Serve with a Savory Yogurt Bowl
    7. More Mediterranean Breakfast Recipes
    8. Savory Yogurt Bowls Recipe
    + + +
    Ingredients for savory yogurt bowls including greek yogurt, chickpeas, hard boiled eggs, persian cucumbers, roma tomatoes, olive oil, kosher salt, za'atar, and dukkah.
    + + + +

    What You Need to Make Savory Greek Yogurt Bowls

    + + + +

    Think of this as more of a template than a full recipe, substituting what you have on hand to keep it interesting. I used:

    + + + +
      +
    • Greek yogurt: Any plain yogurt will work, but I like the added protein boost and richness of Greek yogurt. 
    • + + + +
    • Chickpeas: This small but mighty legume is high in protein, vitamins, and minerals—see the full breakdown at the USDA). 
    • + + + +
    • Eggs: Add not only protein but also omega-3 fatty acids and loads of vitamins—the USDA can give you a more in-depth look at eggs as well.  
    • + + + +
    • Vegetables: I used 2 Roma tomatoes and 2 Persian cucumbers, but any fresh tender veggies that are tasty raw will work here, or you can swap in leftover roasted veggies. 
    • + + + +
    • Extra virgin olive oil: Adds a touch of richness and flavor. I love a robust finishing oil for this recipe, like our peppery Spanish Hojiblanca
    • + + + +
    • Salt enhances the savory flavor. You can also use flaky sea salt for added texture if you have it.
    • + + + +
    • Seasoning: I love a sprinkle of Za’atar and/or Dukkah—see Ingredient Spotlight below for more. 
    • +
    + + + +
    A close up of 2 savory yogurt bowls. Next to these are bowls of dukkah and za'atar, 2 spoons, and a cup of coffee.
    + + + +

    Ingredient Spotlight

    + + + +

    Za’atar and Dukkah may seem like a forgettable finishing touch, but they’re what makes this easy breakfast bowl crave-worthy. It’s the authentic Middle Eastern touch that I’d humbly argue sets this recipe ahead of the thousands of other breakfast bowls on the internet. It’s that final sprinkle of flavor that makes you look forward to your first meal!

    + + + +

    Dukkah, with its blend of 3 nutrient-rich nuts and warming spices, is savory and crunchy. Za’atar, with its mix of fragrant wild thyme and tart sumac, leans more aromatic and bright. 

    + + + + + + + +
    An overhead photo of a savory yogurt bowl.
    + + + +

    Swaps and Substitutions

    + + + +

    If your Mediterranean pantry is in need of a refresh, head over to our shop to restock. In the meantime, there are plenty of ways to make this recipe with what you have on hand.

    + + + +
      +
    • Yogurt: Use hummus for a dairy-free version. You can also play with varieties like sweet and savory Beet Hummus and extra creamy Avocado Hummus.
    • + + + +
    • Tomatoes and cucumbers: Anything that will bring you freshness and crunch. Sliced bell peppers, sweet mini peppers, radishes, and fennel all come to mind. 
    • + + + +
    • Za’atar and/or dukkah: Use any savory seasoning blend you like, such as Italian Seasoning. Fresh tender green herbs like parsley, dill, mint, and cilantro would also work. Ideally, you would get some texture in there too with a sprinkling of nuts and/or seeds. 
    • + + + +
    • Eggs: This recipe is delicious and protein-rich without the eggs. You can just leave them out. 
    • +
    + + + +
    An overhead photo of 2 savory yogurt bowls. Next to these are bowls of dukkah and za'atar, 2 spoons, a cup of coffee, and a cup of olive oil with a spoon.
    + + + +

    How to Make Savory Greek Yogurt Bowls

    + + + +

    It only takes 10 minutes or so to make this savory yogurt bowl recipe. The best part? You can make it the night before so busy mornings don’t mean going hungry. Here are the steps: 

    + + + +
      +
    • Get prepped. If you’re serving with Dukkah and want to make it from scratch, get that all set and cooling. Drain and rinse a can of chickpeas (or follow this recipe and use 1/2 cup of cooked chickpeas.) Hard boil 2 eggs—I have a guide for that too. Chop your fresh veggies (I used 2 Roma tomatoes and 2 Persian cucumbers). 
    • + + + +
    • Build the breakfast bowl. Add 1/2 cup Greek yogurt to the bottom of two serving bowls. Grate one egg onto each bowl using the largest side of a box grater (or chop them and add). Top with the chickpeas and fresh veggies.A close up of 2 bowls of greek yogurt.
    • + + + +
    • Finish and serve. Add a drizzle of good extra virgin olive oil, pinch of salt, and a good sprinkle of za’atar or dukkah. Serve or cover and refrigerate for up to one night. A close up of 2 savory yogurt bowls. Next to these are bowls of dukkah and za'atar, 2 spoons, a cup of coffee, and a cup of olive oil with a spoon.
    • +
    + + + +

    Ways to Mix it Up

    + + + +

    This Savory Yogurt Bowl recipe is more of a template situation than an actual recipe. If you keep playing with it you’ll never get bored. Some ideas:

    + + + +
      +
    • Use a different base: Just about any savory spread works well in place of the yogurt. Hummus or a flavored hummus of your choice, like Beet Hummus, is a great option. Smoky Muhammara or Baba Ganoush would also work well. And if you love Greek yogurt, take it a step further with its extra-strained cousin Labneh
    • + + + +
    • Add more crunch: Top with Crispy Quinoa, or swap out the chickpeas for Roasted Chickpeas
    • + + + +
    • Add Mediterranean goodies: Like olives, sun-dried tomatoes, or roasted red peppers. These Greek olives are my favorite. 
    • + + + +
    • Give it even more of a savory kick: Grate garlic into the yogurt, and/or mix with fresh herbs. Top with sliced red or green onions. 
    • + + + +
    • Add heat: Top with harissa, Aleppo pepper or Urfa biber (all of which you can find at our shop). Or add a fresh kick with Zhoug (Spicy Cilantro Sauce).
    • +
    + + + +
    An overhead photo of a savory yogurt bowl. Next to this is a spoon, a cloth napkin, and a cup of coffee.
    + + + +

    What to Serve with a Savory Yogurt Bowl

    + + + +

    This is a complete meal that should keep you full until lunchtime. You don’t need anything more, aside from perhaps a cup of coffee or Black Tea. If you’re used to sweet breakfasts, add a piece of fresh fruit, or make a fruit salad. I love a citrus salad in the winter and a fresh berry salad during the warmer months.

    + + +
    + +

    More Mediterranean Breakfast Recipes

    + +
    + + +

    Browse all Mediterranean recipes.

    + + + +

    Visit Our Shop.

    + + +
    +
    +
    +
    5 from 2 votes
    +

    Savory Yogurt Bowls

    + + Suzy Karadsheh of The Mediterranean Dish. In the kitchenSuzy Karadsheh +
    +
    An overhead close up photo of a savory yogurt bowl.
    +
    +
    This savory breakfast bowl is everything I want for busy weekdays: healthy, easy, keeps me satisfied until lunchtime, and I can prep the night before. Make on repeat all year round! Swap with seasonal vegetables and what you have on hand, and trade out the yogurt for hummus if you're looking for a dairy-free option.
    + +
    +
    +
    +
    +
    Prep – 10 minutes
    Total – 10 minutes
    +
    +
    + Cuisine: +
    +
    Mediterranean
    +
    +
    +
    +
    +
    +
    Serves – 2
    +
    +
    + Course: +
    +
    Breakfast
    +
    +
    +
    +
    +
    + +

    Ingredients
      

    • 1 cup Greek yogurt
    • 1/2 cup cooked chickpeas (cooked from scratch or drained and rinsed canned chickpeas), patted dry
    • 2 hard boiled eggs, grated
    • 2 Persian cucumbers, chopped
    • 2 Roma tomatoes, chopped
    • Extra virgin olive oil
    • Kosher salt
    • Za’atar and/or Dukkah, for serving
    + +

    Instructions
     

    • Build the breakfast bowl. Divide the yogurt into the bottom of two serving bowls. Top with the chickpeas, egg, and veggies.
    • Finish and serve. Add a drizzle of good extra virgin olive oil, pinch of salt, and a good sprinkle of za’atar or dukkah. Serve or cover and refrigerate for up to 1 night.
    +
    +

    Notes

      +
    • Shop this recipe: Visit our shop to browse quality Mediterranean ingredients including the olive oil, za’atar, and chickpeas used in this recipe.
    • +
    • To meal prep for up to 5 days: Boil the eggs and keep them unpeeled in your fridge in a tightly sealed container. Rinse and strain the chickpeas and store in your fridge. Then chop the veggies and build the bowls just before serving. 
    • +
    • Follow my Egyptian Dukkah recipe to make it yourself, or find it at specialty grocery stores and Middle Eastern Markets.
    • +
    • Other veggie options: Sliced sweet peppers, fennel, radish.
    • +
    +

    Nutrition

    Calories: 255.1kcalCarbohydrates: 24.9gProtein: 22.7gFat: 7.4gSaturated Fat: 1.9gPolyunsaturated Fat: 1.5gMonounsaturated Fat: 2.5gTrans Fat: 0.01gCholesterol: 191.5mgSodium: 106.4mgPotassium: 605.4mgFiber: 5.5gSugar: 9.2gVitamin A: 855.2IUVitamin C: 10.8mgCalcium: 180.1mgIron: 2.7mg
    +
    +
    +
    +Tried this recipe? + +
    + +
    Jar of za'atar from the Mediterranean Dish shop.
    + +

    Try Our Favorite Za’atar!

    + + + +

    Jazz up your savory yogurt bowls with this aromatic, tart, and savory spice blend.

    + + + + + +
    +

    Share it with the world

    + +

    I’m Suzy; born and bred right on the shores of the Mediterranean. I’m all about easy, healthy recipes with big Mediterranean flavors. Three values guide my cooking: eat with the seasons; use whole foods; and above all, share! So happy you’re here…
    Learn More

    +
    + +
    Get our best recipes and all Things Mediterranean delivered to your inbox.
    +
    + +
    +
    +
    + 5 from 2 votes
    +
    +
    +

    Leave a comment

    Your email address will not be published. Required fields are marked *

    + +
    + How many stars would you give this recipe? +




    +
    +
    +

    + +

    + +

    +

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    Comments

    +
      +
    1. +
      +
      +
      + Elizabeth Alvarado says:
      + + + +
      + +
      +

      5 stars
      +It was easy to prep, great taste, and it was a large portion.

      +
      + +
      +
    2. +
    3. +
      +
      +
      + ivonne barreto says:
      + + + +
      + +
      +

      5 stars
      +este desayuno me encantooo al 100%, muy facil y rapido para mis dias de rush, para mi que tengo pre-diabetes es perfecto y muy saludable ya que no tiene azucar, simplemente todas las recetas que e probado aqui son deliciosas, y muy delicioso y saciante

      +
      + +
      +
    4. +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/themediterraneandish.com/themediterranedish_2.json b/tests/test_data/themediterraneandish.com/themediterranedish_2.json new file mode 100644 index 000000000..538820769 --- /dev/null +++ b/tests/test_data/themediterraneandish.com/themediterranedish_2.json @@ -0,0 +1,89 @@ +{ + "author": "Suzy Karadsheh", + "canonical_url": "https://www.themediterraneandish.com/baked-chicken-thighs/", + "site_name": "The Mediterranean Dish", + "host": "themediterraneandish.com", + "language": "en-US", + "title": "Baked Chicken Thighs Recipe", + "ingredients": [ + "8 bone-in chicken thighs, (trimmed of excess fat)", + "Kosher salt", + "Extra virgin olive oil", + "3 medium yellow onions, (halved and thinly sliced)", + "1 vine ripe tomato, (halved and sliced)", + "¼ cup water", + "5 tablespoons tomato paste", + "1/3 cup extra virgin olive oil, (more as needed)", + "1 lemon, (juiced)", + "4 garlic cloves, (minced)", + "1 teaspoon dried oregano", + "1 teaspoon smoked paprika", + "1 teaspoon ground cumin", + "1 teaspoon ground black pepper", + "Fresh parsley, (chopped)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "8 bone-in chicken thighs, (trimmed of excess fat)", + "Kosher salt", + "Extra virgin olive oil", + "3 medium yellow onions, (halved and thinly sliced)", + "1 vine ripe tomato, (halved and sliced)", + "¼ cup water" + ], + "purpose": "For the chicken" + }, + { + "ingredients": [ + "5 tablespoons tomato paste", + "1/3 cup extra virgin olive oil, (more as needed)", + "1 lemon, (juiced)", + "4 garlic cloves, (minced)", + "1 teaspoon dried oregano", + "1 teaspoon smoked paprika", + "1 teaspoon ground cumin", + "1 teaspoon ground black pepper", + "Fresh parsley, (chopped)" + ], + "purpose": "For the spiced tomato rub" + } + ], + "instructions_list": [ + "Get ready. Arrange one rack in the center of your oven and another about 6 inches from the broiler. Preheat oven to 425°F", + "Season the chicken. Sprinkle the chicken thighs with kosher salt on both sides and underneath the skins. Set aside briefly while you make the wet rub.", + "Make the Spiced Tomato Rub. In a small bowl or measuring cup, combine the tomato paste, extra virgin olive oil, lemon juice, minced garlic, oregano, smoked paprika, cumin, and black pepper. Whisk until everything is well-incorporated.", + "Add the rub to the chicken. Coat the chicken with the tomato rub on both sides, including underneath the skins.", + "Layer the chicken and vegetables in a baking dish. Brush the bottom of a 9\" X 13\" baking dish with a splash of extra virgin olive oil. Arrange three quarters of the sliced onions on the bottom. Arrange the chicken on top of the onions. Tuck the remaining onions and the sliced tomatoes into the spaces in between the chicken thighs. Pour the water into the corners of the baking dish, taking care not to disturb the rub on the chicken pieces.", + "Bake the chicken. Bake until chicken is cooked through, about 40 minutes.", + "Broil the chicken. Place the pan on the top rack and turn the broiler to high. Broil for 1 to 3 minutes, or just until the top of the chicken browns lightly. Watch closely to avoid overcooking and burning the chicken skin. Remove the chicken from the oven.", + "Serve. Let the chicken rest for 5 to 10 minutes, garnish with chopped fresh parsley, and serve." + ], + "category": "Dinner", + "yields": "8 servings", + "description": "Juicy bone-in chicken thighs baked with tomatoes and onions will become your new weeknight go-to for a hearty and healthy meal. A wet rub of tomato paste, garlic, and spices rub gives this easy recipe a deep savory flavor, no marinating time required!", + "total_time": 60, + "cook_time": 40, + "prep_time": 20, + "cuisine": "Mediterranean", + "ratings": 4.8, + "ratings_count": 263, + "nutrients": { + "servingSize": "1 serving", + "calories": "312.9 kcal", + "fatContent": "28.1 g", + "saturatedFatContent": "6.3 g", + "transFatContent": "0.1 g", + "carbohydrateContent": "8.1 g", + "proteinContent": "20.1 g", + "sodiumContent": "323.2 mg", + "fiberContent": "2 g", + "cholesterolContent": "110.7 mg" + }, + "image": "https://www.themediterraneandish.com/wp-content/uploads/2024/10/Baked-Chicken-Thighs-Cropped-1.jpg", + "keywords": [ + "Baked chicken thighs", + "chicken thigh recipe", + "oven baked chicken thighs" + ] +} diff --git a/tests/test_data/themediterraneandish.com/themediterranedish_2.testhtml b/tests/test_data/themediterraneandish.com/themediterranedish_2.testhtml new file mode 100644 index 000000000..6a5cb0ef8 --- /dev/null +++ b/tests/test_data/themediterraneandish.com/themediterranedish_2.testhtml @@ -0,0 +1,2046 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Baked Chicken Thighs Recipe | The Mediterranean Dish + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Baked Chicken Thighs with Spiced Tomato Rub

    Jump to RecipeJump to Video
    PrintComment

    This post may contain affiliate links.

    +
    + + +

    Perfectly juicy baked chicken thighs with tomatoes and onions will become your new weeknight go-to for a hearty, healthy, and satisfying meal. A tomato paste-based spice rub gives this easy recipe a deep savory flavor. The best part? It all comes together in one pan with minimal effort! 

    + + + +
    A close up of baked chicken thighs in a baking dish.
    Photo Credit: Miriam Novoa
    + + + +

    You cannot go wrong with chicken thighs. They are convenient, affordable, and forgiving; you don’t have to watch the pan like a hawk to get good results. They’re also adaptable! They pair well with lots of different flavors including lemon and oregano, cilantro and lime, fennel and grapes, or harissa and honey

    + + + +

    Today’s recipe for baked chicken thighs with juicy tomato, onion, and spices is one of my personal favorites. It’s easy to make and every bite turns out tender and succulent.

    + + + +

    The star of this recipe is the bold rub made with tomato paste, fresh garlic, and a few warm spices including cumin and smoked paprika (or sweet paprika, if you prefer). The rub gives the chicken thighs a beautiful, mouth-watering color AND quickly infuses them with big flavors without the need to marinate! That’s right, once you coat the pieces with the rub, you can stick them right in the oven.

    + + + +

    With minimal prep, this recipe lets the oven do the work, leaving you with beautifully roasted chicken and the most incredible aroma wafting through your kitchen. 

    + + +
    Table of Contents
    1. Ingredients for Baked Chicken Thighs
    2. Ingredient Spotlight
    3. How to Make Baked Chicken Thighs
    4. Tips for the Best Baked Chicken Thighs
    5. How to Store and Reheat Baked Chicken Thighs
    6. What to Serve with Baked Chicken Thighs
    7. More Weeknight-Friendly Chicken Recipes
    8. Baked Chicken Thighs Recipe Recipe
    + + +
    Ingredients for baked chicken thighs including bone in chicken thighs, salt, black pepper, olive oil, onions, a tomato, tomato paste, lemon, garlic, oregano, smoked paprika, and cumin.
    + + + +

    Ingredients for Baked Chicken Thighs

    + + + +

    This baked chicken thighs recipe is made with simple, wholesome ingredients — most of which are pantry staples — that come together to create a flavorful, comforting meal. Here’s everything you’ll need:

    + + + +
      +
    • Chicken thighs: Bone-in, skin-on chicken thighs are perfect for roasting, ensuring the meat stays juicy and flavorful. You can use boneless, skinless thighs too, your cook time will be a little shorter. 
    • + + + +
    • Extra virgin olive oil adds depth and richness to the chicken rub and will make it easily spreadable. A good-tasting oil can make all the difference here too, like our Private Reserve olive oil from Greece.
    • + + + +
    • Kosher salt season the chicken to bring out all the flavors in this simple dish.
    • + + + +
    • Onions have a wonderful savory flavor that goes sweet in the oven. I call for yellow onions here, but you could easily use red or white instead. 
    • + + + +
    • Tomato: The tomato paste adds lots of umami to the sauce, but I like to add a little fresh tomato to add texture and sweetness, and so people can see the ingredients that flavor the sauce. 
    • + + + +
    • Water: A little water helps the chicken stay juicy. You can use chicken or vegetable stock, if you prefer. 
    • + + + +
    • Tomato paste: this is where the beautiful mouth-watering color on your chicken will come from. Tomato paste is also a great way to add some umami. 
    • + + + +
    • Lemon: A squeeze of fresh lemon juice ties everything together with a bright, tangy flavor. 
    • + + + +
    • Garlic: Freshly minced garlic adds a pungent, savory kick that pairs perfectly with the olive oil. My preference for this is fresh garlic and we’re not shy with our garlic over here. It has all the flavor!
    • + + + +
    • Spices: The combination of dried oregano, smoked paprika, cumin, and black pepper gives this baked chicken thigh recipe smoky, warm, and rich flavors. You can also try sweet paprika in place of the smoked. And if you like a little spicy kick, you can add a pinch of cayenne or a bit of Aleppo-style pepper to the rub.
    • +
    + + + +
    A close up of baked chicken thighs in a baking dish.
    + + + +

    Ingredient Spotlight

    + + + +

    Smoked paprika is a key ingredient in this baked chicken thighs recipe, giving the dish a subtle smokiness and a beautiful red color. It’s made by drying and smoking red peppers over a wood fire, which infuses the spice with deep, earthy flavors. 

    + + + +

    I love using it to add a warm, smoky layer to all kinds of dishes, from Sheet-Pan Smoked Paprika Chicken with Chickpeas and Carrots to Roasted Red Pepper Hummus. For the best flavor, I recommend using our Spanish Smoked Paprika from our shop—its sweet, smoky depth is unmatched! 

    + + + + + + + +
    A close up of baked chicken thighs in a baking dish.
    + + + +

    How to Make Baked Chicken Thighs

    + + + +

    This delicious oven baked chicken thigh recipe will quickly become your go-to, and it takes just a few simple steps. Here’s how to assemble it. 

    + + + +
      +
    • Get ready. Arrange one rack in the center of your oven and another about 6 inches from the broiler. Preheat oven to 425°F
    • + + + +
    • Season the chicken. Sprinkle 8 bone-in chicken thighs, trimmed of excess fat, with kosher salt on both sides and underneath the skins. Set aside briefly while you make the wet rub. 
    • + + + +
    • Make the Spiced Tomato Rub. In a small bowl or measuring cup, combine 5 tablespoons tomato paste, 1/3 cup extra virgin olive oil, juice of 1 lemon, 4 minced garlic cloves, and 1 teaspoon each dried oregano, smoked paprika, ground cumin, and ground black pepper. Whisk until everything is well-incorporated.An overhead photo of the chicken rub in a bowl with a spoon.
    • + + + +
    • Add the rub to the chicken. Coat the chicken with the tomato rub on both sides, including underneath the skins. An overhead photo of 4 unbaked chicken thighs, 3 topped with a tomato rub, on a parchment lined cutting board. Next to these is a bowl of the rub.
    • + + + +
    • Layer the chicken and vegetables in a baking dish. Brush the bottom of a 9″ X 13″ baking dish with a splash of extra virgin olive oil. Arrange three quarters of 3 sliced onions on the bottom. Arrange the chicken on top of the onions. Tuck the remaining onions and 1 sliced tomato into the spaces in between the chicken thighs. Pour 1/4 cup of water into the corners of the baking dish, taking care not to disturb the rub on the chicken pieces. Unbaked chicken thighs topped with a tomato rub on a bed of sliced onions in a baking dish.
    • + + + +
    • Bake the chicken. Bake until chicken is cooked through, about 40 minutes. 
    • + + + +
    • Broil the chicken. Place the pan on the top rack and turn the broiler to high. Broil for 1 to 3 minutes, or just until the top of the chicken browns lightly. Watch closely to avoid overcooking and burning the chicken skin. Remove the chicken from the oven.Unbaked chicken thighs separated with tomato and onion slices topped with a tomato rub on a bed of sliced onions in a baking dish.
    • + + + +
    • Serve. Let the chicken rest for 5 to 10 minutes, garnish with chopped fresh parsley, and serve. 
    • +
    + + + +
    An overhead photo of baked chicken thighs in a baking dish.
    + + + +

    Tips for the Best Baked Chicken Thighs

    + + + +

    Chicken thighs are forgiving, but I often get a number of questions when it comes to getting the best results when cooking them: 

    + + + +
      +
    • How long to cook chicken thighs? In a hot (400 to 425°F) oven bone-in chicken thighs will cook in about 30 to 40 minutes, depending on how large they are. 
    • + + + +
    • How can you tell when chicken thighs are done? The chicken is done when its juices run clear. Chicken thighs should register at 165°F at the thickest part (away from the bone) using an instant-read thermometer. 
    • + + + +
    • Do you need to flip chicken thighs when cooking them? It’s not necessary to flip chicken thighs as you bake them. I like baking them skin side up, uncovered, and then broiling them for a moment, so the skin on the chicken thigh gains some good color. 
    • + + + +
    • Can I make this with chicken breasts instead? Yes, you absolutely can substitute split bone-in, skin-on chicken breasts in place of thighs. Adjust the oven temperature to 375°F and bake them for 30 to 35 minutes. Watch closely as chicken breasts more quickly than thighs. Broil them briefly if the skins need a little more color. Just as with thighs, the internal temperature of chicken breasts should register at 165°F at the thickest part.
    • +
    + + + +
    A close up of a baked chicken thigh with tomatoes and onion and a serving of rice on a plate. In the background is a baking dish with the rest of the chicken thighs.
    + + + +

    How to Store and Reheat Baked Chicken Thighs

    + + + +

    Store leftover baked chicken thighs and any remaining vegetables and sauce in the fridge in an air-tight container for up to 4 days.

    + + + +

    I like to use the oven set on a medium temperature like 325°F to gently reheat baked chicken thighs. If you need to, add a little bit of water or broth to the pan, then cover and heat until warmed through.

    + + + +
    An overhead photo of a baked chicken thigh with tomatoes and onion and a serving of rice on a plate. Next to this is another plate with a chicken thigh and rice, 2 glasses of white wine, and a bowl of green olives.
    + + + +

    What to Serve with Baked Chicken Thighs

    + + + +

    A little crusty bread or couscous for mopping or soaking up the tomatoey sauce is all you need to accompany saucy baked chicken thighs, but a simple side of sautéed asparagus or a crunchy green salad like Smashed Cucumber Salad with Fried Lemon and Feta would add lovely color contrast.

    + + + +

    Want to shake up your usual side dish routine? Try Spanakorizo (Greek Spinach Rice), a beautiful rice dish flecked with lots of herbs, spinach, and tangy crumbled feta. The flavors of this traditional Greek dish would be a grat match for the savory tomato and onion in this baked chicken thigh recipe. 

    + + +
    + +

    More Weeknight-Friendly Chicken Recipes

    + +
    + + +

    Browse all Mediterranean recipes.

    + + + +

    Visit Our Shop.

    + + +
    +
    +
    +
    4.80 from 263 votes
    +

    Baked Chicken Thighs Recipe

    + + Suzy Karadsheh of The Mediterranean Dish. In the kitchenSuzy Karadsheh +
    +
    A close up of baked chicken thighs in a baking dish.
    +
    +
    Juicy bone-in chicken thighs baked with tomatoes and onions will become your new weeknight go-to for a hearty and healthy meal. A wet rub of tomato paste, garlic, and spices rub gives this easy recipe a deep savory flavor, no marinating time required!
    + +
    +
    +
    +
    +
    Prep – 20 minutes
    Cook – 40 minutes
    Total – 1 hour
    +
    +
    + Cuisine: +
    +
    Mediterranean
    +
    +
    +
    +
    +
    +
    Serves – 8 pieces
    +
    +
    + Course: +
    +
    Dinner
    +
    +
    +
    +
    +
    + +

    Ingredients
      

    Ingredients

    For the chicken

    • 8 bone-in chicken thighs, trimmed of excess fat
    • Kosher salt
    • Extra virgin olive oil
    • 3 medium yellow onions, halved and thinly sliced
    • 1 vine ripe tomato, halved and sliced
    • ¼ cup water

    For the spiced tomato rub

    + +

    Instructions
     

    • Get ready. Arrange one rack in the center of your oven and another about 6 inches from the broiler. Preheat oven to 425°F
    • Season the chicken. Sprinkle the chicken thighs with kosher salt on both sides and underneath the skins. Set aside briefly while you make the wet rub.
    • Make the Spiced Tomato Rub. In a small bowl or measuring cup, combine the tomato paste, extra virgin olive oil, lemon juice, minced garlic, oregano, smoked paprika, cumin, and black pepper. Whisk until everything is well-incorporated.
    • Add the rub to the chicken. Coat the chicken with the tomato rub on both sides, including underneath the skins.
    • Layer the chicken and vegetables in a baking dish. Brush the bottom of a 9" X 13" baking dish with a splash of extra virgin olive oil. Arrange three quarters of the sliced onions on the bottom. Arrange the chicken on top of the onions. Tuck the remaining onions and the sliced tomatoes into the spaces in between the chicken thighs. Pour the water into the corners of the baking dish, taking care not to disturb the rub on the chicken pieces.
    • Bake the chicken. Bake until chicken is cooked through, about 40 minutes.
    • Broil the chicken. Place the pan on the top rack and turn the broiler to high. Broil for 1 to 3 minutes, or just until the top of the chicken browns lightly. Watch closely to avoid overcooking and burning the chicken skin. Remove the chicken from the oven.
    • Serve. Let the chicken rest for 5 to 10 minutes, garnish with chopped fresh parsley, and serve.
    +

    Video

    +
    + + + + + +
    +
    +

    Notes

      +
    • Shop this recipe: Visit our shop to browse quality Mediterranean ingredients including the olive oil, cumin, oregano, and paprika used in this recipe.
    • +
    • To use chicken breasts: Substitute bone-in, skin-on chicken breasts in place of thighs. Adjust the oven temperature to 375°F and bake them for 30 to 35 minutes. Watch closely as chicken breasts more quickly than thighs. Broil them briefly if the skins need a little more color. Just as with thighs, the internal temperature of chicken breasts should register at 165°F at the thickest part.
    • +
    • Storage: Store leftover baked chicken thighs and any remaining vegetables and sauce in the fridge in an air-tight container for up to 4 nights.
    • +
    • To reheat: I like to use the oven set on a medium temperature like 325°F to gently reheat baked chicken thighs. If you need to, add a little bit of water or broth to the pan, then cover and heat until warmed through.
    • +
    +

    Nutrition

    Calories: 312.9kcalCarbohydrates: 8.1gProtein: 20.1gFat: 28.1gSaturated Fat: 6.3gTrans Fat: 0.1gCholesterol: 110.7mgSodium: 323.2mgPotassium: 540mgFiber: 2gVitamin A: 502IUVitamin C: 10.7mgCalcium: 49.9mgIron: 1.8mg
    +
    +
    +
    +Tried this recipe? + +
    + +
    Cover of The Mediterranean Dish: Simply Dinner Cookbook with 124 Mediterranean Diet-Inspired Recipes to Eat Well and Live Joyfully from the New York Times Bestselling Author Suzy Karadsheh
    + +

    The Mediterranean Dish: Simply Dinner

    + + + + + + + +

    125 Easy Mediterranean Diet-Inspired Recipes to Eat Well and Live Joyfully

    + +
    +

    Share it with the world

    + +

    I’m Suzy; born and bred right on the shores of the Mediterranean. I’m all about easy, healthy recipes with big Mediterranean flavors. Three values guide my cooking: eat with the seasons; use whole foods; and above all, share! So happy you’re here…
    Learn More

    +
    + +
    Get our best recipes and all Things Mediterranean delivered to your inbox.
    +
    + +
    +
    +
    + 4.80 from 263 votes (177 ratings without comment) +
    +
    +
    +

    Leave a comment

    Your email address will not be published. Required fields are marked *

    + +
    + How many stars would you give this recipe? +




    +
    +
    +

    + +

    + +

    +

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    Comments

    +
      +
    1. +
      +
      +
      + Queen says:
      + + + +
      + +
      +

      5 stars
      +Made this for dinner last as written and it was fantastic. Yes, it’s not overly seasoned but as a NOLA native who’s used to heavy spices, I found this pleasing to my family’s taste. It’s light, fresh and a good start to Mediterranean-style cooking. I topped the chicken, onion and “gravy” on jasmine rice with broccoli on the side. Again, I’m from NOLA and we like things smothered. lol. A must-try!

      +
      + +
      +
    2. +
    3. +
      +
      +
      + Dani says:
      + + + +
      + +
      +

      This looks absolutely delicious! In the past, I’ve noticed that tomato paste tends to burn on my chicken skin when I roast at 400F (confirmed with oven thermometer), do you have any suggestions? I would love to try this recipe!

      +
      + +
      +
    4. +
    5. +
      +
      +
      + Lynette Walker says:
      + + + +
      + +
      +

      If family members are avoiding the nightshade family of foods, can this recipe proceed without the tomato sauces or pastes? Can the thighs be roasted in the same way as your Whole Roasted Chicken in an iron skillet?

      +
      + +
      +
        +
      1. +
        +
        +
        + TMD Team says:
        + + + +
        + +
        +

        Hi, Lynette. The tomato paste and tomatoes are pretty key ingredients in this recipe. If you aren’t able to use night shades, I would recommend trying one of our other fabulous chicken thigh recipes like our Balsamic Chicken or Cilantro Lime Chicken.

        +
        + +
        +
      2. +
      +
    6. +
    7. +
      +
      +
      + I.G.Romov says:
      + + + +
      + +
      +

      1 star
      +Followed directions to a proverbial “T” to get what I consider a burnt mess atop a chicken thigh. Maybe my oven runs hot.

      +
      + +
      +
        +
      1. +
        +
        +
        + TMD Team says:
        + + + +
        + +
        +

        Hello! Yes, ovens temps can vary, so that could very well have been the culprit here. I hope you do give it another try as this recipe is very popular on our site!

        +
        + +
        +
      2. +
      +
    8. +
    9. +
      +
      +
      + P.A. Fletcher says:
      + + + +
      + +
      +

      4 stars
      +Delicious, forgiving, used fresh oregano 2/3 through cooking time.
      +Definitely use meat thermometer. Will make again!

      +
      + +
      +
    10. +
    11. +
      +
      +
      + Tammy Hawley says:
      + + + +
      + +
      +

      I loved this recipe. I definitely plan on making it again and again.

      +
      + +
      +
    12. +
    13. +
      +
      +
      + Kay Norman says:
      + + + +
      + +
      +

      5 stars
      +Yum! I have been very ill for about 8 months and NOTHING tastes good to me. I am starting to feel better and this looked tasty. I made it tonight and it really hit the spot! Easy to make and delicious. I served with jasmine rice. I left the garlic off because it is one taste I can’t deal with currently.

      +
      + +
      +
        +
      1. +
        +
        +
        + TMD Team says:
        + + + +
        + +
        +

        Hi, Kay. I’m so glad to hear you’re feeling better and that was a hit for you! It’s great that you found a way to adjust the recipe to suit your taste—sometimes, small tweaks make all the difference. Wishing you continued recovery and many more delicious meals ahead!

        +
        + +
        +
      2. +
      +
    14. +
    15. +
      +
      +
      + Kay Norman says:
      + + + +
      + +
      +

      5 stars
      +Yum! I have been very ill for about 8 months and NOTHING tastes good to me. I am starting to feel better and this looked tasty. I made it tonight and it really hit the spot! Easy to make and delicious. I served with jasmine rice.

      +
      + +
      +
    16. +
    17. +
      +
      +
      + Maria says:
      + + + +
      + +
      +

      5 stars
      +I made this for the first of many times today. We sliced it into flatbread sandwiches with the cooked onion and tomato slices as well as fresh cucumber. Amazing flavor! I am going to give this recipe a try out on the grill as well. Thank you.

      +
      + +
      +
        +
      1. +
        +
        +
        + TMD Team says:
        + + + +
        + +
        +

        Ooo! What a great idea! Thanks for sharing!!

        +
        + +
        +
      2. +
      +
    18. +
    19. +
      +
      +
      + Deborah says:
      + + + +
      + +
      +

      5 stars
      +Best thigh recipe 😋 Hubby loved ot and I did too.

      +
      + +
      +
    20. +
    21. +
      +
      +
      + Raine says:
      + + + +
      + +
      +

      5 stars
      +This is perfect for the Mediterranean diet we are trying to stay on for our health.

      +
      + +
      +
    22. +
    23. +
      +
      +
      + Ronald Dunning says:
      + + + +
      + +
      +

      5 stars
      +I had an idea that you could bake chicken with an umami coating made with tomato paste, and found that Suzy said it’s a real thing — thank you. It was delicious!

      +
      + +
      +
    24. +
    25. +
      +
      +
      + Pia Marion Evans says:
      + + + +
      + +
      +

      5 stars
      +Can’t even begin to tell you how easy and delicious this recipe was. The chicken was tender and so flavorful.

      +
      + +
      +
        +
      1. +
        +
        +
        + TMD Team says:
        + + + +
        + +
        +

        So glad you loved it, Pia!

        +
        + +
        +
      2. +
      +
    26. +
    27. +
      +
      +
      + Katy says:
      + + + +
      + +
      +

      Made this tonight with boneless thighs as that’s what I had thawed. Cooked a little less time. It was very flavorful and will certainly make it again!!

      +
      + +
      +
    28. +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 14d87ae08e238d35b146ce40b5e41658029a032d Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sat, 7 Dec 2024 11:51:51 -0500 Subject: [PATCH 22/94] lanascooking (#1396) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/lanascooking.py | 16 + .../lanascooking.com/lanascooking_1.json | 57 + .../lanascooking.com/lanascooking_1.testhtml | 1610 ++++++++++++++++ .../lanascooking.com/lanascooking_2.json | 78 + .../lanascooking.com/lanascooking_2.testhtml | 1676 +++++++++++++++++ 7 files changed, 3440 insertions(+) create mode 100644 recipe_scrapers/lanascooking.py create mode 100644 tests/test_data/lanascooking.com/lanascooking_1.json create mode 100644 tests/test_data/lanascooking.com/lanascooking_1.testhtml create mode 100644 tests/test_data/lanascooking.com/lanascooking_2.json create mode 100644 tests/test_data/lanascooking.com/lanascooking_2.testhtml diff --git a/README.rst b/README.rst index 2f053aec0..fc03384c2 100644 --- a/README.rst +++ b/README.rst @@ -283,6 +283,7 @@ Scrapers available for: - `https://kuchnia-domowa.pl/ `_ - `https://kuchynalidla.sk/ `_ - `https://www.kwestiasmaku.com/ `_ +- `https://lanascooking.com/ `_ - `https://www.latelierderoxane.com `_ - `https://leanandgreenrecipes.net `_ - `https://www.lecker.de `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 0228728eb..3b3b2243b 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -231,6 +231,7 @@ from .kuchniadomowa import KuchniaDomowa from .kuchynalidla import KuchynaLidla from .kwestiasmaku import KwestiaSmaku +from .lanascooking import LanasCooking from .latelierderoxane import LAtelierDeRoxane from .leanandgreenrecipes import LeanAndGreenRecipes from .lecker import Lecker @@ -563,6 +564,7 @@ KristinesKitchenBlog.host(): KristinesKitchenBlog, KrollsKorner.host(): KrollsKorner, KuchynaLidla.host(): KuchynaLidla, + LanasCooking.host(): LanasCooking, LittleSunnyKitchen.host(): LittleSunnyKitchen, LeitesCulinaria.host(): LeitesCulinaria, MadameCuisine.host(): MadameCuisine, diff --git a/recipe_scrapers/lanascooking.py b/recipe_scrapers/lanascooking.py new file mode 100644 index 000000000..0bde6be42 --- /dev/null +++ b/recipe_scrapers/lanascooking.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class LanasCooking(AbstractScraper): + @classmethod + def host(cls): + return "lanascooking.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/tests/test_data/lanascooking.com/lanascooking_1.json b/tests/test_data/lanascooking.com/lanascooking_1.json new file mode 100644 index 000000000..aa8637949 --- /dev/null +++ b/tests/test_data/lanascooking.com/lanascooking_1.json @@ -0,0 +1,57 @@ +{ + "author": "Lana Stuart", + "canonical_url": "https://www.lanascooking.com/southern-tomato-cracker-salad/", + "site_name": "Lana's Cooking", + "host": "lanascooking.com", + "language": "en-US", + "title": "Southern Tomato Cracker Salad", + "ingredients": [ + "3 very ripe medium tomatoes", + "1 cup mayonnaise", + "1/2 shallot (finely minced)", + "40 saltine crackers ((1 sleeve))", + "2 tablespoons chives (finely chopped)", + "Kosher salt and ground black pepper to taste" + ], + "instructions_list": [ + "Start by removing the core, or stem end) of the tomatoes and then cut each in half through the middle or \"waist.\"", + "Working over a medium bowl or into the sink, press each tomato half gently to get rid of most of the seeds and juice.", + "Dice the tomatoes. Place the diced tomatoes in a large mixing bowl and sprinkle lightly with salt. Remove a few tablespoons of diced tomatoes for garnish and set them aside.", + "Into the bowl with the diced tomatoes, add the minced shallot, half of the chives, black pepper, and mayonnaise. Fold together gently to combine.", + "Crumble the crackers creating mostly large pieces for the best texture.", + "Add the broken saltine crackers to the bowl with the tomato mixture and fold gently to combine.", + "Taste for seasoning and adjust if necessary.", + "Garnish with the reserved tomatoes and remaining chives.", + "Serve immediately." + ], + "category": "Salads,Side Dishes,Vegetables", + "yields": "4 servings", + "description": "If you like a southern tomato sandwich, then you'll fall head over heels for this 15-minute Southern Tomato Cracker Salad recipe!", + "total_time": 15, + "prep_time": 15, + "cuisine": "Southern, Vintage", + "ratings": 5.0, + "ratings_count": 3, + "nutrients": { + "servingSize": "1 serving", + "calories": "278 kcal", + "fatContent": "15 g", + "saturatedFatContent": "2 g", + "unsaturatedFatContent": "12 g", + "transFatContent": "0.2 g", + "carbohydrateContent": "32 g", + "sugarContent": "5 g", + "proteinContent": "4 g", + "sodiumContent": "750 mg", + "fiberContent": "2 g", + "cholesterolContent": "9 mg" + }, + "image": "https://www.lanascooking.com/wp-content/uploads/2022/06/southern-tomato-cracker-salad-feature-1200.jpg", + "keywords": [ + "cracker salad", + "southern salads", + "southern tomato cracker salad", + "tomato salad", + "vintage salad recipe" + ] +} diff --git a/tests/test_data/lanascooking.com/lanascooking_1.testhtml b/tests/test_data/lanascooking.com/lanascooking_1.testhtml new file mode 100644 index 000000000..b15bf1d5e --- /dev/null +++ b/tests/test_data/lanascooking.com/lanascooking_1.testhtml @@ -0,0 +1,1610 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Southern Tomato Cracker Salad Recipe - Lana's Cooking + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    + +
    + + + + + +
    + + +

    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    Home » Recipes » Salad Recipes » Southern Tomato Cracker Salad

    Southern Tomato Cracker Salad

    +
    + +
    +
    + + + + + +
    5 from 3 votes
    + + +
    +

    If you enjoy the flavors of the classic southern tomato sandwich, then you’ll fall head over heels for this Southern Tomato Cracker Salad recipe! It takes 15 minutes from start to finish and there’s no cooking at all. Perfect for hot summer days when you don’t want to heat up the kitchen.

    + + + +

    There’s not much better in the middle of summer than a classic tomato sandwich. Two pieces of white bread slathered with mayonnaise and topped with salted and peppered tomato slices. Yum!

    A serving of tomato cracker salad on a white plate.
    + + + +

    Well, if you’re a fan of tomato sandwiches, then you’ll love their next of kin, the Southern Tomato Cracker Salad! It takes the same flavor profile and transforms it into a crunchy, creamy salad that’s great for family dinners or entertaining.

    + + + +

    This combination of ripe tomatoes, creamy mayonnaise, and saltine crackers is a great side dish to serve with burgers, grilled chicken, or steaks. It’s a southern summer classic recipe that has been around for decades.

    + + + +
    A serving of tomato cracker salad on a white plate.
    + + + + + +
    +

    ❤️ Why I Love This Recipe

    + + + +
    + + + +
      +
    • It’s a great way to use fresh summer tomatoes!
    • + + + +
    • Tastes like a tomato sandwich in a bowl.
    • + + + +
    • It’s one of those great old southern heritage recipes that people still enjoy.
    • +
    +
    + + + +
    +

    🍅 Ingredient Notes

    + + + +
    + + + +
    Ingredients needed to make cracker salad.
    + + + +

    This post contains affiliate links.

    + + + +
      +
    • Ripe Fresh Tomatoes – Look for medium sized tomatoes that are completely ripe. They should be very bright in color but with no bruising or soft spots. I often use Romas for this recipe because they’re less “juicy” than other varieties. Heirloom tomato varieties make a really beautiful salad but they’re more expensive unless you grow them yourself.
    • + + + +
    • MayonnaiseHomemade mayonnaise is always best but, of course, most of us purchase it. I recommend Duke’s brand in the south and Hellman’s if you don’t have access to Duke’s.
    • + + + +
    • Shallot – I love the flavor of shallots in this recipe. They’re like a mild, sweet onion with a hint of garlic. However, they can be a bit pricey so feel free to substitute with red onion if you like.
    • + + + +
    • Saltine Crackers – You’ll need one “sleeve” (that’s about 40) of plain old Nabisco saltines. No need to try to be fancy with this recipe.
    • + + + +
    • Chives – Cut the chives very finely. You can also substitute very finely chopped green onions.
    • + + + +
    • Kosher Salt and Black Pepper – You won’t need much salt because of the crackers. I like quite a bit of ground black pepper for this.
    • +
    + + +
    + +
    +
    +
    +
    + + + +

    The complete ingredient list with detailed measurements is included in the printable recipe card at the bottom of this post.

    +
    + +
    + + + +
    +

    🔪 How to Make Southern Tomato Cracker Salad

    + + + +
    + + + +

    Prepare the Tomatoes

    + + + +
    Tomatoes being prepared for the salad on a wooden board.
    STEP 1-2.
    + + + +
      +
    1. Start by removing the core (or stem end) of the tomatoes and then cut each in half through the middle or “waist.” 
    2. + + + +
    3. Working over a medium bowl or into the sink, press each tomato half gently to get rid of most of the seeds and juice.
    4. +
    + + + +

    👉 PRO TIP:  You don’t have to remove everything, but try to extract most of the juice to keep the salad from being soggy. It also helps to leave the tomato halves to drain with the cut side down on a paper towel for a few minutes.

    +
    + + + +
    + + + + +
      +
    1. Dice the tomatoes. Place the diced tomatoes in a large mixing bowl and sprinkle lightly with salt. Remove a few tablespoons of diced tomatoes for garnish and set them aside.
    2. + + + +
    3. Into the bowl with the diced tomatoes, add the minced shallot, half of the chives, black pepper, and mayonnaise. Fold together gently to combine.
    4. +
    +
    + + +
    Pyrex Smart Essentials 3-Piece Mixing Bowl Set
    • Set includes 1-qt, 1.5-qt, and 2.5-qt round glass bowls.
    • High-quality tempered glass resists stains and odors. Freezer, microwave, and dishwasher safe. 
    • Loved for generations - experienced cooks and beginners alike have reached for Pyrex brand glassware products because they’re affordable, durable, and great for all their cooking, serving, and storing needs.
    This post contains affiliate links. Lana's Cooking is reader-supported and earns a tiny commission at no extra cost to you when you shop from our links.
    + + + +
    +

    Crumble the Crackers and Mix the Salad

    + + + + + + + +
      +
    1. Crumble the crackers creating mostly large pieces for the best texture.
    2. +
    + + + +

    👉 PRO TIP: Notice the size of the cracker pieces in the photo? You want them to be fairly large pieces. If you crumble them too small the whole salad will turn out mushy. That’s not what you want :-) 

    + + + +
      +
    1. Add the broken saltine crackers to the bowl with the tomato mixture and fold gently to combine.
    2. + + + +
    3. Taste for seasoning and adjust if necessary.
    4. +
    +
    + + + +
    +

    Garnish and Serve

    + + + +
    Garnish added to top of cracker salad.
    STEP 8.
    + + + +
      +
    1. Garnish with the reserved tomatoes and remaining chives.
    2. + + + +
    3. Serve immediately.
    4. +
    + + + +

    For best taste and texture, this salad should be mixed and served immediately. 

    +
    + + + +
    A serving of tomato cracker salad on a white plate.
    + + + +
    +

    🔀 Suggestions and Variations

    + + + +
    + + + +
      +
    • Some cooks include a few chopped, hard boiled eggs in the recipe.
    • + + + +
    • You can easily substitute the shallot and chives with finely diced green onions if you like.
    • + + + +
    • Use halved cherry tomatoes.
    • +
    +
    + + + +
    +

    ❓ Questions and Tips About Southern Tomato Cracker Salad

    + + + +
    + + + +
    Can I make cracker salad ahead of time?

    Because this salad wilts and becomes soggy pretty quickly, it’s best when eaten within minutes of being made. You can, however, prepare all the ingredients ahead of time and combine them when you’re ready to serve.

    How do I store leftover tomato cracker salad?

    It’s best to make the quantity of salad that you think you’ll need for one meal. Leftovers simply don’t keep well.

    +
    + + +
    + +
    + +
    +
    Lana Stuart.
    +
    + + + +
    +

    Questions? I’m happy to help!

    + + + +

    If you have more questions about the recipe, or if you’ve made it and would like to leave a comment, scroll down to leave your thoughts, questions, and/or rating!

    + + + +

    Thanks so much for stopping by!

    +
    + +
    + +
    + + +
    +

    📖 Recipe

    + + +
    +
    +

    Want to save this recipe?

    + + + +

    Enter your email below and get it sent straight to your inbox.

    + + +
    + Save Recipe
    +
    +
    + +
    + +
    +

    My Southern Table cookbook
    by Lana Taylor Stuart

    + + + +
    + + + + + + + +
      +
    • 346 pages; 246 recipes with full-color photos
    • + + + +
    • Durable softcover binding
    • + + + +
    • Personalized and signed by Lana
    • + + + +
    • Retail $39.99; Holiday Price $29.99 with FREE shipping
    • + + + +
    • In stock and ready to ship
    • +
    + + + + + + + + +
    + +
    + + + +
    + +
    A serving of tomato cracker salad on a white plate.
    +
    +
    +

    Southern Tomato Cracker Salad

    +
    +
    If you like a southern tomato sandwich, then you'll fall head over heels for this 15-minute Southern Tomato Cracker Salad recipe!
    +
    +
    5 from 3 votes
    +
    + Print It + + Rate It + + + + + Add to Collection +
    +
    Course: Salads, Side Dishes, Vegetables
    Cuisine: Southern, Vintage
    +
    Prep Time: 15 minutes
    Total Time: 15 minutes
    + +
    Servings: 4 servings
    + + +
    Calories: 278kcal
    +
    Author: Lana Stuart
    + + + +
    + +

    Ingredients

    • 3 very ripe medium tomatoes
    • 1 cup mayonnaise
    • 1/2 shallot finely minced
    • 40 saltine crackers (1 sleeve)
    • 2 tablespoons chives finely chopped
    • Kosher salt and ground black pepper to taste
    + +

    Instructions

    • Start by removing the core, or stem end) of the tomatoes and then cut each in half through the middle or “waist.”
    • Working over a medium bowl or into the sink, press each tomato half gently to get rid of most of the seeds and juice.
    • Dice the tomatoes. Place the diced tomatoes in a large mixing bowl and sprinkle lightly with salt. Remove a few tablespoons of diced tomatoes for garnish and set them aside.
    • Into the bowl with the diced tomatoes, add the minced shallot, half of the chives, black pepper, and mayonnaise. Fold together gently to combine.
    • Crumble the crackers creating mostly large pieces for the best texture.
    • Add the broken saltine crackers to the bowl with the tomato mixture and fold gently to combine.
    • Taste for seasoning and adjust if necessary.
    • Garnish with the reserved tomatoes and remaining chives.
    • Serve immediately.
    + +

    Notes

    This salad is best mixed and served immediately. Leftovers do not store well.
    +When preparing the tomatoes, try to extract most of the juice to keep the salad from being soggy. It also helps to leave the tomato halves to drain with the cut side down on a paper towel for a few minutes.
    +Make sure that the pieces of crumbled crackers are fairly large to keep the best texture in the salad. Crumbling them too small will result in a mushy salad.
    +Look for medium sized tomatoes that are completely ripe. They should be very bright in color but with no bruising or soft spots. I often use Romas for this recipe because they’re less “juicy” than other varieties. Heirloom tomato varieties make a beautiful salad but are more expensive.
    + + +

    Nutrition Information

    Serving 1serving | Calories 278kcal | Carbohydrates 32g | Protein 4g | Fat 15g | Saturated Fat 2g | Polyunsaturated Fat 9g | Monounsaturated Fat 3g | Trans Fat 0.2g | Cholesterol 9mg | Sodium 750mg | Potassium 296mg | Fiber 2g | Sugar 5g | Vitamin A 873IU | Vitamin C 14mg | Calcium 21mg | Iron 2mg
    +
    +

    Nutrition information is calculated by software based on the ingredients in each recipe. It is an estimate only and is provided for informational purposes. You should consult your healthcare provider or a registered dietitian if precise nutrition calculations are needed for health reasons.

    +
    +
    + +
    Share on Facebook + + Pin Recipe +
    +
    +
    Tried this recipe? Pin it for Later!Follow @LanasCookingBlog or tag #LanasCooking!
    +
    + + + +
    +

    🧾 More Recipes You’ll Like

    + + + +
    + + + + +
    +
    +
    +
    +
    +
    + + + + + +
    +
    +
    +
    + 5 from 3 votes (2 ratings without comment) +
    +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +
    +

    + +

    +

    One Comment

      +
    1. +
      +
      +
      + Dasso says:
      + + + +
      + +
      +

      5 stars
      +So good! So quick! So Southern!! So yummy.

      +
      + +
      +
    2. +
    +
    +
    +
    + + +
    +
    +
    + +
    + +
    + +
    + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/lanascooking.com/lanascooking_2.json b/tests/test_data/lanascooking.com/lanascooking_2.json new file mode 100644 index 000000000..5207c641e --- /dev/null +++ b/tests/test_data/lanascooking.com/lanascooking_2.json @@ -0,0 +1,78 @@ +{ + "author": "Lana Stuart", + "canonical_url": "https://www.lanascooking.com/oven-roasted-turkey/", + "site_name": "Lana's Cooking", + "host": "lanascooking.com", + "language": "en-US", + "title": "Oven Roasted Turkey with Gravy", + "ingredients": [ + "1 cup butter (softened)", + "2 tablespoons seasoned salt (recommended: Jane's Crazy Mixed-Up Salt)", + "10 pounds turkey (fresh or frozen)", + "½ cup pan drippings from turkey", + "½ cup all-purpose flour", + "3 ¾ cups turkey or chicken broth or stock" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 cup butter (softened)", + "2 tablespoons seasoned salt (recommended: Jane's Crazy Mixed-Up Salt)", + "10 pounds turkey (fresh or frozen)" + ], + "purpose": "For the Turkey:" + }, + { + "ingredients": [ + "½ cup pan drippings from turkey", + "½ cup all-purpose flour", + "3 ¾ cups turkey or chicken broth or stock" + ], + "purpose": "For the Gravy:" + } + ], + "instructions_list": [ + "To Roast the Turkey:", + "If using a frozen turkey, thaw in the refrigerator allowing at least 24 hours for every 4 pounds of turkey.", + "Approximately 1 1/2 hours before cooking, remove the turkey from the refrigerator and let it sit at room temperature.", + "Preheat the oven to 325 degrees. Drain any juices from the turkey and pat it dry with paper towels.", + "Place the turkey breast side up on a rack in a roasting pan.", + "Tuck the wings under the turkey and secure the legs with kitchen twine if needed.", + "Rub the turkey generously with the butter. Sprinkle evenly with seasoned salt.", + "Place the turkey in the preheated oven.", + "About 2/3 through cooking time, check to make sure the breast and tops of the legs aren't browning too quickly. If needed, cover the turkey loosely with a tent of aluminum foil to prevent overcooking.", + "Turkey is done when the temperature in the thigh registers 180 degrees on a meat thermometer.", + "Remove from the oven and let stand for at least 20 minutes before carving.", + "To Make the Gravy:", + "Remove drippings from the turkey roasting pan and place in a medium saucepan.", + "Using a whisk, blend the flour into the pandrippings.", + "Whisk in the stock or broth a little at a time", + "Place the saucepan over medium high heat and bring to a boil. Reduce the heat to low and simmer for about 5 minutes." + ], + "category": "Main Course,Main Dishes", + "yields": "6 servings", + "description": "A simple method for cooking a beautifully moist Oven Roasted Turkey with golden, crispy skin and instructions for making the best pan gravy.", + "total_time": 215, + "cook_time": 180, + "prep_time": 15, + "cuisine": "American", + "ratings": 5.0, + "ratings_count": 6, + "nutrients": { + "servingSize": "1", + "calories": "1198 kcal", + "fatContent": "72 g", + "saturatedFatContent": "35 g", + "carbohydrateContent": "13 g", + "sugarContent": "3 g", + "proteinContent": "121 g", + "sodiumContent": "3408 mg", + "fiberContent": "1 g", + "cholesterolContent": "472 mg" + }, + "image": "https://www.lanascooking.com/wp-content/uploads/2020/11/oven-roasted-turkey-feature-1200x1200-1.jpg", + "keywords": [ + "oven roasted turkey", + "turkey gravy" + ] +} diff --git a/tests/test_data/lanascooking.com/lanascooking_2.testhtml b/tests/test_data/lanascooking.com/lanascooking_2.testhtml new file mode 100644 index 000000000..548b25746 --- /dev/null +++ b/tests/test_data/lanascooking.com/lanascooking_2.testhtml @@ -0,0 +1,1676 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Oven Roasted Turkey with Gravy Recipe - Lana’s Cooking + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    + +
    + + + + + +
    + + +

    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    Home » Recipes » Main Dish Recipes » Oven Roasted Turkey with Gravy

    Oven Roasted Turkey with Gravy

    +
    + +
    +
    + + + + + +
    5 from 6 votes
    + + +
    +

    Our Thanksgiving dinner just wouldn’t be complete without the turkey! Here’s my simple method for cooking a beautifully moist Oven Roasted Turkey with golden, crispy skin and instructions for making the best pan gravy!

    + + + +

    Turkey is the star of the show at most of our Thanksgiving tables, isn’t it? I know for our family, the holiday just wouldn’t be the same without it.

    Oven Roasted Turkey with Gravy on a white serving platter.
    + + + +

    Don’t be intimidated by the thought of cooking something as large as a turkey. If you can roast a chicken, you can cook a turkey!

    + + + +

    This simple method works just as well whether your turkey is fresh or frozen. It does take a little effort to get the timing right, so I find that making a plan the week before is really helpful.

    + + + +

    I always plan out any necessary thawing time, plus time to bring the turkey to room temperature before cooking, plus time to prep and time to cook and rest. Let’s go over those times together, shall we?

    + + + +
    Carved Oven Roasted Turkey with Gravy presented on a white serving platter.
    + + + + + +
    +

    How to Plan Your Thanksgiving Cooking Timetable

    + + + +
      +
    • When making a plan for cooking Thanksgiving dinner, I start by deciding what time I’ll serve dinner and work backward from there. Begin with the timing for the turkey, which is explained below.
    • + + + +
    • Plan all the side dishes and desserts and determine which can be made in advance. Allow yourself plenty of time so that you don’t feel rushed and overwhelmed. Many steps of individual recipes can be made in advance, with the final dish assembled quickly on Thanksgiving day.
    • + + + +
    • Most desserts can (and should!) be made in advance, with only garnishing reserved for the last moment.
    • + + + +
    • Check to make sure you have all the flatware, china, crystal, and table linens you need well in advance. Don’t forget serving pieces! You’ll need bowls, platters, trays, and serving spoons and forks.
    • + + + +
    • Plan ahead to have beverages ready and ice on hand if needed.
    • +
    +
    + + + +
    +

    👉 PRO TIP: Use a large insulated cooler with ice as an extra refrigerator if you need more space.

    +
    + + + +
    +

    Timing Cooking of the Turkey

    + + + +

    If you’re starting with a frozen turkey, you’ll need to thaw it in its original packaging in the refrigerator (or in a large cooler with a couple of bags of ice), allowing at least 24 hours for every 4 pounds. After it’s thawed, keep it in the fridge (or on ice in a cooler) until you’re ready to cook.

    + + + +

    About 1 1/2 hours before you start cooking, take the turkey out of the fridge to bring it to room temperature. Having it at room temp will help it cook more evenly and faster.

    + + + +

    Prep time is pretty quick. I allow about 15 minutes to slather on the butter and sprinkle on the seasonings.

    + + + +

    Cooking time, of course, varies according to the total weight of the turkey. I’ve included a roasting timetable for you further down in the post. You’ll also need to allow time for the turkey to rest before carving.

    + + + +

    So, let’s get started with the recipe!

    +
    + + + +

    👉 Or just purchase my Thanksgiving Planner and Cookbook with all the timetables, recipes, and menus you need to make your planning easy!

    + + + +
    +

    Ingredient Notes

    + + + +
    The simple ingredients you'll need to make an oven roasted turkey.
    Butter, seasoned salt, turkey. (For the gravy: pan drippings from the turkey, flour, chicken or turkey broth).
    + + + +

    This post contains affiliate links. Lana’s Cooking is reader-supported and earns a tiny commission at no extra cost to you when you shop from our links.

    + + + +
      +
    • Fresh or Frozen Turkey — When choosing your Thanksgiving turkey, you should plan on 1 to 1 1/2 pounds per person; if you’d like to have leftovers, bump it up to 2 pounds per person.
    • + + + +
    • Butter — Like most southern cooks, I use salted butter for everything.
    • + + + +
    • Seasoning Salt — Use any seasoning mixture you like. I prefer Jane’s Crazy Mixed-Up Salt. Other people swear by Bell’s Seasoning or Lawry’s Seasoned Salt. Of course, just plain salt and black pepper work well, too.
    • +
    + + +
    + +
    +
    +
    +
    + + + +

    The complete ingredient list with detailed measurements is included in the printable recipe card at the bottom of this post.

    +
    + +
    + + + +
    +

    What Size Turkey Should I Buy?

    + + + +

    I always plan on 1 to 1 1/2 pounds of turkey per person (this allows for discarding skin, bones, etc.). Go for 2 pounds if you want to have lots of leftovers!

    +
    + + + +
    +

    How to Cook an Oven Roasted Turkey with Gravy

    + + + +

    Preheat the oven to 325 degrees.

    + + + +

    This process for how to cook a turkey in the oven is really simple and basic. All you’ll need are a turkey (thawed if frozen), some butter, and seasoning salt. As far as equipment goes, you will need a roasting pan and a rack of some kind.

    +
    + + + +
    +

    Prepare the Turkey

    + + + +

    Remove the turkey from its packaging and, using disposable paper towels, pat it dry very thoroughly.

    + + + +

    Make sure to remove the packet of giblets and neck from inside the cavity before proceeding with the recipe.

    + + + +
    +

    👉 PRO TIP: Like many cooks, I often use the giblets and neck to make stock for the gravy. Place the giblets in a saucepan and cover them with water and about half a teaspoon of salt. Bring to a boil and reduce to a simmer. Cook for about 30 minutes. Strain the broth and use it to make gravy.

    +
    + + + +

    If using a whole turkey, tuck the wing tips underneath the body. With some brands, the legs will be tucked under a flap of skin. If yours aren’t, simply tie them together with twine.

    + + + +

    Place the turkey on a rack in the roasting pan.

    +
    + + + +
    +
    Turkey in a roasting pan being rubbed with butter.
    + + + +

    Rub the skin all over with a generous amount of softened, room temperature butter.

    + + + +
    +

    👉 PRO TIP: I typically use between one and two sticks of butter for a medium sized turkey. You want it very well coated.

    +
    +
    + + + +
    +
    Turkey in roasting pan coated with butter and seasoned salt.
    + + + +

    Sprinkle well with salt and pepper, a seasoned salt mixture, or your favorite combination of spices. My favorite seasoning to use is Jane’s Crazy Mixed-Up Salt. However, I know many people use Bell’s Seasoning. You use whatever you like.

    +
    + + + +
    +

    Bake Until Golden Brown

    + + + +

    Place the pan in the preheated oven and set a timer for about 2/3 through the cooking time. When the turkey is about 2/3 done, check for browning.

    + + + +
    +

    👉 PRO TIP: Check the turkey periodically throughout the cooking time, and if you feel that the breast and the top of the drumsticks are getting too brown, make a tent of lightweight foil to drape over the top of the turkey to keep it from over-browning.

    +
    +
    + + + +
    +

    Cook according to the following timetable:

    + + + +

    Turkey Roasting Time Table Per Pound

    + + + +
    6-7 pounds2 – 2 1/2 hours
    7-10 pounds2 1/2 – 3 hours
    10 – 18 pounds3 – 3 1/2 hours
    18 – 22 pounds3 1/2 – 4 hours
    22 – 24 pounds4 – 4 1/2 hours
    24 – 30 pounds4 1/2 – 5 hours
    + + + +

    Test for doneness with a meat thermometer. A thermometer placed deep within the thigh should read 180 degrees when done.

    +
    + + + +
    Finished turkey resting in roasting pan.
    + + + +
    +

    Allow Adequate Resting Time

    + + + +

    Remove the turkey from the oven and let it stand for 20 to 30 minutes before carving.

    + + + +

    Resting time is very important as it allows the juices to redistribute through the meat, ensuring the turkey is moist throughout. Carving too quickly can cause a drier end product.

    +
    + + + +
    Gravy poured from a gravy boat onto a plate containing sliced oven roasted turkey and side dishes.
    + + + +
    +

    How to Make Turkey Gravy

    + + + +

    Remove about 1/2 cup of the drippings from the roasting pan and place them in a medium saucepan over medium-high heat. Using a whisk, blend the flour into the pan drippings. Whisk in the stock or broth a little at a time.

    + + + +

    Bring to a boil. Reduce the heat to low and simmer for about 5 minutes. Some cooks dice the giblets and add them to the gravy. It’s optional but tasty! My grandmother always added a chopped, hard-boiled egg. Again, an optional addition.

    + + + +

    Serve sliced roast turkey on a large platter with the gravy drizzled over or on the side.

    +
    + + + +
    +

    Recipe Options

    + + + +

    This is a very basic but quite delicious recipe. I often enhance the flavors by placing halved shallots, garlic, onion, lemons, and oranges inside the cavity, along with fresh herbs such as rosemary, sage, and thyme. Remove and discard these after cooking.

    +
    + + + + + + + +
    +

    Questions About Oven Roasted Turkey

    + + + +
    What if I don’t have a roasting rack?

    If you don’t have a roasting rack, you can form a coil of scrunched up aluminum foil to place in the bottom of your pan or use a bed of vegetables such as carrots and celery to keep the turkey raised off the bottom of the pan.

    How often should I baste the turkey?

    I skip it completely. Basting a turkey means frequently opening the oven door, which results in temperature fluctuations that can cause a dry turkey (particularly the breast meat). The butter rubbed all over will keep the turkey moist without the need for basting

    I’m a little nervous about trying to handle that big bird. Advice?

    I get it. Moving that big, hot turkey around can be intimidating. So, you could always consider roasting two small ones instead! They’ll cook faster, too, since you’ll base your cooking time on the smaller weights.

    Do you cover the turkey when roasting?

    No. Don’t cover the turkey while roasting. If you notice later in the cooking that the breast or legs are getting too brown, you can lightly place some foil over the top, but don’t completely cover the turkey.

    +
    + + +
    + +
    + +
    +
    Lana Stuart.
    +
    + + + +
    +

    Questions? I’m happy to help!

    + + + +

    If you have more questions about the recipe, or if you’ve made it and would like to leave a comment, scroll down to leave your thoughts, questions, and/or rating!

    + + + +

    Thanks so much for stopping by!

    +
    + +
    + +
    + + +
    +

    Recipe

    + + +
    +
    +

    Want to save this recipe?

    + + + +

    Enter your email below and get it sent straight to your inbox.

    + + +
    + Save Recipe
    +
    +
    + +
    + +
    +

    My Southern Table cookbook
    by Lana Taylor Stuart

    + + + +
    + + + + + + + +
      +
    • 346 pages; 246 recipes with full-color photos
    • + + + +
    • Durable softcover binding
    • + + + +
    • Personalized and signed by Lana
    • + + + +
    • Retail $39.99; Holiday Price $29.99 with FREE shipping
    • + + + +
    • In stock and ready to ship
    • +
    + + + + + + + + +
    + +
    + + + +
    + +
    Oven Roasted Turkey with Gravy on a white serving platter.
    +
    +
    +

    Oven Roasted Turkey with Gravy

    +
    +
    A simple method for cooking a beautifully moist Oven Roasted Turkey with golden, crispy skin and instructions for making the best pan gravy.
    +
    +
    5 from 6 votes
    +
    + Print It + + Rate It + + + + + Add to Collection +
    +
    Course: Main Course, Main Dishes
    Cuisine: American
    +
    Prep Time: 15 minutes
    Cook Time: 3 hours
    Resting Time: 20 minutes
    Total Time: 3 hours 35 minutes
    + +
    Servings: 6 servings
    + + +
    Calories: 1198kcal
    +
    Author: Lana Stuart
    + + + +
    + +

    Ingredients

    For the Turkey:

    • 1 cup butter softened
    • 2 tablespoons seasoned salt recommended: Jane's Crazy Mixed-Up Salt
    • 10 pounds turkey fresh or frozen

    For the Gravy:

    • ½ cup pan drippings from turkey
    • ½ cup all-purpose flour
    • 3 ¾ cups turkey or chicken broth or stock
    + +

    Instructions

    To Roast the Turkey:

    • If using a frozen turkey, thaw in the refrigerator allowing at least 24 hours for every 4 pounds of turkey.
    • Approximately 1 1/2 hours before cooking, remove the turkey from the refrigerator and let it sit at room temperature.
    • Preheat the oven to 325 degrees. Drain any juices from the turkey and pat it dry with paper towels.
    • Place the turkey breast side up on a rack in a roasting pan.
    • Tuck the wings under the turkey and secure the legs with kitchen twine if needed.
    • Rub the turkey generously with the butter. Sprinkle evenly with seasoned salt.
    • Place the turkey in the preheated oven.
    • About 2/3 through cooking time, check to make sure the breast and tops of the legs aren't browning too quickly. If needed, cover the turkey loosely with a tent of aluminum foil to prevent overcooking.
    • Turkey is done when the temperature in the thigh registers 180 degrees on a meat thermometer.
    • Remove from the oven and let stand for at least 20 minutes before carving.

    To Make the Gravy:

    • Remove drippings from the turkey roasting pan and place in a medium saucepan.
    • Using a whisk, blend the flour into the pandrippings.
    • Whisk in the stock or broth a little at a time
    • Place the saucepan over medium high heat and bring to a boil. Reduce the heat to low and simmer for about 5 minutes.
    + +

    Notes

    The times, servings, and nutrition information are calculated based on a 10-pound fresh, unfrozen turkey.
    +When purchasing your turkey, allow 1 to 1 1/2 pounds per person. More if you’d like lots of leftovers.
    +Turkey Roasting Time Table:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    6 – 7 pounds2 – 2 1/2 hours
    7 – 10 pounds2 1/2 – 3 hours
    10 – 18 pounds3 – 3 1/2 hours
    18 – 22 pounds3 1/2 – 4 hours
    22 -24 pounds4 – 4 1/2 hours
    24 – 30 pounds4 1/2 – 5 hours
    +Times stated are approximate. Use a meat thermometer to determine when your turkey is done correctly.
    +Tips:
    +
      +
    • If you don’t have a roasting rack, form a coil of aluminum foil to place in the bottom of your pan or use a bed of vegetables such as carrots and celery to keep the turkey raised off the bottom of the pan.
    • +
    • Skip the basting – basting a turkey means frequently opening the oven door which results in temperature fluctuations that can result in a dry finished bird. The butter rubbed all over will keep the turkey moist without the need for basting.
    • +
    + + +

    Nutrition Information

    Serving 1 | Calories 1198kcal | Carbohydrates 13g | Protein 121g | Fat 72g | Saturated Fat 35g | Cholesterol 472mg | Sodium 3408mg | Potassium 1378mg | Fiber 1g | Sugar 3g | Vitamin A 1246IU | Vitamin C 1mg | Calcium 73mg | Iron 5mg
    +
    +

    Nutrition information is calculated by software based on the ingredients in each recipe. It is an estimate only and is provided for informational purposes. You should consult your healthcare provider or a registered dietitian if precise nutrition calculations are needed for health reasons.

    +
    +
    + +
    Share on Facebook + + Pin Recipe +
    +
    +
    Tried this recipe? Pin it for Later!Follow @LanasCookingBlog or tag #LanasCooking!
    +
    + + + +

    — This post was originally published on November 11, 2020. It has been updated with additional information.

    +
    +
    +
    +
    +
    + + + + + +
    +
    +
    +
    + 5 from 6 votes (5 ratings without comment) +
    +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +
    +

    + +

    +

    2 Comments

      +
    1. +
      +
      +
      + Miss P says:
      + + + +
      + +
      +

      5 stars
      +Oh. My. Goodness. Absolutely superb. Nothing compares.
      +And the photography is outstanding!

      +
      + +
      +
        +
      1. +
        + + +
        +

        Thanks! I do enjoy a really good roast turkey.

        +
        + +
        +
      2. +
      +
    2. +
    +
    +
    +
    + + +
    +
    +
    + +
    + +
    + +
    + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 606aec560acff4d945e8a8e9c50b57c47b04e758 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 7 Dec 2024 19:49:56 +0200 Subject: [PATCH 23/94] Update readme not to assume requests is installed. Closes #1419 No point in using .. code:: pycon if we do not show non-python outputs Switch to .. code:: python for easier copy/pasting for the end user --- README.rst | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/README.rst b/README.rst index fc03384c2..c64de98a4 100644 --- a/README.rst +++ b/README.rst @@ -51,18 +51,21 @@ Start by using `Python's built-in package installer ``. -To learn what the library can do, you can open a `Python interpreter session `_, and then begin typing -- and/or modifying -- the statements below (on the lines containing the ``>>>`` prompt): +To learn what the library can do, you can open a `Python interpreter session `_, and then begin typing -- and/or modifying -- the statements below: -.. code:: pycon +.. code:: python + + from urllib.request import urlopen - Python 4.0.4 (main, Oct 26 1985, 09:00:32) [GCC 22.3.4] on linux - Type "help", "copyright", "credits" or "license" for more information. - >>> from recipe_scrapers import scrape_html - >>> url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" - >>> name = input('What is your name, burger seeker?\n') - >>> html = requests.get(url, headers={"User-Agent": f"Burger Seeker {name}"}).content - >>> scraper = scrape_html(html, org_url=url) - >>> help(scraper) + from recipe_scrapers import scrape_html + + url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" + html = urlopen(url).read().decode("utf-8") # retrieves the recipe webpage HTML + scraper = scrape_html(html, org_url=url) + scraper.title() + scraper.instructions() # etc. + # for a complete list of methods: + # help(scraper) Some Python HTTP clients that you can use to retrieve HTML include `requests`_, `httpx`_, and the `urllib.request module`_ included in Python's standard library. Please refer to their documentation to find out what options (timeout configuration, proxy support, etc) are available. @@ -579,15 +582,16 @@ Notes: Run in python shell: -.. code:: pycon +.. code:: python + + # first ensure you have the required packages: + # pip install "recipe-scrapers[online]" - Python 4.0.4 (main, Oct 26 1985, 09:00:32) [GCC 22.3.4] on linux - Type "help", "copyright", "credits" or "license" for more information. - >>> from recipe_scrapers import scrape_html - >>> scraper = scrape_html(html=None, org_url='', online=True, wild_mode=True) - >>> # if no error is raised - there's schema available: - >>> scraper.title() - >>> scraper.instructions() # etc. + from recipe_scrapers import scrape_html + scraper = scrape_html(html=None, org_url='', online=True, wild_mode=True) + # if no error is raised - there's schema available: + scraper.title() + scraper.instructions() # etc. Special thanks to: From 716963fadedc8760532600a0b8591d008dd048a5 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 7 Dec 2024 19:58:40 +0200 Subject: [PATCH 24/94] docs: remove reference to abandoned project from README (inactive since 2016) --- README.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.rst b/README.rst index c64de98a4..776e7078c 100644 --- a/README.rst +++ b/README.rst @@ -37,8 +37,6 @@ If you're using this library to collect large numbers of recipes from the web, p Python's standard library provides a ``robots.txt`` `parser `_ that may be helpful to automatically follow common instructions specified by websites for web crawlers. -Another parser option -- particularly if you find that many web requests from ``urllib.robotparser`` are blocked -- is the `robotexclusionrulesparser `_ library. - Getting Started --------------- From ccdc1452eb225bec6c8aa384ea51fd7cddef7d63 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sat, 7 Dec 2024 15:04:17 -0500 Subject: [PATCH 25/94] inspiredtaste (#1395) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/inspiredtaste.py | 16 + .../inspiredtaste.net/inspiredtaste_1.json | 50 + .../inspiredtaste_1.testhtml | 1303 +++++++++++++++ .../inspiredtaste.net/inspiredtaste_2.json | 92 ++ .../inspiredtaste_2.testhtml | 1465 +++++++++++++++++ 7 files changed, 2929 insertions(+) create mode 100644 recipe_scrapers/inspiredtaste.py create mode 100644 tests/test_data/inspiredtaste.net/inspiredtaste_1.json create mode 100644 tests/test_data/inspiredtaste.net/inspiredtaste_1.testhtml create mode 100644 tests/test_data/inspiredtaste.net/inspiredtaste_2.json create mode 100644 tests/test_data/inspiredtaste.net/inspiredtaste_2.testhtml diff --git a/README.rst b/README.rst index 776e7078c..9b8de7030 100644 --- a/README.rst +++ b/README.rst @@ -255,6 +255,7 @@ Scrapers available for: - `https://www.innit.com/ `_ - `https://insanelygoodrecipes.com `_ - `https://inspiralized.com/ `_ +- `https://inspiredtaste.net/ `_ - `https://irishcentral.com/ `_ - `https://izzycooking.com/ `_ - `https://jamieoliver.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 3b3b2243b..09c102e1d 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -202,6 +202,7 @@ from .innit import Innit from .insanelygoodrecipes import InsanelyGoodRecipes from .inspiralized import Inspiralized +from .inspiredtaste import InspiredTaste from .irishcentral import IrishCentral from .izzycooking import IzzyCooking from .jamieoliver import JamieOliver @@ -553,6 +554,7 @@ HungryHappens.host(): HungryHappens, InBloomBakery.host(): InBloomBakery, InGoodFlavor.host(): InGoodFlavor, + InspiredTaste.host(): InspiredTaste, IrishCentral.host(): IrishCentral, JoCooks.host(): JoCooks, JoshuaWeissman.host(): JoshuaWeissman, diff --git a/recipe_scrapers/inspiredtaste.py b/recipe_scrapers/inspiredtaste.py new file mode 100644 index 000000000..b154e4acd --- /dev/null +++ b/recipe_scrapers/inspiredtaste.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class InspiredTaste(AbstractScraper): + @classmethod + def host(cls): + return "inspiredtaste.net" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".ingredient_heading", + ".itr-ingredients p", + ) diff --git a/tests/test_data/inspiredtaste.net/inspiredtaste_1.json b/tests/test_data/inspiredtaste.net/inspiredtaste_1.json new file mode 100644 index 000000000..f611dedd7 --- /dev/null +++ b/tests/test_data/inspiredtaste.net/inspiredtaste_1.json @@ -0,0 +1,50 @@ +{ + "author": "Joanne Gallagher", + "canonical_url": "https://www.inspiredtaste.net/51500/pressure-cooker-applesauce/", + "site_name": "Inspired Taste - Easy Recipes for Home Cooks", + "host": "inspiredtaste.net", + "language": "en-US", + "title": "Ridiculously Easy Instant Pot Applesauce", + "ingredients": [ + "4 pounds crisp, sweet apples (8 large), rinsed", + "One 3-inch cinnamon stick or 1/2 teaspoon ground cinnamon", + "1 to 2 whole star anise, optional", + "2 tablespoons fresh lemon juice, fresh orange juice, or apple cider vinegar", + "1 ½ teaspoons vanilla extract", + "Brown sugar, honey, maple syrup, or other sweetener to taste, optional" + ], + "instructions_list": [ + "Peel apples, remove the apple cores, and cut apples into 1-inch chunks or wedges.", + "Place the apples, cinnamon stick, lemon juice, vanilla extract, and star anise into the bottom of a 6-quart electric pressure cooker (Instant Pot).", + "Add 1/3 cup of water, then stir the apples around the pot a few times.", + "Close the lid, select the “Pressure Cook” or “Manual” function, and cook on high pressure for 5 minutes. Note that the timer will not start until there is enough pressure inside the pot, so it may not start for a few minutes.", + "When the cooking time is up, do not immediately open the lid and instead let the pressure naturally release for 20 minutes. After 20 minutes, release the remaining pressure using the quick-release button (be careful to keep your hands and face away from the venting steam).", + "Stir or mash the apples into your preferred consistency. An immersion blender also works, but the apples should be so soft that a spoon is enough to mash them into a sauce.", + "Taste the applesauce. If you would like to add a sweetener, add it to taste. Start with a teaspoon and then add more as needed.", + "The applesauce will thicken a little as it cools, but if it seems too watery, return it to the pressure cooker, turn the sauté function on, and simmer until reduced a little." + ], + "category": "Dessert, Sauce", + "yields": "4 cups", + "description": "Instant Pot applesauce is super simple to make, makes the kitchen smell incredible, and tastes much better than anything you can buy at the store. Use apples that you enjoy eating. We particularly love using crisp, sweet apples when making applesauce and generally do not add any sweetener. If you feel the applesauce needs some extra sweetness, add a sweetener to taste at the end of cooking. We recommend brown sugar, maple syrup, or honey. Peeled apples make this recipe easy, but you can use skin-on apples. If you do, use a food mill fitted with a medium disk to blend the sauce and remove most of the cooked skins for the best texture. You can puree the skins into the sauce if you do not have a food mill. Or pass the sauce through a mesh strainer to remove the skins. **The cooking time for this applesauce is 5 minutes, but keep in mind that the pressure cooker takes additional time to reach pressure before the cooking time begins and releases the pressure after the cooking time ends.", + "total_time": 35, + "cook_time": 25, + "prep_time": 10, + "cuisine": "American", + "nutrients": { + "servingSize": "1/4 cup", + "calories": "60", + "fatContent": "0.2g", + "saturatedFatContent": "0g", + "carbohydrateContent": "15.5g", + "sugarContent": "11.6g", + "proteinContent": "0.3g", + "sodiumContent": "1.3mg", + "fiberContent": "2.7g", + "cholesterolContent": "0mg" + }, + "image": "https://www.inspiredtaste.net/wp-content/uploads/2021/10/Instant-Pot-Applesauce-Recipe-4-1200.jpg", + "keywords": [ + "instant pot applesauce", + "pressure cooker applesauce" + ] +} diff --git a/tests/test_data/inspiredtaste.net/inspiredtaste_1.testhtml b/tests/test_data/inspiredtaste.net/inspiredtaste_1.testhtml new file mode 100644 index 000000000..b3fbb3f67 --- /dev/null +++ b/tests/test_data/inspiredtaste.net/inspiredtaste_1.testhtml @@ -0,0 +1,1303 @@ + + + + + + +Ridiculously Easy Instant Pot Applesauce Recipe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +

    Ridiculously Easy Instant Pot Applesauce

    + +
    + +
    + Pin +
    +
    + Save +
    +
    +
    + +

    My family loves this Instant Pot applesauce so much. It’s quick, easy, and tastes incredible! Skip the store-bought jars and packets and make your own. It tastes so much better!

    + + + +
    Easy Instant Pot Applesauce
    + + + +

    I’m still getting over how easy it is to make applesauce in the Instant Pot. Toss in your apples, water, and spices, then close the lid and cook. Release the pressure, and you’ve got applesauce!

    + + + +

    Our family loves homemade applesauce. It tastes way better than the jars or packets at the store and makes your kitchen smell incredible! If you’ve got some leftover apples, try our apple butter recipe. It’s like applesauce but thicker and spreadable.

    + + + +

    Key Ingredients

    + + + +
      +
    • Apples: I love sweet, crisp apples like Honeycrisp, Fuji, Cox, Gala, and Pink Lady. They taste great after cooking, and since they are already on the sweeter side, I usually don’t need to add any sweetener.
    • + + + +
    • Spices: You can experiment with different spices for this recipe, but I love cinnamon sticks and whole star anise. I also add a splash of vanilla extract, which makes the applesauce taste incredible.
    • + + + +
    • Lemon: I love adding a little acid to the apples. Fresh lemon juice is perfect, but fresh orange juice or apple cider vinegar are great substitutes.
    • + + + +
    • Sweetener (optional): I usually skip the sweetener, but you can stir in brown sugar, maple syrup, or honey. If you plan to add some, add the sweetener after the applesauce has finished cooking. This way, you can add to taste.
    • +
    + + + +
    Peeled and chopped apples in an Instant Pot
    + + + +

    How to Make Instant Pot Applesauce

    + + + +

    Making applesauce in a pressure cooker is simple and fuss-free. Toss peeled apples, spices (I like cinnamon and star anise), lemon juice, and water into the pressure cooker. Then, close the lid and cook on high pressure for 5 minutes.

    + + + +
    Making applesauce -- Apples after cooking them in an Instant Pot
    + + + +

    Allow the pressure cooker to release naturally for 20 minutes (this is important for the best texture), and finally, open the lid and mash or stir the apples into a sauce. So easy! If you find the applesauce too tart, stir in a bit of sweetener, like sugar or honey, at the end.

    + + + +
    A bowl of homemade Instant Pot Applesauce
    + + +

    Ridiculously Easy Instant Pot Applesauce

    +
    + Pin +
    +
    + Save +
    +
    + Email +
    +
    +
    +
      +
    • + PREP + +
    • +
    • + COOK + +
    • +
    • + TOTAL + +
    • + +
    +
    +

    Instant Pot applesauce is super simple to make, makes the kitchen smell incredible, and tastes much better than anything you can buy at the store. Use apples that you enjoy eating. We particularly love using crisp, sweet apples when making applesauce and generally do not add any sweetener. If you feel the applesauce needs some extra sweetness, add a sweetener to taste at the end of cooking. We recommend brown sugar, maple syrup, or honey.

    +

    Peeled apples make this recipe easy, but you can use skin-on apples. If you do, use a food mill fitted with a medium disk to blend the sauce and remove most of the cooked skins for the best texture. You can puree the skins into the sauce if you do not have a food mill. Or pass the sauce through a mesh strainer to remove the skins.

    +

    **The cooking time for this applesauce is 5 minutes, but keep in mind that the pressure cooker takes additional time to reach pressure before the cooking time begins and releases the pressure after the cooking time ends.

    +
    +
    Makes 4 Cups
    +
    +

    You Will Need

    4 pounds crisp, sweet apples (8 large), rinsed

    +

    One 3-inch cinnamon stick or 1/2 teaspoon ground cinnamon

    +

    1 to 2 whole star anise, optional

    +

    2 tablespoons fresh lemon juice, fresh orange juice, or apple cider vinegar

    +

    1 ½ teaspoons vanilla extract

    +

    Brown sugar, honey, maple syrup, or other sweetener to taste, optional

    +
    +
    +
    +

    Directions

    +

      1Peel apples, remove the apple cores, and cut apples into 1-inch chunks or wedges.

      +

      2Place the apples, cinnamon stick, lemon juice, vanilla extract, and star anise into the bottom of a 6-quart electric pressure cooker (Instant Pot).

      +

      3Add 1/3 cup of water, then stir the apples around the pot a few times.

      +

      4Close the lid, select the “Pressure Cook” or “Manual” function, and cook on high pressure for 5 minutes. Note that the timer will not start until there is enough pressure inside the pot, so it may not start for a few minutes.

      +

      5When the cooking time is up, do not immediately open the lid and instead let the pressure naturally release for 20 minutes. After 20 minutes, release the remaining pressure using the quick-release button (be careful to keep your hands and face away from the venting steam).

      +

      6Stir or mash the apples into your preferred consistency. An immersion blender also works, but the apples should be so soft that a spoon is enough to mash them into a sauce.

      +

      7Taste the applesauce. If you would like to add a sweetener, add it to taste. Start with a teaspoon and then add more as needed.

      +

      8The applesauce will thicken a little as it cools, but if it seems too watery, return it to the pressure cooker, turn the sauté function on, and simmer until reduced a little.

      +

      +
      + +
    +
    +
    +

    Adam and Joanne's Tips

    +
      +
    • Add more cinnamon: One cinnamon stick adds a little warmth to the applesauce, but it is not overpowering. If you love a lot of cinnamon in your applesauce, add an extra 1/2 teaspoon to the pot.
    • +
    • The nutrition facts provided below are estimates. We did not include sugar in the calculations.
    • +
    +
    +
    + +
    + Nutrition Per Serving + Serving Size + 1/4 cup + / + Calories + 60 + / + Total Fat + 0.2g + / + Saturated Fat + 0g + / + Cholesterol + 0mg + / + Sodium + 1.3mg + / + Carbohydrate + 15.5g + / + Dietary Fiber + 2.7g + / + Total Sugars + 11.6g + / + Protein + 0.3g + + +
    + + AUTHOR: + + Joanne Gallagher +
    + +
    +
    + Inspired Taste Newsletter Signup +
    +
    +
    1 comment… Leave a Review
    +
      +
    • + Conni + October 7, 2021, 12:24 pm +
      +

      Our neighbours gave us a big bucket of ugly duckling looking apples from their tree. Wormy, rotty spots… all kinds. I quartered them, cut out the core & yucky bits and followed your instructions. I normally use a crock pot, but it takes SO much longer. After they cooled a bit I dumped them in the blender (skins on). I’ve NEVER had applesauce THIS fast, THIS easy & THIS good! I froze a bunch in ziplock bags, flat. Perfection! Thank you!

      +
      + Reply +
    • +
    +
    +
    +

    Leave a Reply

    +

    Leave a Review

    Your email address will not be published. Required fields are marked *

    + +

    +
    +

    Rate this recipe!

    + + + + + + + + + + + + + + + + + + + + + + +   +

    + +

    +

    All comments are moderated before appearing on the site. Thank you so much for waiting. First time commenting? Please review our comment guidelines. You must be at least 16 years old to post a comment. All comments are governed by our Privacy Policy & Terms.

    +
    + Previous Post: + Next Post: +
    +
    + +
    + +
    + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/inspiredtaste.net/inspiredtaste_2.json b/tests/test_data/inspiredtaste.net/inspiredtaste_2.json new file mode 100644 index 000000000..ddd6c44ad --- /dev/null +++ b/tests/test_data/inspiredtaste.net/inspiredtaste_2.json @@ -0,0 +1,92 @@ +{ + "author": "Joanne Gallagher", + "canonical_url": "https://www.inspiredtaste.net/76710/strawberry-shortcake-recipe/", + "site_name": "Inspired Taste - Easy Recipes for Home Cooks", + "host": "inspiredtaste.net", + "language": "en-US", + "title": "Perfect Strawberry Shortcake", + "ingredients": [ + "2 ¼ cups (292g) all-purpose flour", + "1 tablespoon (12g) aluminum-free baking powder", + "1/4 cup (50g) sugar", + "1/2 teaspoon (2g) fine sea salt", + "3 tablespoons (42g) cold butter", + "1 cup (236ml) whole milk", + "1 large egg, lightly beaten", + "2 pounds (907g) fresh strawberries, hulled and quartered", + "1 ¼ cups (250g) sugar", + "1 ½ cups (355ml) cold heavy whipping cream", + "3 tablespoons (38g) sugar", + "1 teaspoon vanilla extract" + ], + "ingredient_groups": [ + { + "ingredients": [ + "2 ¼ cups (292g) all-purpose flour", + "1 tablespoon (12g) aluminum-free baking powder", + "1/4 cup (50g) sugar", + "1/2 teaspoon (2g) fine sea salt", + "3 tablespoons (42g) cold butter", + "1 cup (236ml) whole milk", + "1 large egg, lightly beaten" + ], + "purpose": "Shortcakes" + }, + { + "ingredients": [ + "2 pounds (907g) fresh strawberries, hulled and quartered", + "1 ¼ cups (250g) sugar" + ], + "purpose": "Strawberry Filling" + }, + { + "ingredients": [ + "1 ½ cups (355ml) cold heavy whipping cream", + "3 tablespoons (38g) sugar", + "1 teaspoon vanilla extract" + ], + "purpose": "Whipped Cream" + } + ], + "instructions_list": [ + "Make Shortcakes", + "Preheat your oven to 375°F (190°C). Line a baking sheet with parchment paper. If you have them, arrange six 4-inch English muffin rings on the sheet.", + "Whisk the flour, baking powder, sugar, and salt in a mixing bowl.", + "Cut the cold butter into small pieces and work it into the flour mixture with a pastry blender, your fingers, or two knives until it resembles coarse crumbs.", + "Stir in the milk and egg until the batter just comes together.", + "Divide the batter evenly among the rings (about 4 tablespoons each). They will spread out, no need to spread them before baking. If you do not have the rings, spoon the batter in tall mounds directly onto the parchment paper and gently smooth the top.", + "Bake for 15 to 17 minutes, turning the baking sheet halfway through. Let the shortcakes cool completely before building and serving.", + "Prepare the Strawberries and Cream", + "While the shortcakes bake, prepare the strawberries. Place a medium bowl into the freezer to chill.", + "Place a third of the strawberries in a saucepan with the sugar. Cook over medium heat, stirring occasionally, just until the sugar dissolves.", + "Pour the mixture into the chilled bowl, add the remaining strawberries, and refrigerate until chilled.", + "Use a stand mixer or electric hand mixer to beat the heavy cream, sugar, and vanilla extract until medium peaks form. Refrigerate until ready to assemble.", + "Assemble the Shortcakes", + "Slice each shortcake in half horizontally (like an English muffin). Place the bottom half on a serving plate, drizzle with a spoonful of strawberry syrup, then add a generous spoonful of whipped cream. Use a slotted spoon to add some of the strawberries on top of the cream, and then place the other half of the shortcake on top. Repeat with more whipped cream and strawberries." + ], + "category": "Dessert ", + "yields": "6 items", + "description": "This strawberry shortcake recipe is honestly so delicious! The secret to making it best is making the super simple strawberry syrup and drizzling some of it over the bottom of your shortcake before adding the whipped cream and strawberries. It softens the shortcake a bit and adds a lovely strawberry flavor. For perfect rounds, I love using 4-inch English muffin rounds. If you do not have these in your kitchen, you can still bake the shortcakes freeform on the baking sheet. They spread a bit more than if you use the rounds, but they still work well! See our photo in the article showing me baking the shortcake batter in rounds vs. freeform on the baking sheet.", + "total_time": 35, + "cook_time": 15, + "prep_time": 20, + "cuisine": "American", + "ratings": 5.0, + "ratings_count": 4, + "nutrients": { + "servingSize": "1 shortcake", + "calories": "620", + "fatContent": "18.3g", + "saturatedFatContent": "10.9g", + "carbohydrateContent": "107.8g", + "sugarContent": "66.8g", + "proteinContent": "9.2g", + "sodiumContent": "236.8mg", + "fiberContent": "4.3g", + "cholesterolContent": "81mg" + }, + "image": "https://www.inspiredtaste.net/wp-content/uploads/2024/06/Strawberry-Shortcake-Recipe-1.jpg", + "keywords": [ + "strawberry shortcake recipe" + ] +} diff --git a/tests/test_data/inspiredtaste.net/inspiredtaste_2.testhtml b/tests/test_data/inspiredtaste.net/inspiredtaste_2.testhtml new file mode 100644 index 000000000..b069d826c --- /dev/null +++ b/tests/test_data/inspiredtaste.net/inspiredtaste_2.testhtml @@ -0,0 +1,1465 @@ + + + + + + +Perfect Strawberry Shortcake Recipe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +

    Perfect Strawberry Shortcake

    + +
    + +
    + Pin +
    +
    + Save +
    +
    +
    + +

    This is the most delicious strawberry shortcake recipe we’ve ever made! We layer our buttery homemade shortcake with strawberries, whipped cream, and an irresistible strawberry syrup to make it extra delicious.

    + + + +
    Best Homemade Strawberry Shortcake
    + + + +

    These strawberry shortcakes are closer to an authentic shortcake than most recipes I’ve seen. The shortcakes have a buttery biscuit flavor with the most wonderful, tender, almost cake-like consistency (thanks to an egg in the batter). They are truly delicious and surprisingly simple to make!

    + + + +

    We worked on this incredible strawberry dessert with Richard Hattaway, and we’ve all fallen head over heels for it. What I love most is the simple strawberry syrup, which we drizzle over the base of our shortcakes before adding whipped cream and fresh strawberries.

    + + + +
    Easy Strawberry Shortcake
    + + + +

    Key Ingredients

    + + + +
      +
    • Strawberries: I use 2 pounds of fresh strawberries. A third of them are cooked with sugar to make a simple strawberry syrup. I drizzle this over the base of our shortcake before adding the whipped cream and strawberries.
    • + + + +
    • Flour: I use all-purpose flour, but soft white wheat flour (like White Lilly, Martha White, and Bob’s Red Mill Fine Pastry Flour) is also excellent.
    • + + + +
    • Baking Powder: I use 1 tablespoon of baking powder to make the shortcakes fluffy and tender. It’s also my secret for the best fluffy biscuits!
    • + + + +
    • Sugar: I use sugar in three ways: in the shortcake batter, for the strawberry syrup, and to sweeten the whipped cream. Granulated sugar, cane sugar, or coconut sugar are fine.
    • + + + +
    • Milk, Butter, and Egg: These are combined with flour to make the shortcakes tender and delicious.
    • + + + +
    • Cream: I use cold heavy cream or heavy whipping cream to make the whipped cream topping.
    • +
    + + + +

    How to Make Strawberry Shortcake

    + + + +

    Homemade strawberry shortcakes have three parts: the shortcake, strawberries in syrup, and whipped cream. But don’t worry, they’re all super easy to make (I promise!).

    + + + +

    The shortcakes are surprisingly simple, more like biscuits than cake. You’ll “cut in” cold butter to the flour mixture until it forms small butter crumbs. I like to use a pastry blender, but two knives or your fingers work just as well. These butter crumbs are key to creating tender, delicious shortcakes because they melt and puff in the oven. The same is true when making homemade biscuits.

    + + + +

    For baking, you can drop spoonfuls of the batter directly onto a baking sheet or use English muffin rings for perfectly round shortcakes (see photo below). I even have a tip in the recipe for making one large, family-style shortcake that you can slice and serve like a cake.

    + + + +
    Baking Shortcakes
    + + + +

    While the shortcakes bake, you’ll make the strawberry syrup. Simply cook some of your strawberries with sugar until the sugar melts. Take it off the heat and gently toss with the remaining strawberries until they’re coated in the syrup, before popping them in the fridge to chill.

    + + + +
    Strawberries in syrup and baked shortcake ready to assemble
    + + + +

    Homemade whipped cream is easy and tastes much better than the canned stuff! Use a stand or hand mixer to beat heavy cream with sugar and vanilla until it’s thick and softly whipped. It only takes a few minutes.

    + + + +

    Now for the fun part: assembling your shortcakes! Split the shortcakes in half, drizzle a spoonful of that delicious strawberry syrup over the bottom, and top with whipped cream, strawberries, the other half of the shortcake, more whipped cream, and even more strawberries. So good!

    + + + +

    I can’t wait for you to try this strawberry shortcake recipe! For more strawberry recipes, take a look at our fresh strawberry cake or this incredible strawberry pie!

    + + +

    Perfect Strawberry Shortcake

    +
    + Pin +
    +
    + Save +
    +
    + Email +
    +
    +
    +
      +
    • + PREP + +
    • +
    • + COOK + +
    • +
    • + TOTAL + +
    • + +
    +
    +

    This strawberry shortcake recipe is honestly so delicious! The secret to making it best is making the super simple strawberry syrup and drizzling some of it over the bottom of your shortcake before adding the whipped cream and strawberries. It softens the shortcake a bit and adds a lovely strawberry flavor.

    +

    For perfect rounds, I love using 4-inch English muffin rounds. If you do not have these in your kitchen, you can still bake the shortcakes freeform on the baking sheet. They spread a bit more than if you use the rounds, but they still work well! See our photo in the article showing me baking the shortcake batter in rounds vs. freeform on the baking sheet.

    +
    +
    Makes 6
    +
    +

    You Will Need

    + Shortcakes

    2 ¼ cups (292g) all-purpose flour

    +

    1 tablespoon (12g) aluminum-free baking powder

    +

    1/4 cup (50g) sugar

    +

    1/2 teaspoon (2g) fine sea salt

    +

    3 tablespoons (42g) cold butter

    +

    1 cup (236ml) whole milk

    +

    1 large egg, lightly beaten

    +
    + Strawberry Filling

    2 pounds (907g) fresh strawberries, hulled and quartered

    +

    1 ¼ cups (250g) sugar

    +
    + Whipped Cream

    1 ½ cups (355ml) cold heavy whipping cream

    +

    3 tablespoons (38g) sugar

    +

    1 teaspoon vanilla extract

    +
    +
    +
    +

    Directions

    +
      +
    • Make Shortcakes
    • 1Preheat your oven to 375°F (190°C). Line a baking sheet with parchment paper. If you have them, arrange six 4-inch English muffin rings on the sheet.

      +

      2Whisk the flour, baking powder, sugar, and salt in a mixing bowl.

      +

      3Cut the cold butter into small pieces and work it into the flour mixture with a pastry blender, your fingers, or two knives until it resembles coarse crumbs.

      +

      4Stir in the milk and egg until the batter just comes together.

      +

      5Divide the batter evenly among the rings (about 4 tablespoons each). They will spread out, no need to spread them before baking. If you do not have the rings, spoon the batter in tall mounds directly onto the parchment paper and gently smooth the top.

      +

      6Bake for 15 to 17 minutes, turning the baking sheet halfway through. Let the shortcakes cool completely before building and serving.

      +

      +
      + +
    +
      +
    • Prepare the Strawberries and Cream
    • 1While the shortcakes bake, prepare the strawberries. Place a medium bowl into the freezer to chill.

      +

      2Place a third of the strawberries in a saucepan with the sugar. Cook over medium heat, stirring occasionally, just until the sugar dissolves.

      +

      3Pour the mixture into the chilled bowl, add the remaining strawberries, and refrigerate until chilled.

      +

      4Use a stand mixer or electric hand mixer to beat the heavy cream, sugar, and vanilla extract until medium peaks form. Refrigerate until ready to assemble.

      +

      +
      + +
    +
      +
    • Assemble the Shortcakes
    • 1Slice each shortcake in half horizontally (like an English muffin). Place the bottom half on a serving plate, drizzle with a spoonful of strawberry syrup, then add a generous spoonful of whipped cream. Use a slotted spoon to add some of the strawberries on top of the cream, and then place the other half of the shortcake on top. Repeat with more whipped cream and strawberries.

      +

      +
      + +
    +
    +
    +

    Adam and Joanne's Tips

    +
      +
    • Make one family-style shortcake: You can bake this batter in a parchment paper-lined 9-inch cake pan or cast iron pan. Add the batter and gently smooth the top, you do not need to spread it out all the way to the sides. The baking time should be similar, possibly requiring a few more minutes than the individual shortcakes. Allow to cook, cut in half horizontally, and build the shortcake as directed above, but build a family-style shortcake instead. Then, cut into the shortcake like a cake or pie for serving. It’s a little more messy, but it looks amazing on the table and is still just as delicious!
    • +
    • Measuring flour: Fluff the flour in its container, then gently scoop it into your measuring cup until slightly mounded. Level off the top with a knife for accurate measuring. For even more accuracy, use a scale and measure the flour by weight (in grams).
    • +
    • Removing shortcake from rings: Run a thin knife around the rings to loosen the shortcake.
    • +
    • The nutrition facts provided below are estimates. These are likely too high since you will have leftover syrup and this recipe is generous with the cream.
    • +
    +
    +
    + +
    + Nutrition Per Serving + Serving Size + 1 shortcake + / + Calories + 620 + / + Total Fat + 18.3g + / + Saturated Fat + 10.9g + / + Cholesterol + 81mg + / + Sodium + 236.8mg + / + Carbohydrate + 107.8g + / + Dietary Fiber + 4.3g + / + Total Sugars + 66.8g + / + Protein + 9.2g + + +
    + + AUTHOR: + + Joanne Gallagher +
    + +
    +
    + Inspired Taste Newsletter Signup +
    +
    +
    13 comments… Leave a Review
    +
      +
    • + Monica + July 1, 2024, 7:12 pm +
      +

      The strawberry shortcake… the absolute best!

      +
      + Reply +
        +
      • + Adam + July 1, 2024, 7:18 pm +
        +

        Yay! 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Excellent!!! + June 30, 2024, 9:41 am +
      +

      This recipe reminds me of my grandmothers, it’s delicious!

      +

      +
      +

      +
      + Reply +
        +
      • + Adam + July 1, 2024, 7:18 pm +
        +

        That is one of the best compliments a recipe can ever get. We are thrilled you love it 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Anita prosser + June 29, 2024, 11:13 pm +
      +

      This strawberry shortcake is amazing! I really appreciate this web sight. You guys use real food and the clarity of the instructions in your recipes make it easy to create the best food Ive ever eaten. It’s like the love you infuse in the recipes comes out in the taste! Thank you for this website and your labor of love in creating it. Anita

      +

      +
      +

      +
      + Reply +
        +
      • + Adam + July 1, 2024, 7:19 pm +
        +

        You made our day with this review and comment 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Isadora + June 29, 2024, 4:25 am +
      +

      Hi from South Africa! just joined and started receiving your recipes. the website is super-user friendly and recipes thus far are fool-proof. Isidora

      +
      + Reply +
        +
      • + Adam + June 29, 2024, 10:13 pm +
        +

        Hi Isadora, We are so happy that you found us and thank you so much! 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Rosalinda Salcedo + June 28, 2024, 8:24 pm +
      +

      This is absolutely amazing!! Love your recipe!! Strawberry shortcake is my absolute favorite dessert!! This is not too sweet and very light!!

      +

      +
      +

      +
      + Reply +
        +
      • + Adam + June 28, 2024, 8:48 pm +
        +

        Yay! We are thrilled that you loved it 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Donna + June 28, 2024, 7:43 pm +
      +

      This looks wonderful. Hope to make it soon! If you’re in a hurry you can get the giant flakey canned biscuits, dip them in melted butter and the coat in sugar. Bake as directed, slice in half and fill with the strawberries.

      +
      + Reply +
    • +
    • + Mila + June 28, 2024, 6:28 pm +
      +

      The Perfect Strawberry Shortcake looks very yummy and easy to follow. We will certainly try it this strawberry season. Thank you for sharing your recipe.

      +

      +
      +

      +
      + Reply +
        +
      • + Adam + June 28, 2024, 7:24 pm +
        +

        Thank you so much Mila. You are going to those this recipe 🙂

        +
        + Reply +
      • +
      +
    • +
    +
    +
    +

    Leave a Reply

    +

    Leave a Review

    Your email address will not be published. Required fields are marked *

    + +

    +
    +

    Rate this recipe!

    + + + + + + + + + + + + + + + + + + + + + + +   +

    + +

    +

    All comments are moderated before appearing on the site. Thank you so much for waiting. First time commenting? Please review our comment guidelines. You must be at least 16 years old to post a comment. All comments are governed by our Privacy Policy & Terms.

    +
    + Previous Post: + Next Post: +
    +
    + +
    + +
    + + + + + + + + + + + + + \ No newline at end of file From 0375ca4f7db9fd58ad13d0be33db3d3d9d654fa8 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sat, 7 Dec 2024 15:41:19 -0500 Subject: [PATCH 26/94] Idea: add handling to schema ingredients to handle double parentheses (#1407) --- recipe_scrapers/_schemaorg.py | 4 +- .../aflavorjournal.com/aflavorjournal_2.json | 4 +- .../amazingribs.com/amazingribs_2.json | 4 +- .../biancazapatka.com/biancazapatka_2.json | 4 +- .../bitsofcarey.com/bitsofcarey_1.json | 4 +- .../bitsofcarey.com/bitsofcarey_2.json | 8 +- .../bluejeanchef.com/bluejeanchef_1.json | 2 +- .../bowlofdelicious.com/bowlofdelicious.json | 6 +- .../brokenovenbaking_1.json | 2 +- .../cafedelites.com/cafedelites_1.json | 12 +-- .../cafedelites.com/cafedelites_2.json | 6 +- .../carlsbadcravings_2.json | 4 +- .../castironketo.net/castironketo.json | 2 +- .../celebratingsweets_1.json | 2 +- tests/test_data/chefsavvy.com/chefsavvy.json | 2 +- .../dinnerthendessert_2.json | 4 +- .../domesticate-me.com/domesticateme_1.json | 4 +- tests/test_data/elavegan.com/elavegan_1.json | 6 +- tests/test_data/elavegan.com/elavegan_2.json | 12 +-- .../fifteenspatulas.com/fifteenspatulas.json | 2 +- .../glutenfreeonashoestring_1.json | 2 +- .../halfbakedharvest.json | 1 - .../halfbakedharvest_groups.json | 4 +- .../hungryhappens.net/hungryhappens_2.json | 8 +- .../indianhealthyrecipes.json | 8 +- .../izzycooking.com/izzycooking.json | 4 +- .../jimcooksfoodgood.json | 4 +- .../kitchendreaming_1.json | 2 +- .../kitchendreaming_2.json | 4 +- .../kitchensanctuary.json | 8 +- .../leitesculinaria_1.json | 2 +- .../leitesculinaria_2.json | 16 ++-- .../lovingitvegan.com/lovingitvegan.json | 8 +- tests/test_data/madsvin.com/madsvin.json | 4 +- .../minimalistbaker.com/minimalistbaker.json | 2 +- .../modernhoney.com/modernhoney_1.json | 8 +- .../notenoughcinnamon_1.json | 2 +- .../notenoughcinnamon_2.json | 4 +- .../peelwithzeal.com/peelwithzeal_1.json | 2 +- .../rainbowplantlife.json | 8 +- .../rainbowplantlife_groups.json | 16 ++-- .../recipegirl.com/recipegirl_1.json | 4 +- .../recipetineats.com/recipetineats_1.json | 4 +- .../recipetineats.com/recipetineats_2.json | 12 +-- .../redhousespice.com/redhousespice_2.json | 2 +- .../saltpepperskillet_2.json | 8 +- .../simplyquinoa.com/simplyquinoa_1.json | 4 +- .../simplyquinoa.com/simplyquinoa_2.json | 8 +- .../skinnytaste.com/skinnytaste_1.json | 2 +- .../sweetpeasandsaffron_1.json | 12 +-- .../sweetpeasandsaffron_2.json | 80 +++++++++---------- .../thecookierookie_1.json | 2 +- .../thefoodietakesflight_2.json | 16 ++-- .../theloopywhisk.com/theloopywhisk_1.json | 4 +- .../theloopywhisk.com/theloopywhisk_2.json | 12 +-- .../themagicalslowcooker_1.json | 2 +- .../thevintagemixer_2.json | 4 +- .../thewoksoflife.com/thewoksoflife_1.json | 10 +-- .../thewoksoflife.com/thewoksoflife_2.json | 28 +++---- .../vanillaandbean.com/vanillaandbean_1.json | 8 +- .../vegrecipesofindia_2.json | 4 +- .../wearenotmartha.com/wearenotmartha_2.json | 8 +- .../wellplated.com/wellplated_1.json | 8 +- .../wellplated.com/wellplated_2.json | 16 ++-- tests/test_data/whole30.com/whole30.json | 4 +- 65 files changed, 237 insertions(+), 236 deletions(-) diff --git a/recipe_scrapers/_schemaorg.py b/recipe_scrapers/_schemaorg.py index c1d6a4b70..03b58886f 100644 --- a/recipe_scrapers/_schemaorg.py +++ b/recipe_scrapers/_schemaorg.py @@ -222,7 +222,9 @@ def ingredients(self): ingredients = [ingredients] return [ - normalize_string(ingredient) for ingredient in ingredients if ingredient + normalize_string(ingredient).replace("((", "(").replace("))", ")") + for ingredient in ingredients + if ingredient ] def nutrients(self): diff --git a/tests/test_data/aflavorjournal.com/aflavorjournal_2.json b/tests/test_data/aflavorjournal.com/aflavorjournal_2.json index e4375e33c..3a891ee25 100644 --- a/tests/test_data/aflavorjournal.com/aflavorjournal_2.json +++ b/tests/test_data/aflavorjournal.com/aflavorjournal_2.json @@ -26,7 +26,7 @@ "1 tsp. Worcestershire Sauce", "2 tsp. fresh Lemon Juice", "1 tsp. White Miso Paste", - "1/4 cup finely grated Parmesan (use the good stuff :))", + "1/4 cup finely grated Parmesan (use the good stuff :)", "1 tsp. Dijon Mustard", "1/4 tsp. Salt (plus more to taste)", "1/4 tsp. freshly cracked Black Pepper", @@ -65,7 +65,7 @@ "1 tsp. Worcestershire Sauce", "2 tsp. fresh Lemon Juice", "1 tsp. White Miso Paste", - "1/4 cup finely grated Parmesan (use the good stuff :))", + "1/4 cup finely grated Parmesan (use the good stuff :)", "1 tsp. Dijon Mustard", "1/4 tsp. Salt (plus more to taste)", "1/4 tsp. freshly cracked Black Pepper", diff --git a/tests/test_data/amazingribs.com/amazingribs_2.json b/tests/test_data/amazingribs.com/amazingribs_2.json index 4245797da..682f2cc77 100644 --- a/tests/test_data/amazingribs.com/amazingribs_2.json +++ b/tests/test_data/amazingribs.com/amazingribs_2.json @@ -7,7 +7,7 @@ "title": "Brisket Burnt Ends Recipe", "ingredients": [ "6 pound brisket point", - "3 teaspoons Morton Coarse Kosher Salt ((approximately ½ teaspoon per pound))", + "3 teaspoons Morton Coarse Kosher Salt (approximately ½ teaspoon per pound)", "¼ cup Big Bad Beef Rub", "¼ cup Kansas City style barbecue sauce", "¼ tablespoon brown sugar", @@ -17,7 +17,7 @@ { "ingredients": [ "6 pound brisket point", - "3 teaspoons Morton Coarse Kosher Salt ((approximately ½ teaspoon per pound))", + "3 teaspoons Morton Coarse Kosher Salt (approximately ½ teaspoon per pound)", "¼ cup Big Bad Beef Rub", "¼ cup Kansas City style barbecue sauce", "¼ tablespoon brown sugar" diff --git a/tests/test_data/biancazapatka.com/biancazapatka_2.json b/tests/test_data/biancazapatka.com/biancazapatka_2.json index aa6d14ee4..63a1f18da 100644 --- a/tests/test_data/biancazapatka.com/biancazapatka_2.json +++ b/tests/test_data/biancazapatka.com/biancazapatka_2.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "The Best Vegan Blueberry Cake", "ingredients": [ - "1 cup soy milk (or other plant milk, *see notes))", + "1 cup soy milk (or other plant milk, *see notes)", "juice of 1 lemon (approx. ¼ cup lemon juice)", "½ cup vegetable oil (e.g. canola or sunflower or butter-flavored Alba oil)", "1 tsp vanilla extract (or ground bourbon vanilla or the pulp of a vanilla bean)", @@ -30,7 +30,7 @@ "ingredient_groups": [ { "ingredients": [ - "1 cup soy milk (or other plant milk, *see notes))", + "1 cup soy milk (or other plant milk, *see notes)", "juice of 1 lemon (approx. ¼ cup lemon juice)", "½ cup vegetable oil (e.g. canola or sunflower or butter-flavored Alba oil)", "1 tsp vanilla extract (or ground bourbon vanilla or the pulp of a vanilla bean)", diff --git a/tests/test_data/bitsofcarey.com/bitsofcarey_1.json b/tests/test_data/bitsofcarey.com/bitsofcarey_1.json index 1f034bc3f..ebbc0d3ae 100644 --- a/tests/test_data/bitsofcarey.com/bitsofcarey_1.json +++ b/tests/test_data/bitsofcarey.com/bitsofcarey_1.json @@ -6,11 +6,11 @@ "language": "en-ZA", "title": "Asian Style Sweetcorn Fritters", "ingredients": [ - "2 cups (260 g) sweetcorn (canned (drained) or frozen (thawed))", + "2 cups (260 g) sweetcorn (canned (drained) or frozen (thawed)", "2 spring onions (finely chopped)", "½ cup fresh coriander (chopped)", "¼ cup mint leaves (chopped)", - "1 ½ tsp sambal oelek ((Garlic chilli paste))", + "1 ½ tsp sambal oelek (Garlic chilli paste)", "1 lime (zest of)", "salt and pepper (to taste)", "½ cup (65 g) all purpose flour", diff --git a/tests/test_data/bitsofcarey.com/bitsofcarey_2.json b/tests/test_data/bitsofcarey.com/bitsofcarey_2.json index 766900b7d..4fed8d6c7 100644 --- a/tests/test_data/bitsofcarey.com/bitsofcarey_2.json +++ b/tests/test_data/bitsofcarey.com/bitsofcarey_2.json @@ -11,9 +11,9 @@ "½ tsp coarse black pepper (ground)", "1 egg (large)", "45 ml milk", - "¾ c (180 ml) yellow cornmeal ((fine polenta))", + "¾ c (180 ml) yellow cornmeal (fine polenta)", "¾ c (180 ml) parmesan (finely grated)", - "½ c (125 ml) almond meal ((finely ground almonds))", + "½ c (125 ml) almond meal (finely ground almonds)", "½ tsp (2.5 ml) coarse salt (ground)", "½ tsp (2.5 ml) coarse black pepper (ground)", "1 tsp (5 ml) dried rosemary", @@ -34,9 +34,9 @@ }, { "ingredients": [ - "¾ c (180 ml) yellow cornmeal ((fine polenta))", + "¾ c (180 ml) yellow cornmeal (fine polenta)", "¾ c (180 ml) parmesan (finely grated)", - "½ c (125 ml) almond meal ((finely ground almonds))", + "½ c (125 ml) almond meal (finely ground almonds)", "½ tsp (2.5 ml) coarse salt (ground)", "½ tsp (2.5 ml) coarse black pepper (ground)", "1 tsp (5 ml) dried rosemary", diff --git a/tests/test_data/bluejeanchef.com/bluejeanchef_1.json b/tests/test_data/bluejeanchef.com/bluejeanchef_1.json index b45ac062f..fbd4a6e00 100644 --- a/tests/test_data/bluejeanchef.com/bluejeanchef_1.json +++ b/tests/test_data/bluejeanchef.com/bluejeanchef_1.json @@ -7,7 +7,7 @@ "title": "Chicken Tortilla Soup", "ingredients": [ "2 tablespoons olive oil", - "1 onion (finely diced (about 1 cup))", + "1 onion (finely diced (about 1 cup)", "2 cloves garlic (minced)", "1 Jalapeño pepper (minced or sliced into rings)", "1 red bell pepper (chopped)", diff --git a/tests/test_data/bowlofdelicious.com/bowlofdelicious.json b/tests/test_data/bowlofdelicious.com/bowlofdelicious.json index 52924f5b4..a68796ae1 100644 --- a/tests/test_data/bowlofdelicious.com/bowlofdelicious.json +++ b/tests/test_data/bowlofdelicious.com/bowlofdelicious.json @@ -6,15 +6,15 @@ "language": "en-US", "title": "Six-Minute Seared Ahi Tuna Steaks", "ingredients": [ - "2 ahi tuna (yellowfin tuna) steaks ((about 4 oz. each, 1\" thick - see notes for thinner or thicker))", + "2 ahi tuna (yellowfin tuna) steaks (about 4 oz. each, 1\" thick - see notes for thinner or thicker)", "2 tablespoons soy sauce", "1 tablespoon toasted sesame oil (see notes)", "1 tablespoon honey (see notes)", "1/2 teaspoon kosher salt", "1/4 teaspoon black pepper (to taste)", - "1/4 teaspoon cayenne pepper ((optional))", + "1/4 teaspoon cayenne pepper (optional)", "1 tablespoon canola oil (or olive oil)", - "green onions, toasted sesame seeds, and lime wedges (for serving (optional))" + "green onions, toasted sesame seeds, and lime wedges (for serving (optional)" ], "instructions_list": [ "Pat the ahi tuna steaks dry with a paper towel. Place on a plate or inside a plastic bag.", diff --git a/tests/test_data/brokenovenbaking.com/brokenovenbaking_1.json b/tests/test_data/brokenovenbaking.com/brokenovenbaking_1.json index a68de131a..6ff2acc93 100644 --- a/tests/test_data/brokenovenbaking.com/brokenovenbaking_1.json +++ b/tests/test_data/brokenovenbaking.com/brokenovenbaking_1.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Easy Homemade Strawberry Muffins", "ingredients": [ - "2¼ cups all-purpose flour (divided (weighed in grams for best results))", + "2¼ cups all-purpose flour (divided (weighed in grams for best results)", "2 teaspoons baking powder", "½ teaspoon salt", "½ cup vegetable oil (or other neutral oil)", diff --git a/tests/test_data/cafedelites.com/cafedelites_1.json b/tests/test_data/cafedelites.com/cafedelites_1.json index cc0f8c4e4..51725b5c1 100644 --- a/tests/test_data/cafedelites.com/cafedelites_1.json +++ b/tests/test_data/cafedelites.com/cafedelites_1.json @@ -8,13 +8,13 @@ "ingredients": [ "1/2 cup sugar", "1/2 teaspoon ground cinnamon", - "4 oz. butter, ((125g or 1/2 cup))", - "1 cup + 2 tablespoons water ((280ml))", + "4 oz. butter, (125g or 1/2 cup)", + "1 cup + 2 tablespoons water (280ml)", "2 tablespoons white granulated sugar", "1 teaspoon pure vanilla extract", "3/4 teaspoon ground cinnamon", "1/2 teaspoon salt", - "1 1/4 cups all-purpose or plain flour, ((6.3oz | 180g))", + "1 1/4 cups all-purpose or plain flour, (6.3oz | 180g)", "2 large eggs, (at room temperature)" ], "ingredient_groups": [ @@ -27,13 +27,13 @@ }, { "ingredients": [ - "4 oz. butter, ((125g or 1/2 cup))", - "1 cup + 2 tablespoons water ((280ml))", + "4 oz. butter, (125g or 1/2 cup)", + "1 cup + 2 tablespoons water (280ml)", "2 tablespoons white granulated sugar", "1 teaspoon pure vanilla extract", "3/4 teaspoon ground cinnamon", "1/2 teaspoon salt", - "1 1/4 cups all-purpose or plain flour, ((6.3oz | 180g))", + "1 1/4 cups all-purpose or plain flour, (6.3oz | 180g)", "2 large eggs, (at room temperature)" ], "purpose": "CHURROS" diff --git a/tests/test_data/cafedelites.com/cafedelites_2.json b/tests/test_data/cafedelites.com/cafedelites_2.json index 9fd0b57fb..134e5d197 100644 --- a/tests/test_data/cafedelites.com/cafedelites_2.json +++ b/tests/test_data/cafedelites.com/cafedelites_2.json @@ -6,12 +6,12 @@ "language": "en-US", "title": "Easy Creamy Mashed Potatoes", "ingredients": [ - "2 pounds (1kg) potatoes, ((Russet, Yukon Gold, Dutch Creams, Creme Gold, Creme Royale))", + "2 pounds (1kg) potatoes, (Russet, Yukon Gold, Dutch Creams, Creme Gold, Creme Royale)", "1 teaspoon salt", "1/2 cup hot milk, (or more)", - "1/3 cup unsalted butter, (softened (close to room temp is best))", + "1/3 cup unsalted butter, (softened (close to room temp is best)", "6-8 cloves fresh garlic (finely chopped)", - "1/4 cup sour cream ((reduced fat))", + "1/4 cup sour cream (reduced fat)", "1/4 cup fresh shredded parmesan cheese, (optional)", "Salt and Pepper, (to taste)", "1 tablespoon fresh chopped parsley to garnish, (optional to garnish)" diff --git a/tests/test_data/carlsbadcravings.com/carlsbadcravings_2.json b/tests/test_data/carlsbadcravings.com/carlsbadcravings_2.json index 431c2fdf6..0bce8b886 100644 --- a/tests/test_data/carlsbadcravings.com/carlsbadcravings_2.json +++ b/tests/test_data/carlsbadcravings.com/carlsbadcravings_2.json @@ -13,7 +13,7 @@ "2 tablespoons honey", "1/4 tsp EACH ground ginger, ground cinnamon, salt, dried thyme, dried rosemary", "1/8 teaspoon pepper", - "1/2 cup Cranberry Pistachio Coating mixture ((in directions))", + "1/2 cup Cranberry Pistachio Coating mixture (in directions)", "honey" ], "ingredient_groups": [ @@ -31,7 +31,7 @@ "2 tablespoons honey", "1/4 tsp EACH ground ginger, ground cinnamon, salt, dried thyme, dried rosemary", "1/8 teaspoon pepper", - "1/2 cup Cranberry Pistachio Coating mixture ((in directions))" + "1/2 cup Cranberry Pistachio Coating mixture (in directions)" ], "purpose": "Cheese Log" }, diff --git a/tests/test_data/castironketo.net/castironketo.json b/tests/test_data/castironketo.net/castironketo.json index b5a4c28b8..c7cbbe518 100644 --- a/tests/test_data/castironketo.net/castironketo.json +++ b/tests/test_data/castironketo.net/castironketo.json @@ -14,7 +14,7 @@ "8 ounces cream cheese (softened)", "½ cup heavy cream", "¼ cup chicken broth", - "5 jalapeno peppers (halved (ribs removed if you like less spice))", + "5 jalapeno peppers (halved (ribs removed if you like less spice)", "1 cup shredded sharp cheddar cheese", "6 slices bacon (cooked and crumbled)" ], diff --git a/tests/test_data/celebratingsweets.com/celebratingsweets_1.json b/tests/test_data/celebratingsweets.com/celebratingsweets_1.json index 8b9870690..83d1e8159 100644 --- a/tests/test_data/celebratingsweets.com/celebratingsweets_1.json +++ b/tests/test_data/celebratingsweets.com/celebratingsweets_1.json @@ -15,7 +15,7 @@ "6 ounces raspberries", "6 ounces blackberries", "6 ounces blueberries", - "1/2 cup raspberry or strawberry jam (heated just enough to make it pourable (not hot))" + "1/2 cup raspberry or strawberry jam (heated just enough to make it pourable (not hot)" ], "instructions_list": [ "With a hand mixer or stand mixer fitted with a whisk attachment, beat heavy cream*, powdered sugar, vanilla and almond extract until soft peaks form, this will take several minutes. Keep the whipped cream refrigerated while you assemble the other components of the recipe.", diff --git a/tests/test_data/chefsavvy.com/chefsavvy.json b/tests/test_data/chefsavvy.com/chefsavvy.json index 68c370677..e88b7d5d6 100644 --- a/tests/test_data/chefsavvy.com/chefsavvy.json +++ b/tests/test_data/chefsavvy.com/chefsavvy.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Slow Cooker Broccoli Beef", "ingredients": [ - "2 pounds chuck steak (sliced thin (about 1-inch thick))", + "2 pounds chuck steak (sliced thin (about 1-inch thick)", "1 cup low sodium beef broth", "1/2 cup low sodium soy sauce", "4 garlic cloves (minced)", diff --git a/tests/test_data/dinnerthendessert.com/dinnerthendessert_2.json b/tests/test_data/dinnerthendessert.com/dinnerthendessert_2.json index da7704df3..ba4357595 100644 --- a/tests/test_data/dinnerthendessert.com/dinnerthendessert_2.json +++ b/tests/test_data/dinnerthendessert.com/dinnerthendessert_2.json @@ -10,7 +10,7 @@ "1 yellow onion (, chopped)", "4 cups chicken broth", "3 cups sweet corn (, frozen or fresh)", - "2 russet potatoes (, peeled and diced (Yukon okay too))", + "2 russet potatoes (, peeled and diced (Yukon okay too)", "1 cup heavy cream", "1 teaspoon hot sauce", "1/2 teaspoon chili powder", @@ -30,7 +30,7 @@ "1 yellow onion (, chopped)", "4 cups chicken broth", "3 cups sweet corn (, frozen or fresh)", - "2 russet potatoes (, peeled and diced (Yukon okay too))", + "2 russet potatoes (, peeled and diced (Yukon okay too)", "1 cup heavy cream", "1 teaspoon hot sauce", "1/2 teaspoon chili powder", diff --git a/tests/test_data/domesticate-me.com/domesticateme_1.json b/tests/test_data/domesticate-me.com/domesticateme_1.json index b58fdd7bd..a321bbc2d 100644 --- a/tests/test_data/domesticate-me.com/domesticateme_1.json +++ b/tests/test_data/domesticate-me.com/domesticateme_1.json @@ -18,10 +18,10 @@ "¾ cup grated sharp cheddar cheese", "¾ cup grated provolone cheese (Gouda is also great!)", "¼ cup whole-wheat panko breadcrumbs", - "3 scallions (thinly sliced (optional))", + "3 scallions (thinly sliced (optional)", "For the Yogurt Ranch:", "1½ cups nonfat plain Greek yogurt", - "1 teaspoon dried parsley (crushed (Just use your fingers to crush the flakes.))", + "1 teaspoon dried parsley (crushed (Just use your fingers to crush the flakes.)", "½ teaspoon dried dill weed", "½ teaspoon kosher salt", "¼ teaspoon garlic powder", diff --git a/tests/test_data/elavegan.com/elavegan_1.json b/tests/test_data/elavegan.com/elavegan_1.json index aaf00b359..ceb8de8e2 100644 --- a/tests/test_data/elavegan.com/elavegan_1.json +++ b/tests/test_data/elavegan.com/elavegan_1.json @@ -7,21 +7,21 @@ "title": "Red Lentil Dahl", "ingredients": [ "1 1/2 cups dry red lentils", - "1 large carrot (finely diced (see notes))", + "1 large carrot (finely diced (see notes)", "1 small bell pepper", "1 large onion (chopped)", "4 cloves of garlic (minced)", "1 heaped tbsp fresh ginger (minced)", "1/2 tbsp vegetable oil", "3 cups vegetable broth (or water)", - "1 cup canned coconut milk ((see notes))", + "1 cup canned coconut milk (see notes)", "1 1/2 tsp ground cumin", "1 tbsp curry powder", "1/2 tbsp sweetener of choice", "1 tsp ground turmeric", "1 tsp paprika", "Sea salt and black pepper (to taste)", - "1/3 tsp red pepper flakes ((optional))" + "1/3 tsp red pepper flakes (optional)" ], "instructions_list": [ "You can watch the short video for visual instructions.Rinse lentils under running water. Chop the onion, garlic, ginger, bell pepper, and carrot.", diff --git a/tests/test_data/elavegan.com/elavegan_2.json b/tests/test_data/elavegan.com/elavegan_2.json index 5a3a3270b..65932e357 100644 --- a/tests/test_data/elavegan.com/elavegan_2.json +++ b/tests/test_data/elavegan.com/elavegan_2.json @@ -6,8 +6,8 @@ "language": "en-US", "title": "Vegan Coffee Cake", "ingredients": [ - "1 cup oat flour ((gluten-free if needed))", - "1/2 cup rice flour ((see notes))", + "1 cup oat flour (gluten-free if needed)", + "1/2 cup rice flour (see notes)", "2 Tbsp cornstarch (or potato starch)", "1/3 cup Erythritol (or sugar)", "1 1/2 tsp baking powder", @@ -15,7 +15,7 @@ "1/2 tsp sea salt", "3/4 cup almond milk (or any other dairy-free milk)", "2/3 cup applesauce (unsweetened)", - "2 Tbsp oil ((see notes))", + "2 Tbsp oil (see notes)", "1 Tbsp apple cider vinegar", "1 tsp vanilla extract", "1/2 cup rice flour (or regular flour, if you're not gluten-free)", @@ -29,8 +29,8 @@ "ingredient_groups": [ { "ingredients": [ - "1 cup oat flour ((gluten-free if needed))", - "1/2 cup rice flour ((see notes))", + "1 cup oat flour (gluten-free if needed)", + "1/2 cup rice flour (see notes)", "2 Tbsp cornstarch (or potato starch)", "1/3 cup Erythritol (or sugar)", "1 1/2 tsp baking powder", @@ -43,7 +43,7 @@ "ingredients": [ "3/4 cup almond milk (or any other dairy-free milk)", "2/3 cup applesauce (unsweetened)", - "2 Tbsp oil ((see notes))", + "2 Tbsp oil (see notes)", "1 Tbsp apple cider vinegar", "1 tsp vanilla extract" ], diff --git a/tests/test_data/fifteenspatulas.com/fifteenspatulas.json b/tests/test_data/fifteenspatulas.com/fifteenspatulas.json index 851afc54c..ebceb89af 100644 --- a/tests/test_data/fifteenspatulas.com/fifteenspatulas.json +++ b/tests/test_data/fifteenspatulas.com/fifteenspatulas.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Creme Brulee", "ingredients": [ - "zest of 4 oranges* ((about 2 tsp))", + "zest of 4 oranges* (about 2 tsp)", "3 cups heavy cream", "5 large egg yolks", "1/2 cup sugar +1 tsp for each crème brûlée", diff --git a/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json b/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json index 216f988c9..c933ea7c6 100644 --- a/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json +++ b/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json @@ -12,7 +12,7 @@ "1/2 teaspoon kosher salt", "5 1/4 ounces warm water", "1 tablespoon extra virgin olive oil (plus more for handling and brushing)", - "Your favorite pizza toppings ((sauce, shredded or sliced mozzarella cheese))" + "Your favorite pizza toppings (sauce, shredded or sliced mozzarella cheese)" ], "instructions": "To make the pizza dough.\nIn the bowl of your stand mixer fitted with the paddle attachment, place the flour, yeast, and sugar. Whisk to combine with a separate, handheld whisk. Add the salt, and whisk again to combine well.\nAdd the water and olive oil, and mix very slowly until the flour is absorbed into the liquid. The mixture will be lumpy\nRaise the mixer to medium-high speed in your stand mixer until the dough becomes sticky and smooth (about 3 minutes).\nOil a medium-size bowl, and scrape the pizza dough into the bowl.\nUsing very well-oiled hands, loosely shape the dough into a round.\nCover the bowl tightly with plastic and place in a draft-free location until nearly doubled in size. That will take longer in cool, dry environments and less time in warm, moist places.\nTo bake the pizza.\nWhen you’re ready to make the pizza, place a pizza stone or overturned rimmed baking sheet in the oven and preheat it to 450°F.\nPlace a 14-inch round nonstick pizza baking pan or a large piece of parchment paper in front of you on a flat surface\nThe dough will be super soft, and should only be handled once you’ve coated your hands in olive oil. Turn the dough out onto the center of the pan or paper.\nWorking from the center of the dough out to the edges, begin to press it into a round about 14-inches in diameter.\nCreate a smooth, slightly raised edge around the perimeter of the dough by pressing the edges with one hand toward the palm of your other.\nBrush the shaped dough with more oil, concentrating it on the edges.\nTransfer the shaped and topped dough, still on the pizza baking sheet or parchment paper, to a pizza peel or other flat surface like a cutting board, and transfer it to the hot oven.\nBake for 5 to 6 minutes, or until the crust seems set all the way to the center and the edges have expanded in size.\nRemove the pan from the oven, top the dough with sauce, cheese, and any other toppings you like best, and return the pizza on the pan or paper to the oven.\nBake until the has begun to crisp on the underside, is lightly brown on the edges, and the cheese is brown and bubbling (about 5 minutes).\nRemove from the oven, allow to set for just a few minutes, then slice and serve hot.", "instructions_list": [ diff --git a/tests/test_data/halfbakedharvest.com/halfbakedharvest.json b/tests/test_data/halfbakedharvest.com/halfbakedharvest.json index 0f6bf6dc5..898495bc3 100644 --- a/tests/test_data/halfbakedharvest.com/halfbakedharvest.json +++ b/tests/test_data/halfbakedharvest.com/halfbakedharvest.json @@ -26,7 +26,6 @@ "instructions_list": [ "1. Bring a large pot of salted water to a boil. Boil the pasta to al dente, according to package directions. Drain and add the pasta right back to the pot. 2. Meanwhile, cook the prosciutto in a large skillet set over medium heat until crispy, about 2 minutes per side. Remove the prosciutto from the skillet. 3. To the skillet, add the butter. Allow the butter to brown until it smells toasted and is a deep golden color, about 3-4 minutes. Stir in the olive oil, shallot, jalapeño, and thyme. Cook 1-2 minutes, then remove from the heat. Pour the browned butter over the hot orzo. Toss to combine. 4. To the orzo, add the basil, chives, lemon juice, vinegar, and honey. Season with salt and pepper and toss. Stir in the corn, tomatoes, and feta. Top the pasta with crispy prosciutto and avocado. Serve warm or at room temp." ], - "category": null, "yields": "6 servings", "description": "When you’re in need of a quick and simple summer meal that's also bright and colorful, make this orzo!", "total_time": 25, diff --git a/tests/test_data/halfbakedharvest.com/halfbakedharvest_groups.json b/tests/test_data/halfbakedharvest.com/halfbakedharvest_groups.json index 18e60bc6f..cd22054cb 100644 --- a/tests/test_data/halfbakedharvest.com/halfbakedharvest_groups.json +++ b/tests/test_data/halfbakedharvest.com/halfbakedharvest_groups.json @@ -15,7 +15,7 @@ "3/4 cup crumbled cotija or feta cheese", "1 pound short cut pasta", "1 head romaine lettuce, shredded", - "2 cups grilled or roasted corn ((3-4 raw))", + "2 cups grilled or roasted corn (3-4 raw)", "1/2 cup fresh basil leaves, torn", "1/2 cup fresh cilantro, chopped", "1/2 cup spicy cheddar cheese, cubed", @@ -44,7 +44,7 @@ "ingredients": [ "1 pound short cut pasta", "1 head romaine lettuce, shredded", - "2 cups grilled or roasted corn ((3-4 raw))", + "2 cups grilled or roasted corn (3-4 raw)", "1/2 cup fresh basil leaves, torn", "1/2 cup fresh cilantro, chopped", "1/2 cup spicy cheddar cheese, cubed", diff --git a/tests/test_data/hungryhappens.net/hungryhappens_2.json b/tests/test_data/hungryhappens.net/hungryhappens_2.json index e9a036560..abc399c0a 100644 --- a/tests/test_data/hungryhappens.net/hungryhappens_2.json +++ b/tests/test_data/hungryhappens.net/hungryhappens_2.json @@ -9,14 +9,14 @@ "1/2 head green cabbage, (fine shredded)", "1/2 large cucumber", "3 tbs dill, (chopped)", - "1/4 cup champagne vinegar ((or white wine vinegar))", + "1/4 cup champagne vinegar (or white wine vinegar)", "salt and pepper (to taste)", "3 avocadoes", "2 tsp Sriracha sauce", "1 lime, (juiced)", "salt and pepper (to taste)", "2 lbs salmon, (skin removed)", - "2 tsp chipotle powder ((or chili powder))", + "2 tsp chipotle powder (or chili powder)", "1 tsp onion powder", "1 tsp dried oregano", "1 lime, (zested + juiced)", @@ -28,7 +28,7 @@ "1/2 head green cabbage, (fine shredded)", "1/2 large cucumber", "3 tbs dill, (chopped)", - "1/4 cup champagne vinegar ((or white wine vinegar))", + "1/4 cup champagne vinegar (or white wine vinegar)", "salt and pepper (to taste)" ], "purpose": "Slaw:" @@ -45,7 +45,7 @@ { "ingredients": [ "2 lbs salmon, (skin removed)", - "2 tsp chipotle powder ((or chili powder))", + "2 tsp chipotle powder (or chili powder)", "1 tsp onion powder", "1 tsp dried oregano", "1 lime, (zested + juiced)", diff --git a/tests/test_data/indianhealthyrecipes.com/indianhealthyrecipes.json b/tests/test_data/indianhealthyrecipes.com/indianhealthyrecipes.json index 28abb7437..6dc36fb02 100644 --- a/tests/test_data/indianhealthyrecipes.com/indianhealthyrecipes.json +++ b/tests/test_data/indianhealthyrecipes.com/indianhealthyrecipes.json @@ -6,11 +6,11 @@ "language": "en-US", "title": "Banana Cake Recipe", "ingredients": [ - "2 cups (240 grams) all-purpose flour (or wheat flour (refer notes))", + "2 cups (240 grams) all-purpose flour (or wheat flour (refer notes)", "2 ½ teaspoons (12.5 g) baking powder", - "½ teaspoon salt ((or ⅓ teaspoon table salt))", - "1 cup (200 grams) fine sugar ((prefer organic))", - "100 grams (3.53 oz) unsalted butter ((soft & cold) )", + "½ teaspoon salt (or ⅓ teaspoon table salt)", + "1 cup (200 grams) fine sugar (prefer organic)", + "100 grams (3.53 oz) unsalted butter (soft & cold) )", "2 eggs", "2 teaspoons (10 ml) vanilla extract", "160 ml milk", diff --git a/tests/test_data/izzycooking.com/izzycooking.json b/tests/test_data/izzycooking.com/izzycooking.json index ff2da46cb..d10dd0e6c 100644 --- a/tests/test_data/izzycooking.com/izzycooking.json +++ b/tests/test_data/izzycooking.com/izzycooking.json @@ -6,12 +6,12 @@ "language": "en-CA", "title": "Oreo Cheesecake Bites Recipe (+Video)", "ingredients": [ - "22 Oreo cookies ((Chop 6 of them into small pieces))", + "22 Oreo cookies (Chop 6 of them into small pieces)", "16 ounces cream cheese (softened)", "1/2 cup granulated sugar", "1/2 tsp vanilla extract", "2 eggs", - "1/2 cup sour cream ((or plain Greek yogurt))" + "1/2 cup sour cream (or plain Greek yogurt)" ], "instructions_list": [ "Preheat oven to 325°F. (Make sure your oven temperature is accurate, as a higher temp can cause the cheesecake to crack.)", diff --git a/tests/test_data/jimcooksfoodgood.com/jimcooksfoodgood.json b/tests/test_data/jimcooksfoodgood.com/jimcooksfoodgood.json index cf79f3df5..100a43739 100644 --- a/tests/test_data/jimcooksfoodgood.com/jimcooksfoodgood.json +++ b/tests/test_data/jimcooksfoodgood.com/jimcooksfoodgood.json @@ -6,12 +6,12 @@ "language": "en-US", "title": "German Potato Salad", "ingredients": [ - "3 Pounds Yukon Gold Potatoes ((Or a small white potato))", + "3 Pounds Yukon Gold Potatoes (Or a small white potato)", "2/3 Cup Sherry or Apple Cider Vinegar", "1/2 Cup dijon mustard", "1/2 Cup Bread and Butter Pickles", "1/4 Cup olive oil", - "4 Tablespoons capers ((Plus a splash of brine))", + "4 Tablespoons capers (Plus a splash of brine)", "2 Teaspoons salt", "1/2 Cup Fresh Parsley", "1/4 Cup scallions", diff --git a/tests/test_data/kitchendreaming.com/kitchendreaming_1.json b/tests/test_data/kitchendreaming.com/kitchendreaming_1.json index c98e47b7b..e9c80f17f 100644 --- a/tests/test_data/kitchendreaming.com/kitchendreaming_1.json +++ b/tests/test_data/kitchendreaming.com/kitchendreaming_1.json @@ -15,7 +15,7 @@ "1 teaspoon garlic powder", "4 green onions (, sliced thin)", "3/4 cup hot sauce ([See Note 3])", - "1/2 stick ((4 tbsp) butter)", + "1/2 stick (4 tbsp) butter)", "20 celery sticks ([See Note 4])", "20 carrot sticks ([See Note 4])", "1/2 cup chunky blue cheese dressing ( [See Note 5] - plus more for serving)", diff --git a/tests/test_data/kitchendreaming.com/kitchendreaming_2.json b/tests/test_data/kitchendreaming.com/kitchendreaming_2.json index 16eade148..0d115c581 100644 --- a/tests/test_data/kitchendreaming.com/kitchendreaming_2.json +++ b/tests/test_data/kitchendreaming.com/kitchendreaming_2.json @@ -9,7 +9,7 @@ "2 lbs Boneless and skinless chicken, 1-inch cubes (breast or thighs are both fine here)", "1/2 cup plain Greek yogurt", "2 tablespoons minced garlic", - "1 tablespoon minced ginger ((or finely grated))", + "1 tablespoon minced ginger (or finely grated)", "1 teaspoon Indian Kashmiri powder (red chili powder, more or less to taste)", "2 teaspoons garam masala", "1 teaspoon turmeric", @@ -36,7 +36,7 @@ "2 lbs Boneless and skinless chicken, 1-inch cubes (breast or thighs are both fine here)", "1/2 cup plain Greek yogurt", "2 tablespoons minced garlic", - "1 tablespoon minced ginger ((or finely grated))", + "1 tablespoon minced ginger (or finely grated)", "1 teaspoon Indian Kashmiri powder (red chili powder, more or less to taste)", "2 teaspoons garam masala", "1 teaspoon turmeric", diff --git a/tests/test_data/kitchensanctuary.com/kitchensanctuary.json b/tests/test_data/kitchensanctuary.com/kitchensanctuary.json index 31306784b..6f027f88c 100644 --- a/tests/test_data/kitchensanctuary.com/kitchensanctuary.json +++ b/tests/test_data/kitchensanctuary.com/kitchensanctuary.json @@ -20,7 +20,7 @@ "1 tsp paprika", "1 tsp baking powder", "1 tsp chilli flakes", - "vegetable oil for deep frying ((at least 1 litre/four cups))", + "vegetable oil for deep frying (at least 1 litre/four cups)", "2 tbsp gochujang paste", "2 tbsp honey", "4 tbsp brown sugar", @@ -31,7 +31,7 @@ "1 tbsp sesame oil", "3 spring onions (sliced into thin strips)", "1 tsp sesame seeds", - "½ tsp chilli flakes ((red pepper flakes))" + "½ tsp chilli flakes (red pepper flakes)" ], "ingredient_groups": [ { @@ -55,7 +55,7 @@ "1 tsp paprika", "1 tsp baking powder", "1 tsp chilli flakes", - "vegetable oil for deep frying ((at least 1 litre/four cups))" + "vegetable oil for deep frying (at least 1 litre/four cups)" ], "purpose": "Crispy Coating:" }, @@ -71,7 +71,7 @@ "1 tbsp sesame oil", "3 spring onions (sliced into thin strips)", "1 tsp sesame seeds", - "½ tsp chilli flakes ((red pepper flakes))" + "½ tsp chilli flakes (red pepper flakes)" ], "purpose": "Sauce:" } diff --git a/tests/test_data/leitesculinaria.com/leitesculinaria_1.json b/tests/test_data/leitesculinaria.com/leitesculinaria_1.json index 9b44d31f0..f11561805 100644 --- a/tests/test_data/leitesculinaria.com/leitesculinaria_1.json +++ b/tests/test_data/leitesculinaria.com/leitesculinaria_1.json @@ -8,7 +8,7 @@ "ingredients": [ "1 3/4 pounds red jalapeño peppers (stems removed and halved lengthwise)", "3 garlic cloves", - "2 tablespoons garlic powder ((optional))", + "2 tablespoons garlic powder (optional)", "2 tablespoons granulated sugar (plus more as needed)", "1 tablespoon light brown sugar", "1 tablespoon kosher salt (plus more as needed)", diff --git a/tests/test_data/leitesculinaria.com/leitesculinaria_2.json b/tests/test_data/leitesculinaria.com/leitesculinaria_2.json index 13ffbd8aa..36fa55193 100644 --- a/tests/test_data/leitesculinaria.com/leitesculinaria_2.json +++ b/tests/test_data/leitesculinaria.com/leitesculinaria_2.json @@ -14,14 +14,14 @@ "2 bay leaf", "1/2 teaspoon allspice berries", "4 whole cloves", - "Kosher salt (to taste (optional))", + "Kosher salt (to taste (optional)", "3 tablespoons (1 1/2 oz) unsalted butter or lard", "2 cups hearty red table wine", "2 tablespoons store-bought or homemade tomato paste", "1/2 teaspoon ground cinnamon", - "Boiled white potatoes ((optional))", - "Roasted red peppers ((optional))", - "Cooked greens ((optional))" + "Boiled white potatoes (optional)", + "Roasted red peppers (optional)", + "Cooked greens (optional)" ], "ingredient_groups": [ { @@ -34,7 +34,7 @@ "2 bay leaf", "1/2 teaspoon allspice berries", "4 whole cloves", - "Kosher salt (to taste (optional))", + "Kosher salt (to taste (optional)", "3 tablespoons (1 1/2 oz) unsalted butter or lard", "2 cups hearty red table wine", "2 tablespoons store-bought or homemade tomato paste", @@ -44,9 +44,9 @@ }, { "ingredients": [ - "Boiled white potatoes ((optional))", - "Roasted red peppers ((optional))", - "Cooked greens ((optional))" + "Boiled white potatoes (optional)", + "Roasted red peppers (optional)", + "Cooked greens (optional)" ], "purpose": "For serving" } diff --git a/tests/test_data/lovingitvegan.com/lovingitvegan.json b/tests/test_data/lovingitvegan.com/lovingitvegan.json index 476a70b8e..eac85b913 100644 --- a/tests/test_data/lovingitvegan.com/lovingitvegan.json +++ b/tests/test_data/lovingitvegan.com/lovingitvegan.json @@ -6,10 +6,10 @@ "language": "en-US", "title": "Kale Smoothie", "ingredients": [ - "1 1/4 cups Soy Milk ((300ml) or Almond Milk)", - "2 Frozen Bananas ((200g) previously peeled, broken into quarters and frozen for at least 12 hours)", - "1/2 cup Raw Cashews ((75g))", - "2 cups Kale ((56g) Torn up, packed)", + "1 1/4 cups Soy Milk (300ml) or Almond Milk)", + "2 Frozen Bananas (200g) previously peeled, broken into quarters and frozen for at least 12 hours)", + "1/2 cup Raw Cashews (75g)", + "2 cups Kale (56g) Torn up, packed)", "4 Medjool Dates (Pitted)", "1 tsp Minced Ginger", "1/8 tsp Cinnamon", diff --git a/tests/test_data/madsvin.com/madsvin.json b/tests/test_data/madsvin.com/madsvin.json index 4862b3663..6be92492a 100644 --- a/tests/test_data/madsvin.com/madsvin.json +++ b/tests/test_data/madsvin.com/madsvin.json @@ -7,11 +7,11 @@ "title": "Pandekager", "ingredients": [ "125 gram hvedemel", - "3 æg ((mellemstore))", + "3 æg (mellemstore)", "3 dl mælk (jeg brugte sødmælk - anden mælk kan også fint bruges)", "2 spsk sukker (både rørsukker og hvid sukker kan bruges)", "½ stang vanilje (eller 1 spsk vaniljesukker)", - "25 gram smør ((smeltet))", + "25 gram smør (smeltet)", "½ tsk salt", "smør (til stegning - neutral olie kan også bruges)" ], diff --git a/tests/test_data/minimalistbaker.com/minimalistbaker.json b/tests/test_data/minimalistbaker.com/minimalistbaker.json index aaab65d1c..6f166aea7 100644 --- a/tests/test_data/minimalistbaker.com/minimalistbaker.json +++ b/tests/test_data/minimalistbaker.com/minimalistbaker.json @@ -10,7 +10,7 @@ "1 Tbsp lemon juice", "1 Tbsp nutritional yeast, plus more to taste", "1/2 tsp garlic powder", - "1/4-1/2 tsp sea salt ((plus more to taste))", + "1/4-1/2 tsp sea salt (plus more to taste)", "4-6 Tbsp water", "1/4 cup fresh chopped parsley or cilantro" ], diff --git a/tests/test_data/modernhoney.com/modernhoney_1.json b/tests/test_data/modernhoney.com/modernhoney_1.json index 0b51e7978..57e155211 100644 --- a/tests/test_data/modernhoney.com/modernhoney_1.json +++ b/tests/test_data/modernhoney.com/modernhoney_1.json @@ -6,14 +6,14 @@ "language": "en-US", "title": "Honey Garlic Chicken", "ingredients": [ - "1 to 1 1/4 1b. Chicken Breast ((about 4 thinly sliced chicken breasts or 2 large sliced in half))", - "Salt and Pepper ((sprinkle on both sides of chicken)11/)", + "1 to 1 1/4 1b. Chicken Breast (about 4 thinly sliced chicken breasts or 2 large sliced in half)", + "Salt and Pepper (sprinkle on both sides of chicken)11/)", "1/4 cup Flour*", "4 Tablespoons Salted Butter", - "3 Garlic Cloves ((minced))", + "3 Garlic Cloves (minced)", "1 Tablespoon Apple Cider Vinegar", "1 Tablespoon Soy Sauce", - "1/3 cup Honey ((plus more for drizzling, if desired))" + "1/3 cup Honey (plus more for drizzling, if desired)" ], "instructions_list": [ "Generously sprinkle thinly sliced chicken breast with salt and pepper on both sides. Heat a large skillet over medium-high heat. Add 2 Tablespoons of butter to the skillet and let melt.", diff --git a/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_1.json b/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_1.json index 5c171da62..6d0c99e72 100644 --- a/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_1.json +++ b/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_1.json @@ -12,7 +12,7 @@ "1 pinch salt", "1 teaspoon vanilla extract (ideally transparent to keep the mixture white)", "½ teaspoon coconut extract", - "1 1/2 cups pineapple (chopped (see notes))", + "1 1/2 cups pineapple (chopped (see notes)", "2 tablespoons unsweetened coconut flakes" ], "instructions_list": [ diff --git a/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_2.json b/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_2.json index 3e07ec205..79ac9694a 100644 --- a/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_2.json +++ b/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_2.json @@ -9,7 +9,7 @@ "1 lb potato gnocchi (500g fresh shelf-stable, or frozen)", "1 pint cherry or grape tomatoes, cut in half (2 cups)", "1 small red onion (cut into 1-inch chunks)", - "2 bell peppers (cut into 1-inch chunks (I like to use one red and one yellow for color))", + "2 bell peppers (cut into 1-inch chunks (I like to use one red and one yellow for color)", "1 tsp garlic powder", "1 tbsp Italian herbs seasoning", "1/2 teaspoon sea salt", @@ -24,7 +24,7 @@ "1 lb potato gnocchi (500g fresh shelf-stable, or frozen)", "1 pint cherry or grape tomatoes, cut in half (2 cups)", "1 small red onion (cut into 1-inch chunks)", - "2 bell peppers (cut into 1-inch chunks (I like to use one red and one yellow for color))", + "2 bell peppers (cut into 1-inch chunks (I like to use one red and one yellow for color)", "1 tsp garlic powder", "1 tbsp Italian herbs seasoning", "1/2 teaspoon sea salt", diff --git a/tests/test_data/peelwithzeal.com/peelwithzeal_1.json b/tests/test_data/peelwithzeal.com/peelwithzeal_1.json index 1e5dc1474..195f8033b 100644 --- a/tests/test_data/peelwithzeal.com/peelwithzeal_1.json +++ b/tests/test_data/peelwithzeal.com/peelwithzeal_1.json @@ -12,7 +12,7 @@ "2 14-ounce cans pinto beans (drain 1 can only)", "2 14-ounce cans navy beans (drain 1 can only)", "1 cup beef stock", - "1/2 cup molasses ((not blackstrap))", + "1/2 cup molasses (not blackstrap)", "1/2 cup ketchup", "1/4 cup brown sugar", "2 tablespoons brown mustard", diff --git a/tests/test_data/rainbowplantlife.com/rainbowplantlife.json b/tests/test_data/rainbowplantlife.com/rainbowplantlife.json index 46600dc39..40dddab3d 100644 --- a/tests/test_data/rainbowplantlife.com/rainbowplantlife.json +++ b/tests/test_data/rainbowplantlife.com/rainbowplantlife.json @@ -10,9 +10,9 @@ "1/2 cup (75-85g) fresh blueberries", "1/3 cup (45g) brown sugar or coconut sugar", "1 teaspoon ground cinnamon", - "1/4 teaspoon nutmeg ((I recommend freshly grated nutmeg))", + "1/4 teaspoon nutmeg (I recommend freshly grated nutmeg)", "Scant 1/2 teaspoon ground ginger", - "2 pinches of ground cardamom ((optional))", + "2 pinches of ground cardamom (optional)", "10 tablespoons (140g) vegan butter*", "1 1/2 cups (180g) all-purpose flour", "Scant 2/3 cup (60g) (old-fashioned rolled oats)", @@ -21,8 +21,8 @@ "2 teaspoons baking powder", "1 1/3 cups (320 mL) full-fat oat milk***", "1 1/2 teaspoons pure vanilla extract", - "1/4 teaspoon pure almond extract ((optional))", - "For serving: vegan vanilla ice cream ((optional))" + "1/4 teaspoon pure almond extract (optional)", + "For serving: vegan vanilla ice cream (optional)" ], "instructions_list": [ "Arrange a rack in the middle of your oven and preheat it to 375°F/190°C.", diff --git a/tests/test_data/rainbowplantlife.com/rainbowplantlife_groups.json b/tests/test_data/rainbowplantlife.com/rainbowplantlife_groups.json index bd69ab8f8..122df7c1c 100644 --- a/tests/test_data/rainbowplantlife.com/rainbowplantlife_groups.json +++ b/tests/test_data/rainbowplantlife.com/rainbowplantlife_groups.json @@ -6,13 +6,13 @@ "language": "en", "title": "Vegan Pasta Salad", "ingredients": [ - "1 pound fusilli, (rotini, or penne rigate (a ridged pasta))", + "1 pound fusilli, (rotini, or penne rigate (a ridged pasta)", "1 cup (112g) raw walnuts", "5 ounces (140g) sourdough loaf, (baguette, or country-style bread, sliced)", "1 (12-ounce/340g) jar of roasted red bell peppers**, (drained from the liquid in the jar)", "3 garlic cloves, (roughly chopped)", - "1 medium lemon, (zested and juiced (3 tablespoons juice; save the zest for the Topping))", - "½ to 1 teaspoon smoked paprika ((use 1 teaspoon for prominent smokiness))", + "1 medium lemon, (zested and juiced (3 tablespoons juice; save the zest for the Topping)", + "½ to 1 teaspoon smoked paprika (use 1 teaspoon for prominent smokiness)", "½ teaspoon red pepper flakes", "1 teaspoon kosher salt, (plus more to taste)", "Freshly cracked black pepper to taste", @@ -22,14 +22,14 @@ "1 cup (16g) flat-leaf parsley, (finely chopped)", "1 ½ cups (24g) fresh basil, (finely chopped)", "3 tablespoons capers***, (chopped)", - "¼ teaspoon red pepper flakes ((optional) )", + "¼ teaspoon red pepper flakes (optional) )", "½ teaspoon flaky sea salt", "3 cups (60g) baby arugula, (chopped)" ], "ingredient_groups": [ { "ingredients": [ - "1 pound fusilli, (rotini, or penne rigate (a ridged pasta))" + "1 pound fusilli, (rotini, or penne rigate (a ridged pasta)" ], "purpose": null }, @@ -39,8 +39,8 @@ "5 ounces (140g) sourdough loaf, (baguette, or country-style bread, sliced)", "1 (12-ounce/340g) jar of roasted red bell peppers**, (drained from the liquid in the jar)", "3 garlic cloves, (roughly chopped)", - "1 medium lemon, (zested and juiced (3 tablespoons juice; save the zest for the Topping))", - "½ to 1 teaspoon smoked paprika ((use 1 teaspoon for prominent smokiness))", + "1 medium lemon, (zested and juiced (3 tablespoons juice; save the zest for the Topping)", + "½ to 1 teaspoon smoked paprika (use 1 teaspoon for prominent smokiness)", "½ teaspoon red pepper flakes", "1 teaspoon kosher salt, (plus more to taste)", "Freshly cracked black pepper to taste", @@ -55,7 +55,7 @@ "1 cup (16g) flat-leaf parsley, (finely chopped)", "1 ½ cups (24g) fresh basil, (finely chopped)", "3 tablespoons capers***, (chopped)", - "¼ teaspoon red pepper flakes ((optional) )", + "¼ teaspoon red pepper flakes (optional) )", "½ teaspoon flaky sea salt", "3 cups (60g) baby arugula, (chopped)" ], diff --git a/tests/test_data/recipegirl.com/recipegirl_1.json b/tests/test_data/recipegirl.com/recipegirl_1.json index 9c666af3a..238ed7b3c 100644 --- a/tests/test_data/recipegirl.com/recipegirl_1.json +++ b/tests/test_data/recipegirl.com/recipegirl_1.json @@ -10,14 +10,14 @@ "1 tablespoon extra virgin olive oil", "2 tablespoons butter (divided)", "3 medium garlic cloves, (minced)", - "Three 6.5-ounce cans chopped clams, (drained (save the juice))", + "Three 6.5-ounce cans chopped clams, (drained (save the juice)", "¾ cup white wine", "½ medium lemon, (juiced)", "2 tablespoons chopped fresh Italian parsley", "¾ cup whipping cream", "salt and freshly ground black pepper, (to taste)", "grated Parmesan cheese for topping, (if desired)", - "½ medium lemon, (sliced for garnish (optional))" + "½ medium lemon, (sliced for garnish (optional)" ], "instructions_list": [ "Cook the pasta according to package directions. Make the sauce while the pasta is cooking.", diff --git a/tests/test_data/recipetineats.com/recipetineats_1.json b/tests/test_data/recipetineats.com/recipetineats_1.json index d7db858ee..8b8b86d79 100644 --- a/tests/test_data/recipetineats.com/recipetineats_1.json +++ b/tests/test_data/recipetineats.com/recipetineats_1.json @@ -6,8 +6,8 @@ "language": "en-US", "title": "Crispy potato straws (Pommes Paille)", "ingredients": [ - "1 potato ((Aus: Sebago, US: russet, UK: Maris Piper), or other starchy or all-rounder potato (Note 1))", - "1 1/2 - 2 cups vegetable oil ((canola, sunflower or peanut oil))", + "1 potato (Aus: Sebago, US: russet, UK: Maris Piper), or other starchy or all-rounder potato (Note 1)", + "1 1/2 - 2 cups vegetable oil (canola, sunflower or peanut oil)", "Sea salt flakes (, crushed with fingers into a powder)" ], "instructions_list": [ diff --git a/tests/test_data/recipetineats.com/recipetineats_2.json b/tests/test_data/recipetineats.com/recipetineats_2.json index 60c221d24..b0d85fd08 100644 --- a/tests/test_data/recipetineats.com/recipetineats_2.json +++ b/tests/test_data/recipetineats.com/recipetineats_2.json @@ -8,9 +8,9 @@ "ingredients": [ "1/2 cup / 100g brown sugar, tightly packed", "1 tbsp water", - "1 kg / 2 lb pork shoulder ((butt) or boneless skinless pork belly, cut into 3 cm / 1.2\" pieces (Note 1a))", - "1.5 cups / 375 ml coconut water ((Note 1b))", - "1 eschallot / shallot (, very finely sliced (Note 2))", + "1 kg / 2 lb pork shoulder (butt) or boneless skinless pork belly, cut into 3 cm / 1.2\" pieces (Note 1a)", + "1.5 cups / 375 ml coconut water (Note 1b)", + "1 eschallot / shallot (, very finely sliced (Note 2)", "2 garlic cloves (, minced)", "1 1/2 tbsp fish sauce", "1/4 tsp white pepper", @@ -21,9 +21,9 @@ "ingredients": [ "1/2 cup / 100g brown sugar, tightly packed", "1 tbsp water", - "1 kg / 2 lb pork shoulder ((butt) or boneless skinless pork belly, cut into 3 cm / 1.2\" pieces (Note 1a))", - "1.5 cups / 375 ml coconut water ((Note 1b))", - "1 eschallot / shallot (, very finely sliced (Note 2))", + "1 kg / 2 lb pork shoulder (butt) or boneless skinless pork belly, cut into 3 cm / 1.2\" pieces (Note 1a)", + "1.5 cups / 375 ml coconut water (Note 1b)", + "1 eschallot / shallot (, very finely sliced (Note 2)", "2 garlic cloves (, minced)", "1 1/2 tbsp fish sauce", "1/4 tsp white pepper" diff --git a/tests/test_data/redhousespice.com/redhousespice_2.json b/tests/test_data/redhousespice.com/redhousespice_2.json index 4549cecd7..0b1078403 100644 --- a/tests/test_data/redhousespice.com/redhousespice_2.json +++ b/tests/test_data/redhousespice.com/redhousespice_2.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Smashed Cucumber Salad (拍黄瓜)", "ingredients": [ - "1 large cucumber (or 2 small ones (about 350g/12oz))", + "1 large cucumber (or 2 small ones (about 350g/12oz)", "¼ tsp salt", "2 cloves garlic (minced)", "1 tbsp light soy sauce", diff --git a/tests/test_data/saltpepperskillet.com/saltpepperskillet_2.json b/tests/test_data/saltpepperskillet.com/saltpepperskillet_2.json index 75a9771b4..1f0a38d52 100644 --- a/tests/test_data/saltpepperskillet.com/saltpepperskillet_2.json +++ b/tests/test_data/saltpepperskillet.com/saltpepperskillet_2.json @@ -14,10 +14,10 @@ "1/4 tsp kosher salt", "1 teaspoon vanilla extract", "½ cup raisins", - "3 tbsp bourbon for soaking the raisins ((can use the same bourbon for the sauce))", + "3 tbsp bourbon for soaking the raisins (can use the same bourbon for the sauce)", "½ cup butter", "¾ cup packed brown sugar", - "3 tablespoons bourbon ((drained from the raisins))", + "3 tablespoons bourbon (drained from the raisins)", "½ cup heavy cream", "½ teaspoon ground cinnamon" ], @@ -32,7 +32,7 @@ "1/4 tsp kosher salt", "1 teaspoon vanilla extract", "½ cup raisins", - "3 tbsp bourbon for soaking the raisins ((can use the same bourbon for the sauce))" + "3 tbsp bourbon for soaking the raisins (can use the same bourbon for the sauce)" ], "purpose": null }, @@ -40,7 +40,7 @@ "ingredients": [ "½ cup butter", "¾ cup packed brown sugar", - "3 tablespoons bourbon ((drained from the raisins))", + "3 tablespoons bourbon (drained from the raisins)", "½ cup heavy cream", "½ teaspoon ground cinnamon" ], diff --git a/tests/test_data/simplyquinoa.com/simplyquinoa_1.json b/tests/test_data/simplyquinoa.com/simplyquinoa_1.json index e3d4904a5..19206450f 100644 --- a/tests/test_data/simplyquinoa.com/simplyquinoa_1.json +++ b/tests/test_data/simplyquinoa.com/simplyquinoa_1.json @@ -7,9 +7,9 @@ "title": "Dairy-Free Hot Chocolate", "ingredients": [ "2 cups almond milk", - "3 tablespoons unsweetened cocoa powder ((or raw cacao))", + "3 tablespoons unsweetened cocoa powder (or raw cacao)", "2 tablespoons coconut butter", - "Pinch of ground cinnamon ((optional))", + "Pinch of ground cinnamon (optional)", "Stevia or monk fruit extract to taste" ], "instructions_list": [ diff --git a/tests/test_data/simplyquinoa.com/simplyquinoa_2.json b/tests/test_data/simplyquinoa.com/simplyquinoa_2.json index a1c1a305b..937070c13 100644 --- a/tests/test_data/simplyquinoa.com/simplyquinoa_2.json +++ b/tests/test_data/simplyquinoa.com/simplyquinoa_2.json @@ -9,8 +9,8 @@ "1 cup quinoa flour", "1 cup oat flour", "2 teaspoons baking powder", - "1 1/4 cup almond milk ((or milk of choice))", - "2 large eggs ((or flax eggs))", + "1 1/4 cup almond milk (or milk of choice)", + "2 large eggs (or flax eggs)", "2 tablespoons maple syrup", "2 tablespoons oil", "1/3 cup blueberries", @@ -24,8 +24,8 @@ "1 cup quinoa flour", "1 cup oat flour", "2 teaspoons baking powder", - "1 1/4 cup almond milk ((or milk of choice))", - "2 large eggs ((or flax eggs))", + "1 1/4 cup almond milk (or milk of choice)", + "2 large eggs (or flax eggs)", "2 tablespoons maple syrup", "2 tablespoons oil" ], diff --git a/tests/test_data/skinnytaste.com/skinnytaste_1.json b/tests/test_data/skinnytaste.com/skinnytaste_1.json index bfe0f1f39..8d91c854e 100644 --- a/tests/test_data/skinnytaste.com/skinnytaste_1.json +++ b/tests/test_data/skinnytaste.com/skinnytaste_1.json @@ -12,7 +12,7 @@ "3 cloves garlic (crushed)", "10 oz frozen spinach (drained)", "3 oz shredded part skim mozzarella", - "1/2 cup roasted red pepper (sliced in strips (packed in water))", + "1/2 cup roasted red pepper (sliced in strips (packed in water)", "olive oil spray" ], "instructions_list": [ diff --git a/tests/test_data/sweetpeasandsaffron.com/sweetpeasandsaffron_1.json b/tests/test_data/sweetpeasandsaffron.com/sweetpeasandsaffron_1.json index 82d19b846..56d54d0fd 100644 --- a/tests/test_data/sweetpeasandsaffron.com/sweetpeasandsaffron_1.json +++ b/tests/test_data/sweetpeasandsaffron.com/sweetpeasandsaffron_1.json @@ -7,16 +7,16 @@ "title": "Instant Pot Carrot Ginger Soup (Vegan)", "ingredients": [ "1 tablespoon olive oil", - "1 onion ((chopped))", - "2 cloves garlic ((minced))", - "2 tablespoons ginger ((grated or finely chopped))", - "5 cups carrots ((peeled & chopped))", + "1 onion (chopped)", + "2 cloves garlic (minced)", + "2 tablespoons ginger (grated or finely chopped)", + "5 cups carrots (peeled & chopped)", "4 cups vegetable broth", "3/4 teaspoons salt", "1/2 teaspoon pepper", "1 teaspoon dried thyme leaves", - "13.5 oz coconut milk ((400 mL; full fat works best))", - "1/2 lime ((juiced))" + "13.5 oz coconut milk (400 mL; full fat works best)", + "1/2 lime (juiced)" ], "instructions_list": [ "Select the sauté function of the Instant Pot. Add olive oil and onion to the inner pot. Cook for 5-6 minutes, until onions are softened and translucent.", diff --git a/tests/test_data/sweetpeasandsaffron.com/sweetpeasandsaffron_2.json b/tests/test_data/sweetpeasandsaffron.com/sweetpeasandsaffron_2.json index 804fe107c..2b2cd0c10 100644 --- a/tests/test_data/sweetpeasandsaffron.com/sweetpeasandsaffron_2.json +++ b/tests/test_data/sweetpeasandsaffron.com/sweetpeasandsaffron_2.json @@ -6,43 +6,43 @@ "language": "en-US", "title": "7 Healthy Steel Cut Oats Recipes", "ingredients": [ - "1 tablespoon butter ((optional; to toast the oats))", - "1 cup steel cut oats ((see note *))", + "1 tablespoon butter (optional; to toast the oats)", + "1 cup steel cut oats (see note *)", "3 Instant Pot or 4 (slow cooker, stove-top) cups water", "1 teaspoon vanilla extract", "1 teaspoon cinnamon", "After cooking:", "2 tablespoons maple syrup (or more to taste)", "1 large apple (peeled and cut into small pieces)", - "1 cup unsweetened apple sauce ((stir in after cooking if using Instant Pot))", - "1/3 cup chopped pecans ((to top))", + "1 cup unsweetened apple sauce (stir in after cooking if using Instant Pot)", + "1/3 cup chopped pecans (to top)", "1/4 teaspoon ground nutmeg", "1/4 teaspoon ground cloves", "1 teaspoon vanilla extract", - "1 cup pumpkin puree ((stir in after cooking if using Instant Pot))", - "2 tablespoons pumpkin seeds/pepitas ((to top))", - "zest from 1 lemon ((add after cooking base recipe))", - "1-2 cups blueberries ((add after cooking base recipe))", - "chia seeds ((add after cooking base recipe))", + "1 cup pumpkin puree (stir in after cooking if using Instant Pot)", + "2 tablespoons pumpkin seeds/pepitas (to top)", + "zest from 1 lemon (add after cooking base recipe)", + "1-2 cups blueberries (add after cooking base recipe)", + "chia seeds (add after cooking base recipe)", "1 tablespoon cocoa powder", - "2 tablespoons peanut butter ((stir in after cooking base recipe))", - "1-2 cups berries ((to top))", - "chia seeds ((add after cooking base recipe))", - "1 teaspoon coconut extract ((omit cinnamon from base recipe))", - "1 tablespoon key lime zest ((stir in after cooking base recipe))", - "1-2 cups strawberries (kiwis or pineapple (to top))", - "1/4 cup toasted coconut ((to top))", - "1 cup shredded zucchini ((drained of excess liquid; stir in after cooking base recipe))", - "1/4 cup chocolate chips ((to top))", - "1 teaspoon chai spice blend ((omit cinnamon from base recipe; *see note))", + "2 tablespoons peanut butter (stir in after cooking base recipe)", + "1-2 cups berries (to top)", + "chia seeds (add after cooking base recipe)", + "1 teaspoon coconut extract (omit cinnamon from base recipe)", + "1 tablespoon key lime zest (stir in after cooking base recipe)", + "1-2 cups strawberries (kiwis or pineapple (to top)", + "1/4 cup toasted coconut (to top)", + "1 cup shredded zucchini (drained of excess liquid; stir in after cooking base recipe)", + "1/4 cup chocolate chips (to top)", + "1 teaspoon chai spice blend (omit cinnamon from base recipe; *see note)", "1 cup chopped strawberries", - "1-2 cups chopped fresh strawberries ((to top))" + "1-2 cups chopped fresh strawberries (to top)" ], "ingredient_groups": [ { "ingredients": [ - "1 tablespoon butter ((optional; to toast the oats))", - "1 cup steel cut oats ((see note *))", + "1 tablespoon butter (optional; to toast the oats)", + "1 cup steel cut oats (see note *)", "3 Instant Pot or 4 (slow cooker, stove-top) cups water", "1 teaspoon vanilla extract", "1 teaspoon cinnamon", @@ -54,8 +54,8 @@ { "ingredients": [ "1 large apple (peeled and cut into small pieces)", - "1 cup unsweetened apple sauce ((stir in after cooking if using Instant Pot))", - "1/3 cup chopped pecans ((to top))" + "1 cup unsweetened apple sauce (stir in after cooking if using Instant Pot)", + "1/3 cup chopped pecans (to top)" ], "purpose": "Apple Cinnamon" }, @@ -64,49 +64,49 @@ "1/4 teaspoon ground nutmeg", "1/4 teaspoon ground cloves", "1 teaspoon vanilla extract", - "1 cup pumpkin puree ((stir in after cooking if using Instant Pot))", - "2 tablespoons pumpkin seeds/pepitas ((to top))" + "1 cup pumpkin puree (stir in after cooking if using Instant Pot)", + "2 tablespoons pumpkin seeds/pepitas (to top)" ], "purpose": "Pumpkin" }, { "ingredients": [ - "zest from 1 lemon ((add after cooking base recipe))", - "1-2 cups blueberries ((add after cooking base recipe))", - "chia seeds ((add after cooking base recipe))" + "zest from 1 lemon (add after cooking base recipe)", + "1-2 cups blueberries (add after cooking base recipe)", + "chia seeds (add after cooking base recipe)" ], "purpose": "Blueberry Lemon" }, { "ingredients": [ "1 tablespoon cocoa powder", - "2 tablespoons peanut butter ((stir in after cooking base recipe))", - "1-2 cups berries ((to top))", - "chia seeds ((add after cooking base recipe))" + "2 tablespoons peanut butter (stir in after cooking base recipe)", + "1-2 cups berries (to top)", + "chia seeds (add after cooking base recipe)" ], "purpose": "Peanut Butter Chocolate" }, { "ingredients": [ - "1 teaspoon coconut extract ((omit cinnamon from base recipe))", - "1 tablespoon key lime zest ((stir in after cooking base recipe))", - "1-2 cups strawberries (kiwis or pineapple (to top))", - "1/4 cup toasted coconut ((to top))" + "1 teaspoon coconut extract (omit cinnamon from base recipe)", + "1 tablespoon key lime zest (stir in after cooking base recipe)", + "1-2 cups strawberries (kiwis or pineapple (to top)", + "1/4 cup toasted coconut (to top)" ], "purpose": "Coconut Key Lime" }, { "ingredients": [ - "1 cup shredded zucchini ((drained of excess liquid; stir in after cooking base recipe))", - "1/4 cup chocolate chips ((to top))" + "1 cup shredded zucchini (drained of excess liquid; stir in after cooking base recipe)", + "1/4 cup chocolate chips (to top)" ], "purpose": "Zucchini Chocolate Chip" }, { "ingredients": [ - "1 teaspoon chai spice blend ((omit cinnamon from base recipe; *see note))", + "1 teaspoon chai spice blend (omit cinnamon from base recipe; *see note)", "1 cup chopped strawberries", - "1-2 cups chopped fresh strawberries ((to top))" + "1-2 cups chopped fresh strawberries (to top)" ], "purpose": "Strawberry Vanilla Chai" } diff --git a/tests/test_data/thecookierookie.com/thecookierookie_1.json b/tests/test_data/thecookierookie.com/thecookierookie_1.json index 7396e9e4b..e4b5442ab 100644 --- a/tests/test_data/thecookierookie.com/thecookierookie_1.json +++ b/tests/test_data/thecookierookie.com/thecookierookie_1.json @@ -11,7 +11,7 @@ "1 cup brown sugar", "½ cup honey", "⅓ cup Dijon mustard", - "¼ cup unsalted butter ((½ stick))", + "¼ cup unsalted butter (½ stick)", "¼ cup apple cider vinegar", "3 cloves garlic (minced)", "¼ teaspoon ground cinnamon", diff --git a/tests/test_data/thefoodietakesflight.com/thefoodietakesflight_2.json b/tests/test_data/thefoodietakesflight.com/thefoodietakesflight_2.json index 9ed883e68..6dffa42cf 100644 --- a/tests/test_data/thefoodietakesflight.com/thefoodietakesflight_2.json +++ b/tests/test_data/thefoodietakesflight.com/thefoodietakesflight_2.json @@ -7,7 +7,7 @@ "title": "Vietnamese Lemongrass Seitan Crispy Rice", "ingredients": [ "1/2 cup warm vegetable broth (or water)", - "1/2-1 tbsp white miso paste ((see notes))", + "1/2-1 tbsp white miso paste (see notes)", "3/4 cup vital wheat gluten (, 100 g)", "2 tbsp chickpea flour (, 20 g)", "1 tbsp nutritional yeast", @@ -26,13 +26,13 @@ "1 shallot (finely minced)", "4 cloves garlic (minced)", "1 tbsp minced lemongrass (I used frozen)", - "2 tbsp vegan fish sauce ((sub for light soy sauce or Yondu))", - "1 tbsp Chili Garlic Sauce ((Huy Fong or Lee Kum Kee))", + "2 tbsp vegan fish sauce (sub for light soy sauce or Yondu)", + "1 tbsp Chili Garlic Sauce (Huy Fong or Lee Kum Kee)", "2 tbsp sugar (, adjust to taste)", "1 lime (, juiced)", "2 cloves garlic (, minced)", "1/2 cup coconut water", - "1 bird’s eye chili pepper (roughly chopped (optional for heat))", + "1 bird’s eye chili pepper (roughly chopped (optional for heat)", "Salt ( to taste)", "Sliced cucumber and tomatoes", "Pickled carrots/radish", @@ -45,7 +45,7 @@ { "ingredients": [ "1/2 cup warm vegetable broth (or water)", - "1/2-1 tbsp white miso paste ((see notes))" + "1/2-1 tbsp white miso paste (see notes)" ], "purpose": "WET" }, @@ -89,13 +89,13 @@ }, { "ingredients": [ - "2 tbsp vegan fish sauce ((sub for light soy sauce or Yondu))", - "1 tbsp Chili Garlic Sauce ((Huy Fong or Lee Kum Kee))", + "2 tbsp vegan fish sauce (sub for light soy sauce or Yondu)", + "1 tbsp Chili Garlic Sauce (Huy Fong or Lee Kum Kee)", "2 tbsp sugar (, adjust to taste)", "1 lime (, juiced)", "2 cloves garlic (, minced)", "1/2 cup coconut water", - "1 bird’s eye chili pepper (roughly chopped (optional for heat))", + "1 bird’s eye chili pepper (roughly chopped (optional for heat)", "Salt ( to taste)" ], "purpose": "TIFF'S VEGAN NUOC CHAM" diff --git a/tests/test_data/theloopywhisk.com/theloopywhisk_1.json b/tests/test_data/theloopywhisk.com/theloopywhisk_1.json index fda545a50..3e79b4a54 100644 --- a/tests/test_data/theloopywhisk.com/theloopywhisk_1.json +++ b/tests/test_data/theloopywhisk.com/theloopywhisk_1.json @@ -13,8 +13,8 @@ "1 tsp (2 g) spirulina powder", "1/2 tbsp (3 g) matcha powder", "1/4 cup (50 g) melted coconut oil", - "3/8 - 1/2 cup (90 g - 120 g) maple syrup ((depending on how sweet you want the energy bites to be))", - "1.8 oz 50 g melted dairy free white chocolate for the drizzle ((optional))" + "3/8 - 1/2 cup (90 g - 120 g) maple syrup (depending on how sweet you want the energy bites to be)", + "1.8 oz 50 g melted dairy free white chocolate for the drizzle (optional)" ], "instructions_list": [ "In a bowl, mix together all the ingredients except the dairy free white chocolate, until everything is evenly distributed and you get a homogeneous mixture, dough-like in consistency.", diff --git a/tests/test_data/theloopywhisk.com/theloopywhisk_2.json b/tests/test_data/theloopywhisk.com/theloopywhisk_2.json index 324f564d1..d52e7f5de 100644 --- a/tests/test_data/theloopywhisk.com/theloopywhisk_2.json +++ b/tests/test_data/theloopywhisk.com/theloopywhisk_2.json @@ -9,13 +9,13 @@ "210 g (1 1/2 cups) fresh or frozen blackberries", "150 g (1 1/2 cups) crushed digestive biscuits", "45 g (1/3 stick + 1/2 tbsp) unsalted butter, melted", - "400 g (1 3/4 cups) full-fat cream cheese, room temperature ((I used Philadelphia.))", - "80 g (1/3 cup) full-fat plain or Greek-style yoghurt, room temperature ((You can also use sour cream.))", + "400 g (1 3/4 cups) full-fat cream cheese, room temperature (I used Philadelphia.)", + "80 g (1/3 cup) full-fat plain or Greek-style yoghurt, room temperature (You can also use sour cream.)", "100 g (1/2 cup) caster/superfine sugar", "10 g (1 1/2 tbsp) cornstarch", "2 UK medium/US large eggs, room temperature", "1/2 tbsp lemon juice", - "1/2 tsp vanilla bean paste ((or 1 tsp vanilla extract))", + "1/2 tsp vanilla bean paste (or 1 tsp vanilla extract)", "zest of 1 lemon", "70 g (1/2 cup) fresh blackberries" ], @@ -35,13 +35,13 @@ }, { "ingredients": [ - "400 g (1 3/4 cups) full-fat cream cheese, room temperature ((I used Philadelphia.))", - "80 g (1/3 cup) full-fat plain or Greek-style yoghurt, room temperature ((You can also use sour cream.))", + "400 g (1 3/4 cups) full-fat cream cheese, room temperature (I used Philadelphia.)", + "80 g (1/3 cup) full-fat plain or Greek-style yoghurt, room temperature (You can also use sour cream.)", "100 g (1/2 cup) caster/superfine sugar", "10 g (1 1/2 tbsp) cornstarch", "2 UK medium/US large eggs, room temperature", "1/2 tbsp lemon juice", - "1/2 tsp vanilla bean paste ((or 1 tsp vanilla extract))", + "1/2 tsp vanilla bean paste (or 1 tsp vanilla extract)", "zest of 1 lemon" ], "purpose": "For base cheesecake filling:" diff --git a/tests/test_data/themagicalslowcooker.com/themagicalslowcooker_1.json b/tests/test_data/themagicalslowcooker.com/themagicalslowcooker_1.json index b42aca9a1..ed861ac16 100644 --- a/tests/test_data/themagicalslowcooker.com/themagicalslowcooker_1.json +++ b/tests/test_data/themagicalslowcooker.com/themagicalslowcooker_1.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Slow Cooker Ground Beef", "ingredients": [ - "2 lbs. ground beef ((7-20 % fat))", + "2 lbs. ground beef (7-20 % fat)", "1 ½ tsp. salt", "½ tsp. garlic powder", "½ tsp. onion powder", diff --git a/tests/test_data/thevintagemixer.com/thevintagemixer_2.json b/tests/test_data/thevintagemixer.com/thevintagemixer_2.json index 13857dff8..67c84c33e 100644 --- a/tests/test_data/thevintagemixer.com/thevintagemixer_2.json +++ b/tests/test_data/thevintagemixer.com/thevintagemixer_2.json @@ -9,7 +9,7 @@ "2 cups of all purpose flour", "1/4 teaspoon salt", "1/2 teaspoon baking powder", - "1/4 lb. butter, (softened (1 stick))", + "1/4 lb. butter, (softened (1 stick)", "1 cup sugar", "1 large egg, (lightly beaten)", "2 tablespoon of brandy, (or apple juice)", @@ -25,7 +25,7 @@ "2 cups of all purpose flour", "1/4 teaspoon salt", "1/2 teaspoon baking powder", - "1/4 lb. butter, (softened (1 stick))", + "1/4 lb. butter, (softened (1 stick)", "1 cup sugar", "1 large egg, (lightly beaten)", "2 tablespoon of brandy, (or apple juice)", diff --git a/tests/test_data/thewoksoflife.com/thewoksoflife_1.json b/tests/test_data/thewoksoflife.com/thewoksoflife_1.json index a39de89a3..daef7b5ac 100644 --- a/tests/test_data/thewoksoflife.com/thewoksoflife_1.json +++ b/tests/test_data/thewoksoflife.com/thewoksoflife_1.json @@ -6,11 +6,11 @@ "language": "en-US", "title": "The Perfect Whole Wheat Mantou Recipe", "ingredients": [ - "1 ⅔ cups warm milk ((400 ml))", - "1 teaspoon active dry yeast ((3 grams))", - "1 tablespoon sugar ((12 grams))", - "2 ¾ cups all-purpose flour ((400 grams))", - "1¼ to 1½ cups whole wheat flour ((about 170-200 grams; how much you’ll need is dependent on the humidity in your kitchen))" + "1 ⅔ cups warm milk (400 ml)", + "1 teaspoon active dry yeast (3 grams)", + "1 tablespoon sugar (12 grams)", + "2 ¾ cups all-purpose flour (400 grams)", + "1¼ to 1½ cups whole wheat flour (about 170-200 grams; how much you’ll need is dependent on the humidity in your kitchen)" ], "instructions_list": [ "Heat the milk until warm to the touch (not hot). Then stir in the yeast and sugar until it dissolves. Combine the milk mixture with 2 ¾ cups of all-purpose flour in a large mixing bowl. The mixture will be wet. Cover with a damp cloth and let proof in a warm spot for 1-2 hours until the mixture doubles in size. Since it’s winter, I let the dough proof near a heat vent!", diff --git a/tests/test_data/thewoksoflife.com/thewoksoflife_2.json b/tests/test_data/thewoksoflife.com/thewoksoflife_2.json index f17f81b90..28d40748c 100644 --- a/tests/test_data/thewoksoflife.com/thewoksoflife_2.json +++ b/tests/test_data/thewoksoflife.com/thewoksoflife_2.json @@ -9,24 +9,24 @@ "12 ounces boneless skinless chicken breast (or thighs)", "2 tablespoons water", "1 teaspoon cornstarch", - "1 teaspoon neutral oil ((such as vegetable, canola, or avocado oil))", + "1 teaspoon neutral oil (such as vegetable, canola, or avocado oil)", "2 teaspoons oyster sauce", "2/3 cup low sodium chicken stock", - "1 1/2 teaspoons sugar ((or brown sugar))", + "1 1/2 teaspoons sugar (or brown sugar)", "1 tablespoon oyster sauce", "1 1/2 tablespoons soy sauce", - "2 teaspoons dark soy sauce ((can sub regular soy sauce, but color won't be as dark))", + "2 teaspoons dark soy sauce (can sub regular soy sauce, but color won't be as dark)", "1 teaspoon sesame oil", "1/8 teaspoon white pepper", "1 cup small broccoli florets", - "3/4 cup carrot ((thinly sliced on a diagonal))", - "3 tablespoons neutral oil ((such as vegetable, canola, or avocado oil; divided))", - "2 cloves garlic ((chopped))", + "3/4 cup carrot (thinly sliced on a diagonal)", + "3 tablespoons neutral oil (such as vegetable, canola, or avocado oil; divided)", + "2 cloves garlic (chopped)", "1/2 cup large-diced onion", "3/4 cup sliced mushrooms", "1/2 cup red pepper", "1 tablespoon Shaoxing wine", - "1½ tablespoons cornstarch ((mixed into a slurry with 2 tablespoons water))" + "1½ tablespoons cornstarch (mixed into a slurry with 2 tablespoons water)" ], "ingredient_groups": [ { @@ -34,7 +34,7 @@ "12 ounces boneless skinless chicken breast (or thighs)", "2 tablespoons water", "1 teaspoon cornstarch", - "1 teaspoon neutral oil ((such as vegetable, canola, or avocado oil))", + "1 teaspoon neutral oil (such as vegetable, canola, or avocado oil)", "2 teaspoons oyster sauce" ], "purpose": "FOR THE CHICKEN:" @@ -42,21 +42,21 @@ { "ingredients": [ "2/3 cup low sodium chicken stock", - "1 1/2 teaspoons sugar ((or brown sugar))", + "1 1/2 teaspoons sugar (or brown sugar)", "1 tablespoon oyster sauce", "1 1/2 tablespoons soy sauce", - "2 teaspoons dark soy sauce ((can sub regular soy sauce, but color won't be as dark))", + "2 teaspoons dark soy sauce (can sub regular soy sauce, but color won't be as dark)", "1 teaspoon sesame oil", "1/8 teaspoon white pepper", "1 cup small broccoli florets", - "3/4 cup carrot ((thinly sliced on a diagonal))", - "3 tablespoons neutral oil ((such as vegetable, canola, or avocado oil; divided))", - "2 cloves garlic ((chopped))", + "3/4 cup carrot (thinly sliced on a diagonal)", + "3 tablespoons neutral oil (such as vegetable, canola, or avocado oil; divided)", + "2 cloves garlic (chopped)", "1/2 cup large-diced onion", "3/4 cup sliced mushrooms", "1/2 cup red pepper", "1 tablespoon Shaoxing wine", - "1½ tablespoons cornstarch ((mixed into a slurry with 2 tablespoons water))" + "1½ tablespoons cornstarch (mixed into a slurry with 2 tablespoons water)" ], "purpose": "FOR THE REST OF THE DISH:" } diff --git a/tests/test_data/vanillaandbean.com/vanillaandbean_1.json b/tests/test_data/vanillaandbean.com/vanillaandbean_1.json index 74d1c9327..b54dce78a 100644 --- a/tests/test_data/vanillaandbean.com/vanillaandbean_1.json +++ b/tests/test_data/vanillaandbean.com/vanillaandbean_1.json @@ -9,10 +9,10 @@ "1 C (100g) Whole Rolled Oats (plus 2 Tbs for the top)", "1/2 C (105g) Water (room temperature)", "3/4 C (150g) Sourdough Starter (100% hydration, previously feed and bubbly)", - "1 C (230g) Milk ((nut milk or whole dairy milk) I use 1/2 diluted unsweetened cashew milk - 80F (26C))", + "1 C (230g) Milk (nut milk or whole dairy milk) I use 1/2 diluted unsweetened cashew milk - 80F (26C)", "1/4 C (80g) Maple Syrup", "1 Tbs (14g) Olive Oil ( + more for oiling the pan)", - "1/2 C + 1 Tbs (100g) Whole Wheat Bread Flour ((see note**) or whole wheat flour)", + "1/2 C + 1 Tbs (100g) Whole Wheat Bread Flour (see note**) or whole wheat flour)", "2 C + 3 1/2 Tbs (300g) Bread Flour", "1 1/2 tsp (10g) Fine Sea Salt" ], @@ -27,10 +27,10 @@ { "ingredients": [ "3/4 C (150g) Sourdough Starter (100% hydration, previously feed and bubbly)", - "1 C (230g) Milk ((nut milk or whole dairy milk) I use 1/2 diluted unsweetened cashew milk - 80F (26C))", + "1 C (230g) Milk (nut milk or whole dairy milk) I use 1/2 diluted unsweetened cashew milk - 80F (26C)", "1/4 C (80g) Maple Syrup", "1 Tbs (14g) Olive Oil ( + more for oiling the pan)", - "1/2 C + 1 Tbs (100g) Whole Wheat Bread Flour ((see note**) or whole wheat flour)", + "1/2 C + 1 Tbs (100g) Whole Wheat Bread Flour (see note**) or whole wheat flour)", "2 C + 3 1/2 Tbs (300g) Bread Flour", "1 1/2 tsp (10g) Fine Sea Salt" ], diff --git a/tests/test_data/vegrecipesofindia.com/vegrecipesofindia_2.json b/tests/test_data/vegrecipesofindia.com/vegrecipesofindia_2.json index 7d94a619e..aa7aaed0c 100644 --- a/tests/test_data/vegrecipesofindia.com/vegrecipesofindia_2.json +++ b/tests/test_data/vegrecipesofindia.com/vegrecipesofindia_2.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Eggless Black Forest Cake Recipe (Whole Wheat)", "ingredients": [ - "1 cup whole wheat flour ((leveled) - 120 grams)", + "1 cup whole wheat flour (leveled) - 120 grams)", "3 tablespoons cocoa powder", "½ teaspoon baking soda", "1 pinch salt", @@ -27,7 +27,7 @@ "ingredient_groups": [ { "ingredients": [ - "1 cup whole wheat flour ((leveled) - 120 grams)", + "1 cup whole wheat flour (leveled) - 120 grams)", "3 tablespoons cocoa powder", "½ teaspoon baking soda", "1 pinch salt", diff --git a/tests/test_data/wearenotmartha.com/wearenotmartha_2.json b/tests/test_data/wearenotmartha.com/wearenotmartha_2.json index 18de651e5..a5d52adab 100644 --- a/tests/test_data/wearenotmartha.com/wearenotmartha_2.json +++ b/tests/test_data/wearenotmartha.com/wearenotmartha_2.json @@ -8,8 +8,8 @@ "ingredients": [ "10 oz. cold brew", "Ice", - "1 oz. vanilla syrup ((store-bought or recipe below))", - "1/3 cup chocolate cream cold foam ((recipe below)*)", + "1 oz. vanilla syrup (store-bought or recipe below)", + "1/3 cup chocolate cream cold foam (recipe below)*)", "1 cup water", "1 cup granulated sugar", "1 vanilla bean", @@ -23,8 +23,8 @@ "ingredients": [ "10 oz. cold brew", "Ice", - "1 oz. vanilla syrup ((store-bought or recipe below))", - "1/3 cup chocolate cream cold foam ((recipe below)*)" + "1 oz. vanilla syrup (store-bought or recipe below)", + "1/3 cup chocolate cream cold foam (recipe below)*)" ], "purpose": null }, diff --git a/tests/test_data/wellplated.com/wellplated_1.json b/tests/test_data/wellplated.com/wellplated_1.json index b9ea26c25..fa1f80965 100644 --- a/tests/test_data/wellplated.com/wellplated_1.json +++ b/tests/test_data/wellplated.com/wellplated_1.json @@ -11,13 +11,13 @@ "2 tablespoons unsalted butter (divided, or butter with canola oil spread)", "3 large eggs (lightly beaten)", "1 tablespoon canola oil", - "1 large red, yellow, or orange bell pepper (cut into 1/4-inch dice (about 1 1/4 cups))", - "1 bag frozen peas and carrots (thawed (12 ounces))", - "1 cup frozen shelled edamame (thawed (optional, but great for extra protein))", + "1 large red, yellow, or orange bell pepper (cut into 1/4-inch dice (about 1 1/4 cups)", + "1 bag frozen peas and carrots (thawed (12 ounces)", + "1 cup frozen shelled edamame (thawed (optional, but great for extra protein)", "2 cloves garlic (minced)", "2 1/2 cups COLD cooked brown rice (break up large clumps with your fingers)", "1/2 cup chopped green onions (about 3 medium)", - "Red pepper flakes (Sriracha, or hot sauce of choice (optional))" + "Red pepper flakes (Sriracha, or hot sauce of choice (optional)" ], "instructions_list": [ "Stir", diff --git a/tests/test_data/wellplated.com/wellplated_2.json b/tests/test_data/wellplated.com/wellplated_2.json index dd29628b6..be4db2a5a 100644 --- a/tests/test_data/wellplated.com/wellplated_2.json +++ b/tests/test_data/wellplated.com/wellplated_2.json @@ -13,13 +13,13 @@ "1 teaspoon Italian seasoning", "1 teaspoon kosher salt (plus additional to taste)", "1/4 teaspoon cayenne pepper", - "3–4 cups reduced-sodium chicken broth ((or vegetable broth for a vegetarian soup))", - "1 can 2% evaporated milk ((12-ounces) )", + "3–4 cups reduced-sodium chicken broth (or vegetable broth for a vegetarian soup)", + "1 can 2% evaporated milk (12-ounces) )", "3 tablespoons cornstarch", "1 cup shredded sharp cheddar cheese (plus additional for serving)", "1 cup nonfat plain Greek yogurt (plus additional for serving)", - "Cooked crumbled bacon ((optional))", - "Chopped fresh chives ((optional))" + "Cooked crumbled bacon (optional)", + "Chopped fresh chives (optional)" ], "ingredient_groups": [ { @@ -31,8 +31,8 @@ "1 teaspoon Italian seasoning", "1 teaspoon kosher salt (plus additional to taste)", "1/4 teaspoon cayenne pepper", - "3–4 cups reduced-sodium chicken broth ((or vegetable broth for a vegetarian soup))", - "1 can 2% evaporated milk ((12-ounces) )", + "3–4 cups reduced-sodium chicken broth (or vegetable broth for a vegetarian soup)", + "1 can 2% evaporated milk (12-ounces) )", "3 tablespoons cornstarch", "1 cup shredded sharp cheddar cheese (plus additional for serving)", "1 cup nonfat plain Greek yogurt (plus additional for serving)" @@ -41,8 +41,8 @@ }, { "ingredients": [ - "Cooked crumbled bacon ((optional))", - "Chopped fresh chives ((optional))" + "Cooked crumbled bacon (optional)", + "Chopped fresh chives (optional)" ], "purpose": "For Topping:" } diff --git a/tests/test_data/whole30.com/whole30.json b/tests/test_data/whole30.com/whole30.json index 0b5aa58a9..2a1716789 100644 --- a/tests/test_data/whole30.com/whole30.json +++ b/tests/test_data/whole30.com/whole30.json @@ -12,7 +12,7 @@ "1 tsp garlic powder", "1 tsp onion powder", "1/2 tsp paprika", - "8 plantain tortillas ((see below for how to make))", + "8 plantain tortillas (see below for how to make)", "1/2 red onion (diced)", "2 tomatoes (sliced)", "2 cups shredded lettuce", @@ -30,7 +30,7 @@ "1 tsp garlic powder", "1 tsp onion powder", "1/2 tsp paprika", - "8 plantain tortillas ((see below for how to make))" + "8 plantain tortillas (see below for how to make)" ], "purpose": "Whole30 Smash Burger Tacos" }, From 23213d6d7018b65b277fd27072faaffed930c555 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sat, 7 Dec 2024 15:43:11 -0500 Subject: [PATCH 27/94] Addition: Support for Eggs.ca (#1357) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/_schemaorg.py | 6 +- recipe_scrapers/eggsca.py | 56 ++++ tests/test_data/eggs.ca/eggsca_1.json | 27 ++ tests/test_data/eggs.ca/eggsca_1.testhtml | 341 ++++++++++++++++++++++ tests/test_data/eggs.ca/eggsca_2.json | 66 +++++ tests/test_data/eggs.ca/eggsca_2.testhtml | 330 +++++++++++++++++++++ 8 files changed, 828 insertions(+), 1 deletion(-) create mode 100644 recipe_scrapers/eggsca.py create mode 100644 tests/test_data/eggs.ca/eggsca_1.json create mode 100644 tests/test_data/eggs.ca/eggsca_1.testhtml create mode 100644 tests/test_data/eggs.ca/eggsca_2.json create mode 100644 tests/test_data/eggs.ca/eggsca_2.testhtml diff --git a/README.rst b/README.rst index 9b8de7030..1ecf0ae67 100644 --- a/README.rst +++ b/README.rst @@ -195,6 +195,7 @@ Scrapers available for: - `https://eattolerant.de/ `_ - `https://www.eatwell101.com `_ - `https://eatwhattonight.com/ `_ +- `https://eggs.ca/ `_ - `https://elavegan.com/ `_ - `https://emmikochteinfach.de/ `_ - `https://en.wikibooks.org/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 09c102e1d..53b0d2dcf 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -140,6 +140,7 @@ from .eattolerant import EatTolerant from .eatwell101 import EatWell101 from .eatwhattonight import EatWhatTonight +from .eggsca import EggsCa from .elavegan import ElaVegan from .emmikochteinfach import EmmiKochtEinfach from .epicurious import Epicurious @@ -541,6 +542,7 @@ DonalSkehan.host(): DonalSkehan, EatLiveRun.host(): EatLiveRun, EatThisMuch.host(): EatThisMuch, + EggsCa.host(): EggsCa, ElaVegan.host(): ElaVegan, EvolvingTable.host(): EvolvingTable, FamilyfoodOnTheTable.host(): FamilyfoodOnTheTable, diff --git a/recipe_scrapers/_schemaorg.py b/recipe_scrapers/_schemaorg.py index 03b58886f..8d44a0567 100644 --- a/recipe_scrapers/_schemaorg.py +++ b/recipe_scrapers/_schemaorg.py @@ -267,7 +267,11 @@ def _extract_howto_instructions_text(self, schema_item): return instructions_gist def instructions(self): - instructions = self.data.get("recipeInstructions") or "" + instructions = ( + self.data.get("recipeInstructions") + or self.data.get("RecipeInstructions") + or "" + ) if ( instructions diff --git a/recipe_scrapers/eggsca.py b/recipe_scrapers/eggsca.py new file mode 100644 index 000000000..7f1841ff9 --- /dev/null +++ b/recipe_scrapers/eggsca.py @@ -0,0 +1,56 @@ +from ._abstract import AbstractScraper +from ._exceptions import StaticValueException +from ._grouping_utils import IngredientGroup + + +class EggsCa(AbstractScraper): + @classmethod + def host(cls): + return "eggs.ca" + + def author(self): + raise StaticValueException(return_value="Eggs.ca") + + def ingredients(self): + return [ + " ".join( + [ + part.get_text(strip=True) + for part in ingredient.select( + ".ingredient__amount, .ingredient__ingredient" + ) + ] + ) + for ingredient in self.soup.select( + ".ingredients__sections .ingredient, .ingredients__wrap--simple .ingredient" + ) + ] + + def ingredient_groups(self): + all_ingredients = self.ingredients() + sections = self.soup.select(".ingredients__sections .ingredients__section") + if sections: + grouped_ingredients = [] + for section in sections: + section_ingredients = [ + " ".join( + [ + part.get_text(strip=True) + for part in ingredient.select( + ".ingredient__amount, .ingredient__ingredient" + ) + ] + ) + for ingredient in section.select(".ingredient") + ] + grouped_ingredients.append( + IngredientGroup( + ingredients=section_ingredients, + purpose=section.select_one( + ".ingredients__sectionHeading" + ).get_text(), + ) + ) + return grouped_ingredients + else: + return [IngredientGroup(ingredients=all_ingredients, purpose=None)] diff --git a/tests/test_data/eggs.ca/eggsca_1.json b/tests/test_data/eggs.ca/eggsca_1.json new file mode 100644 index 000000000..10ded6c86 --- /dev/null +++ b/tests/test_data/eggs.ca/eggsca_1.json @@ -0,0 +1,27 @@ +{ + "author": "Eggs.ca", + "canonical_url": "https://eggs.ca/recipes/creme-brulee/", + "site_name": "Eggs.ca", + "host": "eggs.ca", + "language": "en", + "title": "Classic Crème Brûlée", + "ingredients": [ + "1 ½ cups (375 mL) whipping cream (35%)", + "4 egg yolks", + "¼ cup (60 mL) granulated sugar", + "1 tsp vanilla extract", + "4-6 tsp granulated sugar, for caramelizing" + ], + "instructions_list": [ + "Preheat oven to 325°F (160°C). Place four 1/2 cup (125 mL) ramekins or custard cups in a baking dish. Set aside. Heat cream in saucepan over medium-high heat until small bubbles form around edge of pan. Meanwhile, whisk egg yolks and a 1/4 cup of sugar until thick and lemon-coloured – about 1 to 2 minutes.", + "When cream is hot, gradually whisk into egg yolk mixture. Stir in vanilla. Pour mixture through sieve into ramekins, dividing evenly. Pour very hot water into baking dish to reach halfway up ramekins. Carefully place baking dish in oven. Bake until mostly set but with a slight jiggle in the centre, about 30 to 35 minutes for taller ramekins (about 2 inches (5 cm) high), and 25 to 30 minutes for shallow ramekins (about 1 inch (2.5 cm) high). Carefully remove ramekins from water. Cool on wire rack. When cool, cover with plastic wrap and refrigerate for least 2 hours and up to 2 days.", + "Just before serving (or up to 2 hours before serving), sprinkle sugar evenly over surface of desserts (1 tsp for taller ramekins and 1-1/2 tsp for shallow ramekins). Using a mini torch or by placing the ramekins directly under the broiler, heat until sugar melts and caramelizes. Serve immediately, or for a firmer texture, chill until serving time." + ], + "category": "Desserts & Sweets", + "yields": "4 servings", + "description": "Breaking through crème brûlée’s crispy caramelized top into a thick creamy custard base is pure bliss. Heavy cream gives this classic recipe its silky, rich quality that's like no other dessert.", + "total_time": 50, + "cook_time": 15, + "prep_time": 15, + "image": "https://eggs.ca/wp-content/uploads/2024/06/Creme-Brulee-1664x832-1.jpg" +} diff --git a/tests/test_data/eggs.ca/eggsca_1.testhtml b/tests/test_data/eggs.ca/eggsca_1.testhtml new file mode 100644 index 000000000..5335f8449 --- /dev/null +++ b/tests/test_data/eggs.ca/eggsca_1.testhtml @@ -0,0 +1,341 @@ + + + + + Classic Crème Brûlée | Eggs.ca + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    Recipes
    +

    Classic Crème Brûlée

    +
    + +
    Breaking through crème brûlée’s crispy caramelized top into a thick creamy custard base is pure bliss. Heavy cream gives this classic recipe its silky, rich quality that's like no other dessert.
    +
    +
    Serves +4 +
    Prep Time +15 min +
    Cook Time +35 min +
    +
    +
    + + +
    +
    +

    Ingredients

    +
    • 1 ½ cups (375 mL) whipping cream (35%)
    • 4 egg yolks
    • ¼ cup (60 mL) granulated sugar
    • 1 tsp vanilla extract
    • 4-6 tsp granulated sugar, for caramelizing
    +
    +

    Instructions

    +
    • Step 1

      Preheat oven to 325°F (160°C). Place four 1/2 cup (125 mL) ramekins or custard cups in a baking dish. Set aside.

      +

      Heat cream in saucepan over medium-high heat until small bubbles form around edge of pan. Meanwhile, whisk egg yolks and a 1/4 cup of sugar until thick and lemon-coloured – about 1 to 2 minutes.

      +
    • Step 2

      When cream is hot, gradually whisk into egg yolk mixture. Stir in vanilla. Pour mixture through sieve into ramekins, dividing evenly. Pour very hot water into baking dish to reach halfway up ramekins. Carefully place baking dish in oven. Bake until mostly set but with a slight jiggle in the centre, about 30 to 35 minutes for taller ramekins (about 2 inches (5 cm) high), and 25 to 30 minutes for shallow ramekins (about 1 inch (2.5 cm) high).

      +

      Carefully remove ramekins from water. Cool on wire rack. When cool, cover with plastic wrap and refrigerate for least 2 hours and up to 2 days.

      +
    • Step 3

      Just before serving (or up to 2 hours before serving), sprinkle sugar evenly over surface of desserts (1 tsp for taller ramekins and 1-1/2 tsp for shallow ramekins). Using a mini torch or by placing the ramekins directly under the broiler, heat until sugar melts and caramelizes. Serve immediately, or for a firmer texture, chill until serving time.

      +
    +
    +

    Nutrition Facts

    +
    + + + +
    Per serving
    Calories441
    Fat38 g
    Saturated Fat22 g
    Trans Fat1 g
    Carbohydrate441 g
    Fibre0 g
    Sugars19 g
    Protein5 g
    Sodium43 mg
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/tests/test_data/eggs.ca/eggsca_2.json b/tests/test_data/eggs.ca/eggsca_2.json new file mode 100644 index 000000000..878c90a82 --- /dev/null +++ b/tests/test_data/eggs.ca/eggsca_2.json @@ -0,0 +1,66 @@ +{ + "author": "Eggs.ca", + "canonical_url": "https://eggs.ca/recipes/fudgey-brownies/", + "site_name": "Eggs.ca", + "host": "eggs.ca", + "language": "en", + "title": "Fudgy Brownies", + "ingredients": [ + "1 ¼ cup (315 mL) all-purpose flour", + "1 tsp baking powder", + "½ tsp (2.5 mL) salt", + "¾ cup (175 mL) butter or margarine", + "¾ cup (175 mL) unsweetened cocoa powder", + "1 cup packed brown sugar", + "1 cup granulated sugar", + "4 eggs", + "2 tsp vanilla extract", + "1 cup chopped walnuts", + "2 tbsp butter or margarine", + "¼ cup (60 mL) unsweetened cocoa powder", + "½ tsp (2.5 mL) vanilla extract", + "2 cups sifted icing sugar", + "¼ cup (60 mL) milk (1%)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 ¼ cup (315 mL) all-purpose flour", + "1 tsp baking powder", + "½ tsp (2.5 mL) salt", + "¾ cup (175 mL) butter or margarine", + "¾ cup (175 mL) unsweetened cocoa powder", + "1 cup packed brown sugar", + "1 cup granulated sugar", + "4 eggs", + "2 tsp vanilla extract", + "1 cup chopped walnuts" + ], + "purpose": "Brownies" + }, + { + "ingredients": [ + "2 tbsp butter or margarine", + "¼ cup (60 mL) unsweetened cocoa powder", + "½ tsp (2.5 mL) vanilla extract", + "2 cups sifted icing sugar", + "¼ cup (60 mL) milk (1%)" + ], + "purpose": "Fudgey Icing" + } + ], + "instructions_list": [ + "Brownies", + "Preheat oven to 350°F (180°C).", + "Combine flour, baking powder and salt in medium bowl; set aside. Melt butter in large saucepan over low heat; remove from heat. Stir in cocoa. Beat in brown sugar, sugar, eggs and vanilla. Stir in dry ingredients and walnuts. Spray or butter a 9-inch (23 cm) square pan. Spread batter in pan. Bake in preheated 350°F (180°C) oven for 40 minutes. Do not overbake. Cool completely.", + "Fudgey Icing", + "Melt butter over low heat in medium saucepan. Remove from heat. Stir in cocoa and vanilla. Stir in icing sugar and milk until smooth and of spreading consistency. Spread icing over cooled brownies." + ], + "category": "Desserts & Sweets", + "yields": "20 servings", + "description": "Fudgey brownies are every kid's favourite. These brownies make a decadent dessert and are a great recipe for any bake sale, potluck or birthday celebration.", + "total_time": 55, + "cook_time": 15, + "prep_time": 15, + "image": "https://eggs.ca/wp-content/uploads/2024/06/Fudgey-Brownies-UPDATED-CMS.jpg" +} diff --git a/tests/test_data/eggs.ca/eggsca_2.testhtml b/tests/test_data/eggs.ca/eggsca_2.testhtml new file mode 100644 index 000000000..4fce17787 --- /dev/null +++ b/tests/test_data/eggs.ca/eggsca_2.testhtml @@ -0,0 +1,330 @@ + + + + + + Fudgy Brownies | Eggs.ca + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    Recipes
    +

    Fudgy Brownies

    +
    + +
    Fudgey brownies are every kid's favourite. These brownies make a decadent dessert and are a great recipe for any bake sale, potluck or birthday celebration.
    +
    +
    Serves +20 +
    Prep Time +15 min +
    Cook Time +40 min +
    +
    +
    + + +
    +
    +

    Ingredients

    +
    • Brownies

      • 1 ¼ cup (315 mL) all-purpose flour
      • 1 tsp baking powder
      • ½ tsp (2.5 mL) salt
      • ¾ cup (175 mL) butter or margarine
      • ¾ cup (175 mL) unsweetened cocoa powder
      • 1 cup packed brown sugar
      • 1 cup granulated sugar
      • 4 eggs
      • 2 tsp vanilla extract
      • 1 cup chopped walnuts
    • Fudgey Icing

      • 2 tbsp butter or margarine
      • ¼ cup (60 mL) unsweetened cocoa powder
      • ½ tsp (2.5 mL) vanilla extract
      • 2 cups sifted icing sugar
      • ¼ cup (60 mL) milk (1%)
    +
    +

    Instructions

    +
    • Brownies

      • Step 1

        Preheat oven to 350°F (180°C).

        +
      • Step 2

        Combine flour, baking powder and salt in medium bowl; set aside. Melt butter in large saucepan over low heat; remove from heat. Stir in cocoa. Beat in brown sugar, sugar, eggs and vanilla. Stir in dry ingredients and walnuts. Spray or butter a 9-inch (23 cm) square pan. Spread batter in pan. Bake in preheated 350°F (180°C) oven for 40 minutes. Do not overbake. Cool completely.

        +
    • Fudgey Icing

      • Step 1

        Melt butter over low heat in medium saucepan. Remove from heat. Stir in cocoa and vanilla. Stir in icing sugar and milk until smooth and of spreading consistency. Spread icing over cooled brownies.

        +
    +
    +

    Nutrition Facts

    +
    + + + +
    Per serving
    Calories294
    Fat14 g
    Saturated Fat6 g
    Trans Fat0 g
    Carbohydrate294 g
    Fibre2 g
    Sugars33 g
    Protein5 g
    Sodium167 mg
    +
    +
    +
    +
    + + + + \ No newline at end of file From e0b8c6384bf71fbdfe9d09564b809008556185ea Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 7 Dec 2024 23:03:01 +0200 Subject: [PATCH 28/94] Fix broken tests as we remove double parentheses starting from #1407 --- tests/test_data/lanascooking.com/lanascooking_1.json | 2 +- .../themediterraneandish.com/themediterranedish_1.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_data/lanascooking.com/lanascooking_1.json b/tests/test_data/lanascooking.com/lanascooking_1.json index aa8637949..1584b13e5 100644 --- a/tests/test_data/lanascooking.com/lanascooking_1.json +++ b/tests/test_data/lanascooking.com/lanascooking_1.json @@ -9,7 +9,7 @@ "3 very ripe medium tomatoes", "1 cup mayonnaise", "1/2 shallot (finely minced)", - "40 saltine crackers ((1 sleeve))", + "40 saltine crackers (1 sleeve)", "2 tablespoons chives (finely chopped)", "Kosher salt and ground black pepper to taste" ], diff --git a/tests/test_data/themediterraneandish.com/themediterranedish_1.json b/tests/test_data/themediterraneandish.com/themediterranedish_1.json index a8682a12c..ebc700ace 100644 --- a/tests/test_data/themediterraneandish.com/themediterranedish_1.json +++ b/tests/test_data/themediterraneandish.com/themediterranedish_1.json @@ -7,7 +7,7 @@ "title": "Savory Yogurt Bowls", "ingredients": [ "1 cup Greek yogurt", - "1/2 cup cooked chickpeas ((cooked from scratch or drained and rinsed canned chickpeas), patted dry)", + "1/2 cup cooked chickpeas (cooked from scratch or drained and rinsed canned chickpeas), patted dry)", "2 hard boiled eggs, (grated)", "2 Persian cucumbers, (chopped)", "2 Roma tomatoes, (chopped)", From 8e8335f4280dbbcf4d0bf73e0e7364c5f00c0ecf Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:46:48 -0500 Subject: [PATCH 29/94] Adds additional coverages to 11 tests & removes 1 unneeded test key (#1424) --- tests/test_data/40aprons.com/fortyaprons_1.json | 2 +- tests/test_data/40aprons.com/fortyaprons_2.json | 5 +++++ .../ahealthysliceoflife.json | 2 ++ tests/test_data/aldi-nord.de/aldinord.json | 2 ++ tests/test_data/argiro.gr/argiro.json | 5 +++++ tests/test_data/eggs.ca/eggsca_1.json | 12 ++++++++++++ tests/test_data/eggs.ca/eggsca_2.json | 12 ++++++++++++ .../glutenfreeonashoestring_1.json | 1 - .../goodfooddiscoveries.json | 2 ++ .../madamecuisine.de/madamecuisine_1.json | 14 +++++++++++++- .../madamecuisine.de/madamecuisine_2.json | 17 ++++++++++++++++- tests/test_data/rewe.de/rewe.json | 13 ++++++++++++- 12 files changed, 82 insertions(+), 5 deletions(-) diff --git a/tests/test_data/40aprons.com/fortyaprons_1.json b/tests/test_data/40aprons.com/fortyaprons_1.json index 3bcb46694..5ae44003f 100644 --- a/tests/test_data/40aprons.com/fortyaprons_1.json +++ b/tests/test_data/40aprons.com/fortyaprons_1.json @@ -74,7 +74,7 @@ "prep_time": 10, "cuisine": "American", "ratings": 5.0, - "ratings_count": 1.0, + "ratings_count": 1, "equipment": [ "Small bowl", "Muddler", diff --git a/tests/test_data/40aprons.com/fortyaprons_2.json b/tests/test_data/40aprons.com/fortyaprons_2.json index 01c715e5a..84e114c30 100644 --- a/tests/test_data/40aprons.com/fortyaprons_2.json +++ b/tests/test_data/40aprons.com/fortyaprons_2.json @@ -26,6 +26,11 @@ "cook_time": 15, "prep_time": 5, "cuisine": "American", + "equipment": [ + "Large saucepan light-colored saucepan recommended", + "whisk", + "Pastry brush" + ], "nutrients": { "servingSize": "1 serving", "calories": "283 kcal", diff --git a/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json index aebc7e85e..d43c15787 100644 --- a/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json +++ b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json @@ -27,5 +27,7 @@ "Take off the lid, add spinach and lime juice and stir to combine. Serve over hot buttered rice." ], "description": "This nourishing curry recipe is perfect for when you need something comforting and delicious on the dinner table quickly!", + "ratings": 5.0, + "ratings_count": 1, "image": "https://www.ahealthysliceoflife.com/wp-content/uploads/2021/08/A-Healthy-Slice_Lentil-Curry-9-scaled-225x225.jpg" } diff --git a/tests/test_data/aldi-nord.de/aldinord.json b/tests/test_data/aldi-nord.de/aldinord.json index d62a73f10..d80024177 100644 --- a/tests/test_data/aldi-nord.de/aldinord.json +++ b/tests/test_data/aldi-nord.de/aldinord.json @@ -32,5 +32,7 @@ ], "yields": "2 servings", "total_time": 35, + "cook_time": 15, + "prep_time": 20, "image": "https://www.aldi-nord.de/content/dam/aldi/germany/rezepte/2024/ato/kw45/AN_Rezepte_KW49_Kaiserschmarrn_Stage_3840x1200.jpg/_jcr_content/renditions/original.transform/1817w/img.241101.jpg" } diff --git a/tests/test_data/argiro.gr/argiro.json b/tests/test_data/argiro.gr/argiro.json index 3d0881aa9..47a2f6767 100644 --- a/tests/test_data/argiro.gr/argiro.json +++ b/tests/test_data/argiro.gr/argiro.json @@ -54,5 +54,10 @@ "cook_time": 75, "prep_time": 30, "cuisine": "Ελληνική Κουζίνα", + "ratings": 5.0, + "ratings_count": 6418, + "nutrients": { + "calories": "468 Θερμίδες" + }, "image": "https://www.argiro.gr/wp-content/uploads/2023/08/gemista-400x400.jpg?v=1715951925" } diff --git a/tests/test_data/eggs.ca/eggsca_1.json b/tests/test_data/eggs.ca/eggsca_1.json index 10ded6c86..61fd01dac 100644 --- a/tests/test_data/eggs.ca/eggsca_1.json +++ b/tests/test_data/eggs.ca/eggsca_1.json @@ -23,5 +23,17 @@ "total_time": 50, "cook_time": 15, "prep_time": 15, + "nutrients": { + "calories": "441", + "fatContent": "38 g", + "saturatedFatContent": "22 g", + "transFatContent": "1 g", + "carbohydrateContent": "22 g", + "sugarContent": "19 g", + "proteinContent": "5 g", + "sodiumContent": "43 mg", + "fiberContent": "0 g", + "cholesterolContent": "0 mg" + }, "image": "https://eggs.ca/wp-content/uploads/2024/06/Creme-Brulee-1664x832-1.jpg" } diff --git a/tests/test_data/eggs.ca/eggsca_2.json b/tests/test_data/eggs.ca/eggsca_2.json index 878c90a82..d76e5b89d 100644 --- a/tests/test_data/eggs.ca/eggsca_2.json +++ b/tests/test_data/eggs.ca/eggsca_2.json @@ -62,5 +62,17 @@ "total_time": 55, "cook_time": 15, "prep_time": 15, + "nutrients": { + "calories": "294", + "fatContent": "14 g", + "saturatedFatContent": "6 g", + "transFatContent": "0 g", + "carbohydrateContent": "42 g", + "sugarContent": "33 g", + "proteinContent": "5 g", + "sodiumContent": "167 mg", + "fiberContent": "2 g", + "cholesterolContent": "2 mg" + }, "image": "https://eggs.ca/wp-content/uploads/2024/06/Fudgey-Brownies-UPDATED-CMS.jpg" } diff --git a/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json b/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json index c933ea7c6..f0fa60bf4 100644 --- a/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json +++ b/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json @@ -14,7 +14,6 @@ "1 tablespoon extra virgin olive oil (plus more for handling and brushing)", "Your favorite pizza toppings (sauce, shredded or sliced mozzarella cheese)" ], - "instructions": "To make the pizza dough.\nIn the bowl of your stand mixer fitted with the paddle attachment, place the flour, yeast, and sugar. Whisk to combine with a separate, handheld whisk. Add the salt, and whisk again to combine well.\nAdd the water and olive oil, and mix very slowly until the flour is absorbed into the liquid. The mixture will be lumpy\nRaise the mixer to medium-high speed in your stand mixer until the dough becomes sticky and smooth (about 3 minutes).\nOil a medium-size bowl, and scrape the pizza dough into the bowl.\nUsing very well-oiled hands, loosely shape the dough into a round.\nCover the bowl tightly with plastic and place in a draft-free location until nearly doubled in size. That will take longer in cool, dry environments and less time in warm, moist places.\nTo bake the pizza.\nWhen you’re ready to make the pizza, place a pizza stone or overturned rimmed baking sheet in the oven and preheat it to 450°F.\nPlace a 14-inch round nonstick pizza baking pan or a large piece of parchment paper in front of you on a flat surface\nThe dough will be super soft, and should only be handled once you’ve coated your hands in olive oil. Turn the dough out onto the center of the pan or paper.\nWorking from the center of the dough out to the edges, begin to press it into a round about 14-inches in diameter.\nCreate a smooth, slightly raised edge around the perimeter of the dough by pressing the edges with one hand toward the palm of your other.\nBrush the shaped dough with more oil, concentrating it on the edges.\nTransfer the shaped and topped dough, still on the pizza baking sheet or parchment paper, to a pizza peel or other flat surface like a cutting board, and transfer it to the hot oven.\nBake for 5 to 6 minutes, or until the crust seems set all the way to the center and the edges have expanded in size.\nRemove the pan from the oven, top the dough with sauce, cheese, and any other toppings you like best, and return the pizza on the pan or paper to the oven.\nBake until the has begun to crisp on the underside, is lightly brown on the edges, and the cheese is brown and bubbling (about 5 minutes).\nRemove from the oven, allow to set for just a few minutes, then slice and serve hot.", "instructions_list": [ "To make the pizza dough.", "In the bowl of your stand mixer fitted with the paddle attachment, place the flour, yeast, and sugar. Whisk to combine with a separate, handheld whisk. Add the salt, and whisk again to combine well.", diff --git a/tests/test_data/goodfooddiscoveries.com/goodfooddiscoveries.json b/tests/test_data/goodfooddiscoveries.com/goodfooddiscoveries.json index d18987620..ac4cafbd3 100644 --- a/tests/test_data/goodfooddiscoveries.com/goodfooddiscoveries.json +++ b/tests/test_data/goodfooddiscoveries.com/goodfooddiscoveries.json @@ -36,6 +36,8 @@ "cook_time": 25, "prep_time": 5, "cuisine": "Italian", + "ratings": 5.0, + "ratings_count": 1, "image": "https://goodfooddiscoveries.com/wp-content/uploads/2023/03/lemon-parmesan-risotto.jpeg", "keywords": [ "lemon", diff --git a/tests/test_data/madamecuisine.de/madamecuisine_1.json b/tests/test_data/madamecuisine.de/madamecuisine_1.json index 4646f6507..fb89fc05c 100644 --- a/tests/test_data/madamecuisine.de/madamecuisine_1.json +++ b/tests/test_data/madamecuisine.de/madamecuisine_1.json @@ -46,6 +46,18 @@ "yields": "4 servings", "description": "Dieser leckere Eintopf wird mit viel Gemüse, Bohnen, Gewürzen und Kräutern zubereitet. Die Gemüse-Sorten lassen sich - je nach Geschmack und Saison - beliebig variieren. Ein einfaches Essen, das sich wunderbar vorbereiten lässt und durchaus auch Gäste tauglich ist. ", "total_time": 60, + "cook_time": 40, + "prep_time": 20, "cuisine": "Amerikanisch, Deutsch", - "image": "https://www.madamecuisine.de/wp-content/uploads/2024/10/gemueseeintopf-mit-wintergemuese04.jpg" + "ratings": 5.0, + "ratings_count": 4, + "nutrients": { + "servingSize": "1 Portion", + "calories": "540 kcal" + }, + "image": "https://www.madamecuisine.de/wp-content/uploads/2024/10/gemueseeintopf-mit-wintergemuese04.jpg", + "keywords": [ + "Eintopf", + "Gemüseeintopf" + ] } diff --git a/tests/test_data/madamecuisine.de/madamecuisine_2.json b/tests/test_data/madamecuisine.de/madamecuisine_2.json index 97af5c1b7..b16afb6e2 100644 --- a/tests/test_data/madamecuisine.de/madamecuisine_2.json +++ b/tests/test_data/madamecuisine.de/madamecuisine_2.json @@ -35,6 +35,21 @@ "yields": "2 servings", "description": "Shakshuka, das sind versunkene Eier in einer Tomatensoße mit Paprika und Zwiebeln. Die Soße in einer Pfanne langsam einköcheln, dann die Eier im Ofen stocken lassen.", "total_time": 60, + "cook_time": 45, + "prep_time": 15, "cuisine": "Israelisch / Arabisch", - "image": "https://www.madamecuisine.de/wp-content/uploads/2019/11/shakshuka02-720x480.jpg" + "ratings": 4.64, + "ratings_count": 495, + "nutrients": { + "servingSize": "1 Portion", + "calories": "440 kcal" + }, + "image": "https://www.madamecuisine.de/wp-content/uploads/2019/11/shakshuka02-720x480.jpg", + "keywords": [ + "Paprika", + "Schakschuka", + "Shakshuka", + "Tomaten", + "Versunkene Eier" + ] } diff --git a/tests/test_data/rewe.de/rewe.json b/tests/test_data/rewe.de/rewe.json index ab5e5d8ba..3821029b6 100644 --- a/tests/test_data/rewe.de/rewe.json +++ b/tests/test_data/rewe.de/rewe.json @@ -38,5 +38,16 @@ "total_time": 45, "ratings": 4.63, "ratings_count": 35, - "image": "https://c.rewe-static.de/31535699/6/31535699.png" + "nutrients": { + "servingSize": "4 Portionen", + "calories": "677 kcal" + }, + "image": "https://c.rewe-static.de/31535699/6/31535699.png", + "keywords": [ + "Vegetarisch", + "Winter", + "Party", + "Dip", + "gesund" + ] } From 17d9c78ffd2236e3c49abbb29fd880a55b5e94c2 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Mon, 9 Dec 2024 17:17:57 -0500 Subject: [PATCH 30/94] Adds support for recipeland (#1403) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/recipeland.py | 55 + .../recipeland.com/recipeland_1.json | 45 + .../recipeland.com/recipeland_1.testhtml | 2874 +++++++++++++++++ .../recipeland.com/recipeland_2.json | 93 + .../recipeland.com/recipeland_2.testhtml | 2838 ++++++++++++++++ 7 files changed, 5908 insertions(+) create mode 100644 recipe_scrapers/recipeland.py create mode 100644 tests/test_data/recipeland.com/recipeland_1.json create mode 100644 tests/test_data/recipeland.com/recipeland_1.testhtml create mode 100644 tests/test_data/recipeland.com/recipeland_2.json create mode 100644 tests/test_data/recipeland.com/recipeland_2.testhtml diff --git a/README.rst b/README.rst index 1ecf0ae67..74aff352e 100644 --- a/README.rst +++ b/README.rst @@ -378,6 +378,7 @@ Scrapers available for: - `https://receptyprevas.sk/ `_ - `https://recette.plus/ `_ - `https://www.recipegirl.com/ `_ +- `https://recipeland.com/ `_ - `https://reciperunner.com/ `_ - `https://recipes.farmhousedelivery.com/ `_ - `https://recipes.timesofindia.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 53b0d2dcf..80bcbfbc8 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -326,6 +326,7 @@ from .receptyprevas import ReceptyPreVas from .recetteplus import RecettePlus from .recipegirl import RecipeGirl +from .recipeland import RecipeLand from .reciperunner import RecipeRunner from .recipetineats import RecipeTinEats from .redhousespice import RedHouseSpice @@ -595,6 +596,7 @@ RecettePlus.host(): RecettePlus, RecipeGirl.host(): RecipeGirl, Rewe.host(): Rewe, + RecipeLand.host(): RecipeLand, RicettePerBimby.host(): RicettePerBimby, SandwhichTribunal.host(): SandwhichTribunal, SavoryNothings.host(): SavoryNothings, diff --git a/recipe_scrapers/recipeland.py b/recipe_scrapers/recipeland.py new file mode 100644 index 000000000..a5f4504e3 --- /dev/null +++ b/recipe_scrapers/recipeland.py @@ -0,0 +1,55 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import IngredientGroup +from ._utils import normalize_string + + +class RecipeLand(AbstractScraper): + @classmethod + def host(cls): + return "recipeland.com" + + def _parse_ingredient_row(self, row): + amount = row.select_one(".amount") and row.select_one(".amount").get_text() + measure = row.select_one(".measure") and row.select_one(".measure").get_text() + ingredient_elem = row.select_one(".ingred") + ingredient = ingredient_elem and ingredient_elem.get_text() + + full_ingredient = f"{amount} {measure} {ingredient}" + return normalize_string(full_ingredient) + + def ingredients(self): + ingredient_rows = self.soup.select("#ingredient_list tbody tr") + return [ + self._parse_ingredient_row(row) + for row in ingredient_rows + if not row.select_one("th.i-head") + ] + + def ingredient_groups(self): + ingredient_rows = self.soup.select("#ingredient_list tbody tr") + groups = [] + current_group = None + grouped_ingredients = [] + + for row in ingredient_rows: + group_header = row.select_one("th.i-head") + if group_header: + if current_group or grouped_ingredients: + groups.append( + IngredientGroup( + ingredients=grouped_ingredients, purpose=current_group + ) + ) + current_group = group_header.get_text(strip=True) + grouped_ingredients = [] + else: + full_ingredient = self._parse_ingredient_row(row) + if full_ingredient: + grouped_ingredients.append(full_ingredient) + + if current_group or grouped_ingredients: + groups.append( + IngredientGroup(ingredients=grouped_ingredients, purpose=current_group) + ) + + return groups diff --git a/tests/test_data/recipeland.com/recipeland_1.json b/tests/test_data/recipeland.com/recipeland_1.json new file mode 100644 index 000000000..5ac107c91 --- /dev/null +++ b/tests/test_data/recipeland.com/recipeland_1.json @@ -0,0 +1,45 @@ +{ + "author": "L-monti @ Recipeland", + "canonical_url": "https://recipeland.com/recipe/v/peanut-butter-pretzel-cookies-52124", + "site_name": "RecipeLand.com", + "host": "recipeland.com", + "language": "en", + "title": "Peanut Butter Pretzel Cookies", + "ingredients": [ + "1 ½ cups all-purpose flour", + "1 teaspoon baking soda", + "1 stick butter room temp.", + "½ stick butter flavored crisco", + "1 1/4 cup sugar", + "1 cup peanut butter", + "2 large eggs room temp.", + "6 cups pretzels crushed" + ], + "instructions_list": [ + "Preheat oven to 350℉ (180℃).", + "In a bowl, whisk together flour and baking soda.", + "In a large bowl, beat the butter, sugar, and peanut butter on medium speed, about five minutes.", + "Add the eggs, one at a time, beating between each addition.", + "Gradually add the flour mixture, beating just until combined.", + "Place crushed pretzels in a bowl.", + "Using a medium-sized cookie scoop, make balls of dough and drop them into the crushed pretzels, and coat.", + "Bake cookie for 10 to 15 minutes or until golden brown but soft to the touch." + ], + "yields": "30 servings", + "description": "Perfect mix of sweet and salty! Pretzels add crunch and bring out the peanutty flavor of the peanut butter.", + "total_time": 60, + "cook_time": 30, + "prep_time": 30, + "cuisine": "Fusion", + "ratings": 3.8, + "ratings_count": 153, + "nutrients": { + "calories": "150 calories" + }, + "image": "https://recipeland.com/images/r/3328/b0ba99dd45cba4e36ffe_1024.jpg", + "keywords": [ + "Cookies", + "Peanut Butter", + "Sweets" + ] +} diff --git a/tests/test_data/recipeland.com/recipeland_1.testhtml b/tests/test_data/recipeland.com/recipeland_1.testhtml new file mode 100644 index 000000000..8defa155d --- /dev/null +++ b/tests/test_data/recipeland.com/recipeland_1.testhtml @@ -0,0 +1,2874 @@ + + + + + + + + + + + + + + + + +Peanut Butter Pretzel Cookies Recipe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    + + +
    +
    +
    + + Search + +
    +
    +
    + + + by Ingredient
    +
    +
    +
    + +
    + + +
    +
    +
    +
    + + +
    +
    + +
    +
    + + + + + + + +
    +
    + +
    + + +
    + + + + +
    +
    + + + +
    + +
    + +
    +
    +

    Peanut Butter Pretzel Cookies

    +
    + + + + + + + + + + + +
    +
    StarStarStarHalf starEmpty star
    +
    +

    Your rating

    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    + +
    + + +
    + Peanut Butter Pretzel Cookies +
    + + + + +
    + + +
    +
    + L-monti - home chef
    +

    Perfect mix of sweet and salty! Pretzels add crunch and bring out the peanutty flavor of the peanut butter.

    +
     
    + +
    + + +
    +
    +
    +

    Yield

    + 30 + servings +
    +
    +

    Prep

    + 30 + min +
    +
    +

    Cook

    + 30 + min +
    +
    +

    Ready

    + 1 + hrs +
    +
    + +
    Trans-fat Free, Low Sodium
    +
    + + +
    +

    Ingredients

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AmountMeasureIngredientFeatures
    1 ½cups +all-purpose flour +
    +
    + + Camera +
    1teaspoon +baking soda +
    +
    + + Camera +
    1stick +butter +
    room temp. +
    + + Camera +
    ½stick +butter +
    flavored crisco +
    + + Camera +
    1 1/4 cup +sugar +
    +
    + + Camera +
    1cup +peanut butter +
    +
    + + Camera +
    2large +eggs +
    room temp. +
    + + Camera +
    6cups +pretzels +
    crushed +
    +* + +
    +
    +
    +

    Ingredients

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AmountMeasureIngredientFeatures
    + 355 + ml + all-purpose flour +
    +
    + + Camera +
    + 5 + ml + baking soda +
    +
    + + Camera +
    + 113 + g + butter +
    room temp. +
    + + Camera +
    + 56.5 + g + butter +
    flavored crisco +
    + + Camera +
    + 296 + ml + sugar +
    +
    + + Camera +
    + 237 + ml + peanut butter +
    +
    + + Camera +
    + 2 + large + eggs +
    room temp. +
    + + Camera +
    + 1.4 + l + pretzels +
    crushed +
    + * +
    +
    +
    + + +
    + + + + +
    +
    +

    Directions

    +

    Preheat oven to 350℉ (180℃).

    + +

    In a bowl, whisk together flour and baking soda.

    + +

    In a large bowl, beat the butter, sugar, and peanut butter on medium speed, about five minutes.

    + +

    Add the eggs, one at a time, beating between each addition.

    + +

    Gradually add the flour mixture, beating just until combined.

    + +

    Place crushed pretzels in a bowl.

    + +

    Using a medium-sized cookie scoop, make balls of dough and drop them into the crushed pretzels, and coat.

    + +

    Bake cookie for 10 to 15 minutes or until golden brown but soft to the touch.

    +
    +
    + + + + +
    + +
    + +
    + +
    + + +
    + + + +
    + * not incl. in nutrient facts + + Arrow up button +
    + +
    +

    Comments

    +
    +
    +
    +
    + recipeUser + + +
    +
    +

    Great recipe, thanks :)

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + recipeUser + + +
    +
    +

    Great recipe, thanks :)

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + anonymous + + +
    +
    +

    Could I use powdered sugar instead of regular sugar? I have a texture problem with regular sugar.

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + railrecipe + + +
    +
    +

    Peanut is always good for health. Your recipe of Peanut Butter Pretzel Cookies is nice. +
    https://www.railrecipe.com

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + Barth deRosa + + +
    +
    +

    Could I use backing powder instead of baking soda for this peanut butter pretzel cookies ? +

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + GF weir + + +
    +
    +

    Looks great . I will be making them.

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + Pinkerstar + + +
    +
    +

    Great recipe, thank you so much

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + anonymous + + +
    +
    +

    I took this recipe one step further, I melted some chocolate and poured over the tops of them.... When cookies have cooled I set them out on a large sheet of parchment paper,.. melted Hershey's Kisses in the Microwave and covered the tops of them, they came out great

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + Box lunches seattle + + +
    +
    +

    Discover the best meal kit from Box-lunches.com - fresh, delicious, and nutritious ingredients delivered right to your door. Enjoy the convenience of home-cooked meals without the hassle of grocery shopping.

    + +

    https://box-lunches.com/box-meals

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + MenuValley + + +
    +
    +

    recipe is good for startups, and its test must be delicious. Let me know who is the lover of fast food like https://jackintheboxmenuprices.us/

    +
    + + +
    + Reply + +
    +
    +
    +
    + +
    + +

     

    + +
    +
    +

     

    +
    + +
    + +
    +
    +
    +
    + + + +
    + + + + + + +
    + + + + + +
    +

    Nutrition Facts

    +Serving Size 32g (1.1 oz) +
    +
    Amount per Serving
    +
    +Calories 15056% from fat +
    +
     % Daily Value *
    +
    +Total Fat 9g +14% +
    +
    +Saturated Fat 4g +20% +
    +
    +Trans Fat +0g +
    +
    +Cholesterol 26mg +9% +
    +
    +Sodium 95mg +4% +
    +
    +Total Carbohydrate +5g +5% +
    +
    +Dietary Fiber 1g +3% +
    +
    +Sugars g +
    +
    +Protein +7g +
    +
    +
    +Vitamin A 3% + +Vitamin C 0% +
    +
    +Calcium 1% + +Iron 3% +
    +
    +* based on a 2,000 calorie diet +How is this calculated? +
    +
    +
    + + + +
    + + + + + + +
    + + +
    + +
    + +
    +
     
    + + + + + + +
    +

    Email this recipe

    +
    +

    +
    +
    + +
    +
    + +
    + + + + + +
    +
    + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    +
    + Recipes by Recipeland logo +
    +
    + + +
    +
    + +
    +
    +

    About

    + +
    + +

    Founded in 1996, years before Google and the term blogger existed, RecipeLand.com™ was created to answer an elusive question faced by home cooks everywhere.

    + + Sean and Zhangbo Wenzel, Founders RecipeLand.com +

    What recipes can I make with these ingredients?

    + +

    Tired of buying ingredients for new recipes every time you cook? Imagine if you could type what ingredients you have into a recipe finder, and it would only show you recipes based on what you already have. No more wasted food, save time, save money.

    +

    Now you too can find recipes by ingredients and save your favorites in your own recipe box.

    +

    Fast-forward 28 years and Recipeland™ is a family affair, exclusively run by Sean, Zhangbo, and their daughter Keira.

    + +

    Save time

    + +

    RecipeLand, stands out from other recipe websites, many of which have been acquired by large corporations and turned into clickbait machines. Instead of bombarding you with endless scrolling before you get to recipes, you will find the tools you need to easily search and find the exact recipe you're looking for. Our goal is to make your recipe search process as efficient and enjoyable as possible.

    +

    Family owned and operated we are kept busy testing recipes in the RecipeLand.com kitchen and shooting photographs of the final main dish in the RecipeLand.com studio.

    +
    +
    + + +
    + +
    +
    +

    56,025

    + recipes +
    +
    +

    400+

    + collections  +
    +
    +

    152K

    + members +
    +
    +
    +
    +

    Send feedback

    +

    Tell us what you like, what you would like to see, bug reports and support questions are all welcome!

    +
    +
    + +
    +
    + +
    + +
    +
    + +
    + ©1996-2024 Sean Wenzel & Infinite Networks Inc. + All rights reserved. + Legal Privacy
    +
    +
    + + + + + + + diff --git a/tests/test_data/recipeland.com/recipeland_2.json b/tests/test_data/recipeland.com/recipeland_2.json new file mode 100644 index 000000000..0ddfe2ee3 --- /dev/null +++ b/tests/test_data/recipeland.com/recipeland_2.json @@ -0,0 +1,93 @@ +{ + "author": "RecipeLand", + "canonical_url": "https://recipeland.com/recipe/v/ropa-vieja-43426", + "site_name": "RecipeLand.com", + "host": "recipeland.com", + "language": "en", + "title": "Ropa Vieja", + "ingredients": [ + "2 pounds beef, flank steak (london broil)", + "1 each bay leaves", + "1 small onions", + "1 whole tomatoes ripe", + "1 each celery stalks", + "1 tablespoon salt", + "1 ¼ cups olive oil", + "½ each green bell peppers finely chopped", + "2 each garlic cloves minced", + "1 each bay leaves", + "½ teaspoon oregano", + "¼ teaspoon cumin", + "10 ½ ounces tomato sauce", + "¼ teaspoon sugar", + "1 tablespoon white wine vinegar", + "½ cup stock from cooked meat", + "1 teaspoon salt", + "¼ cup wine burgandy" + ], + "ingredient_groups": [ + { + "ingredients": [ + "2 pounds beef, flank steak (london broil)", + "1 each bay leaves", + "1 small onions", + "1 whole tomatoes ripe", + "1 each celery stalks", + "1 tablespoon salt" + ], + "purpose": null + }, + { + "ingredients": [ + "1 ¼ cups olive oil", + "½ each green bell peppers finely chopped", + "2 each garlic cloves minced", + "1 each bay leaves", + "½ teaspoon oregano", + "¼ teaspoon cumin", + "10 ½ ounces tomato sauce", + "¼ teaspoon sugar", + "1 tablespoon white wine vinegar", + "½ cup stock from cooked meat", + "1 teaspoon salt", + "¼ cup wine burgandy" + ], + "purpose": "Tomato sauce for ropa vieja" + } + ], + "instructions_list": [ + "In a suitable soup kettle, place the meat, bay leaf, whole onion, tomato, celery rib cut in half, and the salt.", + "Cover with cold water and bring to a rapid boil.", + "Skim several times.", + "Lower heat and cook until meat is tender (approximately 1 hour).", + "Allow meat to cool in stock, then remove to platter and shred.", + "Strain stock and reserve to be used in sauce and the rest for a hearty soup.", + "TOMATO SAUCE FOR ROPA VIEJA: Heat oil in large skillet.", + "Add onion and green pepper and sauté until transparent.", + "Add the garlic, bay leaf, oregano, cumin, and cook 5 minutes longer.", + "Combine tomato sauce, sugar, vinegar, stock, salt, and wine.", + "Add to sauté.", + "Stir to mix well and bring to a boil.", + "Lower heat and cook for approximately 30 minutes, stirring at intervals.", + "In a 2½ quart casserole with cover, place the shredded meat.", + "Pour sauce over the meat and mix well.", + "Cover and simmer for another 20 to 30 minutes, stirring occasionally.", + "Serve over white rice accompanied by very ripe fried plantains, when available." + ], + "category": "Main Dish", + "yields": "6 servings", + "total_time": 150, + "cook_time": 130, + "prep_time": 20, + "cuisine": "Fusion", + "ratings": 5.0, + "ratings_count": 2, + "nutrients": { + "calories": "650 calories" + }, + "image": "https://recipeland.com/images/r/9821/d89290e8de19f5bf9da3_1024.jpg", + "keywords": [ + "Rice", + "Meats" + ] +} diff --git a/tests/test_data/recipeland.com/recipeland_2.testhtml b/tests/test_data/recipeland.com/recipeland_2.testhtml new file mode 100644 index 000000000..c9e32fee4 --- /dev/null +++ b/tests/test_data/recipeland.com/recipeland_2.testhtml @@ -0,0 +1,2838 @@ + + + + + + + + + + + + + + + + + +Ropa Vieja Recipe | RecipeLand + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    + + +
    +
    +
    + + Search + +
    +
    +
    + + + by Ingredient
    +
    +
    +
    + +
    + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + + + + + + +
    +
    + +
    + + +
    + + + + +
    +
    + + + +
    + +
    + +
    +
    +

    Ropa Vieja

    +
    + + + + + + + + + + + +
    +
    StarStarStarStarStar
    +
    +

    Your rating

    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    + +
    + + +
    + Ropa Vieja +
    + + + + +
    + + +
    +
    + Ashley1234 - home chef
    +

    +
     
    +
    + + +
    +
    +
    +

    Yield

    + 6 + servings +
    +
    +

    Prep

    + 20 + min +
    +
    +

    Cook

    + 130 + min +
    +
    +

    Ready

    + 150 + min +
    +
    + +
    Trans-fat Free, Low Carb
    +
    + + +
    +

    Ingredients

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AmountMeasureIngredientFeatures
    2pounds +beef, flank steak (london broil) +
    +
    + + Camera +
    1each +bay leaves +
    +
    +* + Camera +
    1small +onions +
    +
    + + Camera +
    1whole +tomatoes +
    ripe +
    +* + Camera +
    1each +celery stalks +
    +
    + + Camera +
    1tablespoon +salt +
    +
    + + Camera +
    + Tomato sauce for ropa vieja +
    1 ¼cups +olive oil +
    +
    + + Camera +
    ½each +green bell peppers +
    finely chopped +
    + + Camera +
    2each +garlic cloves +
    minced +
    + + Camera +
    1each +bay leaves +
    +
    +* + Camera +
    ½teaspoon +oregano +
    +
    + + Camera +
    ¼teaspoon +cumin +
    +
    + + Camera +
    10 ½ounces +tomato sauce +
    +
    + + Camera +
    ¼teaspoon +sugar +
    +
    + + Camera +
    1tablespoon +white wine vinegar +
    +
    + + Camera +
    ½cup +stock +
    from cooked meat +
    + + Camera +
    1teaspoon +salt +
    +
    + + Camera +
    ¼cup +wine +
    burgandy +
    +* + Camera +
    +
    +
    +

    Ingredients

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AmountMeasureIngredientFeatures
    + 907.2 + g + beef, flank steak (london broil) +
    +
    + + Camera +
    + 1 + each + bay leaves +
    +
    + * + Camera +
    + 1 + small + onions +
    +
    + + Camera +
    + 1 + whole + tomatoes +
    ripe +
    + * + Camera +
    + 1 + each + celery stalks +
    +
    + + Camera +
    + 15 + ml + salt +
    +
    + + Camera +
    + Tomato sauce for ropa vieja +
    + 296 + ml + olive oil +
    +
    + + Camera +
    + 0.5 + each + green bell peppers +
    finely chopped +
    + + Camera +
    + 2 + each + garlic cloves +
    minced +
    + + Camera +
    + 1 + each + bay leaves +
    +
    + * + Camera +
    + 2.5 + ml + oregano +
    +
    + + Camera +
    + 1.3 + ml + cumin +
    +
    + + Camera +
    + 303.5 + ml/g + tomato sauce +
    +
    + + Camera +
    + 1.3 + ml + sugar +
    +
    + + Camera +
    + 15 + ml + white wine vinegar +
    +
    + + Camera +
    + 118 + ml + stock +
    from cooked meat +
    + + Camera +
    + 5 + ml + salt +
    +
    + + Camera +
    + 59 + ml + wine +
    burgandy +
    + * + Camera +
    +
    +
    + + +
    + + + + +
    +
    +

    Directions

    +

    In a suitable soup kettle, place the meat, bay leaf, whole onion, tomato, celery rib cut in half, and the salt.

    + +

    Cover with cold water and bring to a rapid boil.

    + +

    Skim several times.

    + +

    Lower heat and cook until meat is tender (approximately 1 hour).

    + +

    Allow meat to cool in stock, then remove to platter and shred.

    + +

    Strain stock and reserve to be used in sauce and the rest for a hearty soup.

    + +

    TOMATO SAUCE FOR ROPA VIEJA: Heat oil in large skillet.

    + +

    Add onion and green pepper and sauté until transparent.

    + +

    Add the garlic, bay leaf, oregano, cumin, and cook 5 minutes longer.

    + +

    Combine tomato sauce, sugar, vinegar, stock, salt, and wine.

    + +

    Add to sauté.

    + +

    Stir to mix well and bring to a boil.

    + +

    Lower heat and cook for approximately 30 minutes, stirring at intervals.

    + +

    In a 2½ quart casserole with cover, place the shredded meat.

    + +

    Pour sauce over the meat and mix well.

    + +

    Cover and simmer for another 20 to 30 minutes, stirring occasionally.

    + +

    Serve over white rice accompanied by very ripe fried plantains, when available.

    +
    +
    + + + + +
    + +
    + +
    + +
    + + +
    + + + +
    + * not incl. in nutrient facts + + Arrow up button +
    + +
    +

    Comments

    +
    +
    + +
    + +

     

    + +
    +
    +

     

    +
    + +
    + +
    +
    +
    +
    + + + +
    + + + + + + +
    + + + + + +
    +

    Nutrition Facts

    +Serving Size 307g (10.8 oz) +
    +
    Amount per Serving
    +
    +Calories 65074% from fat +
    +
     % Daily Value *
    +
    +Total Fat 54g +83% +
    +
    +Saturated Fat 9g +47% +
    +
    +Trans Fat +0g +
    +
    +Cholesterol 51mg +17% +
    +
    +Sodium 1681mg +70% +
    +
    +Total Carbohydrate +3g +3% +
    +
    +Dietary Fiber 1g +5% +
    +
    +Sugars g +
    +
    +Protein +69g +
    +
    +
    +Vitamin A 5% + +Vitamin C 28% +
    +
    +Calcium 6% + +Iron 18% +
    +
    +* based on a 2,000 calorie diet +How is this calculated? +
    +
    +
    + + + +
    + + + + + + +
    + +
    +
    +
    + +
    + +
    +
     
    + + + + + + +
    +

    Email this recipe

    +
    +

    +
    +
    + +
    +
    + +
    + + + + + +
    +
    + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    +
    + Recipes by Recipeland logo +
    +
    + + +
    +
    + +
    +
    +

    About

    + +
    + +

    Founded in 1996, years before Google and the term blogger existed, RecipeLand.com™ was created to answer an elusive question faced by home cooks everywhere.

    + + Sean and Zhangbo Wenzel, Founders RecipeLand.com +

    What recipes can I make with these ingredients?

    + +

    Tired of buying ingredients for new recipes every time you cook? Imagine if you could type what ingredients you have into a recipe finder, and it would only show you recipes based on what you already have. No more wasted food, save time, save money.

    +

    Now you too can find recipes by ingredients and save your favorites in your own recipe box.

    +

    Fast-forward 28 years and Recipeland™ is a family affair, exclusively run by Sean, Zhangbo, and their daughter Keira.

    + +

    Save time

    + +

    RecipeLand, stands out from other recipe websites, many of which have been acquired by large corporations and turned into clickbait machines. Instead of bombarding you with endless scrolling before you get to recipes, you will find the tools you need to easily search and find the exact recipe you're looking for. Our goal is to make your recipe search process as efficient and enjoyable as possible.

    +

    Family owned and operated we are kept busy testing recipes in the RecipeLand.com kitchen and shooting photographs of the final main dish in the RecipeLand.com studio.

    +
    +
    + + +
    + +
    +
    +

    56,029

    + recipes +
    +
    +

    400+

    + collections  +
    +
    +

    152K

    + members +
    +
    +
    +
    +

    Send feedback

    +

    Tell us what you like, what you would like to see, bug reports and support questions are all welcome!

    +
    +
    + +
    +
    + +
    + +
    +
    + +
    + ©1996-2024 Sean Wenzel & Infinite Networks Inc. + All rights reserved. + Legal Privacy
    +
    +
    + + + + + + + From d8defcd7d1a4147b297a6e3a8d96cad392800259 Mon Sep 17 00:00:00 2001 From: Brian Strauch Date: Tue, 10 Dec 2024 20:17:26 -0800 Subject: [PATCH 31/94] Add noracooks.com (#1427) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/noracooks.py | 40 + tests/test_data/noracooks.com/noracooks.json | 66 ++ .../noracooks.com/noracooks.testhtml | 827 ++++++++++++++++++ 5 files changed, 936 insertions(+) create mode 100644 recipe_scrapers/noracooks.py create mode 100644 tests/test_data/noracooks.com/noracooks.json create mode 100644 tests/test_data/noracooks.com/noracooks.testhtml diff --git a/README.rst b/README.rst index 74aff352e..f8581a171 100644 --- a/README.rst +++ b/README.rst @@ -333,6 +333,7 @@ Scrapers available for: - `https://myvegetarianroots.com/ `_ - `https://www.nhs.uk/healthier-families/ `_ - `https://nibbledish.com/ `_ +- `https://noracooks.com/ `_ - `https://norecipes.com/ `_ - `https://nosalty.hu/ `_ - `https://www.notenoughcinnamon.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 80bcbfbc8..05ebcfdc9 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -280,6 +280,7 @@ from .nhshealthierfamilies import NHSHealthierFamilies from .nibbledish import NibbleDish from .nihhealthyeating import NIHHealthyEating +from .noracooks import NoraCooks from .norecipes import NoRecipes from .nosalty import NoSalty from .notenoughcinnamon import NotEnoughCinnamon @@ -583,6 +584,7 @@ MyJewishLearning.host(): MyJewishLearning, MyKoreanKitchen.host(): MyKoreanKitchen, MyVegetarianRoots.host(): MyVegetarianRoots, + NoraCooks.host(): NoraCooks, NotEnoughCinnamon.host(): NotEnoughCinnamon, NutritionFacts.host(): NutritionFacts, OneSweetAppetite.host(): OneSweetAppetite, diff --git a/recipe_scrapers/noracooks.py b/recipe_scrapers/noracooks.py new file mode 100644 index 000000000..d2b46301c --- /dev/null +++ b/recipe_scrapers/noracooks.py @@ -0,0 +1,40 @@ +from ._abstract import AbstractScraper + + +class NoraCooks(AbstractScraper): + @classmethod + def host(cls): + return "noracooks.com" + + def author(self): + return self.schema.author() + + def title(self): + return self.schema.title() + + def category(self): + return self.schema.category() + + def total_time(self): + return self.schema.total_time() + + def yields(self): + return self.schema.yields() + + def image(self): + return self.schema.image() + + def ingredients(self): + return self.schema.ingredients() + + def instructions(self): + return self.schema.instructions() + + def ratings(self): + return self.schema.ratings() + + def cuisine(self): + return self.schema.cuisine() + + def description(self): + return self.schema.description() diff --git a/tests/test_data/noracooks.com/noracooks.json b/tests/test_data/noracooks.com/noracooks.json new file mode 100644 index 000000000..51a082d7e --- /dev/null +++ b/tests/test_data/noracooks.com/noracooks.json @@ -0,0 +1,66 @@ +{ + "author": "Nora", + "canonical_url": "https://www.noracooks.com/vegan-chocolate-cake/", + "site_name": "Nora Cooks", + "host": "noracooks.com", + "language": "en-US", + "title": "The Best Vegan Chocolate Cake", + "ingredients": [ + "1 cup unsweetened almond milk", + "1 tablespoon apple cider vinegar", + "2 cups all purpose flour", + "1 3/4 cups granulated sugar", + "3/4 cup cocoa powder", + "2 teaspoons baking powder", + "1 1/2 teaspoons baking soda", + "1 teaspoon salt", + "1/2 cup canola oil OR melted coconut oil", + "2/3 cup unsweetened applesauce", + "1 tablespoon pure vanilla extract", + "1 cup boiling water", + "1 cup cocoa powder", + "1 1/2 cups vegan butter, softened (baking sticks preferred)", + "4-5 cups powdered sugar", + "2 teaspoons pure vanilla extract", + "1/4-1/2 cup unsweetened almond milk" + ], + "instructions_list": [ + "For the Chocolate Cake", + "Preheat oven to 350 degrees F and grease two 9-inch cake pans. I also line them with parchment rounds and lightly flour for easy removal of the cakes later.", + "Measure 1 cup unsweetened almond milk and add the tablespoon of vinegar to it. Stir slightly and set aside to curdle.", + "In a large bowl, add the flour, sugar, cocoa powder, baking powder, baking soda and salt. Whisk well to combine.", + "Now add the oil, applesauce, vanilla and almond milk/vinegar mixture. Mix on medium speed with a hand mixer (or stand mixer with the paddle attachment) until well combined.", + "Lower the speed and carefully pour in the boiling water, continuing to mix into the cake batter until combined. The batter will seem very runny at this point; that is how it should be, trust me!", + "Divide the batter evenly between your cake pans. Bake for 30-35 minutes, or until a toothpick inserted in the center comes out clean. After 10 minutes of cooling in the pan, carefully remove the cakes from the pans and let cool completely before frosting.", + "For the Chocolate Buttercream Frosting", + "Add the cocoa powder to a large bowl (I just wipe out the cake bowl and use it for the frosting). Whisk well to remove any clumps.", + "Add the softened vegan butter and mix with a hand mixer until creamed and well combined.", + "Add half of the powdered sugar and half of the almond milk, and mix until combined. Add the rest of the powdered sugar and vanilla extract. Mix starting on low, and turn to high. Mix until fluffy and combined.", + "If the frosting seems too dry, add more milk, a tablespoon or two at a time. If the frosting seems too wet and doesn't hold it's shape, add more powdered sugar until it thickens up.", + "Frost the cake using an icing spatula or just a butter knife." + ], + "category": "Dessert", + "yields": "16 servings", + "description": "The Best Vegan Chocolate Cake- A quick and easy recipe, made in 1 bowl! This really is the best chocolate cake ever, vegan or otherwise. It's super moist, rich and full of chocolate.", + "total_time": 55, + "cook_time": 35, + "prep_time": 20, + "cuisine": "American", + "ratings": 4.96, + "ratings_count": 1806, + "nutrients": { + "servingSize": "1 serving", + "calories": "496 kcal", + "fatContent": "25 g", + "saturatedFatContent": "4 g", + "carbohydrateContent": "71 g", + "sugarContent": "53 g", + "proteinContent": "4 g", + "sodiumContent": "408 mg", + "fiberContent": "4 g" + }, + "image": "https://www.noracooks.com/wp-content/uploads/2018/07/IMG_8885.jpg", + "keywords": [ + "vegan chocolate cake" + ] +} diff --git a/tests/test_data/noracooks.com/noracooks.testhtml b/tests/test_data/noracooks.com/noracooks.testhtml new file mode 100644 index 000000000..cb0cc1972 --- /dev/null +++ b/tests/test_data/noracooks.com/noracooks.testhtml @@ -0,0 +1,827 @@ + + + + + + + + + + + + + + + + + + + + + + + + + The Best Vegan Chocolate Cake - Nora Cooks + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    The Best Vegan Chocolate Cake

    PublishedJul 26, 2018

    Updated Feb 07, 2024

    4.96 stars (1806 ratings)
    Jump to Recipe

    This post may contain affiliate links. Read my full disclosure here.

    +

    The Best Vegan Chocolate Cake- A quick and easy recipe, made in 1 bowl! This really is the best chocolate cake ever, vegan or otherwise. It’s super moist, rich and full of chocolate. 

    +

    slice of vegan chocolate cake on a plate

    +

    My birthday was a few weeks ago, so what did I do? I asked my mom to watch all 3 kids for a few hours so I could create and photograph the BEST EVER Vegan Chocolate Cake. Pretty great birthday if you ask me! 😉

    +

    For some reason, every time I get a vegan piece of cake out (such as at Whole Foods or elsewhere), I am disappointed. The frosting is usually yummy, but the cake part is either 1. strange tasting OR 2. super dry, not moist at all. Seriously disappointing.

    +

    I’ve also made a few of the vegan chocolate cake recipes out there, but even those weren’t quite moist enough or perfect enough for my taste. So I did a little thinking and experimenting and I finally came up with the best, most perfectly moist and delicious vegan chocolate cake recipe!

    +

    vegan chocolate cake with a slice taken out of it

    +

    The frosting is a mouthwatering, ultra rich chocolate buttercream. I recommend using earth balance vegan buttery sticks, I haven’t found another brand that tastes quite as good.

    +

    If you are looking for a lighter alternative, check out this Chocolate Cake with Cashew Vanilla Frosting. There is nothing “light” about this Chocolate Cake! It is a full on indulgent recipe. And I’m okay with that.

    +

     

    +

     

    +

    vegan chocolate frosting in a bowl with a whisk

    +

    What is the secret to a super moist vegan chocolate cake?

    +

    A couple of things make this cake super moist. The applesauce helps (don’t worry, you can’t taste it). But the BIG secret is to add a cup of boiling hot water to the cake batter right before baking. It makes such a difference!

    +

    The batter will appear runny when you add it, but don’t worry, that is completely correct and exactly what it should be like. It results in the most moist, delicious chocolate cake I’ve ever tasted!

    +

    vegan chocolate cake frosted close up

    +

    If you are craving a chocolate fix about now, or are new to being vegan and miss good tasting cake, give this recipe a try! It’s easy to make and hard to mess it up.

    +

    OR if you are wanting to try something other than chocolate, give this Vegan Lemon Cake a go! It’s one of my most popular dessert recipes, and impresses people every time I make it.

    +

    slice of vegan chocolate cake with a fork taking a bite.

    +

    Sign-up to get new recipes by email and receive a FREE 5 Day Family Friendly Vegan Meal Plan! SUBSCRIBE NOW.

    +

    Recipe inspired by Add A Pinch.

    +
    +
    slice of vegan chocolate cake with a fork taking a bite.
    +
    4.96 stars (1806 ratings)
    +

    The Best Vegan Chocolate Cake

    +
    The Best Vegan Chocolate Cake- A quick and easy recipe, made in 1 bowl! This really is the best chocolate cake ever, vegan or otherwise. It's super moist, rich and full of chocolate. 
    +
    Prep: 20 minutes
    Cook: 35 minutes
    Total: 55 minutes
    Servings: 16 servings
    +
    + + +

    Ingredients 
     

    Chocolate Cake

    • 1 cup unsweetened almond milk
    • 1 tablespoon apple cider vinegar
    • 2 cups all purpose flour
    • 1 3/4 cups granulated sugar
    • 3/4 cup cocoa powder
    • 2 teaspoons baking powder
    • 1 1/2 teaspoons baking soda
    • 1 teaspoon salt
    • 1/2 cup canola oil OR melted coconut oil
    • 2/3 cup unsweetened applesauce
    • 1 tablespoon pure vanilla extract
    • 1 cup boiling water

    Chocolate Buttercream Frosting

    • 1 cup cocoa powder
    • 1 1/2 cups vegan butter, softened baking sticks preferred
    • 4-5 cups powdered sugar
    • 2 teaspoons pure vanilla extract
    • 1/4-1/2 cup unsweetened almond milk
    +

    Instructions 

    For the Chocolate Cake

    • Preheat oven to 350 degrees F and grease two 9-inch cake pans. I also line them with parchment rounds and lightly flour for easy removal of the cakes later.
    • Measure 1 cup unsweetened almond milk and add the tablespoon of vinegar to it. Stir slightly and set aside to curdle.
    • In a large bowl, add the flour, sugar, cocoa powder, baking powder, baking soda and salt. Whisk well to combine.
    • Now add the oil, applesauce, vanilla and almond milk/vinegar mixture. Mix on medium speed with a hand mixer (or stand mixer with the paddle attachment) until well combined. 
    • Lower the speed and carefully pour in the boiling water, continuing to mix into the cake batter until combined. The batter will seem very runny at this point; that is how it should be, trust me!
    • Divide the batter evenly between your cake pans. Bake for 30-35 minutes, or until a toothpick inserted in the center comes out clean. After 10 minutes of cooling in the pan, carefully remove the cakes from the pans and let cool completely before frosting.

    For the Chocolate Buttercream Frosting

    • Add the cocoa powder to a large bowl (I just wipe out the cake bowl and use it for the frosting). Whisk well to remove any clumps.
    • Add the softened vegan butter and mix with a hand mixer until creamed and well combined.
    • Add half of the powdered sugar and half of the almond milk, and mix until combined. Add the rest of the powdered sugar and vanilla extract. Mix starting on low, and turn to high. Mix until fluffy and combined.
    • If the frosting seems too dry, add more milk, a tablespoon or two at a time. If the frosting seems too wet and doesn't hold it's shape, add more powdered sugar until it thickens up. 
    • Frost the cake using an icing spatula or just a butter knife.
    +

    Video

    +

    Notes

      +
    1. For cupcakes, fill liners half full and bake for 20-25 minutes. The whole recipe will yield approximately 24 cupcakes.
    2. +
    3. Double the recipe to make a 4 layer cake, or cut in half to make a 1 layer round cake. You can also make a bundt cake, simply bake for 45 minutes. Or a 9 x 13 inch cake, baking for about 35-40 minutes.
    4. +
    5. Don't like a lot of frosting? Cut the frosting ingredients in half. The recipe as written makes enough for thick layers of frosting.
    6. +
    7. Nut allergy? You may substitute soy milk or another milk for the almond milk, any non-dairy milk will work here.
    8. +
    9. No applesauce? Substitute 2 flax eggs (2 tbs ground flax + 5 tbs water), whipped aquafaba or another egg replacer such as Bob's Red Mill (2 eggs worth). 
    10. +
    +

    Nutrition

    Serving: 1serving | Calories: 496kcal | Carbohydrates: 71g | Protein: 4g | Fat: 25g | Saturated Fat: 4g | Sodium: 408mg | Potassium: 222mg | Fiber: 4g | Sugar: 53g | Vitamin C: 1mg | Calcium: 59mg | Iron: 2mg
    +
    Course: Dessert
    Cuisine: American
    Author: Nora Taylor
    +
    Did you make this recipe?Mention @nora_cooks_vegan_ or tag #noracooks!
    +
    PLEASE NOTE THIS PAGE DOES CONTAIN AFFILIATE LINKS. I ONLY LINK TO PRODUCTS I ABSOLUTELY LOVE AND RECOMMEND. THANK YOU FOR YOUR SUPPORT.
    +

    We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to amazon.com. Read my full disclosure here.

    +
    +
    +
    +

    About Nora

    + + +
    +
    +
    +

    Posted In: , , , , ,

    +
    + +
    +
    +
    +

    you may also like:

    +
    +
    +
    + + + + +
    +
    +
    +
    + +

    Comments

    +
      +
    1. +
      + + +
      +

      I just baked this to make 3 9” round layer cakes and doubled the recipe and the cakes inside are like mush but tooth pick is coming out dry? I followed the recipe put it in for 35 mins

      +
      + +
      +
        +
      1. +
        + + +
        +

        Did you make any substitutions or changes to the recipe? I’m not sure how long they will need to bake if you doubled and are using 9 inch pans, they may need more time.

        +
        + +
        +
      2. +
      +
    2. +
    3. +
      + + +
      +

      My husband & I are detoxing from mold spores that you couldn’t see or smell. We can’t have any type of sugar while detoxing. Can this cake be made with just stevia? If so how much?

      +
      + +
      +
        +
      1. + +
      2. +
      +
    4. +
    5. +
      + + +
      +

      I’m looking to make this into a 4 layer 6” cake! I’m guessing adjusting the ingredients x1.5 should be enough batter, any idea what the baking time should be? Thank you!

      +
      + +
      +
        +
      1. +
        + + +
        +

        Hi there! I think 1.5 times the batter should be enough for a 4 layer 6 inch cake. I’m guessing a bit less time but I’m not sure, perhaps check often after 20 minutes or so until a toothpick inserted in the middle comes out clean.

        +
        + +
        +
      2. +
      +
    6. +
    7. + +
        +
      1. + +
      2. +
      +
    8. +
    9. +
      + + +
      +
      + +
      +

      I make this cake once a year for my partner’s birthday. This year my non-vegan Mother In Law wanted to make it for Thanksgiving and it was the most popular dish of the day for all! Sorry Nora, everyone calls it my chocolate cake recipe. 😉

      +
      + +
      +
    10. +
    11. +
      + + +
      +
      + +
      +

      Made this for thanksgiving and everyone loved it. Super moist, fluffy frosting and not too sweet. This will be my go to recipe for chocolate cake. And very easy to make too. Thank you.

      +
      + +
      +
        +
      1. +
        + + +
        +

        You are welcome, Maria! I’m thrilled you loved the cake! Thanks for your fabulous review and feedback! Happy cooking!

        +
        + +
        +
      2. +
      +
    12. +
    13. +
      + + +
      +
      + +
      +

      This is a fabulous cake! It is moist, wonderfully chocolatey, easy to make without any “special” ingredients that most vegan recipes seem to require, and my Thanksgiving guests absolutely loved it. They couldn’t believe it was vegan!

      +

      Thank you for this great recipe – it’s a keeper and I know I’ll make it again and again! So yummy!

      +
      + +
      +
        +
      1. +
        + + +
        +

        You are welcome! We love this cake at our place! I’m so glad it was a it with your guests! Thanks for your awesome review and feedback! Happy cooking!

        +
        + +
        +
      2. +
      +
    14. +
    15. +
      + + +
      +
      + +
      +

      INCREDIBLE. I made this for a party and everyone, vegans and non vegans alike, LOVED it.

      +

      Note: I reduced the sugar by about 30g and used sweetened applesauce. I also used a whipped ganache instead of buttercream!

      +
      + +
      +
        +
      1. +
        + + +
        +

        I’m thrilled you loved the cake and that it came out wonderful with your adjustments! Thanks for sharing your great review and baking experience! Happy cooking!

        +
        + +
        +
      2. +
      +
    16. +
    17. +
      + + +
      +
      + +
      +

      This recipe is wonderful! Both the cake and cupcakes turned out great. I was wondering if you had a suggestion for a gluten-free flour to use for this? Thanks.

      +
      + +
      +
        +
      1. +
        + + +
        +

        Hi Cliff. I am glad you are lo king the cake! Thanks for your awesome review! You can simply substitute a quality gluten free flour like Better Batter or King Arthur Measure for Measure. For gluten free, I prefer to make my Gluten Free Vegan Chocolate Cake, which is almost identical, but gluten free. Happy baking!

        +
        + +
        +
          +
        1. +
          + + +
          +

          I use a cup of Yogi’s Turmeric Honey Chai instead of the water. The comments I have received have been nothing short of “the best” comments for any cake I have made. Thanks for this recipe.

          +
          + +
          +
            +
          1. +
            + + +
            +

            You are welcome, Chris! Your addition sounds amazing! Thanks for sharing this idea! Glad the cake was a hit!

            +
            + +
            +
          2. +
          +
        2. +
        +
      2. +
      +
    18. +
    19. +
      + + +
      +
      + +
      +

      This is absolutely the most amazing chocolate cake ever.
      +My granddaughter is learning to be a vegan baker and I keep throwing your recipes at her.
      +This cake is the one that I make and take pieces to my family, who are not vegans, and they rave over it. It is so dense, moist and yet fluffy and keeping it in the fridge just makes it even more delicious. Thanks for all of your amazing recipes.

      +
      + +
      +
    20. +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +

    + +

    +

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 404f704f5341be1f966f18d1e0b9478a6786de87 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Wed, 11 Dec 2024 12:26:11 -0500 Subject: [PATCH 32/94] Adds support for makeitdairyfree (#1429) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/makeitdairyfree.py | 31 + .../makeitdairyfree_1.json | 65 + .../makeitdairyfree_1.testhtml | 2424 +++++++++++++++++ .../makeitdairyfree_2.json | 109 + .../makeitdairyfree_2.testhtml | 1873 +++++++++++++ 7 files changed, 4505 insertions(+) create mode 100644 recipe_scrapers/makeitdairyfree.py create mode 100644 tests/test_data/makeitdairyfree.com/makeitdairyfree_1.json create mode 100644 tests/test_data/makeitdairyfree.com/makeitdairyfree_1.testhtml create mode 100644 tests/test_data/makeitdairyfree.com/makeitdairyfree_2.json create mode 100644 tests/test_data/makeitdairyfree.com/makeitdairyfree_2.testhtml diff --git a/README.rst b/README.rst index f8581a171..3d6a4b65d 100644 --- a/README.rst +++ b/README.rst @@ -303,6 +303,7 @@ Scrapers available for: - `https://www.madamecuisine.de `_ - `https://madensverden.dk/ `_ - `https://madsvin.com/ `_ +- `https://makeitdairyfree.com/ `_ - `https://marmiton.org/ `_ - `https://www.marthastewart.com/ `_ - `https://matprat.no/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 05ebcfdc9..5d1f6544c 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -250,6 +250,7 @@ from .madamecuisine import MadameCuisine from .madensverden import MadensVerden from .madsvin import Madsvin +from .makeitdairyfree import MakeItDairyFree from .marmiton import Marmiton from .marthastewart import MarthaStewart from .matprat import Matprat @@ -574,6 +575,7 @@ LittleSunnyKitchen.host(): LittleSunnyKitchen, LeitesCulinaria.host(): LeitesCulinaria, MadameCuisine.host(): MadameCuisine, + MakeItDairyFree.host(): MakeItDairyFree, McCormick.host(): McCormick, MeganVsKitchen.host(): MeganVsKitchen, Miljuschka.host(): Miljuschka, diff --git a/recipe_scrapers/makeitdairyfree.py b/recipe_scrapers/makeitdairyfree.py new file mode 100644 index 000000000..8e2d2b486 --- /dev/null +++ b/recipe_scrapers/makeitdairyfree.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class MakeItDairyFree(AbstractScraper): + @classmethod + def host(cls): + return "makeitdairyfree.com" + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.json b/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.json new file mode 100644 index 000000000..9ee7dc34c --- /dev/null +++ b/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.json @@ -0,0 +1,65 @@ +{ + "author": "Andrew Bernard", + "canonical_url": "https://makeitdairyfree.com/the-best-vegan-mac-and-cheese/", + "site_name": "Make It Dairy Free", + "host": "makeitdairyfree.com", + "language": "en-US", + "title": "The Best Baked Vegan Mac and Cheese", + "ingredients": [ + "1 pound macaroni noodles, (uncooked (16oz or 454g) (Use gluten free if needed)", + "15 oz can butter beans, (drained and rinsed (439g)", + "2 cups dairy free milk (480g)", + "1/2 cup vegetable stock (120g)", + "1/2 cup vegan butter (113g)", + "1/3 cup nutritional yeast (27g)", + "2 tablespoon lemon juice", + "1 teaspoon salt", + "1 teaspoon cracked black pepper", + "1/4 teaspoon paprika", + "2 cups vegan shredded cheddar cheese, (divided (240g)", + "1 cup vegan parmesan cheese (115g)", + "1/3 cup seasoned panko breadcrumbs (20g)", + "2 teaspoon olive oil, (optional)" + ], + "instructions_list": [ + "Bring a salted pot of water to a boil. Preheat oven to 350˚F/180˚C degrees. Cook 1lb macaroni noodles according to the package. Drain noodles once done and set aside.", + "While noodles cook, to a high powdered blender, add 15oz can butter beans, 2 cups dairy free milk, 1/2 cup stock, 1/2 cup vegan butter, 1/3 cupnutritional yeast, 2 tablespoons lemon juice, 1 teaspoon each salt and pepper, 1/4 teaspoon paprika, 1 cup each non-dairy cheddar shreds and parmesan cheese. Blend this until smooth. Set aside.", + "In a lightly greased 9x13 casserole dish, add the drained, cooked noodles. Pour the sauce mixture over the noodles and carefully stir together.", + "Top with remaining 1 cup of the cheese shreds. If using the oil, in a small bowl combine the oil with the breadcrumbs and stir to well coated. Sprinkle evenly across the top.", + "Bake for 25-30 minutes or until breadcrumbs have started turning golden brown on top. Remove from oven and let set for 15 minutes before cutting into." + ], + "category": "Main Course,Side Dish", + "yields": "16 servings", + "description": "This is the best vegan mac and cheese recipe ever! Directions for stovetop version and the most delicious baked vegan mac and cheese ever! Not cashew based, so allergy friendly!", + "total_time": 50, + "cook_time": 30, + "prep_time": 15, + "cuisine": "American", + "ratings": 4.91, + "ratings_count": 125, + "equipment": [ + "9×13 casserole dish" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "127 kcal", + "fatContent": "5 g", + "saturatedFatContent": "1 g", + "carbohydrateContent": "16 g", + "sugarContent": "2 g", + "proteinContent": "3 g", + "sodiumContent": "384 mg", + "fiberContent": "1 g" + }, + "image": "https://makeitdairyfree.com/wp-content/uploads/2019/10/the-best-vegan-mac-and-cheese-6.jpg", + "keywords": [ + "dairy free holidays", + "dairy free main course", + "dairy free recipes", + "dairy free side dish", + "vegan holidays", + "vegan main course", + "vegan recipes", + "vegan side dish" + ] +} diff --git a/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.testhtml b/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.testhtml new file mode 100644 index 000000000..010132622 --- /dev/null +++ b/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.testhtml @@ -0,0 +1,2424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Baked Vegan Mac and Cheese - Make It Dairy Free + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
      + + +
    • +
    • +
    +
    + +
    + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.json b/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.json new file mode 100644 index 000000000..3bc68e408 --- /dev/null +++ b/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.json @@ -0,0 +1,109 @@ +{ + "author": "Larisha Bernard", + "canonical_url": "https://makeitdairyfree.com/veggie-packed-crispy-rice-salad-with-peanut-dressing/", + "site_name": "Make It Dairy Free", + "host": "makeitdairyfree.com", + "language": "en-US", + "title": "The Best Crispy Rice Salad with Veggies and Peanut Dressing", + "ingredients": [ + "2 cups pre-cooked rice, (cooled)", + "1 tablespoon chili garlic sauce", + "1 tablespoon chili crunch oil", + "1 tablespoon sesame oil", + "1 tablespoon soy sauce", + "1 lime (juice from 1/2 and zest from whole)", + "5 mini cucumbers, (thinly sliced)", + "2 avocados, (cubed)", + "1 red bell pepper, (chopped)", + "3-5 green onions, (chopped)", + "2 cups red cabbage, (finely sliced)", + "1 cup unsalted peanuts, (chopped (150g)", + "1 cup edamame, (shelled and cooked (160g)", + "1 cup fresh basil, (chopped (16g)", + "½ cup cilantro, (chopped (8g)", + "1/4 cup peanut butter (65g)", + "3 tablespoons Olive Oil", + "3 Tablespoons rice vinegar", + "3 Cloves garlic, (minced)", + "1/2 lime, ( juiced)", + "2 Tablespoons Toasted Sesame Oil", + "2 Tablespoons soy sauce", + "1 1/2 Tablespoons maple syrup", + "1 inch fresh ginger, (grated (2.5cm)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "2 cups pre-cooked rice, (cooled)", + "1 tablespoon chili garlic sauce", + "1 tablespoon chili crunch oil", + "1 tablespoon sesame oil", + "1 tablespoon soy sauce", + "1 lime (juice from 1/2 and zest from whole)" + ], + "purpose": "For the Crispy Rice:" + }, + { + "ingredients": [ + "5 mini cucumbers, (thinly sliced)", + "2 avocados, (cubed)", + "1 red bell pepper, (chopped)", + "3-5 green onions, (chopped)", + "2 cups red cabbage, (finely sliced)", + "1 cup unsalted peanuts, (chopped (150g)", + "1 cup edamame, (shelled and cooked (160g)", + "1 cup fresh basil, (chopped (16g)", + "½ cup cilantro, (chopped (8g)" + ], + "purpose": "For the Salad:" + }, + { + "ingredients": [ + "1/4 cup peanut butter (65g)", + "3 tablespoons Olive Oil", + "3 Tablespoons rice vinegar", + "3 Cloves garlic, (minced)", + "1/2 lime, ( juiced)", + "2 Tablespoons Toasted Sesame Oil", + "2 Tablespoons soy sauce", + "1 1/2 Tablespoons maple syrup", + "1 inch fresh ginger, (grated (2.5cm)" + ], + "purpose": "For the Creamy Peanut Ginger Dressing:" + } + ], + "instructions_list": [ + "Make Crispy Rice: Preheat oven to 400˚F (200˚C). Add 2 cups cooked and cooled rice to a bowl, along with 1 tbsp each chili garlic sauce, chili crunch oil, sesame oil and soy sauce, and the zest from 1 lime and juice from 1/2 of it. Stir to combine everything evenly. Place on baking sheet and bake for 25-35 minutes or just until crispy.", + "While that's baking, to a large bowl, add the 5 mini sliced cucumbers, 2 cubed avocados, 1 chopped red bell pepper, 3-5 chopped green onions, 2 cups shredded cabbage, 1 cup each chopped peanuts, edamame, fresh chopped basil, and 1/2 cup chopped cilantro. Stir together very well.", + "In a small blender, add 1/4 cup peanut butter, 3 tbsp each olive oil and rice vinegar, 3 cloves garlic, 1/2 lime juiced, 2 tbsp each toasted sesame oil and soy sauce, 1 1/2 cups maple syrup, and 1 inch grated ginger. Blend until combined.*Note: If you don't have a small blender, you can do this by whisking by hand, just finely mince the garlic first.", + "When rice is finished, let cool and then add to the bowl with the peanut butter sauce and combine so the sauce is evenly all over." + ], + "category": "Main Course,Salad", + "yields": "4 servings", + "description": "If you've never made crispy rice salad then you are in for a treat! This meal prep, no leafy green salad option is perfect for those looking for amazing flavor, with little effort.", + "total_time": 45, + "cook_time": 30, + "prep_time": 15, + "cuisine": "Asian", + "nutrients": { + "servingSize": "0.25 g", + "calories": "1172 kcal", + "fatContent": "68 g", + "saturatedFatContent": "10 g", + "unsaturatedFatContent": "52 g", + "transFatContent": "0.003 g", + "carbohydrateContent": "122 g", + "sugarContent": "20 g", + "proteinContent": "31 g", + "sodiumContent": "1282 mg", + "fiberContent": "22 g" + }, + "dietary_restrictions": [ + "Vegan Diet", + "Vegetarian Diet" + ], + "image": "https://makeitdairyfree.com/wp-content/uploads/2024/12/crispy-rice-salad-6.jpg", + "keywords": [ + "vegan main course" + ] +} diff --git a/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.testhtml b/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.testhtml new file mode 100644 index 000000000..889607e85 --- /dev/null +++ b/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.testhtml @@ -0,0 +1,1873 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Veggie Packed Crispy Rice Salad with Peanut Dressing - Make It Dairy Free + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
      + + +
    • +
    • +
    +
    + +
    + + + + + + + + + + + + + + + + + From 7c6f8749fc96571fb13b6d3d54f8267b8c6a78e5 Mon Sep 17 00:00:00 2001 From: supfors Date: Sat, 14 Dec 2024 13:25:06 +0100 Subject: [PATCH 33/94] update instructions (#1432) --- recipe_scrapers/jamieoliver.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/recipe_scrapers/jamieoliver.py b/recipe_scrapers/jamieoliver.py index 6f4ce75e4..a2cf8e61e 100644 --- a/recipe_scrapers/jamieoliver.py +++ b/recipe_scrapers/jamieoliver.py @@ -8,5 +8,7 @@ def host(cls): return "jamieoliver.com" def instructions(self): - instructions = self.soup.find("ol", {"class": "recipeSteps"}).findAll("li") + method_heading = self.soup.find("h2", string="Method") + instructions_list = method_heading.find_next("ol") + instructions = instructions_list.find_all("li") return "\n".join([normalize_string(inst.get_text()) for inst in instructions]) From 9fc364d617ba490f6acceeb25a30ce41853ce998 Mon Sep 17 00:00:00 2001 From: hhursev Date: Sat, 14 Dec 2024 15:59:58 +0200 Subject: [PATCH 34/94] docs: Add MkDocs with Material theme and essential plugins (#1433) * docs: Add MkDocs with Material theme and essential plugins - Configure MkDocs with Material theme as documentation framework - Configure core documentation plugins: - search: Enable full-text search within docs - markdown-exec: generate dynamic content (used to auto-list supported hosts for example) - mkdocstrings: Auto-generate API docs from Python docstrings - Configure initial navigation structure - Add example markdown files demonstrating key features - Add recipe-scrapers[docs] optional dependency for documentation work - Add guide on contributing to the documentation - Remove markdownlint configuration for better developer experience * Pin minimum versions for all dev deps * Add pre_commit to dev deps.. --- .markdownlint.json | 18 ---- .pre-commit-config.yaml | 4 - docs/README.md | 20 ----- docs/api/exceptions.md | 3 + docs/api/scraper.md | 5 ++ docs/api/utils.md | 3 + docs/contributing-to-our-documentation.md | 39 +++++++++ ...-to-develop-scraper.md => contributing.md} | 2 +- docs/getting-started.md | 15 ++++ docs/index.md | 53 ++++++++++++ docs/supported-sites.md | 17 ++++ mkdocs.yml | 85 +++++++++++++++++++ pyproject.toml | 16 +++- 13 files changed, 233 insertions(+), 47 deletions(-) delete mode 100644 .markdownlint.json delete mode 100644 docs/README.md create mode 100644 docs/api/exceptions.md create mode 100644 docs/api/scraper.md create mode 100644 docs/api/utils.md create mode 100644 docs/contributing-to-our-documentation.md rename docs/{how-to-develop-scraper.md => contributing.md} (99%) create mode 100644 docs/getting-started.md create mode 100644 docs/index.md create mode 100644 docs/supported-sites.md create mode 100644 mkdocs.yml diff --git a/.markdownlint.json b/.markdownlint.json deleted file mode 100644 index bdbf52591..000000000 --- a/.markdownlint.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "_": "Adapted from: https://github.com/DavidAnson/markdownlint/blob/b2305efafb034b1f328845aec9928b5363ffd646/schema/.markdownlint.jsonc#L67-L85", - "_MD007": "// Indentation: use kramdown-compatible indentation : https://kramdown.gettalong.org/syntax.html#ordered-and-unordered-lists", - "MD007": { - "indent": 3 - }, - "_MD013": "// Line length : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md013.md", - "MD013": { - "line_length": 800, - "heading_line_length": 80, - "code_block_line_length": 800, - "code_blocks": true, - "tables": true, - "headings": true, - "strict": false, - "stern": false - } -} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 883c6ac0c..4da96614d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,7 +40,3 @@ repos: hooks: - id: sphinx-lint args: ["-e", "all", "-d", "line-too-long"] -- repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.43.0 - hooks: - - id: markdownlint diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index ec48b55ec..000000000 --- a/docs/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Scraper Development Guide - -## Goal - -This library has the goals of - -* making recipe information **accessible**, -* ensuring the author is **attributed** correctly, -* representing the recipes **accurately** and **authentically** - -Sometimes it is simple and straightforward to achieve all these goals, and sometimes it is more difficult (which is why this library exists). Where some interpretation or creativity is required to scrape a recipe, we should always keep those goals in mind. Occasionally, that might mean that we can't support a particular website. - -## Contents - -* [How To: Develop a New Scraper](how-to-develop-scraper.md) -* In Depth Guides: - * [Debugging](in-depth-guide-debugging.md) (coming soon) - * [HTML Scraping](in-depth-guide-html-scraping.md) - * [Ingredient Groups](in-depth-guide-ingredient-groups.md) - * [Scraper Functions](in-depth-guide-scraper-functions.md) diff --git a/docs/api/exceptions.md b/docs/api/exceptions.md new file mode 100644 index 000000000..ac4ad47be --- /dev/null +++ b/docs/api/exceptions.md @@ -0,0 +1,3 @@ +# Exceptions + +::: recipe_scrapers._exceptions diff --git a/docs/api/scraper.md b/docs/api/scraper.md new file mode 100644 index 000000000..5652de510 --- /dev/null +++ b/docs/api/scraper.md @@ -0,0 +1,5 @@ +# Base Scraper + +::: recipe_scrapers.scrape_html + options: + show_root_members: true diff --git a/docs/api/utils.md b/docs/api/utils.md new file mode 100644 index 000000000..0dfbfb000 --- /dev/null +++ b/docs/api/utils.md @@ -0,0 +1,3 @@ +# Utility Functions + +::: recipe_scrapers._utils diff --git a/docs/contributing-to-our-documentation.md b/docs/contributing-to-our-documentation.md new file mode 100644 index 000000000..dabf37daf --- /dev/null +++ b/docs/contributing-to-our-documentation.md @@ -0,0 +1,39 @@ +# Contributing to Our Documentation + +We're excited to have you help improve our documentation! Here's a step-by-step guide to get you started. + + +### Setting Up Your Local Environment +First, let's set up your development environment: + +```bash +git clone git@github.com:hhursev/recipe-scrapers.git && +cd recipe-scrapers && +python -m venv .venv && +source .venv/bin/activate && +python -m pip install --upgrade pip && +pip install -e ".[docs]" +``` + +### Viewing the Documentation Locally + +Start the documentation server with: + +``` +mkdocs serve +``` + +You can now view the documentation at http://localhost:8000/. +The server will automatically refresh when you make changes. + + +### Making Your Contributions + +1. Navigate to the `docs/` directory where all documentation files are stored +2. Make your desired changes to the documentation files +3. If needed, update the navigation structure in mkdocs.yml (particularly the nav section) +4. Preview your changes in real-time through the local server +5. Once you're satisfied with your updates, create a pull request + +We appreciate your contributions to making our documentation better! +If you have any questions during this process, please don't hesitate to reach out. diff --git a/docs/how-to-develop-scraper.md b/docs/contributing.md similarity index 99% rename from docs/how-to-develop-scraper.md rename to docs/contributing.md index 75d3b02f9..83a35aad6 100644 --- a/docs/how-to-develop-scraper.md +++ b/docs/contributing.md @@ -164,7 +164,7 @@ If the website does not support Recipe Schema, or the schema does not include al An example of a scraper that uses this approach is [Przepisy](https://github.com/hhursev/recipe-scrapers/blob/main/recipe_scrapers/przepisy.py). -The [BeautifulSoup documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.html) is a good resource for getting started with extracting information from HTML. A guide of common patterns and best practice used in this library can be found [here](in-depth-guide-html-scraping). +The [BeautifulSoup documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.html) is a good resource for getting started with extracting information from HTML. A guide of common patterns and best practice used in this library can be found [here](in-depth-guide-html-scraping.md). Some helper functions are available in the `_utils.py` file. These are functions that are commonly needed when extracting information from HTML, such as `normalize_string()`. diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 000000000..61c280842 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,15 @@ +# Getting Started + +!!! note "Installation" + This documentation is in **early** development and actively being improved. For now, please refer to the repository's [README](https://github.com/hhursev/recipe-scrapers/blob/main/README.rst). + + +```bash +pip install recipe-scrapers +``` + +or + +```bash +pip install recipe-scrapers[online] +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..9e8f8d2ef --- /dev/null +++ b/docs/index.md @@ -0,0 +1,53 @@ +# Recipe Scrapers + +Welcome to Recipe Scrapers - a Python package that makes extracting recipes from websites a piece of cake! 🍰 + +This documentation is in **early** development and actively being improved. For now, please refer to the repository's [README](https://github.com/hhursev/recipe-scrapers/blob/main/README.rst). + + +[We support the following sites](supported-sites.md) + +[Contributing to Our Documentation](contributing-to-our-documentation.md) + + +---- + + +## Goal + +This library has the goals of + +* making recipe information **accessible**, +* ensuring the author is **attributed** correctly, +* representing the recipes **accurately** and **authentically** + +Sometimes it is simple and straightforward to achieve all these goals, and sometimes it is more difficult (which is why this library exists). Where some interpretation or creativity is required to scrape a recipe, we should always keep those goals in mind. Occasionally, that might mean that we can't support a particular website. + +## Contents: + +- [Contributing to Our Documentation](contributing-to-our-documentation.md) +* [How To: Develop a New Scraper](contributing.md) +* In Depth Guides: + * [HTML Scraping](in-depth-guide-html-scraping.md) + * [Ingredient Groups](in-depth-guide-ingredient-groups.md) + * [Scraper Functions](in-depth-guide-scraper-functions.md) + * [Debugging](in-depth-guide-debugging.md) (coming soon) + + +## What is Recipe Scrapers? + +Recipe Scrapers is a Python library that simplifies the process of extracting structured recipe data from cooking and recipe websites. It handles the complexities of web scraping while providing you with clean, structured recipe data. + +```python +from urllib.request import urlopen + +from recipe_scrapers import scrape_html + +url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" +html = urlopen(url).read().decode("utf-8") # retrieves the recipe webpage HTML +scraper = scrape_html(html, org_url=url) +scraper.title() +scraper.instructions() # etc. +# for a complete list of methods: +# help(scraper) +``` diff --git a/docs/supported-sites.md b/docs/supported-sites.md new file mode 100644 index 000000000..c54788094 --- /dev/null +++ b/docs/supported-sites.md @@ -0,0 +1,17 @@ +# Supported Websites + +!!! note "Contributing" + Want to help maintain or add support for a site? Join our community of contributors! See our [contributing guidelines](contributing.md). + See something missing or incorrect? [Open an issue](https://github.com/hhursev/recipe-scrapers/issues) or submit a pull request. + + +```python exec="on" +import sys +sys.path.insert(0, '.') +from recipe_scrapers import SCRAPERS + +sites = sorted(SCRAPERS.keys()) +print(f"Currently, there are {len(sites)} sites that this package supports.\n") +print(f"### Currently Supported Sites:\n") +print("\n".join(f"- [{host}](https://{host}/)" for host in sites)) +``` diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 000000000..420da9ea8 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,85 @@ +site_name: recipe-scrapers +site_url: https://docs.recipe-scrapers.com +site_description: Documentation for recipe-scrapers - Python package for scraping recipes data from the web +repo_url: https://github.com/hhursev/recipe-scrapers +repo_name: hhursev/recipe-scrapers + +theme: + name: material + palette: + - scheme: default + primary: teal + accent: teal + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - scheme: slate + primary: teal + accent: teal + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - navigation.instant + - navigation.tracking + - navigation.sections + - navigation.expand + - navigation.top + - search.suggest + - search.highlight + +nav: + - Home: index.md + - Getting Started: getting-started.md + - Supported Sites: supported-sites.md + - Contributing: + - Contributing to Our Documentation: contributing-to-our-documentation.md + - Overview: contributing.md + - "In Depth: HTML Scraping": in-depth-guide-html-scraping.md + - "In Depth: Scraper Functions": in-depth-guide-scraper-functions.md + - "In Depth: Ingredient Groups": in-depth-guide-ingredient-groups.md + - "In Depth: Debugging": in-depth-guide-debugging.md + - API Reference: + - Base Scraper: api/scraper.md + - Exceptions: api/exceptions.md + - Utils: api/utils.md + +markdown_extensions: + - admonition + - attr_list + - md_in_html + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.tabbed: + alternate_style: true + - tables + +plugins: + - search + - markdown-exec # used in supported-sites.md + - mkdocstrings: + default_handler: python + handlers: + python: + paths: recipe_scrapers + options: + show_source: true + show_root_heading: true + heading_level: 1 + show_category_heading: true + docstring_style: google +# show_signature_annotations: true +# show_if_no_docstring: true +# show_root_full_path: true +# members: true +# show_private_members: true +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/hhursev/recipe-scrapers + - icon: fontawesome/brands/python + link: https://pypi.org/project/recipe-scrapers/ diff --git a/pyproject.toml b/pyproject.toml index a70094310..e8cdf641b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,12 +39,20 @@ dependencies = [ [project.optional-dependencies] dev = [ - "coverage >=7.4.4", - "types-beautifulsoup4>=4.12.0", - "importlib-metadata>=4.6 ; python_version < '3.10'", + "pre_commit >= 4.0.1", + "coverage >= 7.4.4", + "types-beautifulsoup4 >= 4.12.0", + "importlib-metadata >= 4.6 ; python_version < '3.10'", ] online = [ - "requests >= 2.31.0", + "requests>=2.31.0", +] +docs = [ + "mkdocs >= 1.6.1", + "mkdocs-material >= 9.5.48", + "mkdocstrings >= 0.27.0", + "mkdocstrings-python >= 1.12.2", + "markdown-exec >= 1.10.0", ] [tool.setuptools.packages.find] From 9dc47fa5c77e047ca9b55cdc5e9dc8cc2721770e Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 17:11:03 +0200 Subject: [PATCH 35/94] Remove sphinx-lint as it's overkill for single README.rst The sphinx-lint tool is primarily designed for Sphinx documentation projects, checking things like directives, cross-references, role syntax, and documentation structure. For our simple README.rst file (the only .rst in the project), these checks are unnecessary, especially as the README is being simplified. --- .pre-commit-config.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4da96614d..c366d331f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,8 +35,3 @@ repos: hooks: - id: pyupgrade args: [--py39-plus] -- repo: https://github.com/sphinx-contrib/sphinx-lint - rev: v0.9.1 - hooks: - - id: sphinx-lint - args: ["-e", "all", "-d", "line-too-long"] From 9c01543dfbb0df3e871d7fa7be9f94ff69862676 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 17:15:23 +0200 Subject: [PATCH 36/94] Remove pyupgrade from .pre-commit-config This is a tool used to automatically upgrade syntax to newer versions. Our library requires python3.9+ already. We are using Black which handles most (if not all) of the formatting concerns we may have. Black already enforices consistant modern formatting --- .pre-commit-config.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c366d331f..b711ce65b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,13 +25,9 @@ repos: rev: 24.2.0 hooks: - id: black + args: ["--target-version", "py39"] - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.9.0 hooks: - id: mypy additional_dependencies: [types-beautifulsoup4, types-requests] -- repo: https://github.com/asottile/pyupgrade - rev: v3.15.1 - hooks: - - id: pyupgrade - args: [--py39-plus] From 107e8bd1d1388f458bbd8b1b37f34cd31c940298 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 17:22:14 +0200 Subject: [PATCH 37/94] Remove isort with profile --black from pre-commit-config --- .pre-commit-config.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b711ce65b..76bc323f9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,11 +16,6 @@ repos: hooks: - id: flake8 additional_dependencies: [flake8-use-fstring, pep8-naming] -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - args: ["--profile", "black", "--filter-files"] - repo: https://github.com/psf/black rev: 24.2.0 hooks: From 75bfd69fe519c3e0c817a70a1f5f205978ee7e9f Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 17:38:03 +0200 Subject: [PATCH 38/94] Using flake8-use-fstring while ignoring FS002 is contradictory.. simplify --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 76bc323f9..910d1b32f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: rev: 7.0.0 hooks: - id: flake8 - additional_dependencies: [flake8-use-fstring, pep8-naming] + additional_dependencies: [pep8-naming] - repo: https://github.com/psf/black rev: 24.2.0 hooks: From ded573f0ad13e6d12f69e81651693933b9c50561 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 17:38:50 +0200 Subject: [PATCH 39/94] Rearrange .flake8 a bit. Add comments on what is what --- .flake8 | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/.flake8 b/.flake8 index 76661ede4..3f0b0afb9 100644 --- a/.flake8 +++ b/.flake8 @@ -1,10 +1,43 @@ [flake8] -# FS002 comes from pugin "flake8-use-fstring" -# and would error on `str.format()` usage -ignore = E203, E501, W503, FS002, N818 +# Error codes we ignore: +# +# Ignored because Black handles code formatting: +# E203: Whitespace before ':' +# E501: Line too long (82 > 79 characters) +# W503: Line break occurred before a binary operator +# +# Other ignored rules: +# N818: Exception names should end in 'Error' +ignore = + E203, + E501, + W503, + N818 + +# To match Black's default max-line-length = 88 + +# McCabe complexity checker +# Standard is 10, we should aim to improve max-complexity = 21 -select = B,C,E,F,N,W,T4,B9 + +# Selected error codes: +# B: bugbear checks +# C: complexity checks +# E: pycodestyle errors +# F: pyflakes +# N: naming checks (from pep8-naming) +# W: pycodestyle warnings +# T4: mypy type checks +select = + B, + C, + E, + F, + N, + W, + T4 + exclude = ./.tox/ ./.venv/ From 0ffdf3e366e0997746912c8c4e5900cfcf330015 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 17:53:27 +0200 Subject: [PATCH 40/94] Update versions in .pre-commit-config and adjust pyproject.toml optional deps a bit --- .pre-commit-config.yaml | 10 +++++----- pyproject.toml | 40 +++++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 910d1b32f..f10bae483 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ exclude: '.test(html|json)' repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: check-yaml - id: end-of-file-fixer @@ -12,17 +12,17 @@ repos: - "--no-sort-keys" - "--no-ensure-ascii" - repo: https://github.com/pycqa/flake8.git - rev: 7.0.0 + rev: 7.1.1 hooks: - id: flake8 - additional_dependencies: [pep8-naming] + additional_dependencies: ["pep8-naming==0.14.1"] - repo: https://github.com/psf/black - rev: 24.2.0 + rev: 24.10.0 hooks: - id: black args: ["--target-version", "py39"] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.9.0 + rev: v1.13.0 hooks: - id: mypy additional_dependencies: [types-beautifulsoup4, types-requests] diff --git a/pyproject.toml b/pyproject.toml index e8cdf641b..33aa5a1fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,22 +38,40 @@ dependencies = [ ] [project.optional-dependencies] -dev = [ - "pre_commit >= 4.0.1", - "coverage >= 7.4.4", - "types-beautifulsoup4 >= 4.12.0", - "importlib-metadata >= 4.6 ; python_version < '3.10'", -] online = [ "requests>=2.31.0", ] +# Documentation dependencies +# Install these to build and serve the documentation: +# pip install -e ".[docs]" +# +# Common commands: +# mkdocs serve # Start local docs server at http://127.0.0.1:8000 +# # The server auto-reloads when you change files in docs/ docs = [ - "mkdocs >= 1.6.1", - "mkdocs-material >= 9.5.48", - "mkdocstrings >= 0.27.0", - "mkdocstrings-python >= 1.12.2", - "markdown-exec >= 1.10.0", + "mkdocs >= 1.6.1", # Core documentation generator + "mkdocs-material >= 9.5.48", # Material theme for MkDocs + "mkdocstrings >= 0.27.0", # API documentation from docstrings + "mkdocstrings-python >= 1.12.2", # Python handler for mkdocstrings + "markdown-exec >= 1.10.0", # Execute code blocks in markdown +] +dev = [ + "recipe-scrapers[test]", # assuming you have test dependencies + "pre-commit == 5.0.0", # use whatever is .pre-commit-config.yaml + "black == 24.10.0", # match what's in .pre-commit-config.yaml + "flake8 == 7.1.1", # match what's in .pre-commit-config.yaml + "pep8-naming == 0.14.1", # match what's in .pre-commit-config.yaml + "mypy == 1.13.0", # match what's in .pre-commit-config.yaml + "types-beautifulsoup4", # needed for mypy + "types-requests", # needed for mypy ] +test = [ + "coverage >= 7.4.4", +] +all = [ + "recipe_scrapers[online,docs,test]" +] + [tool.setuptools.packages.find] include = ["recipe_scrapers", "recipe_scrapers.*"] From c8890669872448856f57226f1794fdf6b6696a76 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 17:53:53 +0200 Subject: [PATCH 41/94] Swap couple .format() occurrances to fstrings --- recipe_scrapers/_utils.py | 4 ++-- recipe_scrapers/dishnz.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/recipe_scrapers/_utils.py b/recipe_scrapers/_utils.py index 438b6f970..6985e1dd1 100644 --- a/recipe_scrapers/_utils.py +++ b/recipe_scrapers/_utils.py @@ -224,9 +224,9 @@ def get_yields(element): return best_match if SERVE_REGEX_ITEMS.search(serve_text) is not None: - return "{} item{}".format(matched, "" if int(matched) == 1 else "s") + return f"{matched} item{'s' if int(matched) != 1 else ''}" - return "{} serving{}".format(matched, "" if int(matched) == 1 else "s") + return f"{matched} serving{'s' if int(matched) != 1 else ''}" def get_equipment(equipment_items): diff --git a/recipe_scrapers/dishnz.py b/recipe_scrapers/dishnz.py index e4496b3c4..d6b2da769 100644 --- a/recipe_scrapers/dishnz.py +++ b/recipe_scrapers/dishnz.py @@ -28,9 +28,7 @@ def yields(self): ) def image(self): - return "https://{}{}".format( - self.host(), self.soup.find("img", itemprop="image").attrs["src"] - ) + return f"https://{self.host()}{self.soup.find('img', itemprop='image').attrs['src']}" def ingredients(self): ingredients = [] From 2ea8dac1d1a798bb9406499086c94660b07b7376 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 18:52:29 +0200 Subject: [PATCH 42/94] Remove test_publish.yaml. It's not used --- .github/workflows/test_publish.yaml | 34 ----------------------------- 1 file changed, 34 deletions(-) delete mode 100644 .github/workflows/test_publish.yaml diff --git a/.github/workflows/test_publish.yaml b/.github/workflows/test_publish.yaml deleted file mode 100644 index 8e03ef01d..000000000 --- a/.github/workflows/test_publish.yaml +++ /dev/null @@ -1,34 +0,0 @@ -name: test_publish - - -# Will attempt to build + publish package in test.pypi.org -# -# the build can be tested if it works as expected by installing the package with: -# pip install --index-url https://test.pypi.org/simple/ --no-deps recipe-scrapers -# -# or by inspecting the files: https://test.pypi.org/project/recipe-scrapers/#files -on: workflow_dispatch - -jobs: - test_publish: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.x" - - name: Build the package - run: | - python -m pip install --upgrade build - python -m build . - - name: Publish a Python distribution to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.TEST_PYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ - verbose: true - skip_existing: true - - name: Show build version used - run: pip list | grep build From db1c2935999dbeb8a4a3591dcb425aae5370dcc2 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 18:54:07 +0200 Subject: [PATCH 43/94] Use .yaml file extension to match our GitHub Actions files and maintain consistency. --- mkdocs.yml => mkdocs.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mkdocs.yml => mkdocs.yaml (100%) diff --git a/mkdocs.yml b/mkdocs.yaml similarity index 100% rename from mkdocs.yml rename to mkdocs.yaml From cc4cb3929268de04b979fe6b1e4b175ae9de0a20 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 19:02:53 +0200 Subject: [PATCH 44/94] Oops use latest pre-commit version from PyPI --- .pre-commit-config.yaml | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f10bae483..1ff711bb2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ exclude: '.test(html|json)' repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v4.0.1 hooks: - id: check-yaml - id: end-of-file-fixer diff --git a/pyproject.toml b/pyproject.toml index 33aa5a1fd..b87108b36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ docs = [ ] dev = [ "recipe-scrapers[test]", # assuming you have test dependencies - "pre-commit == 5.0.0", # use whatever is .pre-commit-config.yaml + "pre-commit == 4.0.1", # use whatever is .pre-commit-config.yaml "black == 24.10.0", # match what's in .pre-commit-config.yaml "flake8 == 7.1.1", # match what's in .pre-commit-config.yaml "pep8-naming == 0.14.1", # match what's in .pre-commit-config.yaml From 0a93d9c520009f44039b57ebe24c72c0c95e1fe8 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 19:04:30 +0200 Subject: [PATCH 45/94] Oops use latest pre-commit version from PyPI --- .pre-commit-config.yaml | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1ff711bb2..f10bae483 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ exclude: '.test(html|json)' repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v5.0.0 hooks: - id: check-yaml - id: end-of-file-fixer diff --git a/pyproject.toml b/pyproject.toml index b87108b36..2b504f075 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ docs = [ ] dev = [ "recipe-scrapers[test]", # assuming you have test dependencies - "pre-commit == 4.0.1", # use whatever is .pre-commit-config.yaml + "pre-commit == 4.0.1", # latest from PyPI "black == 24.10.0", # match what's in .pre-commit-config.yaml "flake8 == 7.1.1", # match what's in .pre-commit-config.yaml "pep8-naming == 0.14.1", # match what's in .pre-commit-config.yaml From a22b2b60bd297378f02ae18a251f3278069551e3 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 19:10:02 +0200 Subject: [PATCH 46/94] Update [test] optional dependancies. Include importlib-metadata for test_readme in py39 --- pyproject.toml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2b504f075..aef915ca6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,8 +65,19 @@ dev = [ "types-beautifulsoup4", # needed for mypy "types-requests", # needed for mypy ] +# Testing dependencies +# Install these to run tests and check coverage: +# pip install -e ".[test]" +# Common commands: +# python -m unittest # Run tests sequentially +# python -m unittest_parallel --level test # Run tests in parallel (speeed) +# coverage run -m unittest # Run tests with coverage +# coverage report # View coverage report in terminal +# coverage html # Generate HTML coverage report test = [ - "coverage >= 7.4.4", + "coverage >= 7.6.9", # Code coverage measurement tool + "unittest-parallel >= 1.7.0", # Run unittest tests in parallel + "importlib-metadata >= 4.6 ; python_version < '3.10'", # used in test_readme ] all = [ "recipe_scrapers[online,docs,test]" From 9c97c4012088aaa5d3232843777fe59f238134e7 Mon Sep 17 00:00:00 2001 From: hhursev Date: Sat, 14 Dec 2024 21:19:34 +0200 Subject: [PATCH 47/94] GH actions update (#1435) * Update our [all] optional deps to include everything above it * Remove Codacy badge. Will remove Codacy integration from the repo too * Update some of our GH actions to using the greatest and latest action versions * Update our coverage action to use the oficial coveralls action. Remove codacy. Remove tox from it * Misc updates in pyprojec.toml and the linters action * Use the pyproject.toml setup in our actions. Run GH actions on specific PR events * Remove tox.ini file. No longer needed * Misc typos and wording and etc. ann unimportant one * Continue using the legacy github-token for coveralls.io integration We currently have multiple project configurations in coveralls.io and I'm working with their support team to understand how to consolidate or properly migrate these legacy setups. Until this is resolved, we need to keep using the old token-based authentication. * Well.. switch back to AndreMiras GH action. Spotted more issues with the "official" one * Move covergae and mypy configs into the pyproject.toml file Will insist on devs using python 3.11 when developing (as it comes with TOML support) * Pin the python version used in our coverage and linters actions * Oh my.. swich back to the official coveralls action.. --- .coveragerc | 13 -------- .github/workflows/coverage.yaml | 41 +++++++++--------------- .github/workflows/linters.yaml | 22 ++++++------- .github/workflows/publish.yaml | 4 +-- .github/workflows/unittests.yaml | 19 +++++------ README.rst | 3 -- mypy.ini | 12 ------- pyproject.toml | 54 +++++++++++++++++++++++++------- tox.ini | 16 ---------- 9 files changed, 76 insertions(+), 108 deletions(-) delete mode 100644 .coveragerc delete mode 100644 mypy.ini delete mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 57702d326..000000000 --- a/.coveragerc +++ /dev/null @@ -1,13 +0,0 @@ -[run] -branch = True -source = recipe_scrapers -relative_files = True - -[report] -omit = recipe_scrapers/__version__.py - recipe_scrapers/plugins/template.py - recipe_scrapers/settings/template.py - -exclude_lines = - # Don't complain if tests don't hit defensive assertion code: - raise NotImplementedError diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index aa74d1880..2ea65d880 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -2,39 +2,28 @@ name: coverage on: push: - branches: - - main - - v14 + branches: [ main, v14 ] pull_request: - branches: - - main - - v14 + branches: [ main, v14 ] + types: [ opened, synchronize, reopened ] jobs: coverage: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: "3.x" - - name: run unittests - run: | - pip install tox - tox -e py - - name: (coveralls.io) Report code coverage - uses: AndreMiras/coveralls-python-action@develop + python-version: "3.12" + cache: pip + - name: Install test packages + run: pip install ".[tests]" + - name: Run tests with coverage + env: + PYTHONWARNINGS: "always:::recipe_scrapers,ignore:::recipe_scrapers.plugins.static_values" + run: coverage run -m unittest + - name: Report coverage to coveralls.io + uses: coverallsapp/github-action@v2 with: github-token: "SmlfzlVJy4ow55rduU7IU5GmmFCfAdGeq" - - if: github.event_name == 'push' - name: (codacy) Create coverage xml report - run: | - pip install coverage - coverage xml - - if: github.event_name == 'push' - name: (codacy) Report code coverage - uses: codacy/codacy-coverage-reporter-action@v1 - with: - project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} - coverage-reports: "coverage.xml" diff --git a/.github/workflows/linters.yaml b/.github/workflows/linters.yaml index 4449d24b4..5ec88b17e 100644 --- a/.github/workflows/linters.yaml +++ b/.github/workflows/linters.yaml @@ -2,24 +2,22 @@ name: linters on: push: - branches: - - main - - v14 + branches: [ main, v14 ] pull_request: - branches: - - main - - v14 + branches: [ main, v14 ] + types: [ opened, synchronize, reopened ] jobs: linters: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: "3.x" + python-version: "3.12" cache: pip - cache-dependency-path: .pre-commit-config.yaml - - run: pip install pre-commit - - run: pre-commit run --all-files + - name: Install linters related packages + run: pip install ".[linters]" + - name: Run pre-commit hooks + run: pre-commit run --all-files diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 7f10e4b63..c751f9509 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -8,9 +8,9 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.x" - name: Build the package diff --git a/.github/workflows/unittests.yaml b/.github/workflows/unittests.yaml index 879b0f7fc..bcac524b7 100644 --- a/.github/workflows/unittests.yaml +++ b/.github/workflows/unittests.yaml @@ -2,13 +2,10 @@ name: unittests on: push: - branches: - - main - - v14 + branches: [ main, v14 ] pull_request: - branches: - - main - - v14 + branches: [ main, v14 ] + types: [ opened, synchronize, reopened ] jobs: test: @@ -19,16 +16,14 @@ jobs: python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: pip - - name: Install dependencies - run: python -m pip install .[dev] - - name: Install parallel test runner - run: python -m pip install unittest-parallel + - name: Install tests dependencies + run: pip install ".[tests]" - name: Run Tests env: PYTHONWARNINGS: "always:::recipe_scrapers,ignore:::recipe_scrapers.plugins.static_values" diff --git a/README.rst b/README.rst index 3d6a4b65d..42f5cec60 100644 --- a/README.rst +++ b/README.rst @@ -19,9 +19,6 @@ .. image:: https://img.shields.io/github/license/hhursev/recipe-scrapers? :target: https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE :alt: License -.. image:: https://app.codacy.com/project/badge/Grade/3ee8da77aaa3475a8085ca22287dea89 - :target: https://app.codacy.com/gh/hhursev/recipe-scrapers/dashboard - :alt: Codacy Badge ------ diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 0738deb4c..000000000 --- a/mypy.ini +++ /dev/null @@ -1,12 +0,0 @@ -[mypy] - -[mypy-recipe_scrapers.*] -disable_error_code = union-attr - -# Third-party libraries - -[mypy-isodate] -ignore_missing_imports = true - -[mypy-extruct] -ignore_missing_imports = true diff --git a/pyproject.toml b/pyproject.toml index aef915ca6..38426ae8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,16 +55,6 @@ docs = [ "mkdocstrings-python >= 1.12.2", # Python handler for mkdocstrings "markdown-exec >= 1.10.0", # Execute code blocks in markdown ] -dev = [ - "recipe-scrapers[test]", # assuming you have test dependencies - "pre-commit == 4.0.1", # latest from PyPI - "black == 24.10.0", # match what's in .pre-commit-config.yaml - "flake8 == 7.1.1", # match what's in .pre-commit-config.yaml - "pep8-naming == 0.14.1", # match what's in .pre-commit-config.yaml - "mypy == 1.13.0", # match what's in .pre-commit-config.yaml - "types-beautifulsoup4", # needed for mypy - "types-requests", # needed for mypy -] # Testing dependencies # Install these to run tests and check coverage: # pip install -e ".[test]" @@ -74,13 +64,25 @@ dev = [ # coverage run -m unittest # Run tests with coverage # coverage report # View coverage report in terminal # coverage html # Generate HTML coverage report -test = [ +tests = [ "coverage >= 7.6.9", # Code coverage measurement tool "unittest-parallel >= 1.7.0", # Run unittest tests in parallel "importlib-metadata >= 4.6 ; python_version < '3.10'", # used in test_readme ] +linters = [ + "pre-commit == 4.0.1", # latest from PyPI + "black == 24.10.0", # match what's in .pre-commit-config.yaml + "flake8 == 7.1.1", # match what's in .pre-commit-config.yaml + "pep8-naming == 0.14.1", # match what's in .pre-commit-config.yaml + "mypy == 1.13.0", # match what's in .pre-commit-config.yaml + "types-beautifulsoup4", # needed for mypy + "types-requests", # needed for mypy +] +dev = [ + "recipe-scrapers[docs,tests,linters]", +] all = [ - "recipe_scrapers[online,docs,test]" + "recipe_scrapers[online,docs,tests,linters,dev]" ] @@ -94,3 +96,31 @@ version = {attr = "recipe_scrapers.__version__.__version__"} [tool.setuptools.package-data] recipe_scrapers = ["py.typed"] + +[tool.coverage.run] +branch = true +source = ["recipe_scrapers"] +relative_files = true + +[tool.coverage.report] +omit = [ + "recipe_scrapers/__version__.py", + "recipe_scrapers/plugins/template.py", + "recipe_scrapers/settings/template.py" +] +exclude_lines = [ + "raise NotImplementedError" +] + +[tool.mypy] +[[tool.mypy.overrides]] +module = "recipe_scrapers.*" +disable_error_code = "union-attr" + +[[tool.mypy.overrides]] +module = "isodate" +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = "extruct" +ignore_missing_imports = true diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 9a116f7d1..000000000 --- a/tox.ini +++ /dev/null @@ -1,16 +0,0 @@ -[tox] -isolated_build = true - -[testenv] -extras = dev -passenv = PYTHONWARNINGS -commands = coverage run -m unittest {posargs} - -# The system-provided libxml2 on MacOS is typically outdated and this can lead to lxml parsing issues -# Using PyPi-provided binary wheels instead resolves this -# We are affected by https://bugs.launchpad.net/lxml/+bug/1949271 in test_wild_mode when using system-provided libxml2 on MacOS -platform = - workaround-darwin: darwin -install_command = - py: python -I -m pip install {opts} {packages} - workaround-darwin: python -I -m pip install --only-binary=lxml {opts} {packages} From 3d5f6e455a86c6667d5fcc801f9bed12a005ca8b Mon Sep 17 00:00:00 2001 From: hhursev Date: Sat, 14 Dec 2024 21:52:34 +0200 Subject: [PATCH 48/94] Use "Trusted Publishing" w/o the manual user/pass config. (#1436) --- .github/workflows/publish.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index c751f9509..89dd981df 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -6,7 +6,13 @@ on: jobs: publish: + name: Upload release to PyPI runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/recipe-scrapers + permissions: + id-token: write steps: - uses: actions/checkout@v4 - name: Set up Python @@ -20,8 +26,6 @@ jobs: - name: Publish a Python distribution to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} verbose: true - name: Show build version used run: pip list | grep build From 5fc6dedd8eb52bf14a9f65636f225c8927bc9294 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sat, 14 Dec 2024 14:54:37 -0500 Subject: [PATCH 49/94] Groupings and Improved Ingredient Parsing for JamieOliver (#1434) --- recipe_scrapers/jamieoliver.py | 15 + .../jamieoliver.com/jamieoliver.testhtml | 1223 ----------------- .../{jamieoliver.json => jamieoliver_1.json} | 58 +- .../jamieoliver.com/jamieoliver_1.testhtml | 197 +++ .../jamieoliver.com/jamieoliver_2.json | 110 ++ .../jamieoliver.com/jamieoliver_2.testhtml | 155 +++ 6 files changed, 501 insertions(+), 1257 deletions(-) delete mode 100644 tests/test_data/jamieoliver.com/jamieoliver.testhtml rename tests/test_data/jamieoliver.com/{jamieoliver.json => jamieoliver_1.json} (56%) create mode 100644 tests/test_data/jamieoliver.com/jamieoliver_1.testhtml create mode 100644 tests/test_data/jamieoliver.com/jamieoliver_2.json create mode 100644 tests/test_data/jamieoliver.com/jamieoliver_2.testhtml diff --git a/recipe_scrapers/jamieoliver.py b/recipe_scrapers/jamieoliver.py index a2cf8e61e..6dccee576 100644 --- a/recipe_scrapers/jamieoliver.py +++ b/recipe_scrapers/jamieoliver.py @@ -1,4 +1,5 @@ from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients from ._utils import normalize_string @@ -12,3 +13,17 @@ def instructions(self): instructions_list = method_heading.find_next("ol") instructions = instructions_list.find_all("li") return "\n".join([normalize_string(inst.get_text()) for inst in instructions]) + + def ingredients(self): + ingredients_list = self.soup.select(".ingredients-rich-text p.type-body") + return [ + normalize_string(ingredient.get_text()) for ingredient in ingredients_list + ] + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".ingredients-rich-text p.type-h5", + ".ingredients-rich-text p.type-body", + ) diff --git a/tests/test_data/jamieoliver.com/jamieoliver.testhtml b/tests/test_data/jamieoliver.com/jamieoliver.testhtml deleted file mode 100644 index 3c1cb875f..000000000 --- a/tests/test_data/jamieoliver.com/jamieoliver.testhtml +++ /dev/null @@ -1,1223 +0,0 @@ - - - - - - - - - - - - - - - Easy chocolate brownie recipe | Best brownie guide | Jamie Oliver - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - -
    - -
    -
    - - -
    -
    - - - - - - - - - - -
    - - - - -
    - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -
    - -
    - -
    - - -
    -
    - - - -
    - -
    - -
    -
    - -
    -

    Bloomin' brilliant brownies

    -

    Rich dark chocolate, nuts & sour cherries

    -
    - -
    -
    - -
    -
    - -
    -
    - - - - -
    -
    -
    -
    - -
    - Bloomin' brilliant brownies
    - -
    - -
    - - - -
    - -
    - -
    -

    Bloomin' brilliant brownies

    - - - - - -
    - - -
    -
    -
    -
    - Serves - Serves 20
    - -
    - Time - Cooks In40 minutes plus chilling time
    - -
    - DifficultySuper easy
    -
    -
    -
    - -
    - - - - -
    - -
    - Nutrition per serving Plus - -
    - -
    -
      -
    • - -
      - - Calories - - 291 - - 15% -
      - -
    • -
    • - -
      - - Fat - - 18.4g - - 26% -
      - -
    • -
    • - -
      - - Saturates - - 10.1g - - 51% -
      - -
    • -
    • - -
      - - Sugars - - 24.6g - - 27% -
      - -
    • -
    • - -
      - - Salt - - 0.2g - - 3% -
      - -
    • -
    • - -
      - - Protein - - 3.9g - - 8% -
      - -
    • -
    • - -
      - - Carbs - - 28.3g - - 11% -
      - -
    • -
    • - -
      - - Fibre - - 1.6g - - - -
      - -
    • -
    - -
    - Of an adult's reference intake
    - -
    - -
    - - -
    - -
    - -
    -
    - - Cook with Jamie -
    - -
    - -
    -
    recipe adapted from
    -

    Cook with Jamie

    - - - By Jamie Oliver - - - - -
    -
    - -
    -
    -
    - - - - - - -
    - -
    - -
    -
    - -
    -
    - -
    - -
    - -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Tap For Method
    -
    -
    - - - - - - -
    -

    Ingredients

    -
    - - - - - -
    -
    - -
      -
    • - 200 g quality dark chocolate (70%)
    • -
    • - 250 g unsalted butter
    • -
    • - 75 g dried sour cherries , optional
    • -
    • - 50 g chopped nuts , optional
    • -
    • - 80 g quality cocoa powder
    • -
    • - 65 g plain flour
    • -
    • - 1 teaspoon baking powder
    • -
    • - 360 g caster sugar
    • -
    • - 4 large free-range eggs
    • -
    -
    -
    -
    - -
    -
    - Tap For Method - - -
    -
    - -
    -

    The cost per serving below is generated by Whisk.com and is based on costs in individual supermarkets.  For more information about how we calculate costs per serving read our FAQS

    - -
    - -
    - -
    - -
    - -
    -
    - - Cook with Jamie -
    - -
    - -
    -
    recipe adapted from
    -

    Cook with Jamie

    - - - By Jamie Oliver - - - - -
    -
    - -
    - -
    - -
    -
    - -
    - -
    - - -
    - - -
    - -
    -
    -
    -
    - -
    -
    - Tap For Ingredients
    -
    -
    - -
    -
    -
    -

    Method

    -
    -
    1. Preheat the oven to 180°C/350°F/gas 4. Line a 24cm square baking tin with greaseproof paper.
    2. Snap the chocolate into a large bowl, add the butter and place over a pan of simmering water, until melted, stirring regularly. Stir through the cherries and nuts (if using).
    3. Sift the cocoa powder and flour into a separate bowl, add the baking powder and sugar, then mix together.
    4. Add the dry ingredients to the chocolate, cherry and nut mixture and stir together well. Beat the eggs, then mix in until you have a silky consistency.
    5. Pour the brownie mix into the baking tin, 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 clean – the brownies should be slightly springy on the outside but still gooey in the middle.
    6. Allow to cool in the tray, then carefully transfer to a large chopping board and cut into chunky squares. Delicious served with a dollop of crème fraîche or yoghurt mixed with some orange zest.
    - - - - -
    - -
    -
    - -
    - -
    - -
    - - - - -
    - -
    -
    -
    -
    - - - - - - - - -
    - - - - -
    - -
    - -
    - -
    -
    - - Cook with Jamie -
    - -
    - -
    -
    recipe adapted from
    -

    Cook with Jamie

    - - - By Jamie Oliver - - - - -
    -
    - -
    - -
    -
    - - -
    -
    - -
    - -
    - - - -
    -
    - -
    -
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - -
    - -
    - - - - - - - - - diff --git a/tests/test_data/jamieoliver.com/jamieoliver.json b/tests/test_data/jamieoliver.com/jamieoliver_1.json similarity index 56% rename from tests/test_data/jamieoliver.com/jamieoliver.json rename to tests/test_data/jamieoliver.com/jamieoliver_1.json index de0d00c42..9730e1fd6 100644 --- a/tests/test_data/jamieoliver.com/jamieoliver.json +++ b/tests/test_data/jamieoliver.com/jamieoliver_1.json @@ -1,19 +1,19 @@ { "author": "Jamie Oliver", - "canonical_url": "https://www.jamieoliver.com/recipes/chocolate-recipes/bloomin-brilliant-brownies/", + "canonical_url": "https://www.jamieoliver.com/recipes/chocolate/bloomin-brilliant-brownies/", "site_name": "Jamie Oliver", "host": "jamieoliver.com", - "language": "en", + "language": "en-GB", "title": "Bloomin' brilliant brownies", "ingredients": [ - "200 g quality dark chocolate (70%)", - "250 g unsalted butter", - "75 g dried sour cherries optional", - "50 g chopped nuts optional", - "80 g quality cocoa powder", - "65 g plain flour", + "200g quality dark chocolate (70%)", + "250g unsalted butter", + "optional: 75g dried sour cherries", + "optional: 50g chopped nuts", + "80g quality cocoa powder", + "65g plain flour", "1 teaspoon baking powder", - "360 g caster sugar", + "360g caster sugar", "4 large free-range eggs" ], "instructions_list": [ @@ -24,36 +24,26 @@ "Pour the brownie mix into the baking tin, 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 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. Delicious served with a dollop of crème fraîche or yoghurt mixed with some orange zest." ], - "category": "Desserts", + "category": "Baking", "yields": "20 servings", - "description": "This is a great little recipe for easy, fail-safe, gloriously gooey chocolate brownies", + "description": "This easy brownie recipe from Jamie Oliver never disappoints. It's totally foolproof, and packed with dark chocolate, chopped nuts, cocoa powder and sour cherries. Perfect for weekend baking.", "total_time": 40, - "cuisine": "https://schema.org/VegetarianDiet", + "cook_time": 40, "nutrients": { "calories": "291 calories", - "fatContent": "18.4 g fat", - "saturatedFatContent": "10.1 g saturated fat", - "carbohydrateContent": "28.3 g carbohydrate", - "sugarContent": "24.6 g sugar", - "proteinContent": "3.9 g protein", - "sodiumContent": "0.2 g salt", - "fiberContent": "1.6 g fibre" + "fat": "18.4 g", + "portionWeight": "45.9 g", + "protein": "3.9 g", + "salt": "0.2 g", + "saturatedFat": "10.1 g", + "carbs": "28.3 g", + "classification": "140", + "fibre": "1.6 g", + "sugars": "24.6 g" }, - "image": "https://img.jamieoliver.com/jamieoliver/recipe-database/oldImages/large/88_1_1441269331.jpg?tr=w-800,h-800", + "image": "https://asset.jamieoliver.com/images/cq7w2e71/production/f1e42faa99fb1756e2e1463a8b6af3429a4c323a-1447x2171.jpg/brillbrownies.jpg?rect=0,432,1447,1447&w=600&h=600&fm=webp&q=75&fit=crop&auto=format", "keywords": [ - "chocolate", - "brownies", - "brownie", - "vegetarian", - "sweets and desserts", - "baking", - "cooking", - "chocolate brownies", - "party food", - "baking and desserts", - "Christmas", - "Dinner Party", - "non-promotable", - "Popular" + "Party Food", + "Chocolate Main Ingredient" ] } diff --git a/tests/test_data/jamieoliver.com/jamieoliver_1.testhtml b/tests/test_data/jamieoliver.com/jamieoliver_1.testhtml new file mode 100644 index 000000000..dd8b9593e --- /dev/null +++ b/tests/test_data/jamieoliver.com/jamieoliver_1.testhtml @@ -0,0 +1,197 @@ + +Easy chocolate brownie recipe + + + + + + + + + + +
    Jamie drizzling honey on top of a fig tart

    Share your review and contribute to our community!

    Save and access your favourite recipes and products.

    +Enter the email address associated with your account, and we’ll email you a link to reset your + password. +

    Password Strength

    Must contain at least

    +*Enter your email to receive news and exclusive offers from Jamie Oliver Limited about Jamie's + businesses, including books, TV shows, restaurants, products, commercial partners and + campaigning activities. By signing up, you agree to our Terms of Use . Learn how we collect, use and share your data in our Privacy Policy . +

    Cart item

    Just Added

    Easy chocolate brownies stacked on top of each other
    Save recipe

    Bloomin' brilliant brownies

    Rich dark chocolate, nuts & sour cherries

    Easy chocolate brownies stacked on top of each other
    Save recipe

    40 mins plus chilling time
    Super easy

    serves 20

    About the recipe

    This is a great little recipe for easy, fail-safe, gloriously gooey chocolate brownies


    nutrition per serving

    Calories

    g

    Fat

    g

    Saturates

    g

    Sugars

    g

    Salt

    g

    Protein

    g

    Carbs

    g

    Fibre

    of an adult’s reference intake


    Recipe From

    Cook with Jamie

    Cook with Jamie

    +By Jamie Oliver

    +Ingredients +

    200g quality dark chocolate (70%)

    250g unsalted butter

    optional: 75g dried sour cherries

    optional: 50g chopped nuts

    80g quality cocoa powder

    65g plain flour

    1 teaspoon baking powder

    360g caster sugar

    4 large free-range eggs

    Method

    1. Preheat the oven to 180°C/350°F/gas 4. Line a 24cm square baking tin with greaseproof paper.
    2. Snap the chocolate into a large bowl, add the butter and place over a pan of simmering water, until melted, stirring regularly. Stir through the cherries and nuts (if using).
    3. Sift the cocoa powder and flour into a separate bowl, add the baking powder and sugar, then mix together.
    4. Add the dry ingredients to the chocolate, cherry and nut mixture and stir together well. Beat the eggs, then mix in until you have a silky consistency.
    5. Pour the brownie mix into the baking tin, 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 clean – the brownies should be slightly springy on the outside but still gooey in the middle.
    6. Allow to cool in the tray, then carefully transfer to a large chopping board and cut into chunky squares. Delicious served with a dollop of crème fraîche or yoghurt mixed with some orange zest.

    Tags

    Perfect Christmas gifts

    Recipes you may like

    related features

    \ No newline at end of file diff --git a/tests/test_data/jamieoliver.com/jamieoliver_2.json b/tests/test_data/jamieoliver.com/jamieoliver_2.json new file mode 100644 index 000000000..e6b5ac29b --- /dev/null +++ b/tests/test_data/jamieoliver.com/jamieoliver_2.json @@ -0,0 +1,110 @@ +{ + "author": "Romy Gill", + "canonical_url": "https://www.jamieoliver.com/recipes/chicken/murg-makhani", + "site_name": "Jamie Oliver", + "host": "jamieoliver.com", + "language": "en-GB", + "title": "Butter chicken", + "ingredients": [ + "750g (1 lb 10 oz) skinless, boneless chicken (thighs and breast), cut into bite-size pieces", + "10g (½ oz) ginger root, peeled and grated (shredded)", + "3 large garlic cloves, peeled and grated (shredded)", + "2 tsp tandoori masala", + "1 tsp ground cumin", + "1 tsp ground coriander", + "1 tsp ground black pepper", + "1 tsp salt", + "2 tbsp yoghurt", + "juice of ½ lemon", + "30ml (1 fl oz/2 tbsp) sunflower oil", + "500g (1 lb 2 oz) tomatoes", + "50g (2 oz) butter", + "20g (3/4 oz) ginger root, peeled and grated (shredded)", + "6 large garlic cloves, peeled and grated (shredded)", + "1 tsp tomato purée (paste)", + "1 tsp tandoori masala", + "1 tsp ground cumin", + "1 tsp ground coriander", + "1 tsp chilli powder", + "1 tsp salt", + "1 tsp sugar", + "30g (1½ oz) ground cashew nuts", + "30ml (1 fl oz/2 tbsp) double (heavy) cream", + "6–8 green cardamom seeds, crushed", + "2 tsp dried fenugreek leaves (kasoori methi)", + "your choice of Indian flatbreads or rice" + ], + "ingredient_groups": [ + { + "ingredients": [ + "750g (1 lb 10 oz) skinless, boneless chicken (thighs and breast), cut into bite-size pieces" + ], + "purpose": null + }, + { + "ingredients": [ + "10g (½ oz) ginger root, peeled and grated (shredded)", + "3 large garlic cloves, peeled and grated (shredded)", + "2 tsp tandoori masala", + "1 tsp ground cumin", + "1 tsp ground coriander", + "1 tsp ground black pepper", + "1 tsp salt", + "2 tbsp yoghurt", + "juice of ½ lemon", + "30ml (1 fl oz/2 tbsp) sunflower oil" + ], + "purpose": "FOR THE MARINADE" + }, + { + "ingredients": [ + "500g (1 lb 2 oz) tomatoes", + "50g (2 oz) butter", + "20g (3/4 oz) ginger root, peeled and grated (shredded)", + "6 large garlic cloves, peeled and grated (shredded)", + "1 tsp tomato purée (paste)", + "1 tsp tandoori masala", + "1 tsp ground cumin", + "1 tsp ground coriander", + "1 tsp chilli powder", + "1 tsp salt", + "1 tsp sugar", + "30g (1½ oz) ground cashew nuts", + "30ml (1 fl oz/2 tbsp) double (heavy) cream", + "6–8 green cardamom seeds, crushed", + "2 tsp dried fenugreek leaves (kasoori methi)" + ], + "purpose": "FOR THE SAUCE" + }, + { + "ingredients": [ + "your choice of Indian flatbreads or rice" + ], + "purpose": "TO SERVE" + } + ], + "instructions_list": [ + "To make the marinade, mix all of the marinade ingredients together in a large bowl. Prick the chicken pieces with a fork to allow the marinade to penetrate the meat. Add the chicken to the bowl and stir well to coat thoroughly. Cover the bowl and set aside in the fridge to marinate for at least a couple of hours.", + "When ready to cook, preheat the oven to 180ºC fan/400ºF/gas 6. Spread the marinated chicken out on a baking tray and cook in the hot oven for 15 minutes.", + "While the chicken is cooking, make the sauce. If the chicken finishes cooking before you have finished making the sauce, switch the oven off after the 15 minutes and leave the meat to rest in the oven.", + "Blanch the tomatoes in a bowl of boiling water for a few minutes, then remove their skins. Cut into quarters and remove the seeds, then roughly chop and place in a food processor. Blitz to a smooth purée.", + "Heat the butter in a saucepan over a medium heat. Once the butter has melted, add the ginger and garlic and cook for 1 minute. Add the puréed fresh tomatoes as well as the tomato purée and cook for 8–10 minutes until the tomatoes are cooked through, stirring regularly to avoid them sticking and burning. Add all the spices, chilli powder, salt and sugar, mix well and cook for a further 2 minutes until emulsified. Lower the heat, then add the ground cashew nuts and cream, and stir well. Add 500–600 ml (20–24 fl oz/ 2½ cups–scant 3 cups) water – the quantity you choose to add depends on how runny you want the sauce to be. Bring the mixture to a boil, and when it starts bubbling, add the chicken, lower the heat and cook for a further 8–10 minutes.", + "Sprinkle over the cardamom seeds and dried fenugreek leaves. Stir and leave to rest for at least 10 minutes before serving with rice or any Indian flatbreads." + ], + "category": "Cookbook Club", + "yields": "5 servings", + "description": "There's so many different ways to cook butter chicken – discover Romy Gill's take on this iconic dish.", + "cuisine": "Indian", + "nutrients": { + "forKids": "false" + }, + "image": "https://asset.jamieoliver.com/images/cq7w2e71/production/b76ba59841d87b3d49ad8d16b5a2380a505e579a-958x1280.jpg/160329475?rect=0,161,958,958&w=600&h=600&fm=webp&q=75&fit=crop&auto=format", + "keywords": [ + "Cookbook Club", + "Curry", + "Chicken", + "Indian-style", + "Dinner Party", + "Dinner" + ] +} diff --git a/tests/test_data/jamieoliver.com/jamieoliver_2.testhtml b/tests/test_data/jamieoliver.com/jamieoliver_2.testhtml new file mode 100644 index 000000000..c70821728 --- /dev/null +++ b/tests/test_data/jamieoliver.com/jamieoliver_2.testhtml @@ -0,0 +1,155 @@ + +Butter Chicken | Jamie Oliver Cookbook Club + + + + + + + + + + +
    Jamie drizzling honey on top of a fig tart

    Share your review and contribute to our community!

    Save and access your favourite recipes and products.

    +Enter the email address associated with your account, and we’ll email you a link to reset your + password. +

    Password Strength

    Must contain at least

    +*Enter your email to receive news and exclusive offers from Jamie Oliver Limited about Jamie's + businesses, including books, TV shows, restaurants, products, commercial partners and + campaigning activities. By signing up, you agree to our Terms of Use . Learn how we collect, use and share your data in our Privacy Policy . +

    Cart item

    Just Added

    Murg makhani
    Save recipe

    Butter chicken

    Murg makhani

    Murg makhani
    Save recipe
    Not Too Tricky

    serves 4-5

    About the recipe

    There are so many different recipes for butter chicken. This is my take, because there is a lot of spark and dispute going on in India about butter chicken. We served so much butter chicken in our restaurant, so I went in search of the very best butter chicken recipe and researched how it all started. I found this gave me a better understanding of this best-loved dish. With its silky smooth, gently spiced tomato, cashew and cream gravy, it’s a comforting, warming dish that feels decadent. It was in 2013 when I started to take a closer look at butter chicken and its history. My mentor, chef Manjit Gill, took me to the first ever Moti Mahal restaurant in Daryagang in Delhi. A restaurant co-founded by Kundan Lal Jaggi, Kundal Lal Gujral and Maggu (also known as Thakur Das) and it was where they created both butter chicken and dal makhani.



    Recipe From

    Romy Gill's India

    Romy Gill's India

    +By Romy Gill

    +Ingredients +

    750g (1 lb 10 oz) skinless, boneless chicken (thighs and breast), cut into bite-size pieces

    FOR THE MARINADE

    10g (½ oz) ginger root, peeled and grated (shredded)

    3 large garlic cloves, peeled and grated (shredded)

    2 tsp tandoori masala

    1 tsp ground cumin

    1 tsp ground coriander

    1 tsp ground black pepper

    1 tsp salt

    2 tbsp yoghurt

    juice of ½ lemon

    30ml (1 fl oz/2 tbsp) sunflower oil

    FOR THE SAUCE

    500g (1 lb 2 oz) tomatoes

    50g (2 oz) butter

    20g (3/4 oz) ginger root, peeled and grated (shredded)

    6 large garlic cloves, peeled and grated (shredded)

    1 tsp tomato purée (paste)

    1 tsp tandoori masala

    1 tsp ground cumin

    1 tsp ground coriander

    1 tsp chilli powder

    1 tsp salt

    1 tsp sugar

    30g (1½ oz) ground cashew nuts

    30ml (1 fl oz/2 tbsp) double (heavy) cream

    6–8 green cardamom seeds, crushed

    2 tsp dried fenugreek leaves (kasoori methi)

    TO SERVE

    your choice of Indian flatbreads or rice

    Method

    1. To make the marinade, mix all of the marinade ingredients together in a large bowl. Prick the chicken pieces with a fork to allow the marinade to penetrate the meat. Add the chicken to the bowl and stir well to coat thoroughly. Cover the bowl and set aside in the fridge to marinate for at least a couple of hours.
    2. When ready to cook, preheat the oven to 180ºC fan/400ºF/gas 6. Spread the marinated chicken out on a baking tray and cook in the hot oven for 15 minutes.
    3. While the chicken is cooking, make the sauce. If the chicken finishes cooking before you have finished making the sauce, switch the oven off after the 15 minutes and leave the meat to rest in the oven.
    4. Blanch the tomatoes in a bowl of boiling water for a few minutes, then remove their skins. Cut into quarters and remove the seeds, then roughly chop and place in a food processor. Blitz to a smooth purée.
    5. Heat the butter in a saucepan over a medium heat. Once the butter has melted, add the ginger and garlic and cook for 1 minute. Add the puréed fresh tomatoes as well as the tomato purée and cook for 8–10 minutes until the tomatoes are cooked through, stirring regularly to avoid them sticking and burning. Add all the spices, chilli powder, salt and sugar, mix well and cook for a further 2 minutes until emulsified. Lower the heat, then add the ground cashew nuts and cream, and stir well. Add 500–600 ml (20–24 fl oz/ 2½ cups–scant 3 cups) water – the quantity you choose to add depends on how runny you want the sauce to be. Bring the mixture to a boil, and when it starts bubbling, add the chicken, lower the heat and cook for a further 8–10 minutes.
    6. Sprinkle over the cardamom seeds and dried fenugreek leaves. Stir and leave to rest for at least 10 minutes before serving with rice or any Indian flatbreads.

    Tags

    More Romy Gill recipes

    More Indian-style recipes

    related features

    \ No newline at end of file From 2f9fc3e5feadc36242f181ad150cc64d10f486a8 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sat, 14 Dec 2024 22:10:51 +0200 Subject: [PATCH 50/94] Bump version to 15.3.3 Adds support for: - 40aprons.com - irishcentral.com - shelikesfood.com - wedishitup.com - ameessavorydish.com - meganvskitchen.com - ahealthysliceoflife.com - recette.plus - schoolofwok.co.uk - veroniquecloutier.com - chefjeanpierre.com - themediterraneandish.com - lanascooking.co - inspiredtaste.net - eggs.ca - recipeland.com - noracooks.com - makeitdairyfree.com Bugfixes: - jamieoliver: instructions retrieval fix Misc: - fix double parentheses occurences in some ingredients(_groups) fetching #1407 - launching docs.recipe-scrapers.com (not usable yet) --- recipe_scrapers/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe_scrapers/__version__.py b/recipe_scrapers/__version__.py index 85829d2f9..0a9a395ea 100644 --- a/recipe_scrapers/__version__.py +++ b/recipe_scrapers/__version__.py @@ -1 +1 @@ -__version__ = "15.3.2" +__version__ = "15.3.3" From 592c9bc920093b35dc1f2006ee5a010124ebd1da Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sun, 15 Dec 2024 13:36:54 +0200 Subject: [PATCH 51/94] docs: remove api/* stuff. no need to 'showcase' mkdocs like that --- docs/api/exceptions.md | 3 --- docs/api/scraper.md | 5 ----- docs/api/utils.md | 3 --- mkdocs.yaml | 4 ---- 4 files changed, 15 deletions(-) delete mode 100644 docs/api/exceptions.md delete mode 100644 docs/api/scraper.md delete mode 100644 docs/api/utils.md diff --git a/docs/api/exceptions.md b/docs/api/exceptions.md deleted file mode 100644 index ac4ad47be..000000000 --- a/docs/api/exceptions.md +++ /dev/null @@ -1,3 +0,0 @@ -# Exceptions - -::: recipe_scrapers._exceptions diff --git a/docs/api/scraper.md b/docs/api/scraper.md deleted file mode 100644 index 5652de510..000000000 --- a/docs/api/scraper.md +++ /dev/null @@ -1,5 +0,0 @@ -# Base Scraper - -::: recipe_scrapers.scrape_html - options: - show_root_members: true diff --git a/docs/api/utils.md b/docs/api/utils.md deleted file mode 100644 index 0dfbfb000..000000000 --- a/docs/api/utils.md +++ /dev/null @@ -1,3 +0,0 @@ -# Utility Functions - -::: recipe_scrapers._utils diff --git a/mkdocs.yaml b/mkdocs.yaml index 420da9ea8..2dc47eab0 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -39,10 +39,6 @@ nav: - "In Depth: Scraper Functions": in-depth-guide-scraper-functions.md - "In Depth: Ingredient Groups": in-depth-guide-ingredient-groups.md - "In Depth: Debugging": in-depth-guide-debugging.md - - API Reference: - - Base Scraper: api/scraper.md - - Exceptions: api/exceptions.md - - Utils: api/utils.md markdown_extensions: - admonition From 46d0ec66aa86f785c3300a6c8977fdd3941af3c2 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sun, 15 Dec 2024 22:47:17 +0200 Subject: [PATCH 52/94] docs: Initial docs site structure and setup --- docs/contributing-to-our-documentation.md | 39 --- docs/contributing.md | 226 ------------------ docs/contributing/code-contribution.md | 0 docs/contributing/documentation.md | 0 docs/contributing/how-to-contribute.md | 0 .../in-depth-guide-debugging.md | 0 .../in-depth-guide-html-scraping.md | 0 .../in-depth-guide-ingredient-groups.md | 0 .../in-depth-guide-scraper-functions.md | 0 docs/copyright-and-usage.md | 0 docs/getting-started.md | 15 -- docs/getting-started/advanced-usage.md | 0 docs/getting-started/examples.md | 0 docs/getting-started/releases-and-license.md | 0 docs/{ => getting-started}/supported-sites.md | 2 +- docs/index.md | 53 ---- mkdocs.yaml | 27 ++- 17 files changed, 19 insertions(+), 343 deletions(-) delete mode 100644 docs/contributing-to-our-documentation.md delete mode 100644 docs/contributing.md create mode 100644 docs/contributing/code-contribution.md create mode 100644 docs/contributing/documentation.md create mode 100644 docs/contributing/how-to-contribute.md rename docs/{ => contributing}/in-depth-guide-debugging.md (100%) rename docs/{ => contributing}/in-depth-guide-html-scraping.md (100%) rename docs/{ => contributing}/in-depth-guide-ingredient-groups.md (100%) rename docs/{ => contributing}/in-depth-guide-scraper-functions.md (100%) create mode 100644 docs/copyright-and-usage.md delete mode 100644 docs/getting-started.md create mode 100644 docs/getting-started/advanced-usage.md create mode 100644 docs/getting-started/examples.md create mode 100644 docs/getting-started/releases-and-license.md rename docs/{ => getting-started}/supported-sites.md (85%) diff --git a/docs/contributing-to-our-documentation.md b/docs/contributing-to-our-documentation.md deleted file mode 100644 index dabf37daf..000000000 --- a/docs/contributing-to-our-documentation.md +++ /dev/null @@ -1,39 +0,0 @@ -# Contributing to Our Documentation - -We're excited to have you help improve our documentation! Here's a step-by-step guide to get you started. - - -### Setting Up Your Local Environment -First, let's set up your development environment: - -```bash -git clone git@github.com:hhursev/recipe-scrapers.git && -cd recipe-scrapers && -python -m venv .venv && -source .venv/bin/activate && -python -m pip install --upgrade pip && -pip install -e ".[docs]" -``` - -### Viewing the Documentation Locally - -Start the documentation server with: - -``` -mkdocs serve -``` - -You can now view the documentation at http://localhost:8000/. -The server will automatically refresh when you make changes. - - -### Making Your Contributions - -1. Navigate to the `docs/` directory where all documentation files are stored -2. Make your desired changes to the documentation files -3. If needed, update the navigation structure in mkdocs.yml (particularly the nav section) -4. Preview your changes in real-time through the local server -5. Once you're satisfied with your updates, create a pull request - -We appreciate your contributions to making our documentation better! -If you have any questions during this process, please don't hesitate to reach out. diff --git a/docs/contributing.md b/docs/contributing.md deleted file mode 100644 index 83a35aad6..000000000 --- a/docs/contributing.md +++ /dev/null @@ -1,226 +0,0 @@ -# How To: Develop a New Scraper - -## 1. Find a website - -If you have found a website you want to scrape the recipes from, first of all check to see if the website is already supported. - -The project [README](https://github.com/hhursev/recipe-scrapers/blob/main/README.rst) has a list of the hundreds of websites already supported. - -You can also check from within Python: - -```python ->>> from recipe_scrapers import SCRAPERS -``` - -`SCRAPERS` is a dict where the keys are the hostnames of the supported websites and the values are the scraper classes for each supported website. - -```python ->>> from recipe_scrapers import SCRAPERS ->>> SCRAPERS.get("bbcgoodfood.com") -recipe_scrapers.bbcgoodfood.BBCGoodFood -``` - -It's a good idea to file an [issue](https://github.com/hhursev/recipe-scrapers/issues/new/choose) on GitHub to track support for the website, and to indicate whether you are working on it. - -## 2. Fork the recipe-scrapers repository and clone - -If this is your first time contributing to this repository then you will need to create a fork of the repository and clone it to your computer. - -To create a fork, click the Fork button near the top of page on the project GitHub page. This will create a copy of the repository under your GitHub user. - -You can then clone the fork to your computer and set it up for development. - -**Clone the repository**, replacing \ with your username: - -```shell -git clone git@github.com:/recipe-scrapers.git -cd recipe-scrapers -``` - -**Create a virtual environment, activate and install dependencies**: - -```shell -python -m venv .venv --upgrade-deps -source .venv/bin/activate -pip install -e .[dev] -pip install pre-commit -pre-commit install -``` - -**Check that everything is working by running the tests**: - -```shell -python -m unittest -``` - -This will run all the tests for all the scrapers. You should not see any errors or failures. - -**OPTIONAL: To run the full test suite in parallel**: - -```shell -pip install unittest-parallel -unittest-parallel --level test -``` - -## 3. Identify a recipe and generate the scraper and test file - -To develop the scraper for the website, first identify a recipe. This will be used to create the test case that will validate that the scraper is working correctly. - -> [!TIP] -> Try to pick a recipe that involves more than one instruction, if you can. The test suite considers single-instruction recipes to indicate possible human error. If you need to, though, you can [indicate that that's expected](https://github.com/hhursev/recipe-scrapers/blob/98ead6fc6e9653805b01539a3f46fbfb4e096136/tests/test_allrecipes.py#L147-L150). - -Next, find out if the website supports [Recipe Schema](https://schema.org/Recipe). If the website does support Recipe Schema, this will make creating the scraper straightforward. If not, supporting the site will be more complex but still possible. - -```python ->>> from recipe_scrapers import scrape_html ->>> scraper = scrape_html(HTML, URL, wild_mode=True) ->>> scraper.schema.data -{'@context': 'https://schema.org', - '@type': 'Recipe', - ... -} -``` - -If Recipe Schema is available, then `scraper.schema.data` will return a dict containing information about the recipe. - -If Recipe Schema is not available, then `scraper.schema.data` will return an empty dict. - -Next, generate the scraper class and test files by running this command: - -```shell -python generate.py -``` - -This will generate a file for the scraper with name \ with basic code that you will need to modify. This will also download the recipe at \ and create a test case. - -You can find the generated scraper class in the `recipe_scrapers/` directory in a file the same as \ but all lower case. The generated scraper class will look something like this: - -```python -from ._abstract import AbstractScraper - -class ScraperName(AbstractScraper): - @classmethod - def host(cls): - return "websitehost.com" - - def author(self): - return self.schema.author() - - def title(self): - return self.schema.title() - - def category(self): - return self.schema.category() - - def total_time(self): - return self.schema.total_time() - - def yields(self): - return self.schema.yields() - - def image(self): - return self.schema.image() - - def ingredients(self): - return self.schema.ingredients() - - def instructions(self): - return self.schema.instructions() - - def ratings(self): - return self.schema.ratings() - - def cuisine(self): - return self.schema.cuisine() - - def description(self): - return self.schema.description() -``` - -The generated scraper class will automatically be populated with functions that assume the Recipe Schema is available, regardless of whether it is or not. - -## 4. Add functionality to the scraper - -If the website supports Recipe Schema, then this is mostly done for you already. You can check if the output from each function is what you would expect from the recipe by using the scraper. - -```python ->>> from recipe_scrapers import scrape_html ->>> scraper = scrape_html(HTML, URL) ->>> scraper.title() -"..." ->>> scraper.ingredients() -[ - "...", - "..." -] -# etc. -``` - -Some additional functionality may be required in the scraper functions to make the output match the recipe on the website. - -An in-depth guide on all the functions a scraper can support and what their output should be can be found [here](in-depth-guide-scraper-functions.md). The automatically generated scraper does not include all of these functions by default, so you may wish to add some of the additional functions listed if the website can support them. - -If the website does not support Recipe Schema, or the schema does not include all of the recipe information, then you can scrape the information out of the website HTML. Each scraper has a `bs4.BeautifulSoup` object made available in `self.soup` which contains the parsed HTML. This can be used to extract the recipe information needed. - -An example of a scraper that uses this approach is [Przepisy](https://github.com/hhursev/recipe-scrapers/blob/main/recipe_scrapers/przepisy.py). - -The [BeautifulSoup documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.html) is a good resource for getting started with extracting information from HTML. A guide of common patterns and best practice used in this library can be found [here](in-depth-guide-html-scraping.md). - -Some helper functions are available in the `_utils.py` file. These are functions that are commonly needed when extracting information from HTML, such as `normalize_string()`. - -## 5. Create the test - -A test case was automatically created when the scraper class was created. It can be found in the `tests/test_data/` directory, where `host` is the hostname of the website the scraper is for. - -The test case comprises two parts: - -1. testhtml file containing the html from the URL used to generate the scraper -1. json file containing the expected output from the scraper when the scraper is run on the testhtml file. - -The generated json file will look something like this, with only the host field populated: - -```json -{ - "host": "", - "canonical_url": "", - "site_name": "", - "author": "", - "language": "", - "title": "", - "ingredients": "", - "instructions_list": "", - "total_time": "", - "yields": "", - "image": "", - "description": "", -} -``` - -Each of the fields in this file has the same name as the related scraper function. You will need to add the correct output from the scraper to each of these fields. - -If the scraper implements any of the optional functions listed in the [Scraper Functions guide](in-depth-guide-scraper-functions.md), then you should add the appropriate fields to the json file. - -In some cases, a scraper is not able to support one or more of the mandatory functions because the website doesn't provide the information. In these cases, remove the field from the json file. What will happen is that the test case will check to see if the scraper raises an exception if any of the unsupported functions are called. - -You can check whether your scraper is passing the tests by running - -```shell -python -m unittest -k -``` - -Where `ClassName` is the name that you used earlier to generate the scraper. - -> [!TIP] -> It is also recommended that you manually test the scraper with a couple of different recipes from the website, to check that there aren't any special cases the scraper will need to handle. You don't need to create test cases for each of these. - -## 6. Update the README - -Add the website's domain to the supported scraper list in README.rst, ensuring alphabetical order. - -If your site supports multiple top level domains (e.g. `.com.au`, `.co.ul`, `.at`, etc.) then list these on an indented entry under the primary domain (the default value of `host()` when no arguments are provided). For an example of this, check out the `hellofresh` listings. - -## 7. Open a pull request - -Once you have finished developing the scraper and test case, you can commit the files to git and push them to GitHub. You should also update the README.rst to list the site, alphabetically, under the [Scrapers available for:](https://github.com/hhursev/recipe-scrapers#scrapers-available-for) header. - -After you have pushed the changes to GitHub, you can open a pull request in the [recipe-scrapers project](https://github.com/hhursev/recipe-scrapers/pulls). Your changes will undergo some automatic tests (no different to running the all the tests in the project, but this time on all supported platforms and using all supported Python versions) and be reviewed by other project contributors. diff --git a/docs/contributing/code-contribution.md b/docs/contributing/code-contribution.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/contributing/documentation.md b/docs/contributing/documentation.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/contributing/how-to-contribute.md b/docs/contributing/how-to-contribute.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/in-depth-guide-debugging.md b/docs/contributing/in-depth-guide-debugging.md similarity index 100% rename from docs/in-depth-guide-debugging.md rename to docs/contributing/in-depth-guide-debugging.md diff --git a/docs/in-depth-guide-html-scraping.md b/docs/contributing/in-depth-guide-html-scraping.md similarity index 100% rename from docs/in-depth-guide-html-scraping.md rename to docs/contributing/in-depth-guide-html-scraping.md diff --git a/docs/in-depth-guide-ingredient-groups.md b/docs/contributing/in-depth-guide-ingredient-groups.md similarity index 100% rename from docs/in-depth-guide-ingredient-groups.md rename to docs/contributing/in-depth-guide-ingredient-groups.md diff --git a/docs/in-depth-guide-scraper-functions.md b/docs/contributing/in-depth-guide-scraper-functions.md similarity index 100% rename from docs/in-depth-guide-scraper-functions.md rename to docs/contributing/in-depth-guide-scraper-functions.md diff --git a/docs/copyright-and-usage.md b/docs/copyright-and-usage.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/getting-started.md b/docs/getting-started.md deleted file mode 100644 index 61c280842..000000000 --- a/docs/getting-started.md +++ /dev/null @@ -1,15 +0,0 @@ -# Getting Started - -!!! note "Installation" - This documentation is in **early** development and actively being improved. For now, please refer to the repository's [README](https://github.com/hhursev/recipe-scrapers/blob/main/README.rst). - - -```bash -pip install recipe-scrapers -``` - -or - -```bash -pip install recipe-scrapers[online] -``` diff --git a/docs/getting-started/advanced-usage.md b/docs/getting-started/advanced-usage.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/getting-started/examples.md b/docs/getting-started/examples.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/getting-started/releases-and-license.md b/docs/getting-started/releases-and-license.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/supported-sites.md b/docs/getting-started/supported-sites.md similarity index 85% rename from docs/supported-sites.md rename to docs/getting-started/supported-sites.md index c54788094..e1cdcc5d9 100644 --- a/docs/supported-sites.md +++ b/docs/getting-started/supported-sites.md @@ -1,7 +1,7 @@ # Supported Websites !!! note "Contributing" - Want to help maintain or add support for a site? Join our community of contributors! See our [contributing guidelines](contributing.md). + Want to help maintain or add support for a site? Join our community of contributors! See our [contributing guidelines](../contributing/how-to-contribute.md). See something missing or incorrect? [Open an issue](https://github.com/hhursev/recipe-scrapers/issues) or submit a pull request. diff --git a/docs/index.md b/docs/index.md index 9e8f8d2ef..e69de29bb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,53 +0,0 @@ -# Recipe Scrapers - -Welcome to Recipe Scrapers - a Python package that makes extracting recipes from websites a piece of cake! 🍰 - -This documentation is in **early** development and actively being improved. For now, please refer to the repository's [README](https://github.com/hhursev/recipe-scrapers/blob/main/README.rst). - - -[We support the following sites](supported-sites.md) - -[Contributing to Our Documentation](contributing-to-our-documentation.md) - - ----- - - -## Goal - -This library has the goals of - -* making recipe information **accessible**, -* ensuring the author is **attributed** correctly, -* representing the recipes **accurately** and **authentically** - -Sometimes it is simple and straightforward to achieve all these goals, and sometimes it is more difficult (which is why this library exists). Where some interpretation or creativity is required to scrape a recipe, we should always keep those goals in mind. Occasionally, that might mean that we can't support a particular website. - -## Contents: - -- [Contributing to Our Documentation](contributing-to-our-documentation.md) -* [How To: Develop a New Scraper](contributing.md) -* In Depth Guides: - * [HTML Scraping](in-depth-guide-html-scraping.md) - * [Ingredient Groups](in-depth-guide-ingredient-groups.md) - * [Scraper Functions](in-depth-guide-scraper-functions.md) - * [Debugging](in-depth-guide-debugging.md) (coming soon) - - -## What is Recipe Scrapers? - -Recipe Scrapers is a Python library that simplifies the process of extracting structured recipe data from cooking and recipe websites. It handles the complexities of web scraping while providing you with clean, structured recipe data. - -```python -from urllib.request import urlopen - -from recipe_scrapers import scrape_html - -url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" -html = urlopen(url).read().decode("utf-8") # retrieves the recipe webpage HTML -scraper = scrape_html(html, org_url=url) -scraper.title() -scraper.instructions() # etc. -# for a complete list of methods: -# help(scraper) -``` diff --git a/mkdocs.yaml b/mkdocs.yaml index 2dc47eab0..1604335d5 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -27,18 +27,27 @@ theme: - navigation.top - search.suggest - search.highlight + - navigation.top + - navigation.tabs + - navigation.tabs.sticky nav: - - Home: index.md - - Getting Started: getting-started.md - - Supported Sites: supported-sites.md + - Getting Started: + - Home: index.md + - Examples: getting-started/examples.md + - Supported Sites: getting-started/supported-sites.md + - Advanced Usage: getting-started/advanced-usage.md + - Releases & License: getting-started/releases-and-license.md - Contributing: - - Contributing to Our Documentation: contributing-to-our-documentation.md - - Overview: contributing.md - - "In Depth: HTML Scraping": in-depth-guide-html-scraping.md - - "In Depth: Scraper Functions": in-depth-guide-scraper-functions.md - - "In Depth: Ingredient Groups": in-depth-guide-ingredient-groups.md - - "In Depth: Debugging": in-depth-guide-debugging.md + - How to Contribute: contributing/how-to-contribute.md + - Documentation: contributing/documentation.md + - Code Contribution: contributing/code-contribution.md + - In-Depth Guides: + - HTML Scraping: contributing/in-depth-guide-html-scraping.md + - Scraper Functions: contributing/in-depth-guide-scraper-functions.md + - Ingredient Groups: contributing/in-depth-guide-ingredient-groups.md + - Debugging: contributing/in-depth-guide-debugging.md + - Copyright and Usage: copyright-and-usage.md markdown_extensions: - admonition From 088ce8ed76d0271e3b7ee44bd267d63e199e2464 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Sun, 15 Dec 2024 23:55:22 +0200 Subject: [PATCH 53/94] docs: Polish the index.md --- docs/index.md | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/docs/index.md b/docs/index.md index e69de29bb..73abd3b31 100644 --- a/docs/index.md +++ b/docs/index.md @@ -0,0 +1,103 @@ +# Recipe Scrapers + +[![Github](https://img.shields.io/github/stars/hhursev/recipe-scrapers?style=social)](https://github.com/hhursev/recipe-scrapers/) +[![Version](https://img.shields.io/pypi/v/recipe-scrapers.svg)](https://pypi.org/project/recipe-scrapers/) +[![Python Version](https://img.shields.io/pypi/pyversions/recipe-scrapers)](https://pypi.org/project/recipe-scrapers/) +[![Downloads](https://pepy.tech/badge/recipe-scrapers)](https://pepy.tech/project/recipe-scrapers) +[![GitHub Actions Unittests](https://github.com/hhursev/recipe-scrapers/workflows/unittests/badge.svg?branch=main)](https://github.com/hhursev/recipe-scrapers/actions/) +[![Coveralls](https://coveralls.io/repos/hhursev/recipe-scraper/badge.svg?branch=main&service=github)](https://coveralls.io/github/hhursev/recipe-scraper?branch=main) +[![License](https://img.shields.io/github/license/hhursev/recipe-scrapers)](https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE) + +--- + +`recipe-scrapers` is a Python package designed to scrape recipes from cooking websites. It provides a simple and consistent API to extract recipe data like ingredients, instructions, cooking time, and more from popular cooking websites. Works with the python versions listed above. + + +## Installation + +You can install Recipe Scrapers using pip or your preferred Python package manager: + +``` console +pip install recipe-scrapers +``` + +!!! note + + This should produce output about the installation process, with the final line reading: `Successfully installed recipe-scrapers-`. + + +## Overview + +```python exec="on" +import sys +sys.path.insert(0, ".") +from recipe_scrapers import SCRAPERS + +print(f"There are **{len(SCRAPERS.keys())}** cooking websites currently supported.") +``` + +For a full list check our [Supported Sites](./getting-started/supported-sites.md) section. + +With `recipe-scrapers`, you should easily extract structured recipe data such as: + +- title +- ingredients +- instructions +- cooking and preparation times +- yields +- image +- and many more... + +Check out our [Examples](./getting-started/examples.md) section to see how to get started with the library. + +## Core Functionality + +`recipe-scrapers` long term aim is to focus **solely on HTML parsing** and not to handle networking operations. This design choice provides flexibility in how you retrieve HTML content and allows you to: + +- Implement your own networking logic +- Handle rate limiting +- Manage caching +- Control error handling +- Use your preferred HTTP client + + +## TLDR; + +👋 We suspect you've missed a few key links, such as us mentioning the [Examples](./getting-started/examples.md) and the [Supported Sites](./getting-started/supported-sites.md) section. + +Thus, we drop this tiny Python snippet for you (using Python's built-in `urllib`) to showcase how you can use this package: + +```python +from urllib.request import urlopen + +from recipe_scrapers import scrape_html + +url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" +html = urlopen(url).read().decode("utf-8") # retrieves the recipe webpage HTML +scraper = scrape_html(html, org_url=url) +scraper.title() +scraper.instructions() # etc. +# for a complete list of methods: +# help(scraper) +``` + +## Why recipe-scrapers Exists + +Born from late-night coding sessions and a love for both food and programming, `recipe-scrapers` +evolved from a personal project into a community tool. It's open-sourced and under the [MIT license](https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE) +with a simple goal: let developers focus on building amazing food-related applications without reinventing the recipe-parsing wheel. + +Today, our library helps power diverse projects across the cooking landscape: + +- Meal prep and planning applications +- Smart shopping list generators +- Recipe collection managers +- Cooking time estimators +- Diet and nutrition trackers +- Food blogs and recipe aggregators + +We're excited to see what you'll create! Feel free to share your project in our [community showcase](https://github.com/hhursev/recipe-scrapers/issues/9) - we love seeing what others build with the library. + +While building, remember to be mindful of websites' terms and fair usage - our [Copyright and Usage Guidelines](copyright-and-usage.md) will help you stay on track. + +Happy cooking with code! 👋 From 35decbba879b007619e1dcdb958077429c2c4d62 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Mon, 16 Dec 2024 00:06:06 +0200 Subject: [PATCH 54/94] docs: Add (rather) clear guidelines about copyright responsibility --- docs/copyright-and-usage.md | 69 +++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/docs/copyright-and-usage.md b/docs/copyright-and-usage.md index e69de29bb..f17b2b349 100644 --- a/docs/copyright-and-usage.md +++ b/docs/copyright-and-usage.md @@ -0,0 +1,69 @@ +# Copyright and Usage + +## Overview + +`recipe-scrapers` is a Python library that provides tools for extracting structured recipe data from websites. This document outlines our approach to copyright considerations and clarifies responsibilities for library maintainers and end users. + +## Copyright Responsibility + +### Library's Role + +`recipe-scrapers` is a tool that facilitates data extraction. The library itself: + +- Provides methods to access made available web content +- Transforms unstructured recipe data into structured formats +- Does not store, host, or redistribute any content +- Does not circumvent any technical access controls +- Makes no claims about the copyright status of accessed content + +### End User Responsibility + +Users of `recipe-scrapers` are responsible for: + +- Ensuring their use of scraped content complies with applicable laws +- Respecting website terms of service and *robots.txt* directives +- Obtaining necessary permissions for their intended use of scraped content +- Managing any copyright or licensing requirements for scraped content + +## Fair Use Considerations + +Many uses of `recipe-scrapers` may fall under fair use doctrine, particularly: + +- Personal recipe collection and organization +- Academic research and analysis +- Transformative uses that add value to the original content +- Non-commercial educational purposes + +However, users should conduct their own legal analysis based on their specific use case and jurisdiction. + +## Best Practices for Users + +We recommend users: + +- Cache scraped content appropriately to minimize server load +- Include attribution when displaying scraped content +- Respect rate limits and *robots.txt* directives +- Consider websites' terms of service +- Implement appropriate error handling and fallbacks + +## Library Development Guidelines + +For contributors and maintainers: + +- Focus on structural improvements and bug fixes +- Maintain the library's role as a neutral tool +- Keep copyright considerations proportional and practical +- Balance legal compliance with usability +- Avoid features that could only serve infringing purposes + +## Disclaimer + +`recipe-scrapers` is provided "as is" without warranty of any kind. The maintainers make no representations about the suitability, reliability, availability, timeliness, or accuracy of the software or its content extraction capabilities. + +## Additional Resources + +For more information about web scraping and copyright: + +- [Stanford Libraries: Copyright and Fair Use](https://fairuse.stanford.edu/) +- [EFF: Legal Guide for Developers](https://www.eff.org/issues/coders) +- [Digital Media Law Project: Legal Risks in Scraping](https://www.dmlp.org/legal-guide) From 8f80e250546fc2e8f7c0bcd70582417931fdb8f4 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Mon, 16 Dec 2024 00:28:38 +0200 Subject: [PATCH 55/94] docs: polish the supported-sites section --- docs/getting-started/supported-sites.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/getting-started/supported-sites.md b/docs/getting-started/supported-sites.md index e1cdcc5d9..1cf3f4a58 100644 --- a/docs/getting-started/supported-sites.md +++ b/docs/getting-started/supported-sites.md @@ -1,9 +1,11 @@ # Supported Websites -!!! note "Contributing" - Want to help maintain or add support for a site? Join our community of contributors! See our [contributing guidelines](../contributing/how-to-contribute.md). - See something missing or incorrect? [Open an issue](https://github.com/hhursev/recipe-scrapers/issues) or submit a pull request. +!!! success "Join Our Community" + 🌟 Want to add your favorite recipe site? We'd love your help! + - 📖 Check our [contributing guidelines](../contributing/how-to-contribute.md) + - 🐛 Found a bug? [Open an issue](https://github.com/hhursev/recipe-scrapers/issues) + - 🚀 Ready to contribute? Submit a pull request! ```python exec="on" import sys @@ -11,7 +13,9 @@ sys.path.insert(0, '.') from recipe_scrapers import SCRAPERS sites = sorted(SCRAPERS.keys()) -print(f"Currently, there are {len(sites)} sites that this package supports.\n") -print(f"### Currently Supported Sites:\n") + +print(f"## What we offer?") +print(f"We currently support over **{len(sites)} popular recipe websites** out of the box! And with our `wild_mode` option, you can potentially scrape many more sites that follow common patterns - making this probably the most extensive recipe scraping library available.\n") +print(f"## Supported Sites List\n") print("\n".join(f"- [{host}](https://{host}/)" for host in sites)) ``` From 33301333be1dd04d19a8d7c3a1f404e7c92ae669 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Mon, 16 Dec 2024 00:38:58 +0200 Subject: [PATCH 56/94] docs: Add releases and license doc --- docs/getting-started/releases-and-license.md | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/getting-started/releases-and-license.md b/docs/getting-started/releases-and-license.md index e69de29bb..4306559cd 100644 --- a/docs/getting-started/releases-and-license.md +++ b/docs/getting-started/releases-and-license.md @@ -0,0 +1,26 @@ +# Releases & License + +## Releases + +- **PyPI**: All versions available on [PyPI](https://pypi.org/project/recipe-scrapers/#history) +- **GitHub**: All versions tagged in our [releases page](https://github.com/hhursev/recipe-scrapers/releases) with detailed changelogs + +## Installation + +Want a specific version? We've got all of them available: + +- **From PyPI**: +```console +pip install recipe-scrapers==14.25.0 # replace with desired version +``` + +- **From GitHub:** +```console +pip install git+https://github.com/hhursev/recipe-scrapers.git@14.25.0 +``` + +## License +This project is licensed under the [MIT License](https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE). + +### Test Data Notice +The `test_data` directory contains content from various recipe websites used for testing purposes only. This content is used under copyright exceptions including Fair Use (USA), Fair Dealing (UK, Canada, Australia), and other international copyright doctrines that permit limited use of copyrighted material for technical testing purposes. See the [test data license](https://github.com/hhursev/recipe-scrapers/blob/main/tests/test_data/LICENSE.md) for more details. From bcd48abac8073285d47250186ae62d8052115ca2 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Mon, 16 Dec 2024 00:58:43 +0200 Subject: [PATCH 57/94] docs: polish the how to contribute section --- docs/contributing/how-to-contribute.md | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/contributing/how-to-contribute.md b/docs/contributing/how-to-contribute.md index e69de29bb..3bf4ad8a7 100644 --- a/docs/contributing/how-to-contribute.md +++ b/docs/contributing/how-to-contribute.md @@ -0,0 +1,32 @@ +# How to Contribute + +!!! success "Better For Everyone" + We welcome all forms of contribution to `recipe-scrapers`! + Whether you're reporting bugs, suggesting new sites to support, or contributing code, + your help makes this project better for everyone. + +## Ways to Contribute + +### Opening Issues + +Found a bug? A scraper not working for a particular site? Please open an issue! +With the number of [Supported Sites](../getting-started/supported-sites.md) and their possible design changes, +bugs are inevitable and your reports help us maintain quality. + +Want support for a new site? Feel free to request it by opening an issue. Please use our _issue templates_ whenever possible. + +All issues should be opened on our [GitHub repository](https://github.com/hhursev/recipe-scrapers/issues). + +### Contributing Code + +If you'd like to contribute code, whether it's fixing a bug, adding support for a new site, or closing a raised issue +we're happy to help you through the process. Check out our development guidelines [starting here](./documentation.md). + +## Our Contributors + +This project thrives thanks to our amazing contributors. +Every contribution, whether big or small, helps make `recipe-scrapers` better for everyone. + +## Wall of Fame + +[![Contributors](https://contrib.rocks/image?repo=hhursev/recipe-scrapers)](https://github.com/hhursev/recipe-scrapers/graphs/contributors) From 8d6461344afd2cfe52f328b5920ef48d0b3cf283 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Mon, 16 Dec 2024 02:20:01 +0200 Subject: [PATCH 58/94] docs: Add the documentation contribution page --- .../documentation.md => assets/.gitkeep} | 0 .../documentation-contribution.md | 96 +++++++++++++++++++ docs/contributing/how-to-contribute.md | 2 +- docs/index.md | 7 +- mkdocs.yaml | 2 +- 5 files changed, 102 insertions(+), 5 deletions(-) rename docs/{contributing/documentation.md => assets/.gitkeep} (100%) create mode 100644 docs/contributing/documentation-contribution.md diff --git a/docs/contributing/documentation.md b/docs/assets/.gitkeep similarity index 100% rename from docs/contributing/documentation.md rename to docs/assets/.gitkeep diff --git a/docs/contributing/documentation-contribution.md b/docs/contributing/documentation-contribution.md new file mode 100644 index 000000000..c5e5c6120 --- /dev/null +++ b/docs/contributing/documentation-contribution.md @@ -0,0 +1,96 @@ +# Contributing to Documentation + +!!! note "Prerequisites" + This guide assumes you have basic familiarity with Python development, including using `pip`, + `virtual environments`, and `git`. Teaching these core concepts is beyond the scope of this + documentation - please ensure you're comfortable with them before proceeding. + +!!! warning "Python Version Requirement" + We strongly recommend using Python 3.11 or above for all development work related to `recipe-scrapers`. + This version comes with `tomllib` support built-in, which is essential for the project's configuration handling. + +The documentation for `recipe-scrapers` is hosted at [docs.recipe-scrapers.com](https://docs.recipe-scrapers.com). +We welcome contributions to improve and expand our documentation! This guide will help you get started with making +documentation changes. + +## Initial Setup + +Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers) on GitHub and follow these setup steps: + +!!! tip "Quick Setup" + ```bash + # Clone your fork + git clone https://github.com/YOUR-USERNAME/recipe-scrapers.git + cd recipe-scrapers + + # Set up Python environment + python -m venv .venv + source .venv/bin/activate # On Windows use: .venv\Scripts\activate + python -m pip install --upgrade pip + pip install -e ".[all]" + ``` + +!!! note "Virtual Environment" + Remember to activate your virtual environment each time you work on the project: + ```bash + source .venv/bin/activate # On Windows use: .venv\Scripts\activate + ``` + +Create a new branch for your documentation changes: +```bash +git checkout -b docs/your-feature-name +``` + +## Previewing Documentation Changes + +!!! example "Local Development" + 1. From the project root directory, start the MkDocs development server: + ```bash + mkdocs serve + ``` + 2. Open your browser and navigate to `http://127.0.0.1:8000` + +The preview will automatically update as you make changes to the documentation files. + +## Making Documentation Changes + +!!! info "Documentation Structure" + - Documentation source files are written in Markdown and located in the `docs/` directory + - Images and other assets should be placed in the `docs/assets/` directory + - The documentation structure is defined in `mkdocs.yaml` at the root of the repository + +## Submitting Your Changes + +1. Commit your changes with a descriptive message: + ```bash + git add docs/ + git commit -m "docs: describe your changes here" + ``` + +2. Push your changes to your fork: + ```bash + git push origin docs/your-feature-name + ``` + +3. Create a Pull Request (PR) from your fork to the main [recipe-scrapers](https://github.com/hhursev/recipe-scrapers) repository. + +!!! success "PR Preview" + When you create a PR, a special preview URL will be generated where your documentation changes can be reviewed. This will make it easy for maintainers to see your changes in action. + +## Documentation Style Guidelines + +!!! note "Style Guide" + - Use clear, concise language + - Include code examples where appropriate + - Follow the existing documentation structure + - Add screenshots or diagrams when they help explain concepts + - Ensure all links are working + - Use proper Markdown formatting + +## Need Help? + +!!! question "Getting Support" + If you have questions or need assistance with documentation contributions, please: + + - Open an [issue on GitHub](https://github.com/hhursev/recipe-scrapers/issues) + - Check existing documentation for reference diff --git a/docs/contributing/how-to-contribute.md b/docs/contributing/how-to-contribute.md index 3bf4ad8a7..6e083d1bb 100644 --- a/docs/contributing/how-to-contribute.md +++ b/docs/contributing/how-to-contribute.md @@ -20,7 +20,7 @@ All issues should be opened on our [GitHub repository](https://github.com/hhurse ### Contributing Code If you'd like to contribute code, whether it's fixing a bug, adding support for a new site, or closing a raised issue -we're happy to help you through the process. Check out our development guidelines [starting here](./documentation.md). +we're happy to help you through the process. Check out our development guidelines [starting here](./documentation-contribution.md). ## Our Contributors diff --git a/docs/index.md b/docs/index.md index 73abd3b31..8678e7364 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,9 +17,10 @@ You can install Recipe Scrapers using pip or your preferred Python package manager: -``` console -pip install recipe-scrapers -``` +!!! tip "Install (assuming python 3.9+)" + ``` console + pip install recipe-scrapers + ``` !!! note diff --git a/mkdocs.yaml b/mkdocs.yaml index 1604335d5..afd0d1626 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -40,7 +40,7 @@ nav: - Releases & License: getting-started/releases-and-license.md - Contributing: - How to Contribute: contributing/how-to-contribute.md - - Documentation: contributing/documentation.md + - Documentation: contributing/documentation-contribution.md - Code Contribution: contributing/code-contribution.md - In-Depth Guides: - HTML Scraping: contributing/in-depth-guide-html-scraping.md From 0b73c604e98983d130279b08fd74aef92f6d3ff8 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Mon, 16 Dec 2024 03:07:55 +0200 Subject: [PATCH 59/94] docs: add code contribution section. wip --- docs/contributing/code-contribution.md | 121 +++++++++++++++++++++++++ mkdocs.yaml | 2 +- 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/docs/contributing/code-contribution.md b/docs/contributing/code-contribution.md index e69de29bb..b029ba1bd 100644 --- a/docs/contributing/code-contribution.md +++ b/docs/contributing/code-contribution.md @@ -0,0 +1,121 @@ +# Code Contribution + +!!! note "Prerequisites" + This guide assumes you have basic familiarity with Python development, including using `pip`, + `virtual environments`, and `git`. Teaching these core concepts is beyond the scope of this + documentation - please ensure you're comfortable with them before proceeding. + +!!! warning "Python Version Requirement" + We strongly recommend using Python 3.11 or above for all development work related to `recipe-scrapers`. + This version comes with `tomllib` support built-in, which is essential for the project's configuration handling. + +We welcome various types of code contributions to `recipe-scrapers`, including: + +- Bug fixes +- New recipe site scrapers +- Performance improvements +- Feature enhancements +- Test coverage improvements + +## Initial Setup + +Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers) on GitHub and follow these setup steps: + +!!! tip "Quick Setup" + ```bash + # Clone your fork + git clone https://github.com/YOUR-USERNAME/recipe-scrapers.git + cd recipe-scrapers + + # Set up Python environment + python -m venv .venv + source .venv/bin/activate # On Windows use: .venv\Scripts\activate + python -m pip install --upgrade pip + pip install -e ".[all]" + ``` + +!!! note "Virtual Environment" + Remember to activate your virtual environment each time you work on the project: + ```bash + source .venv/bin/activate # On Windows use: .venv\Scripts\activate + ``` + +## Development Workflow + +Create a new branch for your changes: +```bash +git checkout -b feature/your-feature-name # for new features +# or +git checkout -b fix/your-fix-name # for bug fixes +# or +git checkout -b site/website-name # for new site scrapers +``` + +After making your changes commit them: + +```bash +git add -p # Review changes before adding them +git commit -m "meaningful commit message" +git push origin your-branch-name +``` + +Then create a Pull Request back to the [main repository](https://github.com/hhursev/recipe-scrapers) from your fork. + +### Pre-commit Hooks + +The project uses pre-commit hooks to ensure code quality and consistency. These hooks run +automatically when you commit changes, handling tasks like: + +- Code formatting (black, isort) +- Linting (flake8) +- Type checking +- Other code quality checks + + +## What happens after a PR + +When you submit your PR: + +1. Our CI suite will run against your code to ensure everything works as expected. You can run the tests locally before submitting: + ```bash + python -m unittest + # or + unittest-parallel --level test + ``` + +2. Community members and core contributors will review your code. They may: + - Request changes or improvements + - Suggest alternative approaches + - Provide feedback on test coverage + - Ask for documentation updates + +3. Once approved, a core contributor will merge your PR + - Your contribution will be included in the next release + - Feel free to tackle any follow-up improvements in subsequent PRs + +Don't worry if your first PR needs some adjustments - this is normal and part of the collaborative development process! + + +## Development Guidelines (Coming Soon) + +While we're working on comprehensive documentation, the codebase is designed to be self-explanatory. As a developer, you can understand our patterns and expectations by taking a look at existing scrapers in the `recipe_scrapers/` directory. + +!!! tip "Generator Tool" + If you're adding a new site scraper, you can use our generator command to create a template: + + ```bash + python generate.py + ``` + + Where: + + - `ClassName`: The name of your new scraper class (e.g., `BBCGoodFood`) + - `URL`: A sample recipe URL from the target site. This will be saved in `test_data/` for testing. + +!!! warning "Work in Progress" + This contributing guide is currently being developed. Meanwhile, you can check these PRs as examples of good contribution standards: + + - [#1414](https://github.com/hhursev/recipe-scrapers/pull/1414/) - Adding a new site scraper + - [#1432](https://github.com/hhursev/recipe-scrapers/pull/1432/) - Fixing broken functionality + - [#1434](https://github.com/hhursev/recipe-scrapers/pull/1434/) - Test improvements + - [#1345](https://github.com/hhursev/recipe-scrapers/pull/1345/) - CI Improvements diff --git a/mkdocs.yaml b/mkdocs.yaml index afd0d1626..f933dd669 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -40,7 +40,7 @@ nav: - Releases & License: getting-started/releases-and-license.md - Contributing: - How to Contribute: contributing/how-to-contribute.md - - Documentation: contributing/documentation-contribution.md + - Documentation Contribution: contributing/documentation-contribution.md - Code Contribution: contributing/code-contribution.md - In-Depth Guides: - HTML Scraping: contributing/in-depth-guide-html-scraping.md From 256c388fd1af5693741b930a7cb4b24d934d8e5c Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Mon, 16 Dec 2024 04:49:06 +0200 Subject: [PATCH 60/94] docs: add migration from v14, examples and advances usage (draft versions) --- docs/contributing/code-contribution.md | 4 +- docs/getting-started/advanced-usage.md | 56 ++++++++++++++++ docs/getting-started/examples.md | 70 +++++++++++++++++++ docs/index.md | 8 +-- docs/misc/migrating-from-v14.md | 93 ++++++++++++++++++++++++++ mkdocs.yaml | 3 +- 6 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 docs/misc/migrating-from-v14.md diff --git a/docs/contributing/code-contribution.md b/docs/contributing/code-contribution.md index b029ba1bd..53450baea 100644 --- a/docs/contributing/code-contribution.md +++ b/docs/contributing/code-contribution.md @@ -98,7 +98,9 @@ Don't worry if your first PR needs some adjustments - this is normal and part of ## Development Guidelines (Coming Soon) -While we're working on comprehensive documentation, the codebase is designed to be self-explanatory. As a developer, you can understand our patterns and expectations by taking a look at existing scrapers in the `recipe_scrapers/` directory. +While we're working on comprehensive documentation, the codebase is designed to +be self-explanatory. As a developer, you can understand our patterns and expectations +by taking a look at existing scrapers in the `recipe_scrapers/` directory. !!! tip "Generator Tool" If you're adding a new site scraper, you can use our generator command to create a template: diff --git a/docs/getting-started/advanced-usage.md b/docs/getting-started/advanced-usage.md index e69de29bb..37f2c348a 100644 --- a/docs/getting-started/advanced-usage.md +++ b/docs/getting-started/advanced-usage.md @@ -0,0 +1,56 @@ +# Advanced Usage + +!!! warning "Under Construction" + This whole page is currently under construction. + + Not worth your time at this point. + +!!! warning "Under Construction" + Just making sure the previous warning was not missed. + + This page is not worth your time at this point. + +## Overview + +This page covers the advanced internals of `recipe-scrapers`, including abstract +classes, schema.org parsing, utility functions, exception handling, and the +plugin system. These components are primarily useful for contributors and +developers looking to extend the library's functionality. + + +## Core Components + +??? abstract "Abstract Base Classes" + ::: recipe_scrapers._abstract + options: + heading_level: 3 + show_root_heading: false + show_source: true + +??? abstract "Schema.org Parser" + ::: recipe_scrapers._schemaorg + options: + heading_level: 3 + show_root_heading: false + show_source: true + +??? abstract "Utility Functions" + ::: recipe_scrapers._utils + options: + heading_level: 3 + show_root_heading: false + show_source: true + +??? abstract "Exception Handling" + ::: recipe_scrapers._exceptions + options: + heading_level: 3 + show_root_heading: false + show_source: true + +??? abstract "Plugin System" + ::: recipe_scrapers.plugins + options: + heading_level: 3 + show_root_heading: false + show_source: true diff --git a/docs/getting-started/examples.md b/docs/getting-started/examples.md index e69de29bb..a3dc2b667 100644 --- a/docs/getting-started/examples.md +++ b/docs/getting-started/examples.md @@ -0,0 +1,70 @@ +# Examples + +!!! important + `recipe-scrapers` is designed to focus **exclusively on HTML parsing**. + + This core principle guides our development and support. You'll need to implement your own solution for fetching + recipe HTML files and managing network requests. The library works best when you + provide both the HTML content and its source domain. + + +## Basic Usage + +Here's a simple example of how to use the library: + +```python title="Basic Usage Example" linenums="1" +from urllib.request import urlopen +from recipe_scrapers import scrape_html + +url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" +html = urlopen(url).read().decode("utf-8") # retrieves the recipe webpage HTML +scraper = scrape_html(html, org_url=url) + +# Extract recipe information +scraper.title() +scraper.instructions() +scraper.links() +scraper.to_json() +scraper.nutrients() + +# To see all available methods +help(scraper) +``` + +For optimal results, always provide both the HTML content and its original URL. +This helps the library correctly parse website-specific elements. + +## Available Methods + +Recipe websites vary in the amount of information they provide. While some offer +comprehensive details like nutritional information (`.nutrients()`), others may +not. + +### Core Methods + +These methods should be available for all supported websites: + +!!! warning "Under Construction" + This documentation section is currently being updated and improved. + +::: tests.MANDATORY_TESTS + options: + heading_level: 4 + + +### Optional Methods + +These additional methods are available for some websites: + +!!! warning "Under Construction" + This documentation section is currently being updated and improved. + +::: tests.OPTIONAL_TESTS + options: + heading_level: 4 + + +## Common Patterns + +!!! warning "Under Construction" + This documentation section is currently being updated and improved. diff --git a/docs/index.md b/docs/index.md index 8678e7364..8c4456d51 100644 --- a/docs/index.md +++ b/docs/index.md @@ -77,7 +77,8 @@ url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/ html = urlopen(url).read().decode("utf-8") # retrieves the recipe webpage HTML scraper = scrape_html(html, org_url=url) scraper.title() -scraper.instructions() # etc. +scraper.instructions() +scraper.to_json() # for a complete list of methods: # help(scraper) ``` @@ -99,6 +100,5 @@ Today, our library helps power diverse projects across the cooking landscape: We're excited to see what you'll create! Feel free to share your project in our [community showcase](https://github.com/hhursev/recipe-scrapers/issues/9) - we love seeing what others build with the library. -While building, remember to be mindful of websites' terms and fair usage - our [Copyright and Usage Guidelines](copyright-and-usage.md) will help you stay on track. - -Happy cooking with code! 👋 +!!! tip "Happy cooking with code! 👋" + While building, remember to be mindful of websites' terms and fair usage - our [Copyright and Usage Guidelines](copyright-and-usage.md) will help you stay on track. diff --git a/docs/misc/migrating-from-v14.md b/docs/misc/migrating-from-v14.md new file mode 100644 index 000000000..e7795ea2c --- /dev/null +++ b/docs/misc/migrating-from-v14.md @@ -0,0 +1,93 @@ +# Migrating from v14 to v15 + +!!! warning "Under Construction" + This documentation section is currently being updated and improved. + +## Overview + +Version 15 introduces important changes to the core API of recipe-scrapers, particularly regarding how recipes are scraped from websites. The main change is the deprecation of the `scrape_me` function in favor of more explicit HTML parsing methods. + +## Key Changes + +### 1. Deprecation of `scrape_me` + +The `scrape_me` function, which was the primary method for scraping recipes in v14, is being deprecated. While it still works in v15, you'll receive deprecation warnings when using it: + +```python +# Old v14 approach (deprecated) +from recipe_scrapers import scrape_me +scraper = scrape_me('https://example.com/recipe') # Will show deprecation warning +``` + +### 2. New Recommended Approach + +The new approach separates HTML fetching from parsing: + +```python +# New v15 approach +from urllib.request import urlopen +from recipe_scrapers import scrape_html + +# Fetch HTML (you can use any HTTP client) +url = "https://example.com/recipe" +html = urlopen(url).read().decode("utf-8") + +# Parse HTML +scraper = scrape_html(html, org_url=url) +``` + +## Why This Change? + +1. **Better Separation of Concerns**: The library now focuses solely on HTML parsing, letting you handle HTTP requests as you see fit +2. **More Flexibility**: You can use your preferred HTTP client (requests, httpx, aiohttp, etc.) +3. **Better Error Handling**: Separate networking issues from parsing issues + +## Migration Steps + +1. Replace `scrape_me` imports: + ```python + # Before + from recipe_scrapers import scrape_me + + # After + from recipe_scrapers import scrape_html + ``` + +2. Update scraping code: + ```python + # Before + scraper = scrape_me('https://example.com/recipe') + + # After + from urllib.request import urlopen + + url = 'https://example.com/recipe' + html = urlopen(url).read().decode("utf-8") + scraper = scrape_html(html, org_url=url) + ``` + +3. If you're using a web framework or need to handle many requests, consider using a more robust HTTP client: + ```python + # Example with requests + import requests + from recipe_scrapers import scrape_html + + def get_recipe(url): + response = requests.get(url) + response.raise_for_status() + return scrape_html(response.text, org_url=url) + ``` + +## Timeline + +- v14.x.x: Still supported but will only receive critical bug fixes +- v15.x.x: Current stable version with new API +- Future versions: Will build upon the v15 API structure + +## Getting Help + +If you encounter issues during migration: + +1. Check the [GitHub issues](https://github.com/hhursev/recipe-scrapers/issues) for similar problems +2. Open a new issue if you find a bug +3. Join the community discussions for migration-related questions diff --git a/mkdocs.yaml b/mkdocs.yaml index f933dd669..580ef3be6 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -37,6 +37,7 @@ nav: - Examples: getting-started/examples.md - Supported Sites: getting-started/supported-sites.md - Advanced Usage: getting-started/advanced-usage.md + - Migrating from v14: misc/migrating-from-v14.md - Releases & License: getting-started/releases-and-license.md - Contributing: - How to Contribute: contributing/how-to-contribute.md @@ -70,7 +71,7 @@ plugins: default_handler: python handlers: python: - paths: recipe_scrapers + paths: [tests, recipe_scrapers] options: show_source: true show_root_heading: true From e435374b91ca13ed582f71c1d60d07ba4d19efa0 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Mon, 16 Dec 2024 04:55:40 +0200 Subject: [PATCH 61/94] docs: misc tiny updates in the index --- docs/index.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/index.md b/docs/index.md index 8c4456d51..952d22eaf 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,14 +10,13 @@ --- -`recipe-scrapers` is a Python package designed to scrape recipes from cooking websites. It provides a simple and consistent API to extract recipe data like ingredients, instructions, cooking time, and more from popular cooking websites. Works with the python versions listed above. - +`recipe-scrapers` is a Python package designed to extract recipe data from HTM content of cooking websites. It parses the HTML structure of recipe pages to provide a simple and consistent API for retrieving structured data like ingredients, instructions, cooking time, and more. Works with the python versions listed above. ## Installation -You can install Recipe Scrapers using pip or your preferred Python package manager: +You can install `recipe-scrapers` using pip or your preferred Python package manager: -!!! tip "Install (assuming python 3.9+)" +!!! tip "Install" ``` console pip install recipe-scrapers ``` @@ -100,5 +99,5 @@ Today, our library helps power diverse projects across the cooking landscape: We're excited to see what you'll create! Feel free to share your project in our [community showcase](https://github.com/hhursev/recipe-scrapers/issues/9) - we love seeing what others build with the library. -!!! tip "Happy cooking with code! 👋" - While building, remember to be mindful of websites' terms and fair usage - our [Copyright and Usage Guidelines](copyright-and-usage.md) will help you stay on track. +!!! tip "Happy cooking with code!" + While building awesome stuff, remember to be mindful of websites' terms and fair usage - our [Copyright and Usage Guidelines](copyright-and-usage.md) will help you stay on track. From 78da43762ac0d1d446d3fb01aef76c98d5222dec Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Mon, 16 Dec 2024 06:39:26 +0200 Subject: [PATCH 62/94] docs: Bring back the how to develop a scaper guide --- docs/contributing/how-to-develop-a-scraper.md | 142 ++++++++++++++++++ mkdocs.yaml | 1 + 2 files changed, 143 insertions(+) create mode 100644 docs/contributing/how-to-develop-a-scraper.md diff --git a/docs/contributing/how-to-develop-a-scraper.md b/docs/contributing/how-to-develop-a-scraper.md new file mode 100644 index 000000000..65ee40c70 --- /dev/null +++ b/docs/contributing/how-to-develop-a-scraper.md @@ -0,0 +1,142 @@ +# How To Develop a New Scraper + +## Find a website + +First, check if the website is already supported: + +- Check the [Supported Sites](../getting-started/supported-sites.md) +- Or verify programmatically: + +```python +from recipe_scrapers import SCRAPERS +# Check if site is supported +print(SCRAPERS.get("bbcgoodfood.com")) +``` + +!!! note "Track Your Progress" + Create an [issue](https://github.com/hhursev/recipe-scrapers/issues/new/choose) to track your work. + +## Setup Repository + +Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers) on GitHub and follow these steps: + +!!! tip "Quick Setup" + ```bash + # Clone your fork + git clone https://github.com/YOUR-USERNAME/recipe-scrapers.git + cd recipe-scrapers + + # Set up Python environment + python -m venv .venv + source .venv/bin/activate # On Windows use: .venv\Scripts\activate + python -m pip install --upgrade pip + pip install -e ".[all]" + ``` + +Create a new branch: + +```bash +git checkout -b site/website-name +``` + +!!! tip "Run Tests" + ```bash + python -m unittest + + # Optional: Parallel testing + pip install unittest-parallel + unittest-parallel --level test + ``` + +## Generate Scraper Files + +### 1. Select Recipe URL + +!!! tip "Recipe Selection" + Choose a recipe with multiple instructions when possible. Single-instruction recipes may indicate parsing errors, unless [explicitly handled](https://github.com/hhursev/recipe-scrapers/blob/98ead6fc6e9653805b01539a3f46fbfb4e096136/tests/test_allrecipes.py#L147-L150). + +### 2. Check Schema Support + +Test if the site uses [Recipe Schema](https://schema.org/Recipe): + +```python +from recipe_scrapers import scrape_html + +scraper = scrape_html(html, url, wild_mode=True) +print(scraper.schema.data) # Empty dict if schema not supported +``` + +### 3. Generate Files + +```bash +python generate.py +``` + +This creates: + +- Scraper file in `recipe_scrapers/` +- Test files in `tests/test_data//` + +## Implementation + +=== "With Recipe Schema" + ```python + from recipe_scrapers import scrape_html + + scraper = scrape_html(html, url) + print(scraper.title()) + print(scraper.ingredients()) + ``` + +=== "Without Recipe Schema" + ```python + def title(self): + return self.soup.find('h1').get_text() + ``` + +!!! info "Resources" + - [Scraper Functions Guide](in-depth-guide-scraper-functions.md) + - [HTML Scraping Guide](in-depth-guide-html-scraping.md) + - [BeautifulSoup Documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) + +## Testing + +### 1. Update Test Data + +Edit `tests/test_data//test.json`: +```json +{ + "host": "", + "canonical_url": "...", + "site_name": "...", + "author": "...", + "language": "...", + "title": "...", + "ingredients": "...", + "instructions_list": "...", + "total_time": "...", + "yields": "...", + "image": "...", + "description": "..." +} +``` + +### 2. Run Tests + +```bash +python -m unittest -k +``` + +!!! warning "Edge Cases" + Test with multiple recipes to catch potential edge cases. + +## Submit Changes + +1. Commit your work: +```bash +git add -p # Review changes +git commit -m "Add scraper for example.com" +git push origin site/website-name +``` + +2. Create a pull request at [recipe-scrapers](https://github.com/hhursev/recipe-scrapers/pulls) diff --git a/mkdocs.yaml b/mkdocs.yaml index 580ef3be6..3984539a7 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -43,6 +43,7 @@ nav: - How to Contribute: contributing/how-to-contribute.md - Documentation Contribution: contributing/documentation-contribution.md - Code Contribution: contributing/code-contribution.md + - How To Develop A Scraper: contributing/how-to-develop-a-scraper.md - In-Depth Guides: - HTML Scraping: contributing/in-depth-guide-html-scraping.md - Scraper Functions: contributing/in-depth-guide-scraper-functions.md From fd203306b6ab6c429bdfa282f8941f2f27cdd018 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Wed, 18 Dec 2024 05:05:18 -0500 Subject: [PATCH 63/94] Adds support for natashaskitchen (#1440) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/natashaskitchen.py | 16 + .../natashaskitchen_1.json | 50 + .../natashaskitchen_1.testhtml | 1563 +++++++++++++ .../natashaskitchen_2.json | 90 + .../natashaskitchen_2.testhtml | 1979 +++++++++++++++++ 7 files changed, 3701 insertions(+) create mode 100644 recipe_scrapers/natashaskitchen.py create mode 100644 tests/test_data/natashaskitchen.com/natashaskitchen_1.json create mode 100644 tests/test_data/natashaskitchen.com/natashaskitchen_1.testhtml create mode 100644 tests/test_data/natashaskitchen.com/natashaskitchen_2.json create mode 100644 tests/test_data/natashaskitchen.com/natashaskitchen_2.testhtml diff --git a/README.rst b/README.rst index 42f5cec60..77d1df839 100644 --- a/README.rst +++ b/README.rst @@ -329,6 +329,7 @@ Scrapers available for: - `https://www.myplate.gov/ `_ - `https://myrecipes.com/ `_ - `https://myvegetarianroots.com/ `_ +- `https://natashaskitchen.com/ `_ - `https://www.nhs.uk/healthier-families/ `_ - `https://nibbledish.com/ `_ - `https://noracooks.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 5d1f6544c..c1c28e626 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -278,6 +278,7 @@ from .mykoreankitchen import MyKoreanKitchen from .myrecipes import MyRecipes from .myvegetarianroots import MyVegetarianRoots +from .natashaskitchen import NatashasKitchen from .nhshealthierfamilies import NHSHealthierFamilies from .nibbledish import NibbleDish from .nihhealthyeating import NIHHealthyEating @@ -586,6 +587,7 @@ MyJewishLearning.host(): MyJewishLearning, MyKoreanKitchen.host(): MyKoreanKitchen, MyVegetarianRoots.host(): MyVegetarianRoots, + NatashasKitchen.host(): NatashasKitchen, NoraCooks.host(): NoraCooks, NotEnoughCinnamon.host(): NotEnoughCinnamon, NutritionFacts.host(): NutritionFacts, diff --git a/recipe_scrapers/natashaskitchen.py b/recipe_scrapers/natashaskitchen.py new file mode 100644 index 000000000..add4d3c8b --- /dev/null +++ b/recipe_scrapers/natashaskitchen.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class NatashasKitchen(AbstractScraper): + @classmethod + def host(cls): + return "natashaskitchen.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/tests/test_data/natashaskitchen.com/natashaskitchen_1.json b/tests/test_data/natashaskitchen.com/natashaskitchen_1.json new file mode 100644 index 000000000..4db5e712e --- /dev/null +++ b/tests/test_data/natashaskitchen.com/natashaskitchen_1.json @@ -0,0 +1,50 @@ +{ + "author": "Natalya Drozhzhin", + "canonical_url": "https://natashaskitchen.com/sugar-cookies-recipe/", + "site_name": "NatashasKitchen.com", + "host": "natashaskitchen.com", + "language": "en-US", + "title": "Christmas Sugar Cookies Recipe", + "ingredients": [ + "1 cup unsalted butter (softened at room temperature)", + "1 cup granulated sugar", + "1 egg (large)", + "1 tsp vanilla extract", + "3 cups all-purpose flour (measured correctly)", + "1 Tbsp baking powder", + "1/4 tsp salt" + ], + "instructions_list": [ + "Preheat oven to 350 °F with a rack in the center. Whisk together flour with baking powder and salt in a small bowl and set aside.", + "Using a stand-up or handheld mixer, beat the butter together with sugar. To the mixture add vanilla extract and egg and beat to combine.", + "To the butter mixture, add flour in 3 parts until fully incorporated.", + "Divide the dough into two equal parts. On a lightly floured surface, roll into ¼-inch thickness. Use a cookie cutter to cut out your favorite shapes.", + "Bake cookies on a parchment or silicone-lined baking sheet at 350˚F for 10 minutes, or until the edges are just beginning to turn golden.", + "Let the cookies cool for about 5 minutes on the baking sheet before moving them to a wire rack to cool completely and decorating with cookie icing." + ], + "category": "Cookies,Dessert", + "yields": "40 servings", + "description": "Everyone needs an Easy Sugar Cookies Recipe! These are literally melt-in-your-mouth delicious. I am positive these Christmas cookies will win you over.", + "total_time": 30, + "cook_time": 10, + "prep_time": 20, + "cuisine": "American", + "ratings": 4.99, + "ratings_count": 575, + "nutrients": { + "servingSize": "1 serving", + "calories": "96 kcal", + "fatContent": "5 g", + "saturatedFatContent": "3 g", + "carbohydrateContent": "12 g", + "sugarContent": "5 g", + "proteinContent": "1 g", + "sodiumContent": "17 mg", + "fiberContent": "1 g", + "cholesterolContent": "16 mg" + }, + "image": "https://natashaskitchen.com/wp-content/uploads/2019/12/Sugar-Cookies-8.jpg", + "keywords": [ + "sugar cookies" + ] +} diff --git a/tests/test_data/natashaskitchen.com/natashaskitchen_1.testhtml b/tests/test_data/natashaskitchen.com/natashaskitchen_1.testhtml new file mode 100644 index 000000000..5645587dd --- /dev/null +++ b/tests/test_data/natashaskitchen.com/natashaskitchen_1.testhtml @@ -0,0 +1,1563 @@ + + + + + + + + + + + + + + + + + + + + + Christmas Sugar Cookies - NatashasKitchen.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + +
    +
    Home > Dessert > Cookies > Christmas Sugar Cookies
    +
    +
    +

    Christmas Sugar Cookies

    + + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + +

    Everyone needs an Easy Sugar Cookie Recipe! These are buttery and literally melt-in-your-mouth delicious and my go-to sugar cookie dough. You can bake them soft or crisp. These Christmas Sugar cookies have been part of my holiday cookie-decorating tradition for years!

    + + + +
    Sugar cookies recipe decorated on a platter for Christmas

    This post may contain affiliate links. Read my disclosure policy.

    + + + +

    I love festive holiday treats like melt-in-your-mouth Snowball Cookies, soft Chocolate Chip Cookies, and of course Baklava. These beautifully decorated sugar cookies are a beautiful addition to the Christmas cookie platter.

    + + + + + + + +

    I love simple dishes that use minimal ingredients. During the holidays, I love baking, but I don’t love the cleanup afterwards. This recipe for Christmas sugar cookies gives me the best of both worlds — perfect cookies and an easy clean-up. You also don’t have to chill the dough so you can cut and bake the cookies right away, saving you time. I’m so excited to share this recipe with you! 

    + + + +

    One of my favorite Christmas traditions is cookie decorating, and my family has been doing this since the kids were tiny. The kids love the creative freedom to do what they want with their cookies, and of course, they are even more excited to eat them!

    + + + +
    + + + +

    Whether you are planning a cookie-making party for your Christmas party or for the holiday cookie platter, you need a sugar cookie recipe that you can rely on. These cookies taste amazing, keep their shape, and are perfect for eating plain or decorating them with sugar cookie icing and sprinkles. Let’s get started! 

    + + + +
    Christmas Sugar cookies decorated with frosting and festive holiday sprinkles
    + + + +

    Tips For The Best Christmas Sugar Cookies

    + + + +

    Sugar cookies may seem simple, but there are a lot of bad recipes out there! After much trial and error, I feel confident that I have mastered the art of the sugar cookie. Here are all the best tips and tricks I have gathered throughout the years to get the best flavor and texture: 

    + + + +

    Tip #1: Soften your butter

    + + + +

    Butter should be softened at room temperature. If the butter is too soft or partially melted, you will end up with a sticky dough that is difficult to roll out.

    + + + +

    Tip #2: Rolling Out Sugar Cookies Dough

    + + + +

    Roll your dough out directly on a silicone baking mat or piece of parchment paper so you do not have to transfer your delicate shapes onto a baking sheet later. You can cut your shapes out right atop the mat and make your life a bit easier.

    + + + +

    Tip #3: How Thick Should Sugar Cookies be Rolled Out?

    + + + +

    Roll your dough out to about ¼-inch thick. This is the sweet spot. You’ll have cookies thick enough to keep their shape, while also thin enough to promote even baking. 

    + + + +
    Sugar cookies rolled to 1/4-inch thickness
    + + + +

    Tip #4: Avoid Crumbly Dough

    + + + +

    Crumbly dough makes for misshapen cookies that are prone to uneven baking. To prevent this, don’t overmix your dough. You want the dough to be as smooth as possible. However, if you do get a crumbly texture, add ½ tbsp of water, or milk to the batter and incorporate it until it remoistens the dough.

    + + + +

    Tip #5: Avoid Overbaking

    + + + +

    10 minutes might seem like a very short baking time for cookies. But, trust me, do not overbake them! At around 10 minutes, the edges of the cookies should just start to turn golden brown. This is the time to pull them! If you continue baking, you risk compromising that signature tenderness of a perfect sugar cookie. 

    + + + +
    How to make perfectly baked Sugar Cookies without over-baking
    + + + +

    How to Make Cut-Out Sugar Cookies

    + + + +
      +
    • Combine your flour, baking powder and salt together in a small bowl and set the dry mixture aside. 
    • + + + +
    • Using a stand mixer or handheld mixer, cream together your butter, sugar and vanilla extract until smooth and creamy.
    • + + + +
    • Add the flour to the butter mixture in thirds, mixing until incorporated between additions.
    • + + + +
    • Divide the dough into two equal parts and dust your work surface with flour to keep the dough from sticking. You can also dust the top of the dough lightly. Use a rolling pin to roll out each piece to an even ¼-inch thickness. Lift the dough gently to ensure it’s not sticking to your counter before cutting out shapes.
    • + + + +
    • Use a cookie cutter to cut out your favorite shapes or freeze your dough for later use. Note that larger cookies will take slightly longer to bake. Transfer the cookies to a cookie sheet, keeping them 1 inch apart (they do expand a bit in the oven).
    • + + + +
    • Bake the cookies at 350˚F for 10 minutes or until the edges are just starting to turn golden. That’s your cue to pull them out. Let the cookies cool on the baking pan for 5 minutes so they are easier to move without cracking then transfer to wire racks and let the cookies cool completely before decorating.
    • +
    + + + +
    Step by step photos how to make sugar cookies by creaming together butter and sugar, adding flour, dividing dough and cutting shapes
    + + + +

    Storing Sugar Cookies

    + + + +

    The great part about this recipe is that it can be made a couple of days in advance and the cookies will still retain their freshness. Below, I will share how you should store them and also how you can freeze your dough or baked cookies for later munching! 

    + + + +
      +
    • Storing Cookies at Room Temperature: Store baked sugar cookies on the counter in an airtight container. They will keep for up to a week. Remember, if you have decorated your Christmas Sugar Cookies, let the frosting firm up, and then store them between layers of parchment paper to prevent sticking and/or destroying your designs. 
    • + + + +
    • To freeze baked sugar cookies: allow cookies to cool completely, then stack the cookies in an airtight container between layers of parchment paper. Freeze cookies for up to 2 months. When you are ready to eat them, thaw at room temperature. 
    • + + + +
    • To freeze your sugar cookie dough: roll it into a ball or a log. Wrap it tightly in plastic wrap and store it in an airtight container or freezer bag. The dough will keep for up to 2 months before you need to use it. When you are ready to bake, allow the dough to thaw in the refrigerator overnight. Then, bring it to room temperature for 1 hour before you shape your cookies and bake them. 
    • +
    + + + +
    Baked sugar cookies ready for baking
    + + + +

    How to Decorate Christmas Cookies

    + + + +

    To decorate sugar cookies, I love to use our 3-ingredient cookie icing from our Gingerbread Cookie Recipe, or you can make a royal icing, and add food coloring. To pipe the frosting, transfer to a squeeze bottle or little zip bags (handy and inexpensive for cookie decorating parties).

    + + + +

    If you prefer, you can purchase an icing decorating kit with pre-made frostings in a variety of colors, which makes it easy. Don’t forget the Christmas sprinkles and crushed candy canes.

    + + + +
    Decorated Christmas cookies with sprinkles and frosting
    + + + +

    Decorated Christmas cookies have a way of making the holidays more merry and bright, even if you aren’t the best at decorating. The perfectly imperfect ones are the most endearing anyway.

    + + + +
    + + + +

    Christmas Sugar Cookies make my heart so happy because they unlock sweet memories over the years, like the cookie decorating party in the photo above when my husband and I hosted the family Christmas Eve party.

    + + + +

    I’d love to hear about your special Christmas traditions around cookies in the comments below.

    + + + + + + + +

    These are our best-loved (and reviewed) Christmas cookies to fill up your holiday cookie tray. These are well-loved by all ages and you’re sure to find some new favorites in this list. Looking for more Christmas recipes and inspiration? Check out our Christmas archives here.

    + + + + + + +
    + +
    + +
    +
    +

    Christmas Sugar Cookies Recipe 

    + +
    4.99 from 575 votes
    + +
    Author: Natalya Drozhzhin
    + +
    +
    +
    Sugar cookies recipe decorated on a Christmas cookie platter
    +
    +
    +
    Everyone needs an Easy Sugar Cookies Recipe! These are literally melt-in-your-mouth delicious. I am positive these Christmas cookies will win you over. 
    + + +
    +
    + +
    +
    Prep Time: 20 minutes
    Cook Time: 10 minutes
    Total Time: 30 minutes
    +
    + +

    Ingredients 

    Servings: 40 cookies
    + + + +

    Instructions

    • Preheat oven to 350 °F with a rack in the center. Whisk together flour with baking powder and salt in a small bowl and set aside. 
    • Using a stand-up or handheld mixer, beat the butter together with sugar. To the mixture add vanilla extract and egg and beat to combine.
    • To the butter mixture, add flour in 3 parts until fully incorporated. 
    • Divide the dough into two equal parts. On a lightly floured surface, roll into ¼-inch thickness. Use a cookie cutter to cut out your favorite shapes. 
    • Bake cookies on a parchment or silicone-lined baking sheet at 350˚F for 10 minutes, or until the edges are just beginning to turn golden.
    • Let the cookies cool for about 5 minutes on the baking sheet before moving them to a wire rack to cool completely and decorating with cookie icing
    + + + + + +

    Nutrition Per Serving

    96kcal Calories12g Carbs1g Protein5g Fat3g Saturated Fat16mg Cholesterol17mg Sodium43mg Potassium1g Fiber5g Sugar148IU Vitamin A16mg Calcium1mg Iron
    + +
    + +
    Nutrition Facts
    Christmas Sugar Cookies Recipe 
    Amount per Serving
    Calories
    96
    % Daily Value*
    Fat
     
    5
    g
    8
    %
    Saturated Fat
     
    3
    g
    19
    %
    Cholesterol
     
    16
    mg
    5
    %
    Sodium
     
    17
    mg
    1
    %
    Potassium
     
    43
    mg
    1
    %
    Carbohydrates
     
    12
    g
    4
    %
    Fiber
     
    1
    g
    4
    %
    Sugar
     
    5
    g
    6
    %
    Protein
     
    1
    g
    2
    %
    Vitamin A
     
    148
    IU
    3
    %
    Calcium
     
    16
    mg
    2
    %
    Iron
     
    1
    mg
    6
    %
    * Percent Daily Values are based on a 2000 calorie diet.
    + +
    +
    Course: Cookies, Dessert
    Cuisine: American
    Keyword: sugar cookies
    Skill Level: Easy
    Cost to Make: $
    +
    Calories: 96
    +
    +
    + Natasha's Kitchen Cookbook
    +
    + +
    +
    + +
    +
    +

    Natalya Drozhzhin

    + +
    +
    +
    +

    Natalya is a food blogger who founded Momsdish to make cooking easier. Growing up on a farm in Ukraine, Natalya was inspired by the amazing dishes that were prepared using simple ingredients. Natalya is most notably known for making cooking approachable for any person.

    + +

    Read more posts by Natalya

    + + +
    +
    +
    + + +
    + +
    + + + + + +
    + +
    +
    +
    +
    + 4.99 from 575 votes (497 ratings without comment) +
    +
    +
    +

    Leave a Comment

    + +
    + Recipe Rating +




    +
    +
    +

    +
    + +

    + +

    +
    + + + + +
    +

    Comments

    + +
    + +
      +
    • +
      + +
      +
      Crystal Gingras
      +
      December 15, 2024
      +
      +
      +

      mine were to crumbly when I was trying to roll them out

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      Jacqueline Heim
      +
      December 14, 2024
      +
      +
      +
      + +
      +

      My cookies tasted good but they spread out to much. Didn’t make out the shapes very well. What can I do?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 14, 2024
        +
        +
        +

        Hi Jacqueline! It could be that the cookie dough was too warm. You can chill it in the refrigerator for a bit if needed. Make sure you oven is fully preheated before you start baking them. I would also ensure you’re measuring all of your ingredients correctly. I have a tutorial on How to Measure Ingredientshere.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Ashmita
      +
      December 14, 2024
      +
      +
      +

      Is it fine to use salted butter instead of unsalted butter?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 14, 2024
        +
        +
        +

        Hi Ashmita! If you do, don’t add salt like the recipe states.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Barbara Norton
      +
      December 11, 2024
      +
      +
      +
      + +
      +

      Make this recipe every year for the last 40 years!! My family asks for them all the time

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      sara
      +
      December 8, 2024
      +
      +
      +

      is it really 1 Tbsp of baking powder? Or is it 1Tsp?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 8, 2024
        +
        +
        +

        Hi Sara! That’s correct, 1 tablespoon. I hope you love the recipe!

        +

        Reply

        +
        + +
        +
      • +
      • +
        + +
        +
        Glenda
        +
        December 14, 2024
        +
        +
        +

        What effect does the baking powder have on the end result? I see so many recipes that do not include baking powder.

        +

        Reply

        +
        + +
        +
          +
        • +
          + +
          +
          NatashasKitchen.com
          +
          December 14, 2024
          +
          +
          +

          Hi Glenda! The baking powder gives these a puffy, soft, cake-like texture.

          +

          Reply

          +
          + +
          +
            +
          • +
            + +
            +
            Jacqueline Randall
            +
            December 14, 2024
            +
            +
            +

            This recipe doesn’t require letting the dough sit in the fridge for an hour?

            +

            Reply

            +
            + +
            +
              +
            • +
              + +
              +
              Natashas Kitchen
              +
              December 14, 2024
              +
              +
              +

              Hi Jacqueline, that’s right it is not required, you can of course if that is your preference, but this recipe doesn’t need it. I hope that helps.

              +
              + +
              +
            • +
            +
          • +
          +
        • +
        +
      • +
      +
    • +
    • +
      + +
      +
      Sarah Dowling
      +
      December 7, 2024
      +
      +
      +
      + +
      +

      Made your recipe with vegan butter because of a dairy intolerance and they turned out perfect. I thought maybe they would spread but the edges were nice and crisp and the cookies tasted delicious.

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 7, 2024
        +
        +
        +

        Hi Sarah! Thank you for sharing that with us. Glad they turned out well for you.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Elizabeth
      +
      December 6, 2024
      +
      +
      +

      Can I use 1/4 of salted and 1/4 of unsalted butter and just omit the tsp of salt?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 6, 2024
        +
        +
        +

        Hi Elizabeth! That should be fine.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Ginger
      +
      November 29, 2024
      +
      +
      +

      I haven’t made sugar cookies in years and this year I thought it would be nice to share with my grandkids. This recipe is great! Dough is easy to work, doesn’t stick and is delicious!!

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      Zhenya
      +
      November 26, 2024
      +
      +
      +
      + +
      +

      Theses cookies are amazing. Simple the best and the easiest recipe i ever tried. And i tried so many and was never happy with the results. Thank you!

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      lilly
      +
      November 23, 2024
      +
      +
      +
      + +
      +

      this was such an easy bake and also delish

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        Pat Martin
        +
        December 8, 2024
        +
        +
        +

        Please get rid of the advertising. It takes too long to write the recipe down & it’s very frustrating

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    + + + +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +

    As Featured On

    + + +
    +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    Never Go "Hangry" Again!

    +

    Get weekly updates on new recipes, exclusive giveaways plus behind the scenes photos.

    +
    +

    +

    +
    + +
    +
    +
    +
    + + +
    + + + + diff --git a/tests/test_data/natashaskitchen.com/natashaskitchen_2.json b/tests/test_data/natashaskitchen.com/natashaskitchen_2.json new file mode 100644 index 000000000..f0514e5a5 --- /dev/null +++ b/tests/test_data/natashaskitchen.com/natashaskitchen_2.json @@ -0,0 +1,90 @@ +{ + "author": "Natasha Kravchuk", + "canonical_url": "https://natashaskitchen.com/cranberry-bread/", + "site_name": "NatashasKitchen.com", + "host": "natashaskitchen.com", + "language": "en-US", + "title": "Cranberry Bread with Orange Glaze", + "ingredients": [ + "1 1/2 cups all-purpose flour", + "1 tsp baking powder", + "1/4 tsp salt", + "1/4 cup milk (room temperature)", + "Zest of 1 large orange (divided)", + "1/4 cup orange juice (freshly squeezed)", + "6 Tbsp unsalted butter (softened)", + "3/4 cup granulated sugar", + "2 large eggs (room temperature)", + "1 1/2 cups fresh cranberries (rinsed and patted dry)", + "1/2 Tbsp all-purpose flour", + "1 cup powdered sugar", + "1 1/2 Tbsp freshly squeezed orange juice (or to reach desired consistency)", + "1 tsp orange zest (reserved from the orange above)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 1/2 cups all-purpose flour", + "1 tsp baking powder", + "1/4 tsp salt", + "1/4 cup milk (room temperature)", + "Zest of 1 large orange (divided)", + "1/4 cup orange juice (freshly squeezed)", + "6 Tbsp unsalted butter (softened)", + "3/4 cup granulated sugar", + "2 large eggs (room temperature)", + "1 1/2 cups fresh cranberries (rinsed and patted dry)", + "1/2 Tbsp all-purpose flour" + ], + "purpose": "Cranberry Bread Ingredients" + }, + { + "ingredients": [ + "1 cup powdered sugar", + "1 1/2 Tbsp freshly squeezed orange juice (or to reach desired consistency)", + "1 tsp orange zest (reserved from the orange above)" + ], + "purpose": "Orange Glaze Ingredients:" + } + ], + "instructions_list": [ + "How to Make Cranberry Orange Bread:", + "Prep: Preheat oven to 350˚F. Butter a 6 cup (8 1/2 by 4 1/2 bread loaf pan) then dust with flour, tapping out the excess flour.", + "In a medium mixing bowl, whisk together: flour, baking powder, and salt. Set aside.", + "In a measuring cup, combine together milk, zest of 1 orange (Reserve 1 tsp zest for the glaze), and orange juice. Set aside.", + "In a large mixing bowl, cream together butter and granulated sugar on medium/high speed (2-3 minutes on high speed). It won’t be smooth, just combined. Beat in 2 large eggs, mixing until well incorporated.", + "Add flour mixture in 2 parts, alternating with the milk mixture and mixing on medium/low speed just until incorporated with each addition. Scrape the sides of the bowl with a spatula as needed.", + "Toss cranberries with 1/2 Tbsp flour then fold them into the batter just until incorporated. Spread the batter into your prepared pan and bake for 45-50 min at 350˚F until golden on top and a toothpick inserted into the center comes out clean. Let cool in pan 10-15 minutes then run a cake release tool or knife around the edges and transfer the loaf to a wire rack to cool completely before glazing.", + "To Make the Glaze:", + "In a separate bowl, stir together powdered sugar, orange juice and reserved teaspoon of zest. Stir until smooth. It should have a drizzling consistency. Add more orange juice to thin it out or powdered sugar to make it thicker." + ], + "category": "Breakfast,Dessert", + "yields": "8 servings", + "description": "Orange Glazed Cranberry bread is loaded with juicy cranberries with a moist and tender crumb. This stays moist for a few days after it’s made so it’s perfect as a homemade Christmas gift.", + "total_time": 60, + "cook_time": 50, + "prep_time": 10, + "cuisine": "American", + "ratings": 4.99, + "ratings_count": 867, + "nutrients": { + "servingSize": "1 serving", + "calories": "326 kcal", + "fatContent": "10 g", + "saturatedFatContent": "6 g", + "unsaturatedFatContent": "4 g", + "transFatContent": "1 g", + "carbohydrateContent": "56 g", + "sugarContent": "36 g", + "proteinContent": "4 g", + "sodiumContent": "95 mg", + "fiberContent": "2 g", + "cholesterolContent": "64 mg" + }, + "image": "https://natashaskitchen.com/wp-content/uploads/2021/12/Cranberry-Bread-SQ.jpg", + "keywords": [ + "Cranberry Bread", + "Cranberry Orange Bread", + "Orange Cranberry Bread" + ] +} diff --git a/tests/test_data/natashaskitchen.com/natashaskitchen_2.testhtml b/tests/test_data/natashaskitchen.com/natashaskitchen_2.testhtml new file mode 100644 index 000000000..d4a11a782 --- /dev/null +++ b/tests/test_data/natashaskitchen.com/natashaskitchen_2.testhtml @@ -0,0 +1,1979 @@ + + + + + + + + + + + + + + + + + + + + + Cranberry Bread with Orange Glaze (VIDEO) - NatashasKitchen.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + + + +
    +
    + +
    +
    +
    + +

    Orange-glazed Cranberry bread has a moist and tender crumb and is loaded with juicy cranberries. It has the perfect balance of sweet and tangy and just like our famous Banana Bread, this loaf stays moist for a few days (in case you needed a homemade Christmas gift idea).

    + + + +

    This is a copycat version of my favorite bakery’s cranberry loaf and this one turned out even better – more cranberries and the orange glaze makes it truly special. You’ll love every bite. 

    + + + +
    Sliced cranberry bread with fresh cranberries

    This post may contain affiliate links. Read my disclosure policy.

    + + + +

    We love cranberry recipes during the holidays like Sugared Cranberries, Cranberry Bundt Cake, and of course this Cranberry Bread recipe. If you love tangy and juicy cranberries, this recipe is a must-try!

    + + + +

    Cranberry Bread Video Tutorial

    + + + +
    + + + +

    If you enjoyed this video for Cranberry Bread, please subscribe to our Youtube Channel (P.S. Click the BELL icon so you can be the first to know when we post a new video). Thank you for subscribing!

    + + + +

    Ingredients for Cranberry Orange Bread

    + + + +
      +
    • Flour – use all-purpose to give the bread structure
    • + + + +
    • Baking powder – leavening to make the loaf rise
    • + + + +
    • Salt – balances the sweetness
    • + + + +
    • Milk – best at room temperature
    • + + + +
    • Orange zest and juice – be sure to zest the orange before juicing it. Reserve a teaspoon of zest for the glaze.
    • + + + +
    • Butter – Adds moisture to the loaf. Use unsalted butter softened at room temperature.
    • + + + +
    • Sugar – to balance the tanginess of the cranberries
    • + + + +
    • Eggs – give the bread a moist, tender crumb
    • + + + +
    • Cranberries – rinsed and dried then tossed in 1/2 Tbsp of flour to keep them from sinking in the batter (see substitution options in common questions section)
    • +
    + + + +
    Ingredients for homemade cranberry bread with orange glaze
    + + + +

    How to Make Cranberry Bread

    + + + +
      +
    1. Whisk dry ingredients – whisk together flour, baking powder and salt.
    2. + + + +
    3. Combine wet ingredients – in a measuring cup, stir together milk, orange juice and zest.
    4. + + + +
    5. Cream butter and sugar together in a large mixing bowl then beat in eggs until well combined.
    6. + + + +
    7. Combine batter – Add flour mixture in 2 additions, alternating with the milk mixture, mixing just until combined.
    8. + + + +
    9. Flour cranberries – rinse and dry cranberries then toss them with 1/2 Tbsp flour to coat. Fold in cranberries just until incorporated. Spread batter into buttered and floured 8.5×4.5 bread pan.
    10. + + + +
    11. Bake the bread for 45-50 minutes until golden on top and a toothpick inserted in the center comes out clean. Cool in the pan for 10-15 minutes then transfer to a rack to cool completely.
    12. +
    + + + +
    Step by step how to make cranberry bread recipe
    + + + +

    Pro Tip: Tossing cranberries in a little flour coats them lightly and prevents them from sinking to the bottom of the loaf as it bakes. This ensures cranberries are evenly disbursed in the finished loaf.

    + + + +
    Cranberry Orange bread in loaf pan
    + + + +

    The Best Glaze for Cranberry Bread

    + + + +

    Orange and cranberry are complimentarily flavored just like peanut butter and jelly. Topping the cranberry bread with orange juice and the orange zest-infused glaze makes this bread irresistible. I’m not sure if it’s breakfast or dessert but I’ve served it both ways. All you need for this easy 3-ingredient glaze is:

    + + + +
      +
    • Powdered sugar – I spoon it into the cup and level the top for a consistent measure.
    • + + + +
    • Orange juice – Freshly squeezed is best and don’t worry about straining. A little pulp won’t hurt the bread.
    • + + + +
    • Orange zest – do not skip the zest. It adds deep orange floral notes to the glaze.
    • +
    + + + +
    Orange glazed cranberry bread slices
    + + + +

    Common Questions

    + + + +
    Can I use frozen cranberries?

    Yes, you can use frozen cranberries in the same quantity and add them frozen (do not thaw). You may need to bake just a few minutes longer or until a toothpick inserted into the center comes out clean.

    Can I Substitute Dried Cranberries?

    You can substitute with 2/3 cup dried cranberries and reduce the sugar in the recipe to 2/3 cup since dried cranberries aren’t as tart. The dried cranberries will be juicer if you soak them in very warm water for 10 minutes then drain and pat dry before using. 

    Can I add nuts?

    You can make this a cranberry nut bread by folding in 1/2 cup of coarsely chopped walnuts or pecans when adding the cranberries to the batter.

    + + + +
    Close up slices of cranberry orange glazed bread
    + + + +

    This sweet bread is total comfort food. All you need is a mug of tea or coffee to go with a thick, fresh slice of cranberry bread.

    + + + +

    Make-Ahead

    + + + +
      +
    • Room Temperature – wrap cranberry bread loosely in plastic wrap or store in an airtight container for up to 3 days.
    • + + + +
    • Refrigerate – you can cover and store the loaf in the refrigerator for up to a week.
    • + + + +
    • Freezing – cool the loaf completely to room temperature then place in a freezer-safe zip bag, removing any excess air. Freeze up to three months. Thaw in the refrigerator overnight before serving.
    • +
    + + + +
    Slice of cranberry bread broken in half to show tender center
    + + + +

    Pro Tip: Cranberries are only available for a season in grocery stores so buy extra and store them in the freezer so you can keep enjoying this cranberry bread year-round.

    + + + +

    More Cranberry Recipes

    + + + +

    These are our best cranberry recipes using both fresh and dried cranberries.

    + + + + + + +
    + +
    + +
    +
    +

    Cranberry Bread with Orange Glaze

    + +
    4.99 from 867 votes
    + +
    Author: Natasha Kravchuk
    + +
    +
    +
    Cranberry Bread with Orange Glaze
    +
    +
    +
    Orange Glazed Cranberry bread is loaded with juicy cranberries with a moist and tender crumb. This stays moist for a few days after it’s made so it’s perfect as a homemade Christmas gift.
    + + +
    +
    + +
    +
    Prep Time: 10 minutes
    Cook Time: 50 minutes
    Total Time: 1 hour
    +
    + +

    Ingredients 

    Servings: 8 people (makes 1 loaf)

    Cranberry Bread Ingredients

    • 1 1/2 cups all-purpose flour
    • 1 tsp baking powder
    • 1/4 tsp salt
    • 1/4 cup milk, room temperature
    • Zest of 1 large orange, divided
    • 1/4 cup orange juice, freshly squeezed
    • 6 Tbsp unsalted butter, softened
    • 3/4 cup granulated sugar
    • 2 large eggs, room temperature
    • 1 1/2 cups fresh cranberries, rinsed and patted dry
    • 1/2 Tbsp all-purpose flour

    Orange Glaze Ingredients:

    • 1 cup powdered sugar
    • 1 1/2 Tbsp freshly squeezed orange juice, or to reach desired consistency
    • 1 tsp orange zest, reserved from the orange above
    + + + +

    Instructions

    How to Make Cranberry Orange Bread:

    • Prep: Preheat oven to 350˚F. Butter a 6 cup (8 1/2 by 4 1/2 bread loaf pan) then dust with flour, tapping out the excess flour.
    • In a medium mixing bowl, whisk together: flour, baking powder, and salt. Set aside.
    • In a measuring cup, combine together milk, zest of 1 orange (Reserve 1 tsp zest for the glaze), and orange juice. Set aside.
    • In a large mixing bowl, cream together butter and granulated sugar on medium/high speed (2-3 minutes on high speed). It won’t be smooth, just combined. Beat in 2 large eggs, mixing until well incorporated.
    • Add flour mixture in 2 parts, alternating with the milk mixture and mixing on medium/low speed just until incorporated with each addition. Scrape the sides of the bowl with a spatula as needed.
    • Toss cranberries with 1/2 Tbsp flour then fold them into the batter just until incorporated. Spread the batter into your prepared pan and bake for 45-50 min at 350˚F until golden on top and a toothpick inserted into the center comes out clean. Let cool in pan 10-15 minutes then run a cake release tool or knife around the edges and transfer the loaf to a wire rack to cool completely before glazing.

    To Make the Glaze:

    • In a separate bowl, stir together powdered sugar, orange juice and reserved teaspoon of zest. Stir until smooth. It should have a drizzling consistency. Add more orange juice to thin it out or powdered sugar to make it thicker.
    + + + + + +

    Nutrition Per Serving

    326kcal Calories56g Carbs4g Protein10g Fat6g Saturated Fat1g Polyunsaturated Fat3g Monounsaturated Fat1g Trans Fat64mg Cholesterol95mg Sodium144mg Potassium2g Fiber36g Sugar370IU Vitamin A8mg Vitamin C47mg Calcium1mg Iron
    + +
    + +
    Nutrition Facts
    Cranberry Bread with Orange Glaze
    Amount per Serving
    Calories
    326
    % Daily Value*
    Fat
     
    10
    g
    15
    %
    Saturated Fat
     
    6
    g
    38
    %
    Trans Fat
     
    1
    g
    Polyunsaturated Fat
     
    1
    g
    Monounsaturated Fat
     
    3
    g
    Cholesterol
     
    64
    mg
    21
    %
    Sodium
     
    95
    mg
    4
    %
    Potassium
     
    144
    mg
    4
    %
    Carbohydrates
     
    56
    g
    19
    %
    Fiber
     
    2
    g
    8
    %
    Sugar
     
    36
    g
    40
    %
    Protein
     
    4
    g
    8
    %
    Vitamin A
     
    370
    IU
    7
    %
    Vitamin C
     
    8
    mg
    10
    %
    Calcium
     
    47
    mg
    5
    %
    Iron
     
    1
    mg
    6
    %
    * Percent Daily Values are based on a 2000 calorie diet.
    + +
    +
    Course: Breakfast, Dessert
    Cuisine: American
    Keyword: Cranberry Bread, Cranberry Orange Bread, Orange Cranberry Bread
    Skill Level: Easy
    Cost to Make: $
    +
    Calories: 326
    +
    +
    + Natasha's Kitchen Cookbook
    +
    + +
    +
    + +
    +
    +

    Natasha Kravchuk

    + +
    +
    +
    +

    Welcome to my kitchen! I am Natasha, the creator behind Natasha's Kitchen (established in 2009), and I share family-friendly, authentic recipes. I am a New York Times Best-Selling cookbook author and a trusted video personality in the culinary world. My husband, Vadim, and I run this blog together, ensuring every recipe we share is thoroughly tested and approved. Our mission is to provide you with delicious, reliable recipes you can count on. Thanks for stopping by! I am so happy you are here.

    + +

    Read more posts by Natasha

    + + +
    +
    +
    + + +
    + +
    + + + + + +
    + +
    +
    +
    +
    + 4.99 from 867 votes (636 ratings without comment) +
    +
    +
    +

    Leave a Comment

    + +
    + Recipe Rating +




    +
    +
    +

    +
    + +

    + +

    +
    + + + + +
    +

    Comments

    + +
    + +
      +
    • +
      + +
      +
      Darcie Jenkins
      +
      December 16, 2024
      +
      +
      +

      Your comment is awaiting moderation.

      +
      + +
      +

      I made this two ways; using the normal recipe and one using Trader Joe’s gluten free flour mix. Both were amazing! I used zest from 3 oranges because I like a strong orange flavor. I’m going to try making it as muffins next time so they are single serving and easier to freeze. Thanks for the recipe!

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 16, 2024
        +
        +
        +

        Thank you for sharing, Darcie!

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Pauline
      +
      December 16, 2024
      +
      +
      +

      I’m wondering if i can make the cake ahead of time andfeweze it?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 16, 2024
        +
        +
        +

        Hi Pauline! Yes, it freezes well.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Mary
      +
      December 16, 2024
      +
      +
      +
      + +
      +

      What did I do wrong? I floured the cranberries so they wouldn’t sink, but they all rose to the top! The taste is good, but the cranberry taste is only at the top. I would like to make these as gifts. Any suggestions?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 16, 2024
        +
        +
        +

        Hi Mary! A few things to try- make sure to coat them well and pat them completely dry before hand. Don’t over-mix the batter. You may even try to layer them in the batter instead of folding them in. For example, pour 1/3 of the batter into the pan, top it with cranberries, repeat. I hope that’s helpful.

        +

        Reply

        +
        + +
        +
          +
        • +
          + +
          +
          denyse
          +
          December 16, 2024
          +
          +
          +

          Hi Natasha
          +First I love your recipes!!
          +Would your cranberry bread recipe work okay with dried cranberries that I could soak in oj before
          +Thanks

          +

          Reply

          +
          + +
          +
            +
          • +
            + +
            +
            NatashasKitchen.com
            +
            December 16, 2024
            +
            +
            +

            Hi Denyse! Yes- see my note in the common questions section regarding using dried cranberries.

            +

            Reply

            +
            + +
            +
          • +
          +
        • +
        +
      • +
      +
    • +
    • +
      + +
      +
      Veronica
      +
      December 15, 2024
      +
      +
      +
      + +
      +

      Prep and bake time are definitely off. Took closer to 20 minutes to get all ingredients prepped and mixed. Baking took 1 hour in a glass pan. I had to cover the bread because it was starting to brown too much. There was also way too much glaze, like double the amount I needed. This is the 2nd sweet bread recipe I’ve tried from NK and both have been lackluster.

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 16, 2024
        +
        +
        +

        Hi Veronica! I’m really sorry to hear that. This recipe generally has great reviews. It’s a very popular one around this time of the year, often used to gift for the holidays. Glass pans affect how it bakes, they require a longer bake time and a lower temperature to prevent browning.
        +You can definitely decrease the glaze, or leave it off entirely.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Charmaine Speltz
      +
      December 15, 2024
      +
      +
      +

      Can frozen cranberries be substituted for fresh cranberries??

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        Natasha's Kitchen
        +
        December 15, 2024
        +
        +
        +

        Yes frozen will work. Please check this portion of the recipe “Common Questions”

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Joan Young
      +
      December 15, 2024
      +
      +
      +
      + +
      +

      This Cranberry/Orange Bread is a favorite with our family; it is delicious. I always make it without the glaze as I think it keeps better.

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      Val
      +
      December 15, 2024
      +
      +
      +

      Oh I just saw the post about using frozen cranberries. Thank you, I should have looked a little better.

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      Val
      +
      December 15, 2024
      +
      +
      +

      I wondered if I could use frozen cranberries?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        Natasha's Kitchen
        +
        December 15, 2024
        +
        +
        +

        Yes frozen will work. Please check this portion of the recipe “Common Questions”

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Alison
      +
      December 15, 2024
      +
      +
      +

      I have used this recipe for the past few years to give to others as Christmas gifts. I bake 2 loaves at a time and add an extra 15 minutes or so to the baking time. It is always well received! Thank you for a great gift-worthy recipe!

      +

      Reply

      +
      + +
      +
    • +
    + + + +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +

    As Featured On

    + + +
    +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    Never Go "Hangry" Again!

    +

    Get weekly updates on new recipes, exclusive giveaways plus behind the scenes photos.

    +
    +

    +

    +
    + +
    +
    +
    +
    + + +
    + + + From 576f46ae1e2e5e9911177415e1a72705c6c735bf Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:27:08 -0500 Subject: [PATCH 64/94] adds support for StacyLing (#1439) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/stacyling.py | 22 + .../test_data/stacyling.com/stacyling_1.json | 58 + .../stacyling.com/stacyling_1.testhtml | 1979 +++++++++++++++++ .../test_data/stacyling.com/stacyling_2.json | 62 + .../stacyling.com/stacyling_2.testhtml | 1827 +++++++++++++++ 7 files changed, 3951 insertions(+) create mode 100644 recipe_scrapers/stacyling.py create mode 100644 tests/test_data/stacyling.com/stacyling_1.json create mode 100644 tests/test_data/stacyling.com/stacyling_1.testhtml create mode 100644 tests/test_data/stacyling.com/stacyling_2.json create mode 100644 tests/test_data/stacyling.com/stacyling_2.testhtml diff --git a/README.rst b/README.rst index 77d1df839..9ea72120a 100644 --- a/README.rst +++ b/README.rst @@ -415,6 +415,7 @@ Scrapers available for: - `https://spainonafork.com/ `_ - `https://spendwithpennies.com/ `_ - `https://www.springlane.de `_ +- `https://stacyling.com/ `_ - `https://www.staysnatched.com/ `_ - `https://steamykitchen.com/ `_ - `https://streetkitchen.hu/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index c1c28e626..51e90b1e9 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -363,6 +363,7 @@ from .spainonafork import SpainOnAFork from .spendwithpennies import SpendWithPennies from .springlane import Springlane +from .stacyling import StacyLing from .staysnatched import StaySnatched from .steamykitchen import SteamyKitchen from .streetkitchen import StreetKitchen @@ -608,6 +609,7 @@ SavoryNothings.host(): SavoryNothings, SheLikesFood.host(): SheLikesFood, SpainOnAFork.host(): SpainOnAFork, + StacyLing.host(): StacyLing, StrongrFastr.host(): StrongrFastr, TasteAtlas.host(): TasteAtlas, TheCookieRookie.host(): TheCookieRookie, diff --git a/recipe_scrapers/stacyling.py b/recipe_scrapers/stacyling.py new file mode 100644 index 000000000..3255f36f7 --- /dev/null +++ b/recipe_scrapers/stacyling.py @@ -0,0 +1,22 @@ +from ._abstract import AbstractScraper +from ._utils import get_equipment + + +class StacyLing(AbstractScraper): + @classmethod + def host(cls): + return "stacyling.com" + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text() + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) diff --git a/tests/test_data/stacyling.com/stacyling_1.json b/tests/test_data/stacyling.com/stacyling_1.json new file mode 100644 index 000000000..7c181449c --- /dev/null +++ b/tests/test_data/stacyling.com/stacyling_1.json @@ -0,0 +1,58 @@ +{ + "author": "Stacy Ling", + "canonical_url": "https://stacyling.com/irish-cheddar-and-beer-fondue-recipe/", + "site_name": "Bricks 'n Blooms with Stacy Ling", + "host": "stacyling.com", + "language": "en-US", + "title": "Irish Cheddar and Beer Fondue Recipe", + "ingredients": [ + "2 cups Small Red Potatoes (about 1-1.5 inches)", + "2 cups Broccoli Florets", + "2 cups Cauliflower Florets", + "3 Apples (Cored and Cut Into Wedges)", + "1 loaf Italian bread (long and skinny with hard exterior)", + "1 lb Irish Cheddar Cheese (Grated)", + "2.5 tbsp All Purpose Flour", + "3/4 - 1 cup Beer (Irish Stout is best)", + "6 tbsp Frozen Apple Juice Concentrate (Thawed)", + "1 tbsp Dijon Mustard" + ], + "instructions_list": [ + "Steam all veggies until tender for about 15 minutes.", + "Arrange vegetables and apples around edge of large platter.", + "Cut up bread into 1 - 1/5\" pieces so it's easy to dip in the fondue.", + "Toss cheese with flour in large bowl.", + "Bring 3/4 cup beer, juice concentrate and mustard to simmer in large saucepan over medium heat.", + "Gradually add cheese.", + "Stir constantly until cheese is smooth and melted. Add more stout to thin out if needed.", + "Season to taste with salt and pepper.", + "Transfer to fondue pot. Serve and enjoy!" + ], + "category": "Appetizer", + "yields": "10 servings", + "description": "The Best Fondue Recipe You'll Ever Have", + "total_time": 60, + "cook_time": 30, + "prep_time": 30, + "cuisine": "Irish", + "ratings": 5.0, + "ratings_count": 1, + "nutrients": { + "servingSize": "1 grams", + "calories": "412 kcal", + "fatContent": "17 g", + "saturatedFatContent": "9 g", + "unsaturatedFatContent": "6 g", + "carbohydrateContent": "47 g", + "sugarContent": "10 g", + "proteinContent": "17 g", + "sodiumContent": "610 mg", + "fiberContent": "5 g", + "cholesterolContent": "45 mg" + }, + "image": "https://stacyling.com/wp-content/uploads/2021/02/Irish-Cheddar-2-scaled.jpg", + "keywords": [ + "Fondue Recipe", + "Irish Cheddar" + ] +} diff --git a/tests/test_data/stacyling.com/stacyling_1.testhtml b/tests/test_data/stacyling.com/stacyling_1.testhtml new file mode 100644 index 000000000..6d2235cf2 --- /dev/null +++ b/tests/test_data/stacyling.com/stacyling_1.testhtml @@ -0,0 +1,1979 @@ + + + + + + + + + + Easy Irish Cheddar and Beer Fondue Recipe - Bricks 'n Blooms with Stacy Ling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + +
    + + +

    Looking for a unique and flavorful appetizer for St. Patrick’s Day? Look no further! This Irish Cheddar and Beer Fondue recipe is easy to make and perfect for dipping bread, veggies, or even meat. Sláinte!

    + + + +

    As St. Patrick’s Day approaches, what better way to celebrate than with a warm and gooey pot of Irish Cheddar and Beer Fondue?

    + + + +

    This decadent dish is the perfect centerpiece for a festive gathering. Rich Irish cheddar cheese melts together with a touch of dark beer, creating a smooth and flavorful dip ideal for crusty bread, crisp vegetables, or even succulent meats.

    + + + +

    So, gather your friends and family, grab some forks (or maybe even skewers!), and prepare to dive into a pot of pure Irish comfort food!

    + + + +

    If you are coming from my good friend Michele from Vintage Home Designs, welcome to my home! Doesn’t that drink sound amazing? I am a huge fan of white sangria so I can’t wait to try it!!!

    + + + +

    (Posts on stacyling.com may contain affiliate links. Click HERE for full disclosure.)

    + + + + + +

    About Fondue Recipes

    + + + +

    Have you ever had fondue before? Gah! It’s my favorite. And my kids love it too! We used to do fondue parties with a groovy 70’s theme for their birthdays and served pizza fondue. And of course, some chocolate fondues. It was so fun!

    + + + +

    Fondue goes beyond just being a delicious dish; it’s a fun and interactive dining experience that’s perfect for gatherings. Here’s why fondue recipes are a great choice and why they’re so much fun:

    + + + +
      +
    • Interactive Dining: Fondue is all about participation! Everyone gets to dip their food of choice into the communal pot, creating a lively and social atmosphere.
    • + + + +
    • Variety is the Spice of Life: The beauty of fondue lies in its versatility. You can choose from a variety of cheese fondues, chocolate fondues, or even savory broth fondues for meat and vegetables. Each dip offers endless possibilities for what you can dunk, keeping things fresh and fun.
    • + + + +
    • A Bit of Playfulness: Let’s face it, dipping food on long forks and trying to avoid drips can be a bit silly.
    • + + + +
    • Surprisingly Simple: Many fondue recipes are surprisingly easy to make. You can usually whip up a delicious fondue in under 30 minutes!
    • + + + +
    • Endless Customization: Fondue recipes are like blank canvases. You can easily adjust the base recipe to suit your tastes.
    • + + + +
    • Perfect for All Seasons: While cheese fondue might seem like a winter dish, the truth is fondue recipes can be enjoyed year-round. Opt for a light and refreshing broth fondue in the summer or a decadent chocolate fondue for a cozy dessert in the colder months.
    • + + + +
    • +
    + + + +
    irish cheddar and beer fondue in fondue pot with broccoli potatoes and bread
    + + + +

    How to Make Easy Irish Cheddar and Beer Fondue Recipe

    + + + +

    This recipe for Irish Cheddar and Beer Fondue is SO GOOD, super easy to make, and perfect to serve for a Saint Patrick’s Day celebration. While you can make this recipe with whatever beer you want, stout makes it that much better.

    + + + +

    Enjoy!

    + + + +

    Ingredients for Easy Irish Cheddar and Beer Fondue Recipe

    + + + +
      +
    • 2 cups Small Red Potatoes (about 1-1.5 inches)
    • + + + +
    • 2 cups Broccoli Florets
    • + + + +
    • 2 cups Cauliflower Florets
    • + + + +
    • 3 Apples Cored and Cut Into Wedges
    • + + + +
    • 1 loaf Italian bread (long and skinny with hard exterior)
    • + + + +
    • 1 lb Irish Cheddar Cheese Grated
    • + + + +
    • 2.5 tbsp All Purpose Flour
    • + + + +
    • ¾ – 1 cup Beer (Irish Stout is best)
    • + + + +
    • 6 tbsp Frozen Apple Juice Concentrate Thawed
    • + + + +
    • 1 tbsp Dijon Mustard
    • +
    + + + +
    Green and White Table Decor Ideas for Saint Patrick's Day
    + + + +
    Irish Cheddar and Beer Fondue Recipe
    + + + +

    Directions to Make This Recipe for Irish Cheddar and Beer Fondue

    + + + +
      +
    • Steam all veggies until tender for about 15 minutes.
    • + + + +
    • Arrange vegetables and apples around edge of large platter.
    • + + + +
    • Cut up bread into 1 – 1/5″ pieces so it’s easy to dip in the fondue.
    • + + + +
    • Toss cheese with flour in large bowl.
    • + + + +
    • Bring 3/4 cup beer, juice concentrate and mustard to simmer in large saucepan over medium heat.
    • + + + +
    • Gradually add cheese.
    • + + + +
    • Stir constantly until cheese is smooth and melted. Add more stout to thin out if needed.
    • + + + +
    • Season to taste with salt and pepper.
    • + + + +
    • Transfer to fondue pot. Serve and enjoy!
    • +
    + + + +

    What to Serve With This and Other Fondue Recipes

    + + + +

    The dipping possibilities are endless with fondue recipes, but here’s a breakdown of some classic and delicious options to pair with different fondue types:

    + + + +

    Cheese Fondue:

    + + + +
      +
    • Breads: Crusty baguettes, sourdough bread cubes, toasted French bread, pretzels, or even breadsticks are all fantastic choices for scooping up that delicious melted cheese.
    • + + + +
    • Vegetables: For a lighter option, consider steamed or roasted vegetables like broccoli florets, cauliflower florets, asparagus spears, cherry tomatoes, or baby carrots.
    • + + + +
    • Meats: Add some protein to your fondue party with cooked and cubed ham, salami slices, cooked sausages, or even thinly sliced steak.
    • + + + +
    • Fruits: For a sweet and savory twist, try dipping apple slices, pear slices, or grapes into your cheese fondue.
    • +
    + + + +
    Irish Cheddar and Beer Fondue Recipe
    + + + +

    Chocolate Fondue:

    + + + +
      +
    • Fruits: This is a classic pairing for a reason! Fresh strawberries, raspberries, blueberries, pineapple chunks, banana slices, or even orange wedges are all perfect for dipping into chocolate fondue.
    • + + + +
    • Cookies: For a delightful textural contrast, try dipping bite-sized cookies like biscotti, shortbread cookies, sugar cookies, or even ladyfingers.
    • + + + +
    • Marshmallows: A nostalgic and fun option, marshmallows are a guaranteed crowd-pleaser when paired with chocolate fondue.
    • + + + +
    • Pretzels: Pretzels offer a salty and sweet combination that is surprisingly addictive when dipped in chocolate fondue.
    • +
    + + + +
    Irish Cheddar and Beef Fondue Recipe
    + + + +

    Broth Fondue (Savory):

    + + + +
      +
    • Meats: Thinly sliced meats like beef, chicken, or pork are perfect for cooking in a simmering broth fondue.
    • + + + +
    • Seafood: Shrimp, scallops, and bite-sized pieces of fish are all excellent choices for dipping in a savory broth fondue.
    • + + + +
    • Vegetables: Similar to cheese fondue, a variety of vegetables like broccoli florets, cauliflower florets, asparagus spears, and mushrooms can be cooked in the broth fondue.
    • + + + +
    • Dumplings: For a heartier option, consider adding cooked dumplings or wontons to your broth fondue.
    • +
    + + + +

    Fondue Recipe Tips:

    + + + +
      +
    • Make sure to cut your dippers into bite-sized pieces for easy dipping.
    • + + + +
    • Have a variety of options to cater to different preferences.
    • + + + +
    • Consider offering a selection of sauces or dips alongside the fondue for extra flavor.
    • + + + +
    • Most importantly, have fun and enjoy the interactive dining experience!
    • +
    + + + +

    I love this recipe because it tastes amazing, but you can use whatever you want to dip in the fondue. You are not limited to what I’ve suggested in this recipe. Feel free to substitute breads, crackers and other yummy vegetables.

    + + + +

    And that’s it! I hope you have an awesome St. Paddy’s Day! Cheers!

    + + + +
    irish cheddar and beer fondue in fondue pot with broccoli potatoes and bread
    + + +
    +
    irish cheddar and beer fondue in fondue pot with broccoli potatoes and bread
    +
    +

    Irish Cheddar and Beer Fondue Recipe

    +
    +Stacy Ling +
    +
    The Best Fondue Recipe You'll Ever Have
    +
    +
    5 from 1 vote
    +
    + +
    +
    +
    Prep Time 30 minutes
    Cook Time 30 minutes
    Total Time 1 hour
    +
    +
    +
    +
    +
    Course Appetizer
    Cuisine Irish
    +
    +
    +
    +
    Servings 10 People
    Calories 412 kcal
    +
    +
    + +

    Ingredients
      

    • 2 cups Small Red Potatoes (about 1-1.5 inches)
    • 2 cups Broccoli Florets
    • 2 cups Cauliflower Florets
    • 3 Apples Cored and Cut Into Wedges
    • 1 loaf Italian bread (long and skinny with hard exterior)
    • 1 lb Irish Cheddar Cheese Grated
    • 2.5 tbsp All Purpose Flour
    • ¾ – 1 cup Beer (Irish Stout is best)
    • 6 tbsp Frozen Apple Juice Concentrate Thawed
    • 1 tbsp Dijon Mustard
    +

    Instructions
     

    • Steam all veggies until tender for about 15 minutes.
      irish cheddar and beer fondue in fondue pot with broccoli potatoes and bread
    • Arrange vegetables and apples around edge of large platter.
    • Cut up bread into 1 – 1/5" pieces so it's easy to dip in the fondue.
    • Toss cheese with flour in large bowl.
    • Bring 3/4 cup beer, juice concentrate and mustard to simmer in large saucepan over medium heat.
    • Gradually add cheese.
    • Stir constantly until cheese is smooth and melted. Add more stout to thin out if needed.
    • Season to taste with salt and pepper.
    • Transfer to fondue pot. Serve and enjoy!
    +
    + +

    Nutrition

    Serving: 1gramsCalories: 412kcalCarbohydrates: 47gProtein: 17gFat: 17gSaturated Fat: 9gPolyunsaturated Fat: 6gCholesterol: 45mgSodium: 610mgFiber: 5gSugar: 10g
    +
    +
    +
    Keyword Fondue Recipe, Irish Cheddar
    +
    +
    Tried this recipe?Let us know how it was!
    + + +

    More About Irish Cheddar and Beer Fondue Recipe

    + + + +

    Do you love making fondue? What is your favorite fondue recipe? I would love to know more in the comments below.

    + + + +

    And don’t miss joining my Gardening DIY and Decorating Community on Facebook for more chatter. And follow along there and on Instagram as well. There are behind-the-scenes daily things that I share on Instagram that don’t make it to the blog. Would love to see you there too!

    + + + +

    If you prefer to binge-watch Bricks ’n Blooms on TV, we go more in-depth with tours and posts on my YouTube channel. Would love to hang out with you there!

    + + + +

    And… If you’re catching up on blog posts you may have missed, be sure to sign-up to get my newest posts via email to stay up to date with everything that’s happening here on the blog and more.

    + + + +
    Stacy Ling with her green and white table decor idea for saint patricks day
    + + + +

    Shop For Kitchen Supplies

    + + +
    + +
    + + +
    +
    + + + +

    Buy My Book!

    + + + +
    Stacy Ling with her book the bricks n blooms guide to a beauitful and easy care flower garden
    +

    If you’ve always dreamed of bringing country charm to your home while creating a beautiful, relaxing space, I got you! Learn how to grow flowers in even the smallest of spaces with my easy-care, low-maintenance approach.

    + + + + +
    + + + +

    More Great Recipe Ideas for a Saint Patrick’s Day Menu

    + + + +

    Delicious Sparkling White Sangria

    + + + +

    Michele from Vintage Home Designs

    + + + +
    Saint Patrick's Day Drink Idea
    + + + +

    Baked Chicken Reuben Recipe

    + + + +

    by Rachel from The Ponds Farmhouse

    + + + +
    Baked Chicken Reuben Recipe
    + + + +

    Garlic and Chive Roasted Baby Potatoes

    + + + +

    by Jen from Midwest Life and Style

    + + + +
    Garlic and Chive Roasted Baby Potatoes
    + + + +

    The Ultimate Double Chocolate Irish Whiskey Cheesecake Cups

    + + + +

    By Anne and AnnMarie from Simply 2 Moms

    + + + +
    Couble Chocolate Irish Whiskey Cheesecake Cups
    + + + + + +
    Irish Cheddar and Beer Fondue Recipe
    + + + +

    Thanks for stopping by the blog today!

    + + + +

    Enjoy your day! xoxo

    + + + +
    stacy ling logo
    + + + + + + + +
    Irish Cheddar and Beer Fondue Recipe for Saint Patrick's Day
    + + + +
    Green and White Table for Saint Patrick's Day
    + + + +

    Next up on the Saint Patrick’s Recipe Tour is Jen’s at Midwest Life and Style. She makes the best dishes and those roasted baby potatoes sound like my jam!

    + + + +
    Irish Cheddar and Beer Fondue Recipe
    + + + +
    Irish Cheddar and Beer Fondue Recipe
    + + + +

    If you like this post, please follow me @bricksnblooms on Pinterest, Facebook, Instagram, and TIk Tok. Subscribe to my YouTube Channel. Or join my Facebook Group.

    + + + +

    Are you doing anything fun for Saint Patrick’s Day 2021? Today, I’m celebrating Saint Patty’s Day with my best blogging friends in our monthly virtual supper club.

    + + + +

    For this month’s theme, we are celebrating Saint Patrick’s Day with an amazing menu and gorgeous table decor ideas.

    + + + +

    And this month, I’m making an appetizer.

    + + + +

    For Saint Patrick’s Day, we shared some green and white table decor ideas.

    + + + +

    And today, each of us is preparing a recipe or beverage for the dinner menu.

    + + + +

    So come join us and see what we’re having!

    + +
    +
    The bricks \'n Blooms guide to a beautiful and easy-care flower garden book by stacy ling
    +
    The Bricks ‘n Blooms Guide to a Beautiful and Easy Care Flower Garden
    + + + +
      +
    • Have you never met a plant you couldn’t kill?
    • + + + +
    • Have you dug around in the dirt with nothing to show for it except a sunburn and a sore back?
    • + + + +
    • Do you currently enjoy growing flowers, but are looking for more tips and ideas to level up your gardening game?
    • +
    + + + +

    Then the Bricks ‘n Blooms Guide is for YOU

    + + + + +
    +
    + +
    + +
    +
    +
    + + +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +

    + +

    +

    13 Comments

      +
    1. +
      + Pingback: Baked Chicken Reuben Recipe - The Ponds Farmhouse
      +
    2. +
    3. +
      + + +
      +

      This look delicious Stacy! I am definitely trying this out this weekend!

      +
      + +
      +
        +
      1. + +
      2. +
      +
    4. +
    5. + +
        +
      1. + +
      2. +
      +
    6. +
    7. + +
    8. +
    9. +
      + + +
      +

      Yum!! Nothing better than beer cheese. I need to try your recipe with my family. So fun throwing this virtual party together.

      +
      + +
      +
        +
      1. +
        + + +
        +

        Thank you! I couldn’t agree more – beer cheese is the best! Someday soon hopefully we’ll be in person! xoxo

        +
        + +
        +
      2. +
      +
    10. +
    11. +
      + Pingback: Delicious Sparkling White Sangria - Vintage Home Designs
      +
    12. +
    13. +
      + Pingback: Garlic And Chive Roasted Baby Potatoes - Midwest Life and Style Blog
      +
    14. +
    15. +
      + Pingback: 50 Best Irish Recipes for Dinner - Efox News
      +
    16. +
    17. + +
        +
      1. + +
      2. +
      +
    18. +
    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + + + +

    +
    +
    + + + +
    +
    + + + +
    +

    Join the VIP Subscriber List to receive access to my FREE Resource Library that is only available to Members.

    + + + +

    + + + + + + + + +
    + + + +
    +
    + + +
    + + + +
    + + + + + + + +
    +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/stacyling.com/stacyling_2.json b/tests/test_data/stacyling.com/stacyling_2.json new file mode 100644 index 000000000..fabd894d1 --- /dev/null +++ b/tests/test_data/stacyling.com/stacyling_2.json @@ -0,0 +1,62 @@ +{ + "author": "Stacy Ling", + "canonical_url": "https://stacyling.com/christmas-charcuterie-board-wreath/", + "site_name": "Bricks 'n Blooms with Stacy Ling", + "host": "stacyling.com", + "language": "en-US", + "title": "Christmas Charcuterie Board Wreath: The Easy & Elegant Appetizer", + "ingredients": [ + "1/2 pound Salami (thinly sliced)", + "1/2 pound Pepperoni (thinly sliced)", + "8 ounces Mozzarella cigliene", + "8 ounces Roasted Red Peppers", + "8 ounces Fontina Cheese (Diced )", + "8 ounces Cheddar Cheese (Diced)", + "8 ounces Dill Havarti (Diced)", + "8 ounces Black Olives", + "8 ounces Green Olives", + "4 ounces Mini Pickles", + "15 ounces Artichokes (Marinated)", + "8 ounces Cherry Tomatoes", + "Rosemary Sprigs" + ], + "instructions_list": [ + "Gather all of your antipasto ingredients", + "Prepare the cheeses and meats that need slicing or cubing.", + "Skewer ingredients onto large toothpicks. Avoid making them all the same so the charcuterie wreath doesn't look flat.", + "Then arrange the antipasto skewers into a wreath shape on a round platter or serving board in the shape of a wreath.", + "Tuck in rosemary sprigs to make it look like a Christmas wreath.", + "Store in the refrigerator until you are ready to serve guests." + ], + "category": "Appetizer", + "yields": "12 servings", + "description": "Wow with a Christmas Charcuterie Board Wreath! This unique appetizer is festive, flavorful, and easy to enjoy.", + "total_time": 45, + "prep_time": 45, + "cuisine": "Italian", + "ratings": 5.0, + "ratings_count": 1, + "equipment": [ + "Toothpicks Large, No colored wrappings", + "Knife" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "401 kcal", + "fatContent": "33 g", + "saturatedFatContent": "14 g", + "unsaturatedFatContent": "17 g", + "transFatContent": "0.3 g", + "carbohydrateContent": "8 g", + "sugarContent": "1 g", + "proteinContent": "19 g", + "sodiumContent": "1884 mg", + "fiberContent": "4 g", + "cholesterolContent": "74 mg" + }, + "image": "https://stacyling.com/wp-content/uploads/2023/11/Christmas-Charcuterie-Board-Wreath-5.jpg", + "keywords": [ + "Antipasto Skewers", + "Christmas Charcuterie Board" + ] +} diff --git a/tests/test_data/stacyling.com/stacyling_2.testhtml b/tests/test_data/stacyling.com/stacyling_2.testhtml new file mode 100644 index 000000000..0fe9b06c4 --- /dev/null +++ b/tests/test_data/stacyling.com/stacyling_2.testhtml @@ -0,0 +1,1827 @@ + + + + + + + + + + Christmas Charcuterie Board Wreath: The Easy & Elegant Appetizer - Bricks 'n Blooms with Stacy Ling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + +
    + + +

    Wow with a Christmas Charcuterie Board Wreath! This unique appetizer is festive, flavorful, and easy to enjoy.

    + + + +

    The holiday season calls for something special, and what better way to add festive flair to your celebrations than with a Christmas charcuterie board wreath? This unique creation combines the beauty of a Christmas wreath with the deliciousness of a charcuterie board, making it a show-stopping centerpiece for your holiday gatherings.

    + + + +

    Imagine a wreath crafted not from traditional evergreens, but from an array of delectable cheeses, savory meats, colorful fruits, and fragrant herbs. This edible masterpiece is not only visually stunning but also incredibly easy to enjoy – no more struggling with cheese knives or reaching across the table!

    + + + +

    Wait until you see how easy it is to create this festive appetizer that will have your guests raving.

    + + + +

    (Posts on stacyling.com may contain affiliate links. Click HERE for full disclosure.)

    + + + + + +
    Christmas charcuterie board wreath
    + + + + + +

    Building Your Christmas Charcuterie Board Wreath

    + + + +

    What I love most about this antipasto wreath is the ease of eating it during a Christmas party because it’s a great finger food for Christmas without everyone’s hands grabbing the same cheese knife, meats, and cheeses. In the spirit of the season, let’s craft this unique and visually stunning addition that will be the talk of your holiday spread.

    + + + +

    Ingredients and Supplies for a Charcuterie Wreath

    + + + +
      +
    • Salami
    • + + + +
    • Pepperoni
    • + + + +
    • Mozzarella Cigliene Balls
    • + + + +
    • Roasted Red Peppers
    • + + + +
    • Fontina
    • + + + +
    • Cheddar
    • + + + +
    • Dill Havarti
    • + + + +
    • Green Olives
    • + + + +
    • Black Olives
    • + + + +
    • Marinated Artichokes
    • + + + +
    • Mini Pickles
    • + + + +
    • Cherry Tomatoes
    • + + + +
    • Rosemary Sprigs
    • + + + +
    • Large toothpicks
    • + + + +
    • Round Platter or Serving Board
    • +
    + + + +
    christmas charcuterie wreath
    + + + +

    Tips for Choosing Ingredients

    + + + +
      +
    • Sturdy Choices: Ensure your cheeses and meats are firm enough to hold up on a toothpick without breaking apart.
    • + + + +
    • Toothpick Tip: Opt for larger toothpicks for easier assembly and a more polished look.
    • +
    + + + +

    And before you drop down to the directions to make this festive appetizer, let me tell you how good it tastes! Pop all of the ingredients from skewer into your mouth and you’ll get a medley of the best flavors. So don’t just pick at one meat or cheese!

    + + + +

    Directions to Make a Christmas Charcuterie Board Wreath

    + + + +
      +
    1. Prep Your Ingredients: Slice or cube any cheeses and meats as needed.
    2. + + + +
    3. Assemble the Skewers: Create your antipasto skewers by threading a variety of ingredients onto each toothpick. Vary the combinations for a dynamic look.
    4. + + + +
    5. Create the Wreath: Arrange the skewers on your platter in a wreath shape.
    6. + + + +
    7. Add Festive Touches: Tuck fresh rosemary sprigs around the wreath to mimic the look of a traditional Christmas wreath.
    8. + + + +
    9. Chill and Serve: Store the wreath in the refrigerator until you’re ready to wow your guests.
    10. +
    + + + +
    christmas charcuterie board wreath
    + + + +

    More Christmas Charcuterie Board Inspiration

    + + + +

    Want to explore other festive charcuterie board ideas? Here are 15 more ways to add Christmas cheer to your board:

    + + + +
      +
    • Holiday Shapes: Arrange your charcuterie in the shape of a Christmas tree, a star, or even a reindeer.
    • + + + +
    • Festive Colors: Incorporate red and green elements like grapes, cranberries, and fresh herbs.
    • + + + +
    • Herbal Base: Create a fragrant base for your board with fresh evergreen sprigs like rosemary or thyme.
    • + + + +
    • Ornament Accents: Nestle small Christmas ornaments among the food for a touch of whimsy.
    • + + + +
    • Cranberry Garland: Drape a cranberry garland around your board for a festive border.
    • + + + +
    • Cheese Labels: Use festive labels to identify each cheese variety.
    • + + + +
    • Symmetrical Arrangement: Create a balanced and visually appealing display with symmetrical arrangements.
    • + + + +
    • Meat and Cheese Roses: Craft elegant roses from prosciutto or cheese slices.
    • + + + +
    • Mini Charcuterie Boards: Offer individual mini boards for each guest.
    • + + + +
    • Mini Cheese Wreaths: Form small wreaths using baby cheeses like Babybel.
    • + + + +
    • Edible Greenery: Add pops of fresh green with arugula or microgreens.
    • + + + +
    • Tiered Display: Use tiered platters or cake stands to create height and visual interest.
    • + + + +
    • Festive Bowls: Serve condiments in holiday-themed bowls.
    • + + + +
    • Edible Cutouts: Use cookie cutters to create cheese or meat stars and snowflakes.
    • + + + +
    • Festive Ribbon: Tie a ribbon around your board for an extra touch of elegance.
    • +
    + + + +

    Remember, the key to a beautiful Christmas charcuterie board is to balance colors, textures, and flavors.

    + + + +
    christmas charcuterie board wreath on stone wall
    + + + +

    Final Thoughts About Making a Christmas Charcuterie Board Wreath

    + + + +

    Isn’t this the cutest idea for your holiday spread? Every time I make this Christmas charcuterie wreath, it’s the first thing to disappear! It’s such a show-stopper, and the combination of flavors and festive aromas always creates a memorable experience for my guests. Will you make it this year? What types of charcuterie would you include? I would love to know more in the comments below.

    + + + +

    Want to make a charcuterie board in the shape of a Christmas tree? Check out this post from Ain’t Too Proud to Meg

    + + + +

    Thank you so much for following along.

    + + + +

    Enjoy a beautiful day! xo

    + + + +
    Stacy Ling
    + + + +
    enjoying an antipasto skewer from a christmas charcuterie board wreath
    + + +
    +
    christmas charcuterie board wreath on stone wall
    +
    +

    Christmas Charcuterie Board Wreath: The Easy & Elegant Appetizer

    +
    +Stacy Ling +
    +
    Wow with a Christmas Charcuterie Board Wreath! This unique appetizer is festive, flavorful, and easy to enjoy.
    +
    +
    5 from 1 vote
    +
    + +
    +
    +
    Prep Time 45 minutes
    Total Time 45 minutes
    +
    +
    +
    +
    +
    Course Appetizer
    Cuisine Italian
    +
    +
    +
    +
    Servings 12 servings
    Calories 401 kcal
    +
    +
    +

    Equipment

    • Toothpicks Large, No colored wrappings
    +

    Ingredients
      

    +

    Instructions
     

    • Gather all of your antipasto ingredients
    • Prepare the cheeses and meats that need slicing or cubing.
    • Skewer ingredients onto large toothpicks. Avoid making them all the same so the charcuterie wreath doesn't look flat.
    • Then arrange the antipasto skewers into a wreath shape on a round platter or serving board in the shape of a wreath.
    • Tuck in rosemary sprigs to make it look like a Christmas wreath.
    • Store in the refrigerator until you are ready to serve guests.
    +
    + +

    Nutrition

    Calories: 401kcalCarbohydrates: 8gProtein: 19gFat: 33gSaturated Fat: 14gPolyunsaturated Fat: 3gMonounsaturated Fat: 14gTrans Fat: 0.3gCholesterol: 74mgSodium: 1884mgPotassium: 366mgFiber: 4gSugar: 1gVitamin A: 706IUVitamin C: 17mgCalcium: 289mgIron: 1mg
    +
    +
    +
    Keyword Antipasto Skewers, Christmas Charcuterie Board
    +
    +
    Tried this recipe?Let us know how it was!
    + + + + +
    festive christmas charcuterie board wreath
    + + + +
    Christmas charcuterie wreath
    +
    A luxurious chandelier hangs over a festive holiday display with greenery, poinsettias, and candles. A sign in the background adds to the cozy atmosphere. Text reads: "2024 Holiday Shop - My Top Finds to Deck Your Halls This Season.
    +
    + +
    +
    The bricks \'n Blooms guide to a beautiful and easy-care flower garden book by stacy ling
    +
    The Bricks ‘n Blooms Guide to a Beautiful and Easy Care Flower Garden
    + + + +
      +
    • Have you never met a plant you couldn’t kill?
    • + + + +
    • Have you dug around in the dirt with nothing to show for it except a sunburn and a sore back?
    • + + + +
    • Do you currently enjoy growing flowers, but are looking for more tips and ideas to level up your gardening game?
    • +
    + + + +

    Then the Bricks ‘n Blooms Guide is for YOU

    + + + + +
    +
    + +
    + +
    +
    +
    + + +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +

    + +

    +

    14 Comments

      +
    1. + +
        +
      1. +
        + + +
        +

        Almost is right! Cindy it is so good! And it’s best to pop the whole skewer of goodies in your mouth – the medley of flavors is really good! I usually pick them off but no – its much better when taken together! Thank you!!!

        +
        + +
        +
      2. +
      +
    2. +
    3. +
      + + +
      +

      I do one of these on a large round cutting board with a handle like a pizza board. The rustic wood base as a surround really goes well with the rustic look of charcuterie

      +
      + +
      +
        +
      1. + +
      2. +
      +
    4. +
    5. +
      + + +
      +

      What a great board, Stacy! It’s the perfect option for holiday gatherings! I’ll be sharing it this week on my Mitten Moments! ❤️

      +
      + +
      +
        +
      1. +
        + + +
        +

        I’m so happy to hear that Kim! I appreciate your friendship and that share so much! xoxo

        +
        + +
        +
      2. +
      +
    6. +
    7. + +
        +
      1. + +
      2. +
      +
    8. +
    9. +
      + + +
      +

      Oh wow, Stacy! This almost looks too pretty to eat. What a fun idea. And I love that everything is already on a skewer. Perfect party food so guests can easily mix and mingle while enjoying the spread!

      +
      + +
      +
        +
      1. + +
      2. +
      +
    10. +
    11. +
      + + +
      +

      Love this Stacy! It looks so delicious and so pretty. The perfect holiday appetizer. Pinned!

      +
      + +
      +
        +
      1. + +
      2. +
      +
    12. +
    13. + +
        +
      1. + +
      2. +
      +
    14. +
    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + + + +

    +
    +
    + + + +
    +
    + + + +
    +

    Join the VIP Subscriber List to receive access to my FREE Resource Library that is only available to Members.

    + + + +

    + + + + + + + + +
    + + + +
    +
    + + +
    + + + +
    + + + + + + + +
    +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 03f818b3f31a1832d8dd8886a662f42c39084c6b Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:27:24 -0500 Subject: [PATCH 65/94] Adds support for sugarhero (#1441) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + recipe_scrapers/sugarhero.py | 16 + .../test_data/sugarhero.com/sugarhero_1.json | 68 + .../sugarhero.com/sugarhero_1.testhtml | 1135 ++++++++++++++ .../test_data/sugarhero.com/sugarhero_2.json | 122 ++ .../sugarhero.com/sugarhero_2.testhtml | 1316 +++++++++++++++++ 7 files changed, 2660 insertions(+) create mode 100644 recipe_scrapers/sugarhero.py create mode 100644 tests/test_data/sugarhero.com/sugarhero_1.json create mode 100644 tests/test_data/sugarhero.com/sugarhero_1.testhtml create mode 100644 tests/test_data/sugarhero.com/sugarhero_2.json create mode 100644 tests/test_data/sugarhero.com/sugarhero_2.testhtml diff --git a/README.rst b/README.rst index 9ea72120a..9154357c0 100644 --- a/README.rst +++ b/README.rst @@ -420,6 +420,7 @@ Scrapers available for: - `https://steamykitchen.com/ `_ - `https://streetkitchen.hu/ `_ - `https://www.strongrfastr.com `_ +- `https://sugarhero.com/ `_ - `https://sunbasket.com/ `_ - `https://sundpaabudget.dk/ `_ - `https://www.sunset.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 51e90b1e9..5450e0b9e 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -368,6 +368,7 @@ from .steamykitchen import SteamyKitchen from .streetkitchen import StreetKitchen from .strongrfastr import StrongrFastr +from .sugarhero import SugarHero from .sunbasket import SunBasket from .sundpaabudget import SundPaaBudget from .sunset import Sunset @@ -611,6 +612,7 @@ SpainOnAFork.host(): SpainOnAFork, StacyLing.host(): StacyLing, StrongrFastr.host(): StrongrFastr, + SugarHero.host(): SugarHero, TasteAtlas.host(): TasteAtlas, TheCookieRookie.host(): TheCookieRookie, TheCookingGuy.host(): TheCookingGuy, diff --git a/recipe_scrapers/sugarhero.py b/recipe_scrapers/sugarhero.py new file mode 100644 index 000000000..76e495288 --- /dev/null +++ b/recipe_scrapers/sugarhero.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class SugarHero(AbstractScraper): + @classmethod + def host(cls): + return "sugarhero.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/tests/test_data/sugarhero.com/sugarhero_1.json b/tests/test_data/sugarhero.com/sugarhero_1.json new file mode 100644 index 000000000..fb3a5e8dc --- /dev/null +++ b/tests/test_data/sugarhero.com/sugarhero_1.json @@ -0,0 +1,68 @@ +{ + "author": "Elizabeth LaBau", + "canonical_url": "https://www.sugarhero.com/christmas-pinwheel-cookies/", + "site_name": "SugarHero", + "host": "sugarhero.com", + "language": "en-US", + "title": "Christmas Pinwheel Cookies", + "ingredients": [ + "12.75 oz all-purpose flour (3 cups)", + "1 tsp baking powder", + "½ tsp salt", + "8 oz unsalted butter (1 cup), at room temperature)", + "8.75 oz granulated sugar (1.25 cups)", + "1 large egg (at room temperature)", + "2 tsp vanilla extract", + "Red and green food coloring (I used Americolor gel colors)", + "6.75 oz sprinkles (1 cup)" + ], + "instructions_list": [ + "Whisk together the flour, baking powder, and salt in a medium bowl, and set aside temporarily.", + "Combine the butter and granulated sugar in the bowl of a large stand mixer fitted with a paddle attachment. Mix the butter and sugar together at medium speed for 2-3 minutes until light and fluffy.", + "Turn the mixer to low, add the egg and vanilla extract, and mix until well-incorporated.", + "With the mixer stil on low speed, slowly add the flour and mix until just a few streaks of flour remain. Stop the mixer, and finish scraping down the bottom and sides of the bowl with a rubber spatula. The dough should be soft and supple but not sticky.", + "Divide the dough into 3 equal parts. If you have a kitchen scale, each portion should be approximately 10 ounces.", + "Leave one portion uncolored, and use gel food coloring to color the other two portions red and green. You can stir the food coloring in by hand, knead it in like bread dough, or mix it in using the mixer. (If you use the mixer, keep a close eye on the dough and run it for a short time so the dough doesn’t get overmixed and tough.)", + "Form each color into a disc and wrap them tightly in plastic wrap. Refrigerate for at least 45 minutes, until firm.", + "Roll each color out between two sheets of parchment to a long rectangle, approximately 6 x 13” long. Try to avoid adding additional flour at this step, or else the cookies might be tough. If the dough starts to feel too soft to work with at any point in the rolling/stacking process, chill it again in the refrigerator until you can work with it easily.", + "Stack the dough rectangles on top of each other in this order: green, white, then red on top. Roll the dough up into a long, tight spiral.", + "To roll the edges in sprinkles, brush the outside of the dough log with a very thin layer of corn syrup - you just want enough to make the sprinkles stick. Scatter the sprinkles on a baking sheet, and roll the log around the sprinkles, pressing it into the sprinkles so they adhere and it is completely covered. You can also skip this step and leave the edges plain.", + "Wrap the dough log in plastic wrap, and refrigerate for at least 45 minutes, or until firm.", + "Preheat the oven to 350 F, and cover 2 baking sheets with parchment.", + "Use a large, sharp chef’s knife to slice the log into rounds a little under ½” thick. (You can do thinner, ¼” rounds for a larger yield.) Place them on the baking sheets with a few inches between each cookie.", + "Bake the cookies for 13-15 minutes, until they have spread and puffed, and no longer have a raw shine in the center. They will continue to cook for a few minutes after they’re out of the oven, so don’t wait until they feel firm in the center or they will be overcooked. The perfect pinwheel cookie is crunchy around the edges and soft and tender on the inside!", + "Once cool, remove from the baking sheets and enjoy! Pinwheel cookies can be stored in an airtight container at room temperature and should be enjoyed within 4-5 days for maximum freshness. Unbaked cookies can be frozen, well-wrapped, for up to 3 months." + ], + "category": "Dessert", + "yields": "30 servings", + "description": "These festive Pinwheel Sugar Cookies might be the best Christmas cookie recipe ever! They’re made with a simple sugar cookie dough formed into a beautiful red, white, and green spiral design.", + "total_time": 150, + "cook_time": 15, + "prep_time": 45, + "cuisine": "American", + "ratings": 4.92, + "ratings_count": 12, + "nutrients": { + "servingSize": "1 serving", + "calories": "133 kcal", + "fatContent": "6 g", + "saturatedFatContent": "4 g", + "unsaturatedFatContent": "3 g", + "transFatContent": "1 g", + "carbohydrateContent": "18 g", + "sugarContent": "8 g", + "proteinContent": "1 g", + "sodiumContent": "42 mg", + "fiberContent": "1 g", + "cholesterolContent": "22 mg" + }, + "image": "https://www.sugarhero.com/wp-content/uploads/2022/11/christmas-pinwheel-cookies-square.jpg", + "keywords": [ + "Christmas", + "christmas cookies", + "Christmas dessert", + "pinwheel cookies", + "sugar cookie", + "sugar cookie pinwheels" + ] +} diff --git a/tests/test_data/sugarhero.com/sugarhero_1.testhtml b/tests/test_data/sugarhero.com/sugarhero_1.testhtml new file mode 100644 index 000000000..c3d0cac7c --- /dev/null +++ b/tests/test_data/sugarhero.com/sugarhero_1.testhtml @@ -0,0 +1,1135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Christmas Pinwheel Cookies - SugarHero + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Christmas Pinwheel Cookies

    4.92

    46

    PrintJump to Recipe

    This post may contain affiliate links. As an Amazon Associate I earn from qualifying purchases. Please see my disclosure policy for more information.

    +
    + +

    These festive Pinwheel Sugar Cookies might be the best Christmas cookie recipe ever! They’re made with a simple sugar cookie dough formed into a beautiful red, white, and green spiral design.

    + + + +
    Hand holding up a red, white, and green pinwheel sugar cookie.
    +
    Want to save this recipe?
    Get this sent right to your inbox, plus great new recipes weekly!
    + + + + + + +

    I’m so excited to share this recipe for pinwheel sugar cookies with you, because they are guaranteed to make you feel like a dessert magician. I hope you’re ready to sit back and let the compliments roll in, because these cookies will make you the most popular person at the holiday potluck.

    + + + +

    Don’t let the gorgeous red, white, and green swirls fool you–these cookies are basically a sugar cookie wearing a fancier outfit. They start with a simple 5-minute cookie dough, and from there you roll a little here, cut a little there, abracadabra, and voila–you have beautiful swirled cookies!

    + + + +

    Need a few more easy Christmas cookie ideas for a platter or cookie swap? Try some of my other favorites like Oreo Cookie Christmas Ornaments, Chocolate Peppermint Kiss Cookies or Black Sesame Shortbread Cookies!

    + + + + +
    + + + + + +
    + + + + +
    Christmas Pinwheel Cookies on a white plate with peppermint candies in the background.
    + + + +

    🌀 Pinwheel Cookies: Not Just for Christmas

    + + + +

    The best part is, these are not just a Christmas dessert! Once you get the hang of making them, you can make endless varieties of pinwheel cookies, with other color schemes, sprinkles, and flavoring variations. You could even add some chocolate to make chocolate-swirled pinwheel cookies.

    + + + +

    Ready to make these? I’m going to show you how to make pinwheel sugar cookies from start to finish, with step-by-step photos and all the info you need to make them right on your first try!

    + + + +

    If you’re on a cookie roll after making these (get it??) you’ll love my other cookie recipes, like Big Soft Sugar Cookies, Cinnamon Roll Sugar Cookies, and Watercolor Rose Sugar Cookies. Or get playful and make some Sugar Cookie French Fries!

    + + + +
    Stack of red, white, and green Christmas pinwheel cookies and a mug of milk.
    + + +

    Table of Contents

    + + +

    🧾 What You’ll Need

    + + + +
    Overhead shot of ingredients needed to make Christmas Pinwheel Cookies.
    + + + +

    Ingredients

    + + + +

    The best part of these pinwheels (aside from the taste, texture, and appearance…) is the short and simple ingredient list! Like many cookie recipes, they require just a handful of pantry staples, most of which you probably have on hand already. Here are a few tips to keep in mind when assembling the ingredients. (Links are affiliate links and I earn a small commission from qualifying purchases.)

    + + + +
      +
    • Butter: Your butter should be at room temperature to make these cookies. This means it’s pliable but cool–you don’t want it to be greasy and melty. I always recommend unsalted butter in baking, so you can control the precise amount of salt. If you only have salted butter, use that but omit the additional salt in the recipe.
    • + + + +
    • Egg: The egg you use should be large size, and at room temperature. Tip: if you need to warm up an egg quickly, place it in a bowl of hot water for 5 minutes. This won’t cook the egg, but will bring it to room temperature so it’s perfect for baking.
    • + + + +
    • Vanilla extract: Vanilla is the classic sugar cookie flavor, but you can experiment and add other extracts in addition to or instead of vanilla. Try almond, orange, or lemon!
    • + + + +
    • Food coloring: For the best results, you will want to use gel food coloring. It is more concentrated than typical water-based colorings, so you don’t have to use as much coloring to get strong, vibrant shades. I use and recommend Americolor gel coloring. For this recipe, I used Americolor Super Red and Americolor Leaf Green shades.
    • + + + +
    • Sprinkles: Most sprinkles will work in this recipe. Jimmies, nonpareils, and sparkling sugar are all great choices. Avoid any chocolate pieces (like Sixlets), crushed hard candies (like candy cane pieces), or sprinkle mixes with royal icing decorations. I mixed up my own sprinkle blend for these cookies, but it is very similar to these sprinkle blends: Christmas Past, Elfin Around, and Christmas Magic.
    • +
    + + + +
    Red, white, and green Christmas Pinwheel Cookies arranged on a red and white plate.
    + + + +

    Equipment

    + + + +

    Great news, sugar heroes — no special equipment required for these babies! All you need are some common cookie tools to make your life easier. (Links are affiliate links and I earn a small commission from qualifying purchases.)

    + + + +
      +
    • Baking sheets: Heavy-duty baking sheets will keep the bottoms of the cookies from burning and help cookies bake evenly.
    • + + + +
    • Parchment paper: I never bake directly on my baking sheets–it’s all about the parchment, baby! Save time and cleanup by using silicone liners or parchment paper when baking cookies.
    • + + + +
    • Mixer:a stand mixer or a hand mixer will both work in this recipe.
    • +
    + + + +

    📋 Instructions

    + + + +

    Here’s a quick photo overview showing how to make Christmas Pinwheel Cookies. Grab the full printable instructions in the recipe card down below!

    + + + +
    Two-photo collage showing how to make Christmas pinwheel cookie dough.
    + + + +

    Make the sugar cookie dough

    + + + +
      +
    • Combine the room temperature butter and sugar in the bowl of a large stand mixer, or use a hand mixer and a large mixing bowl.
    • + + + +
    • Beat the butter and sugar together with a paddle attachment at medium speed for 2-3 minutes, until light and fluffy.
    • +
    + + + +
    Two-photo collage showing how to make Christmas pinwheel cookie dough.
    + + + +
      +
    • Add a large egg and vanilla extract (or other flavoring) to the mixing bowl.
    • + + + +
    • Mix on medium-low speed until the egg is completely incorporated.
    • +
    + + + +
    Two-photo collage showing how to make Christmas pinwheel cookie dough.
    + + + +
      +
    • Add flour, baking powder, and salt to the mixing bowl.
    • + + + +
    • Mix on low speed until just a few streaks of flour remain. At this point, stop the mixer and finish by hand, using a spatula to scrape the bottom and sides of the bowl.
    • +
    + + + +
    Two-photo collage showing how to divide and color sugar cookie dough for pinwheel cookies.
    + + + +

    Divide and color the cookie dough

    + + + +
      +
    • Divide the dough evenly into three portions. If you have a kitchen scale, each portion should be about 10 oz. Leave one part of dough plain, and color the remaining parts red and green. You can do this by hand, either stirring the food coloring in or kneading it in. You can also use a mixer, but if you do, only mix for a short period of time so the dough doesn’t become over-mixed and tough.
    • + + + +
    • Form each portion of dough into a disc and wrap well with plastic wrap. Refrigerate for at least 45 minutes, until cool and firm.
    • +
    + + + +
    Two-photo collage showing how to roll out sugar cookie dough and stack it to make pinwheel cookies.
    + + + +

    Roll out and stack the pinwheel cookie dough

    + + + +
      +
    • Roll out each color of dough between two sheets of parchment paper. Try to avoid using extra flour in this step, because too much flour can make the cookies tough. Roll each piece into a rectangle approximately 6.5″ x 13″.
    • + + + +
    • Stack the rectangles on top of each other in this order: green on bottom, then white, then red on top.
    • +
    + + + +
    Two-photo collage showing how to roll up pinwheel cookies and roll them in sprinkles.
    + + + +

    Roll and sprinkle the pinwheel dough

    + + + +
      +
    • Roll the dough up tightly into a long, spiral log. You can use the parchment underneath to help roll the cookie dough around itself.
    • + + + +
    • The sprinkle coating is optional (but gorgeous!). If you want to add sprinkles, brush the outside of the dough lightly with watered-down corn syrup–just enough to help the sprinkles stick.
    • + + + +
    • Scatter sprinkles on a baking sheet, and roll the dough log over the sprinkles until the outside is completely covered.
    • + + + +
    • Wrap the log in plastic wrap, and refrigerate again for at least 45 minutes, until firm.
    • +
    + + + +
    Two-photo collage showing how to slice and bake Christmas Pinwheel Cookies.
    + + + +

    Slice and bake the cookies

    + + + +
      +
    • Use a large sharp knife to cut rounds out of the cookie dough log. I like making my cookies just under 1/2″ thick, which results in about 30 3-inch wide cookies. If you cut thinner rounds, you’ll get a larger yield, and your cookies will be a bit smaller. You might also want to adjust the baking time since they’ll probably be done sooner.
    • + + + +
    • Place the cookies on parchment-covered baking sheets, and bake at 350 F for 13-15 minutes. They’re done when the cookies are puffed and have spread, and have lost the raw shine in the center.
    • + + + +
    • Let them cool, then enjoy!
    • +
    + + + +
    Log of red, white, and green cookie dough in a spiral design.
    + + + +

    💭 Variations

    + + + +

    Christmas-themed pinwheel cookies are just the beginning! Mix it up and try one of these ideas:

    + + + +
      +
    • Change up the colors you use–consider a simple black-and-white swirl for Halloween, or a vibrant 5-color rainbow swirl for St. Patrick’s Day or Pride month.
    • + + + +
    • Instead of sprinkles, roll the cookies in finely chopped nuts or toasted coconut. You can also bake them without rolling the edges in anything!
    • + + + +
    • Mix up the flavorings–add some almond in addition to the vanilla (start with 1/2 tsp and add more to taste), or swap in coconut instead. Or, add some lemon or orange zest and extract to make citrus pinwheels.
    • + + + +
    • Make a chocolate variation: follow this recipe to add a chocolate swirl to your cookies.
    • + + + +
    • Feeling ambitious? Embed shapes in your cookies like in this Stars and Stripes Sugar Cookies.
    • +
    + + + +
    Hand with red fingernail lifting up a Christmas pinwheel cookie from a stack of cookies.
    + + + +

    💡 Tips for Pinwheel Cookies  

    + + + +

    Here are some of the most common questions people have had when making pinwheel cookies:

    + + + +
    What kind of sprinkles should I use?

    Many common sprinkle types will work for pinwheel cookies. You can use just 1 type of sprinkle, or a mix of multiple types–I like to make my own mixes by combining different sprinkles I own, so that my cookies have a variety of colors, shapes, and textures around the edges.

    Sprinkles that work well include: jimmies, nonpareils, sparkling sugar, sanding sugar, sequins, confetti/quins, and edible metallic glitter shapes. Sprinkles to avoid include: anything with chocolate (like Sixlets), anything made of hard candy (like candy cane pieces), anything too large (like some sugar pearls), or any royal icing pieces. If you aren’t sure if your sprinkles will work, you can always bake a test cookie using some dough scraps and see how they do!

    Is it okay to bake the sprinkles?

    Yes! As long as you stick to the sprinkle types mentioned above, you should be fine. Some of them will probably bleed or melt a little, but you’ll still get the sparkling sprinkle effect. (This is also why I like using sprinkle mixes, because even if some melt, others will most likely be fine.) And of course, you can always skip the sprinkles entirely!

    Tips for keeping your cookies round

    Here are my top tips for making sure the cookies look round when you bake them.
    1. After wrapping the cookie dough log in plastic wrap, roll it until it seems nice and round before putting it in the fridge to chill.
    2. If the cookie log develops a flat spot after removing it from the fridge, you can also do a little more rolling before cutting it.
    3. Make sure that the cookie log is quite cold when you start to slice it. If it isn’t well chilled the pressure of cutting with a knife can warp the shape of the cookies.
    4. And, if despite your best efforts you still have a few wonky cookies, you can always do a little last minute shaping by hand. Just gently press them into a round shape as you place them on the cookie sheet.

    Will this pinwheel method work with other recipes?

    I can’t guarantee it will work with your favorite recipe, but I can tell you that it is pretty flexible and forgiving! If you have a sugar/rolled cookie recipe that’s medium textured–meaning not too dry/stiff, and not extremely soft/sticky, then odds are good you can use this technique. If you do try other recipes, please come back and let us know how it goes!

    Make-ahead and storage information

    Pinwheel cookies can be stored in an airtight container at room temperature and should be enjoyed within 4-5 days for maximum freshness.

    If you want to make the dough in advance, you have a few options. You can freeze the whole rolled cookie log, wrapped well, for up to 3 months. I recommend letting it defrost in the refrigerator overnight, then adding the sprinkle layer, slicing, and baking as directed.

    You can also freeze individual unbaked cookie slices. I don’t recommend adding sprinkles if you are planning on freezing unbaked cookies, since many sprinkles will bleed color due to condensation. Freeze the sliced cookies in single layers in an airtight container or freezer zip-top bags for up to 3 months. To bake, let the frozen cookies sit at room temperature while the oven preheats, then add a few extra minutes to the baking time to make sure they’re baked all the way through.

    Finally, you can freeze baked cookies to eat later. Make sure to wrap them tightly and place them in a freezer safe container/storage bag to prevent freezer burn. For the best taste, thaw at room temperature, and enjoy the cookies within 3 months of their freeze date.

    + + + +
    White plate with pinwheel cookies on it and a cookie with a bite taken out of it in the foreground.
    + + + +

    ❤️ Must-Make Christmas Cookies

    + + + + + + +
    Slice of Gingerbread Cheesecake on a white plate with a bite removed on a fork.
    +
    +

    Gingerbread Cheesecake

    +
    This Gingerbread Cheesecake features a spice filling nestled on top of a gingersnap cookie crust and topped with swirls of whipped cream and adorable gingerbread men cookies. It’s perfect for a holiday gathering!
    + View Recipe +
    + +
    Candy Cane Cheesecake on a white plate with candy cane and a green napkin in the background.
    +
    +

    Candy Cane Cheesecake

    +
    This Candy Cane Cheesecake recipe will be the star of your holiday table. It has a creamy peppermint cheesecake filling, an Oreo cookie crust, and lots of candy cane pieces inside and out!
    + View Recipe +
    + + +

    Don’t miss the step-by-step tutorial showing how to make Pinwheel Cookies check out the web story here!

    + + +
    + +

    Leave a Review!

    + + + +

    If you make this recipe, let us know! Leave a ⭐️⭐️⭐️⭐️⭐️ rating on the recipe below, and leave a comment, take a photo and tag me on Instagram @elabau, or use #sugarhero on IG!

    + +
    + +
    +
    + +
    + Save + Pin + Print +
    +
    +
    +
    Hand with red fingernail lifting up a Christmas Pinwheel Cookie from a stack of cookies.
    +
    +
    +

    Christmas Pinwheel Cookies

    + +
    4.92 from 12 votes
    +
    These festive Pinwheel Sugar Cookies might be the best Christmas cookie recipe ever! They’re made with a simple sugar cookie dough formed into a beautiful red, white, and green spiral design.
    +
    Prep45 minutes
    Cook15 minutes
    Chilling Time1 hour 30 minutes
    Total2 hours 30 minutes
    Yields30 cookies
    +
    +
    +
    + +

    Ingredients

    • 12.75 oz all-purpose flour, (3 cups)
    • 1 tsp baking powder
    • ½ tsp salt
    • 8 oz unsalted butter, (1 cup), at room temperature
    • 8.75 oz granulated sugar, (1.25 cups)
    • 1 large egg, at room temperature
    • 2 tsp vanilla extract
    • Red and green food coloring, I used Americolor gel colors
    • 6.75 oz sprinkles, (1 cup)
    Save this recipe!
    Get this sent right to your inbox, plus great new recipes weekly!
    +

    Instructions 

    • Whisk together the flour, baking powder, and salt in a medium bowl, and set aside temporarily.
    • Combine the butter and granulated sugar in the bowl of a large stand mixer fitted with a paddle attachment. Mix the butter and sugar together at medium speed for 2-3 minutes until light and fluffy.
    • Turn the mixer to low, add the egg and vanilla extract, and mix until well-incorporated.
    • With the mixer stil on low speed, slowly add the flour and mix until just a few streaks of flour remain. Stop the mixer, and finish scraping down the bottom and sides of the bowl with a rubber spatula. The dough should be soft and supple but not sticky.
    • Divide the dough into 3 equal parts. If you have a kitchen scale, each portion should be approximately 10 ounces.
    • Leave one portion uncolored, and use gel food coloring to color the other two portions red and green. You can stir the food coloring in by hand, knead it in like bread dough, or mix it in using the mixer. (If you use the mixer, keep a close eye on the dough and run it for a short time so the dough doesn’t get overmixed and tough.)
    • Form each color into a disc and wrap them tightly in plastic wrap. Refrigerate for at least 45 minutes, until firm.
    • Roll each color out between two sheets of parchment to a long rectangle, approximately 6 x 13” long. Try to avoid adding additional flour at this step, or else the cookies might be tough. If the dough starts to feel too soft to work with at any point in the rolling/stacking process, chill it again in the refrigerator until you can work with it easily.
    • Stack the dough rectangles on top of each other in this order: green, white, then red on top. Roll the dough up into a long, tight spiral.
    • To roll the edges in sprinkles, brush the outside of the dough log with a very thin layer of corn syrup – you just want enough to make the sprinkles stick. Scatter the sprinkles on a baking sheet, and roll the log around the sprinkles, pressing it into the sprinkles so they adhere and it is completely covered. You can also skip this step and leave the edges plain.
    • Wrap the dough log in plastic wrap, and refrigerate for at least 45 minutes, or until firm.
    • Preheat the oven to 350 F, and cover 2 baking sheets with parchment.
    • Use a large, sharp chef’s knife to slice the log into rounds a little under ½” thick. (You can do thinner, ¼” rounds for a larger yield.) Place them on the baking sheets with a few inches between each cookie.
    • Bake the cookies for 13-15 minutes, until they have spread and puffed, and no longer have a raw shine in the center. They will continue to cook for a few minutes after they’re out of the oven, so don’t wait until they feel firm in the center or they will be overcooked. The perfect pinwheel cookie is crunchy around the edges and soft and tender on the inside!
    • Once cool, remove from the baking sheets and enjoy! Pinwheel cookies can be stored in an airtight container at room temperature and should be enjoyed within 4-5 days for maximum freshness. Unbaked cookies can be frozen, well-wrapped, for up to 3 months.
    +

    Video

    + +
    +

    Measuring Tips

    +

    Our recipes are developed using weight measurements, and we highly recommend using a kitchen scale for baking whenever possible. However, if you prefer to use cups, volume measurements are provided as well. PLEASE NOTE: the adage “8 oz = 1 cup” is NOT true when speaking about weight, so don’t be concerned if the measurements don’t fit this formula.

    +

    Want to learn more about baking measurements and conversion?

    + +
    +
    +

    Nutrition

    Calories: 133kcal | Carbohydrates: 18g | Protein: 1g | Fat: 6g | Saturated Fat: 4g | Polyunsaturated Fat: 1g | Monounsaturated Fat: 2g | Trans Fat: 1g | Cholesterol: 22mg | Sodium: 42mg | Potassium: 31mg | Fiber: 1g | Sugar: 8g | Vitamin A: 197IU | Calcium: 10mg | Iron: 1mg
    +
    +
    +
    Tried this recipe?Snap a pic and hashtag it #SugarHero. We love to see your creations on our Instagram @elabau.
    + + +

    + + + + + + + +
    Photo of Christmas Pinwheel Cookies with text overlay for Pinterest
    + +
    + + +
    + + + + +

    Meet Elizabeth!

    Hi, I’m Elizabeth — a trained pastry chef, cookbook author, video instructor, and your new Baking BFF! I’m going to teach you everything you need to know to be a sugar hero. ❤️

    +
    + +
    + +

    Related Recipes

    + +
    +
    +
    +
    + 4.92 from 12 votes
    +
    +
    +

    Leave a comment

    Your email address will not be published. Required fields are marked *

    + +
    + Rate This Recipe! +




    +
    +
    +

    + +

    + +

    +

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    46 Comments

    1. +
      + + +
      +
      + +
      +

      Just finishing up 4 batches using this recipe. 1 for each son and family. It is a lot of tedious work but follow recipe EXACTLY (having weight measurements in a good recipe is paramount). These will be given to each of our sons/daughter in laws so our 13 grandchildren can slice & baķe for Santa! Thank you for sharing this, I read thru about 20 recipes looking for one with weight measurement and 4 or 5 stars.

      +
      + +
      +
        +
      1. +
        + + +
        +

        Hi April! So glad you found our recipe and I think it’s so cool that you are giving it as gifts to your kids! Here’s to a wonderful holiday season.

        +
        + +
        +
          +
        1. + +
            +
          1. +
            + + +
            +

            Hi Kim! You can definitely use peppermint extract. You can just swap it for the vanilla 1:1. It will taste delish! Merry Christmas!

            +
            + +
            +
          2. +
          +
        2. +
        +
      2. +
      +
    2. +
    3. +
      + + +
      +

      Could you store the dyed dough in plastic wrap, in a Tupperware, for like a week until you’re ready to bake? Similar to an icebox cookie? Or do these not store well?

      +
      + +
      +
        +
      1. +
        + + +
        +

        Hi Sydney! Great questions. These cookies can definitely be made ahead of time and you’ve got a couple of options. I’m going to post some info here for you but for further reference, you can find this on the blog post in the FAQ section.
        +Pinwheel cookies can be stored in an airtight container at room temperature and should be enjoyed within 4-5 days for maximum freshness.

        +

        If you want to make the dough in advance, you have a few options. You can freeze the whole rolled cookie log, wrapped well, for up to 3 months. I recommend letting it defrost in the refrigerator overnight, then adding the sprinkle layer, slicing, and baking as directed.

        +

        You can also freeze individual unbaked cookie slices. I don’t recommend adding sprinkles if you are planning on freezing unbaked cookies, since many sprinkles will bleed color due to condensation. Freeze the sliced cookies in single layers in an airtight container or freezer zip-top bags for up to 3 months. To bake, let the frozen cookies sit at room temperature while the oven preheats, then add a few extra minutes to the baking time to make sure they’re baked all the way through.

        +

        Finally, you can freeze baked cookies to eat later. Make sure to wrap them tightly and place them in a freezer safe container/storage bag to prevent freezer burn. For the best taste, thaw at room temperature, and enjoy the cookies within 3 months of their freeze date.

        +

        I hope that helps. Merry Christmas!

        +
        + +
        +
      2. +
      +
    4. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/sugarhero.com/sugarhero_2.json b/tests/test_data/sugarhero.com/sugarhero_2.json new file mode 100644 index 000000000..611c37e36 --- /dev/null +++ b/tests/test_data/sugarhero.com/sugarhero_2.json @@ -0,0 +1,122 @@ +{ + "author": "Elizabeth LaBau", + "canonical_url": "https://www.sugarhero.com/flourless-chcolate-buche-de-noel/", + "site_name": "SugarHero", + "host": "sugarhero.com", + "language": "en-US", + "title": "Flourless Chocolate Bûche De Noël", + "ingredients": [ + "10 oz semi-sweet chocolate (1 ⅔ cups), good-quality, chopped in small pieces)", + "12 fl oz heavy cream (1 ½ cups)", + "2 tbsp unsalted butter (softened)", + "2.6 oz granulated sugar (1/4 cup + 2 tablespoons, divided use)", + "6 large eggs (separated)", + "1/2 tsp vanilla extract", + "4 oz semi-sweet chocolate (⅔ cup), good-quality, chopped in small pieces)", + "3/4 tsp cream of tartar", + "Unsweetened cocoa powder (to sprinkle over greased baking sheet and cooling cake)", + "8 fl oz heavy cream (1 cup)", + "0.75 oz powdered sugar (⅓ cup)", + "1 tsp vanilla extract", + "1/2 tsp ground cinnamon", + "Meringue mushrooms", + "Other edible nature decorations (Such as chocolate shavings, chocolate rocks, cocoa powder, powdered sugar, coconut, etc., optional)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "10 oz semi-sweet chocolate (1 ⅔ cups), good-quality, chopped in small pieces)", + "12 fl oz heavy cream (1 ½ cups)", + "2 tbsp unsalted butter (softened)" + ], + "purpose": "For the Chocolate Ganache" + }, + { + "ingredients": [ + "2.6 oz granulated sugar (1/4 cup + 2 tablespoons, divided use)", + "6 large eggs (separated)", + "1/2 tsp vanilla extract", + "4 oz semi-sweet chocolate (⅔ cup), good-quality, chopped in small pieces)", + "3/4 tsp cream of tartar", + "Unsweetened cocoa powder (to sprinkle over greased baking sheet and cooling cake)" + ], + "purpose": "For the Chocolate Cake" + }, + { + "ingredients": [ + "8 fl oz heavy cream (1 cup)", + "0.75 oz powdered sugar (⅓ cup)", + "1 tsp vanilla extract", + "1/2 tsp ground cinnamon" + ], + "purpose": "For the Whipped Cream" + }, + { + "ingredients": [ + "Meringue mushrooms", + "Other edible nature decorations (Such as chocolate shavings, chocolate rocks, cocoa powder, powdered sugar, coconut, etc., optional)" + ], + "purpose": "To Decorate" + } + ], + "instructions_list": [ + "Make the Chocolate Ganache", + "Chop the chocolate into small pieces and place it in a large bowl. Place the softened butter on top. Set aside.", + "Put the heavy cream in a saucepan over medium-high. Heat until it simmers and bubbles appear along the sides of the pan, but do not bring it to a boil.", + "Pour the hot cream over the chopped chocolate and whisk it together until the chocolate melts and the mixture is shiny and smooth.", + "Cover with cling wrap, pressing down until the plastic is touching the top of the ganche. Allow it to firm up to a spoonable consistency (like peanut butter) by setting it out for 1-2 hours at room temperature (overnight is even better).", + "Or, to firm the ganache faster, place it in the refrigerator and whisk every 15 minutes until it has a spoonable consistency. Do not leave it in the fridge too long, or it will get hard! If it accidentally gets too hard, let it rest at room temperature (or microwave briefly), then stir until the consistency is spreadable again.", + "Make the Chocolate Cake", + "Preheat oven to 350°F (180°C) and place the oven rack in the center of the oven. Use a non-stick baking spray or butter to grease a 17x12-inch (43x30cm) baking pan. Line the pan with foil or parchment paper, spray it well with baking spray, and then sprinkle liberally with cocoa powder to help prevent sticking.", + "While the eggs are still cold, separate the eggs, placing the whites in one bowl and the yolks in another. Cover with a lid or plastic wrap, and bring to room temperature before using (about 30 minutes).", + "Meanwhile, melt the chocolate in a microwave-safe bowl in 30 second increments, stirring well between each, until smooth. Remove from microwave and cool. (Alternately, melt the chocolate in a heatproof bowl placed over a saucepan of simmering water, stirring occasionally until smooth. Remove from heat and cool.)", + "Place the egg yolks and 1/4 cup of sugar in the bowl of a stand mixer fitted with a whisk attachment (or use a hand mixer) and beat them on medium-high speed to reach the “ribbon stage\" (about 5 minutes). See Note below.", + "Mix in the vanilla extract and scrape down the sides of the bowl. Then add the cooled, melted chocolate and beat until just combined. Set aside.", + "In a clean mixing bowl, with the whisk attachment, beat the egg whites until foamy. Add the cream of tartar and beat at medium-high speed until soft peaks form. Gradually beat in the remaining 2 tablespoons sugar until stiff peaks form. See Note below.", + "Gently fold a small amount of egg white mixture (about ¼ cup) into the chocolate egg yolk mixture using a rubber spatula or whisk. Once incorporated, fold in the remaining whites just until combined. Don’t over mix or the batter will deflate.", + "Spread the batter evenly into the prepared pan. Bake until the cake is puffed, has lost its shine, and springs back when gently pressed, about 15-17 minutes.", + "Remove from the oven and sprinkle the top generously with cocoa powder. Then cover the cake with a clean, slightly damp tea towel to keep the cake moist. Place the covered cake on a wire rack to cool to room temperature (approximately 30-45 minutes).", + "Make the Whipped Cream", + "In a clean mixing bowl fitted with a whisk attachment, beat together all the whipped cream ingredients until the cream starts to hold firm peaks. Be careful not to whip past firm peaks or the cream will curdle and look more buttery with a chunky texture.", + "Cover the filling and refrigerate until you're ready to assemble the cake.", + "Assemble the Bûche De Noël", + "Once the cake has fully cooled, remove the towel and gently spread the whipped filling over the surface of the cake.", + "The cake can be rolled in the pan it was baked in or on a flat surface. (If you remove the cake from the pan, use the excess foil like handles to lift it from the pan in one piece.) Gently roll the cake, peeling off the foil or parchment paper as you roll. Don't worry if the cake cracks a little, it’ll be covered with ganache and other decorations.", + "Trim one end of the cake at an angle and set it aside. Then place the cake, seam side down, on your serving platter. Take the reserved slice and place it on top of the cake to resemble a branch growing off the log.", + "Gently spread the ganache over the outside of the cake. Once it's completely covered, use a spatula or a fork to create waves and texture in the ganache to resemble tree bark.", + "For the best results cutting the cake, refrigerate it for 30 minutes to firm up slightly. If you are short on time the cake can be decorated and cut immediately.", + "Just before serving, finish the buche de noel with edible natural looking decorations like meringue mushrooms (see Note below), sprinkled cocoa powder or chocolate shavings, candy rocks, powdered sugar or coconut, or anything else you have on hand.", + "To get the cleanest cuts, heat a sharp knife under hot water for a few seconds, wipe the blade clean and cut the cake in 1-inch slices, wiping the blade clean between cuts.", + "If you have leftovers, remove the mushrooms and place them in an airtight container at room temperture before refrigerating the rest of the cake. Place the cake in an airtight container or wrap it with a light covering of plastic wrap. For best taste and texture, enjoy within 5 days." + ], + "category": "Dessert", + "yields": "12 servings", + "description": "This rich Flourless Chocolate Bûche De Noël has the light and airy texture of a baked chocolate mousse wrapped around a filling of freshly whipped cream. It's decorated with chocolate ganache and natural-looking, edible decorations for a beautiful presentation.", + "total_time": 27, + "cook_time": 17, + "prep_time": 10, + "cuisine": "American", + "ratings": 5.0, + "ratings_count": 2, + "nutrients": { + "servingSize": "1 serving", + "calories": "440 kcal", + "fatContent": "34 g", + "saturatedFatContent": "21 g", + "unsaturatedFatContent": "12 g", + "transFatContent": "0.1 g", + "carbohydrateContent": "27 g", + "sugarContent": "22 g", + "proteinContent": "6 g", + "sodiumContent": "48 mg", + "fiberContent": "3 g", + "cholesterolContent": "145 mg" + }, + "image": "https://www.sugarhero.com/wp-content/uploads/2024/11/flourless-chocolate-bouche-de-noel-square.jpg", + "keywords": [ + "Chocolate ganache", + "Christmas", + "flourless", + "yule log" + ] +} diff --git a/tests/test_data/sugarhero.com/sugarhero_2.testhtml b/tests/test_data/sugarhero.com/sugarhero_2.testhtml new file mode 100644 index 000000000..e1cb96aa3 --- /dev/null +++ b/tests/test_data/sugarhero.com/sugarhero_2.testhtml @@ -0,0 +1,1316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Flourless Chocolate Buche de Noel - SugarHero + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Flourless Chocolate Buche de Noel

    5

    8

    PrintJump to Recipe

    This post may contain affiliate links. As an Amazon Associate I earn from qualifying purchases. Please see my disclosure policy for more information.

    +
    + +
    +

    This rich Flourless Chocolate Bûche De Noël has the light and airy texture of a baked chocolate mousse wrapped around a filling of freshly whipped cream. It’s decorated with chocolate ganache and festive edible decorations for a beautiful presentation.

    + + + +
    Top view of a Flourless Chocolate Buche de Noel.
    +
    Want to save this recipe?
    Get this sent right to your inbox, plus great new recipes weekly!
    + + + +
    +

    🪵 A Gorgeous Yule Log Cake

    + + + +

    One dessert I look forward to baking every December is a yule log cake. Also known as a bûche de noël, this classic French delicacy traces back to the 19th century. For many families, including mine, this is a must-bake for Christmas.

    + + + +

    Traditional yule log cakes are made from a genoise cake or springy sponge rolled around a filling, and then decorated to look like yule logs. Don’t get me wrong, I love traditional bûche de noël, but I also love experimenting! In past years I’ve played with different flavors, like this Peanut Butter Cup Yule Log, and different sizes, like these no-bake, Mini Bûche de Noël.

    + + + +

    This recipe is also a bit different than a classic yule log–and dare I say, better!–because it uses a flourless chocolate cake that tastes more like a baked mousse in flavor and texture. It’s rolled around a sweetened vanilla whipped cream, and then covered with rich chocolate ganache and natural looking edible decorations like Meringue Mushrooms. Each bite is super light and airy; the cake practically melts in your mouth.

    +
    + + +
    + +

    More Christmas goodies

    + + + +

    Christmas is a time for baking well-loved family-favorites!

    + + + +

    Here are a few of my family’s most anticipated holiday treats: Oreo Fudge, Big Soft Sugar Cookies with Frosting, Cranberry Sauce Cake and Cherry Hot Chocolate!

    + +
    + +

    Table of Contents

    + + +
    +

    🧾 What You’ll Need

    + + + +
    Labeled ingredients needed to make a Flourless Chocolate Buche de Noel.
    +
    + + + +
    +

    Ingredients

    + + + +

    You’ll likely have many of the ingredients needed for this cake on hand, but you’ll want to plan ahead for the decorations. Check out these helpful tips as you gather your ingredients. (Links are affiliate links and I earn a small commission from qualifying purchases.)

    + + + +

    For the Chocolate Ganache

    + + + +
      +
    • Semi-sweet chocolate: For the best flavor, use a high-quality, flavorful semi-sweet chocolate.
    • + + + +
    • Heavy whipping cream: Gives the ganache its rich, creamy texture and flavor.
    • + + + +
    • Unsalted butter: Use room temperature butter so that it melts easily into the ganache.
    • +
    + + + +

    For the Chocolate Cake

    + + + +
      +
    • Sugar: Use granulated sugar to sweeten the cake. Take note that it will be divided and used in two separate recipe steps.
    • + + + +
    • Large eggs: Make sure you use large eggs (not medium or extra large). You’ll need to separate the eggs into whites and yolks. Check out my egg separating tutorial if you need more help with this.
    • + + + +
    • Vanilla extract: A touch of vanilla extract adds depth to the chocolate flavor.
    • + + + +
    • Semi-sweet chocolate: Use a brand you enjoy to give the cake rich flavor. Make sure to chop the semi-sweet chocolate into small pieces so that it melts more easily.
    • + + + +
    • Cream of tartar: This is a crucial ingredient when making a flourless cake. Cream of tartar helps to stabilize the whipped egg whites so they form stiff peaks. When the whipped egg whites are added to the batter and baked, they give the sheet cake its soft, airy texture.
    • + + + +
    • Cocoa powder: Although not technically an ingredient for the cake, you will need cocoa powder to help prepare the pan for baking and the cake for cooling. In both cases the cocoa powder helps to prevent the cake from sticking. You can use either natural cocoa powder or alkalized cocoa powder — both will both work.
    • +
    + + + +

    For the Whipped Cream Filling

    + + + +
      +
    • Heavy whipping cream: Keep your heavy whipping cream very cold until it’s time to whip it. This helps the cream to whip up faster and fluffier.
    • + + + +
    • Powdered sugar: Powdered sugar adds a bit of sweetness, and the cornstarch in the sugar helps to thicken the whipped cream.
    • + + + +
    • Vanilla extract: For flavor!
    • + + + +
    • Ground cinnamon: This is optional, but I like adding a touch of ground cinnamon in this recipe to make it a bit more warm and cozy.
    • +
    + + + +

    To Decorate

    + + + +
      +
    • Meringue mushrooms: Meringue Mushrooms are a very traditional yule log decoration. Head over to the my meringue mushroom recipe and tutorial to learn how to make them! They will require some advance preparation, so if you are short on time, you can use other decorations to complete your bûche de noël.
    • + + + +
    • Other natural looking decorations: Tap into your creativity to make natural looking decorations with ingredients you have available. +
        +
      • Use cocoa powder to add texture to the log or non-melting powdered sugar for the appearance of snow.
      • + + + +
      • Line the serving plate with chocolate shavings or green coconut shreds to make it look like the forest floor.
      • + + + +
      • Make leaves and berries with piped frosting or a sprig of rosemary and fresh cranberries.
      • + + + +
      • To finish the look, sprinkle chocolate rocks or other edible nature decorations around the yule log as desired.
      • +
      +
    • +
    +
    + + + +
    Sideview of a Flourless Chocolate Buche de Noel.
    + + + +
    +

    Equipment

    + + + +

    It’s important to have the right tools on hand when making something as beautiful as a French yule log cake! (Links are affiliate links and I earn a small commission from qualifying purchases.)

    + + + +
      +
    • Small saucepan: You’ll need a small saucepan to heat the cream for the ganache. This can also be useful in the chocolate melting step if you don’t have a microwave. If that’s the case, you can melt the chocolate in a heatproof bowl over a saucepan of simmering water.
    • + + + +
    • Plastic wrap: To prevent the ganache from forming a thick film as it cools, you’ll need plastic wrap to press along its surface.
    • + + + +
    • Baking sheet: It’s really important to use the correct pan size when making this cake. You need a 17×12″ (43x30cm) baking pan, at least 1″ deep. This type of pan is also known as a half sheet baking pan and is commonly used for baking cookies.
    • + + + +
    • Foil or parchment paper: I recommend using non-stick foil to line your baking sheet, or you can also use parchment paper.
    • + + + +
    • Baking spray: Sheet cakes are notorious for sticking to the pan, so I suggest spraying the foil/parchment and the edge of the baking sheet with non-stick baking spray. If possible, use a baking spray with flour already in it.
    • + + + +
    • Mixer: Although you can use a hand mixer to make this cake, it will be easier and faster if you use a stand mixer with a whisk attachment. It’s also very helpful to have a silicone spatula on hand to scrape down the sides of the bowl.
    • + + + +
    • Tea towel: While the cake cools, you’ll want to take steps to prevent it from drying out. Placing a slightly damp cotton tea towel over the cake works perfectly.
    • + + + +
    • Wire rack: To encourage faster cooling, I set my hot cake on a wire rack so that air can circulate around the entire pan.
    • +
    +
    + + + +
    Two plated slices of Flourless Chocolate Buche de Noel with the rest of the cake in the background.
    + + +
    + +

    Ready to Make This?

    + + + +
      +
    1. Get the recipe below 👇👇
    2. + + + +
    3. Scroll below the recipe for step-by-step photos
    4. + + + +
    5. Read important FAQs and more
    6. +
    + +
    + + + +
    + +

    Leave a Review!

    + + + +

    If you make this recipe, let us know! Leave a ⭐️⭐️⭐️⭐️⭐️ rating on the recipe below, and leave a comment, take a photo and tag me on Instagram @elabau, or use #sugarhero on IG!

    + +
    + +
    +
    + +
    + Save + Pin + Print +
    +
    +
    +
    A fully decorated Flourless Chocolate Buche de Noel.
    +
    +
    +

    Flourless Chocolate Bûche De Noël

    + +
    5 from 2 votes
    +
    This rich Flourless Chocolate Bûche De Noël has the light and airy texture of a baked chocolate mousse wrapped around a filling of freshly whipped cream. It's decorated with chocolate ganache and natural-looking, edible decorations for a beautiful presentation.
    +
    Prep10 minutes
    Cook17 minutes
    Total27 minutes
    Yields12 slices
    +
    +
    +
    + +

    Ingredients

    For the Chocolate Ganache

    • 10 oz semi-sweet chocolate, (1 ⅔ cups), good-quality, chopped in small pieces
    • 12 fl oz heavy cream, (1 ½ cups)
    • 2 tbsp unsalted butter, softened

    For the Chocolate Cake

    For the Whipped Cream

    To Decorate

    • Meringue mushrooms
    • Other edible nature decorations, Such as chocolate shavings, chocolate rocks, cocoa powder, powdered sugar, coconut, etc., optional
    Save this recipe!
    Get this sent right to your inbox, plus great new recipes weekly!
    +

    Instructions 

    Make the Chocolate Ganache

    • Chop the chocolate into small pieces and place it in a large bowl. Place the softened butter on top. Set aside.
    • Put the heavy cream in a saucepan over medium-high. Heat until it simmers and bubbles appear along the sides of the pan, but do not bring it to a boil.
    • Pour the hot cream over the chopped chocolate and whisk it together until the chocolate melts and the mixture is shiny and smooth.
    • Cover with cling wrap, pressing down until the plastic is touching the top of the ganche. Allow it to firm up to a spoonable consistency (like peanut butter) by setting it out for 1-2 hours at room temperature (overnight is even better).
    • Or, to firm the ganache faster, place it in the refrigerator and whisk every 15 minutes until it has a spoonable consistency. Do not leave it in the fridge too long, or it will get hard! If it accidentally gets too hard, let it rest at room temperature (or microwave briefly), then stir until the consistency is spreadable again.

    Make the Chocolate Cake

    • Preheat oven to 350°F (180°C) and place the oven rack in the center of the oven. Use a non-stick baking spray or butter to grease a 17×12-inch (43x30cm) baking pan. Line the pan with foil or parchment paper, spray it well with baking spray, and then sprinkle liberally with cocoa powder to help prevent sticking.
    • While the eggs are still cold, separate the eggs, placing the whites in one bowl and the yolks in another. Cover with a lid or plastic wrap, and bring to room temperature before using (about 30 minutes).
    • Meanwhile, melt the chocolate in a microwave-safe bowl in 30 second increments, stirring well between each, until smooth. Remove from microwave and cool. (Alternately, melt the chocolate in a heatproof bowl placed over a saucepan of simmering water, stirring occasionally until smooth. Remove from heat and cool.)
    • Place the egg yolks and 1/4 cup of sugar in the bowl of a stand mixer fitted with a whisk attachment (or use a hand mixer) and beat them on medium-high speed to reach the “ribbon stage" (about 5 minutes). See Note below.
    • Mix in the vanilla extract and scrape down the sides of the bowl. Then add the cooled, melted chocolate and beat until just combined. Set aside.
    • In a clean mixing bowl, with the whisk attachment, beat the egg whites until foamy. Add the cream of tartar and beat at medium-high speed until soft peaks form. Gradually beat in the remaining 2 tablespoons sugar until stiff peaks form. See Note below.
    • Gently fold a small amount of egg white mixture (about ¼ cup) into the chocolate egg yolk mixture using a rubber spatula or whisk. Once incorporated, fold in the remaining whites just until combined. Don’t over mix or the batter will deflate.
    • Spread the batter evenly into the prepared pan. Bake until the cake is puffed, has lost its shine, and springs back when gently pressed, about 15-17 minutes.
    • Remove from the oven and sprinkle the top generously with cocoa powder. Then cover the cake with a clean, slightly damp tea towel to keep the cake moist. Place the covered cake on a wire rack to cool to room temperature (approximately 30-45 minutes).

    Make the Whipped Cream

    • In a clean mixing bowl fitted with a whisk attachment, beat together all the whipped cream ingredients until the cream starts to hold firm peaks. Be careful not to whip past firm peaks or the cream will curdle and look more buttery with a chunky texture.
    • Cover the filling and refrigerate until you're ready to assemble the cake.

    Assemble the Bûche De Noël

    • Once the cake has fully cooled, remove the towel and gently spread the whipped filling over the surface of the cake.
    • The cake can be rolled in the pan it was baked in or on a flat surface. (If you remove the cake from the pan, use the excess foil like handles to lift it from the pan in one piece.) Gently roll the cake, peeling off the foil or parchment paper as you roll. Don't worry if the cake cracks a little, it’ll be covered with ganache and other decorations.
    • Trim one end of the cake at an angle and set it aside. Then place the cake, seam side down, on your serving platter. Take the reserved slice and place it on top of the cake to resemble a branch growing off the log.
    • Gently spread the ganache over the outside of the cake. Once it's completely covered, use a spatula or a fork to create waves and texture in the ganache to resemble tree bark.
    • For the best results cutting the cake, refrigerate it for 30 minutes to firm up slightly. If you are short on time the cake can be decorated and cut immediately.
    • Just before serving, finish the buche de noel with edible natural looking decorations like meringue mushrooms (see Note below), sprinkled cocoa powder or chocolate shavings, candy rocks, powdered sugar or coconut, or anything else you have on hand.
    • To get the cleanest cuts, heat a sharp knife under hot water for a few seconds, wipe the blade clean and cut the cake in 1-inch slices, wiping the blade clean between cuts.
    • If you have leftovers, remove the mushrooms and place them in an airtight container at room temperture before refrigerating the rest of the cake. Place the cake in an airtight container or wrap it with a light covering of plastic wrap. For best taste and texture, enjoy within 5 days.
    +
    +

    Recipe Notes

    “Ribbon stage” when beating egg yolks

    +When egg yolks and sugar are mixed together they go through a series of different stages. These stages help to identify when the mixture is ready to be used. For this cake, the mixture needs to come to the ribbon stage which means that when you raise the whisk (or beaters), the batter will fall back into the bowl in a slow ribbon that gradually reincorporates itself into the rest of the mixture. It should take about 5 minutes to reach this stage (a little longer if using a hand mixer).
    +

    Soft peaks vs. stiff peaks

    +If you are new to making meringue, you might be unfamiliar with the term “peaks”. This is a method testing how firm the egg whites are as they are whipped. When you lift the whisk or beaters from the bowl, you’ll notice some of the whites rising upward from the bowl. Soft peaks will flop over a little on top of the whisks, while stiff peaks will point upward, holding their shape like a mountain peak. This term is also used when whipping cream.
    +

    Meringue Mushrooms

    +If you want to decorate your cake the way I did, I recommend making the meringue mushrooms in advance. They are a great make-ahead decoration because, although they take almost 3 hours to make, they hold up really well at room temperature. Be aware that meringue mushrooms will begin to loose their dry, crisp texture as soon as they come in contact with the cake, so it’s extra important to wait to place them on the cake until right before serving.
    +This recipe is adapted from the Chocolate Cloud Roll in The Cake Bible by Rose Levy Beranbaum. 
    + 
    +
    +

    Measuring Tips

    +

    Our recipes are developed using weight measurements, and we highly recommend using a kitchen scale for baking whenever possible. However, if you prefer to use cups, volume measurements are provided as well. PLEASE NOTE: the adage “8 oz = 1 cup” is NOT true when speaking about weight, so don’t be concerned if the measurements don’t fit this formula.

    +

    Want to learn more about baking measurements and conversion?

    + +
    +
    +

    Nutrition

    Calories: 440kcal | Carbohydrates: 27g | Protein: 6g | Fat: 34g | Saturated Fat: 21g | Polyunsaturated Fat: 2g | Monounsaturated Fat: 10g | Trans Fat: 0.1g | Cholesterol: 145mg | Sodium: 48mg | Potassium: 297mg | Fiber: 3g | Sugar: 22g | Vitamin A: 918IU | Vitamin C: 0.3mg | Calcium: 67mg | Iron: 3mg
    +
    +
    +
    Tried this recipe?Snap a pic and hashtag it #SugarHero. We love to see your creations on our Instagram @elabau.
    + + +
    +

    📸 Photo Tutorial: How to Make A Chocolate Bûche De Noël

    + + + +

    Let’s get rolling, friends! I’ll walk you through every step of this flourless yule log cake recipe with an easy to follow photo tutorial. Full instructions are included in the recipe card above.

    +
    + + + +
    + + + + +

    Make the GAnache

    + + + +
      +
    1. Prep chocolate and butter: Chop 10 oz of chocolate into small pieces. Place it in a large bowl with 2 TBSP softened butter on top. Set aside.
    2. + + + +
    3. Heat cream: Put 1 1/2 cups (12 fl oz) heavy cream in a small saucepan over medium-high. Heat until it simmers (you’ll notice little bubbles along the sides of the pan). Do not boil.
    4. + + + +
    5. Mix chocolate and hot cream: Pour the hot cream over the chocolate and butter. Whisk until the chocolate melts and the mixture is shiny and smooth.
    6. + + + +
    7. Cover: Cover the ganache with plastic wrap, pressing down until the plastic touches the top of the chocolate.
    8. + + + +
    9. Cool. Allow the ganache to firm up to a spoonable consistency for 1-2 hours at room temperature. Or, speed up the cooling process by placing it in the refrigerator and whisking every 15 minutes until it has a spoonable consistency. Do not chill for too long in the refrigerator – you want to be able to spread it.
    10. +
    +
    + + + +
    + + + + +

    Make the Flourless Chocolate Cake

    + + + +
      +
    1. Prepare to bake: Preheat oven to 350°F (180°C) with the oven rack in the center. Line a 17×12-inch (43x30cm) baking pan with foil or parchment paper. Spray the lined pan well with baking spray, and sprinkle a thin layer of unsweetened cocoa powder on it (to prevent sticking).
    2. + + + +
    3. Separate cold eggs: Crack and separate 6 eggs into two large bowls, with the whites in one and the yolks in the other. Cover each bowl with plastic wrap, and bring to room temperature before using (about 30 minutes).
    4. + + + +
    5. Melt the chocolate: Meanwhile melt 2/3 cup (4 oz) chocolate in the microwave in 30 second increments, stirring well between each, until smooth. Remove from microwave and cool.
    6. + + + +
    7. Whip yolks and sugar to ribbon stage: Place the egg yolks and 1/4 cup of sugar in the bowl of a stand mixer fitted with a whisk attachment and beat on medium-high speed until the batter falls back into the bowl from the raised whisk in a slow ribbon (about 5 minutes).
    8. + + + +
    9. Add vanilla and cooled chocolate: Add 1 tsp vanilla extract and the cooled, melted chocolate, stirring by hand until just combined. Set aside.
    10. +
    +
    + + + +
    + + + + +
      +
    1. Whip egg whites: In a clean mixing bowl, use a whisk attachment to beat the egg whites until foamy. Add 3/4 tsp cream of tartar and beat at medium-high speed until soft peaks form. Gradually beat in the remaining 2 TBSP of sugar until stiff peaks form.
    2. + + + +
    3. Add a small amount of egg whites: Gently fold a small amount of egg whites (about 1/2 cup) into the chocolate-egg yolk mixture.
    4. +
    +
    + + + +
    + + + + +
      +
    1. Fold in remaining egg whites: Once the initial amount of egg whites is incorporated, gently fold in the remaining whites until just combined. Don’t over mix, or the batter will deflate.
    2. +
    + + + + + + + +
      +
    1. Bake: Spread the batter into the prepared pan and bake, about 15-17 minutes, until cooked through.
    2. + + + +
    3. Cool: Remove the cake from the oven and sprinkle the top generously with cocoa powder. Then cover the cake with a clean, slightly damp tea towel to keep the cake moist. Place the covered cake on a wire rack to cool to room temperature (approximately 30-45 minutes).
    4. +
    + + + +

    Make VAnilla Whipped Cream Filling

    + + + +
      +
    1. Make filling: While the cake cools, beat together 1 cup (8 fl oz) heavy cream, 1/3 cup (.75 oz) powdered sugar, 1 tsp vanilla and 1/2 tsp ground cinnamon in a clean mixing bowl until the cream starts to hold firm peaks.
    2. + + + +
    3. Chill: Cover the filling and refrigerate until you’re ready to assemble the cake.
    4. +
    +
    + + + +
    + + + + +

    Assemble the Buche de Noel

    + + + +
      +
    1. Spread the filling: Remove the towel from the cake and gently spread the whipped filling over the surface of the cake.
    2. + + + +
    3. Begin rolling: The cake can be rolled in the pan it was baked in or on a flat surface. (If you remove the cake from the pan, use the excess foil like handles to lift it from the pan in one piece.) Gently roll the cake, peeling off the foil or parchment as you roll. Don’t worry if the cake cracks a little, this is normal. Because this cake is so mousse-y and delicate, some cracking can be expected.
    4. + + + +
    5. Shape the log: Trim one end of the cake at an angle and set it aside. Then place the cake, seam side down, on your serving platter. Spread a dollop of ganache on top of the cake, then place the cut-off end on top of the cake to look like a branch.
    6. +
    +
    + + + +
    + + + + +
      +
    1. Cover with ganache: Gently spread the ganache over the outside of the cake. The ganache needs to be a soft, spreadable texture, or else it will tear the cake. If your ganache is too cold, microwave it in 5-second increments just until it’s soft, like peanut butter. Once it’s completely covered, use a for or toothpick to create waves and texture in the ganache to resemble tree bark.
    2. + + + +
    3. Refrigerate: If you’ve got time, refrigerate the cake for 30 minutes to firm it up slightly. If you’re in a rush, the cake can be decorated and served immediately, but it’ll be messier to cut and serve.
    4. +
    +
    + + + +
    + + + + +
      +
    1. Decorate the cake: Just before serving, finish the buche de noel with edible nature decorations like meringue mushrooms, cocoa powder or chocolate shavings, candy rocks, powdered sugar, coconut, frosting or anything else that catches your eye.
    2. + + + +
    3. Serve and enjoy!
    4. +
    +
    + + + +
    Topview of a Flourless Chocolate Buche de Noel.
    + + + +
    +

    💡 Tips and FAQs for Success

    + + + +

    Avoid common mistakes and learn how to make this Bûche de Noël like a pro! Here’s everything you need to know to be successful.

    + + + +
    How to quickly cool down ganache

    If you are in a hurry and need to speed up the cooling process for the ganache, you can place it in the refrigerator and whisk every 15 minutes until it has a spoonable consistency. You need to be vigilant about stirring it and watching that the texture doesn’t start to get too hard. If you accidentally leave it in the fridge too long, let it rest at room temperature (or microwave briefly) to make it spreadable again.

    What will happen if I accidentally boil the cream?

    To make the smoothest, creamiest ganache the cream needs to be hot enough to melt the chocolate and butter but cool enough it doesn’t overheat the chocolate. When chocolate is overheated it will seize (become lumpy and grainy). The temperature of boiling the cream is too hot for chocolate and will ruin the texture of the ganache. If you accidentally overheat the cream, let it cool slightly before pouring it over the chocolate and butter.

    What is the Ribbon stage?

    If you’ve never heard the term before, you’ve come to the right place! When egg yolks and sugar are mixed together they go through a series of different stages. These stages help to identify when the mixture is ready to be used. For this cake, the mixture needs to come to the ribbon stage which means that when you raise the whisk (or beaters), the batter will fall back into the bowl in a slow ribbon that gradually reincorporates itself into the rest of the mixture. It should take about 5 minutes to reach this stage (a little longer if using a hand mixer).

    How will I know the cake is done baking?

    You’ll know your sheet cake is ready when it looks puffed, has lost its shine, and springs back when gently pressed. For the best taste and texture, don’t overbake the cake.

    What are soft and stiff peaks?

    Learning to recognize the various stages cream goes through as it is whipped is important for any baker. In this recipe you’ll be watching for soft and stiff/firm peaks. You can test for both of these stages by raising the whisk or beaters out of the cream. As the attachment leaves the mixture the cream should extend upward like little mountain peaks. Soft peaks will flop over on top and slowly sink back into the mixture, whereas stiff peaks will be pointy and hold their shape well. Be careful not to whip past firm peaks or the cream will begin to curdle, look more buttery and take on a chunky texture. If you accidentally whip the cream too much, it will still taste fine but the texture won’t be as smooth as it should be. It also might be a little harder to smooth into an even layer over the cake.

    How to remove the cake from the pan

    If you want to remove the cake from the pan before rolling it, here’s an easy trick to try. When you prep the baking pan, leave a little excess foil to fold around the edges. You can unroll the excess foil and use it like handles to gently and quickly move the cake from the pan to a flat surface.

    How to get clean cut slices

    There are a few things you can do to make clean cut slices of cake. My first recommendation is to give yourself enough time to refrigerate the cake for 30 minutes before adding the decorations. This brief chilling period firms up the layers of the cake, making them easier to cut. The next thing you’ll want to do is use a sharp knife to cut the cake. Run the knife under hot water for a few seconds, wipe it dry and then begin cutting the cake in 1-inch slices, reheating the blade under hot water and cleaning the blade off between slices as needed. Viola!

    Storage Information

    If you have leftovers, remove the mushrooms and place them in an airtight container at room temperture before refrigerating the rest of the cake. Place the cake in an airtight container or wrap it with a light covering of plastic wrap. For best taste and texture, enjoy within 5 days.

    +
    + + + +
    A bite of a slice of Flourless Chocolate Buche de Noel on a fork.
    + + + +
    +

    💭 Variations

    + + + +

    Want to change things up a little? Here’s some ideas to get you started.

    + + + +
      +
    • Flavoring: The filling is flavored with vanilla extract and a little ground cinnamon. Feel free to swap the vanilla for another flavor like almond, orange, or peppermint. Likewise, you can leave out the cinnamon.
    • + + + +
    • Chang the filling: Try using a different filling like peanut butter or raspberry. Or, add a 1/4 cup of cocoa powder to the filling to make it chocolatey!
    • + + + +
    • Toppings: In addition to the filling, you can add a layer of jam or preserves like Blueberry Sauce, Strawberry Sauce or Cranberry Orange Sauce. It would also be delicious to sprinkle the filling with a light layer of toasted chopped nuts or fresh berries.
    • + + + +
    • Decorations: If you are short on time or just don’t want to decorate, it’s totally fine to skip all the extra natural looking decorations.
    • +
    +
    + + + + + +
    + + + + +
    Two photo collage of Flourless Chocolate Buche de Noel with text overlay for Pinterest.
    +
    + +
    + + +
    + + + + +

    Meet Elizabeth!

    Hi, I’m Elizabeth — a trained pastry chef, cookbook author, video instructor, and your new Baking BFF! I’m going to teach you everything you need to know to be a sugar hero. ❤️

    +
    + +
    + +

    Related Recipes

    + +
    +
    +
    +
    + 5 from 2 votes (1 rating without comment) +
    +
    +
    +

    Leave a comment

    Your email address will not be published. Required fields are marked *

    + +
    + Rate This Recipe! +




    +
    +
    +

    + +

    + +

    +

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    8 Comments

    1. + +
    2. +
    3. +
      + + +
      +
      + +
      +

      That's an extremely pretty buche de noel. Definitely one of the very nicest I've seen. And your meringue mushrooms look perfect, despite the challenge they presented what with the stormy weather! I like your t-shirt, too–very cute!

      +
      + +
      +
    4. +
    5. + +
    6. +
    7. +
      + + +
      +

      Definitely early! I never got around to making fruit cake for Christmas, so I'm going to bake some in January instead 🙂 Love the log and the mushrooms. Happy New Year!

      +
      + +
      +
    8. +
    9. + +
    10. +
    11. +
      + + +
      +

      That looks gorgeous! i think we're in the same time warp, because I did most of my Christmas baking after the big day, and still have more I want to do.

      +
      + +
      +
    12. +
    13. +
      + + +
      +

      Oh my gosh, the shirt rocks! I think you/he should start mass producing them!
      Love the buche!

      +
      + +
      +
    14. +
    15. +
      + + +
      +

      What a great gift!! Super sweet, and totally awesome!
      The yule log looks great, and the inside sounds really interesting. I've got to wait almost a year to try it 🙁

      +
      + +
      +
    16. +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ab46afee00566076d8c0284744416dcfd5fc14e4 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:27:36 -0500 Subject: [PATCH 66/94] Update FoodRepublic (#1444) * refactor time * Update foodrepublic.py * update html --- recipe_scrapers/foodrepublic.py | 34 +- .../foodrepublic.com/foodrepublic.json | 6 +- .../foodrepublic.com/foodrepublic.testhtml | 680 ++++++++---------- 3 files changed, 308 insertions(+), 412 deletions(-) diff --git a/recipe_scrapers/foodrepublic.py b/recipe_scrapers/foodrepublic.py index 095e6307e..ed430b85a 100644 --- a/recipe_scrapers/foodrepublic.py +++ b/recipe_scrapers/foodrepublic.py @@ -1,5 +1,5 @@ from ._abstract import AbstractScraper -from ._utils import get_yields, normalize_string +from ._utils import get_yields class FoodRepublic(AbstractScraper): @@ -7,27 +7,6 @@ class FoodRepublic(AbstractScraper): def host(cls): return "foodrepublic.com" - def title(self): - title_div = self.soup.find("div", {"class": "recipe-card-title"}) - return title_div.get_text() - - def total_time(self): - prep_time_div = self.soup.find("div", {"class": "recipe-card-prep-time"}) - cook_time_div = self.soup.find("div", {"class": "recipe-card-cook-time"}) - - prep_time = ( - int(prep_time_div.find("div", {"class": "recipe-card-amount"}).text) - if prep_time_div - else 0 - ) - cook_time = ( - int(cook_time_div.find("div", {"class": "recipe-card-amount"}).text) - if cook_time_div - else 0 - ) - - return prep_time + cook_time - def yields(self): servings_div = self.soup.find("div", {"class": "recipe-card-servings"}) servings_amount = ( @@ -36,14 +15,3 @@ def yields(self): else "0" ) return get_yields(servings_amount) - - def ingredients(self): - ingredients = self.soup.select("ul.recipe-ingredients li") - - return [normalize_string(ingredient.get_text()) for ingredient in ingredients] - - def instructions(self): - instruction_list = self.soup.find("ol", {"class": "recipe-directions"}) - instructions = instruction_list.findAll("li") if instruction_list else [] - - return "\n".join([instruction.get_text() for instruction in instructions]) diff --git a/tests/test_data/foodrepublic.com/foodrepublic.json b/tests/test_data/foodrepublic.com/foodrepublic.json index 424abf7c7..42ab880ea 100644 --- a/tests/test_data/foodrepublic.com/foodrepublic.json +++ b/tests/test_data/foodrepublic.com/foodrepublic.json @@ -1,4 +1,5 @@ { + "author": "Michael's Restaurant", "canonical_url": "https://www.foodrepublic.com/recipes/dutch-white-asparagus-recipe/", "site_name": "Food Republic", "host": "foodrepublic.com", @@ -27,7 +28,10 @@ "Goat Cheese And Asparagus Macaroni Salad Recipe", "Roasted Asparagus & Scrambled Eggs Recipe" ], - "yields": "0 servings", + "yields": "4 servings", "total_time": 60, + "cook_time": 40, + "prep_time": 20, + "cuisine": "Dutch", "image": "https://www.foodrepublic.com/img/gallery/dutch-white-asparagus-recipe/intro-import.jpg" } diff --git a/tests/test_data/foodrepublic.com/foodrepublic.testhtml b/tests/test_data/foodrepublic.com/foodrepublic.testhtml index 33a44a70e..15543f4dd 100644 --- a/tests/test_data/foodrepublic.com/foodrepublic.testhtml +++ b/tests/test_data/foodrepublic.com/foodrepublic.testhtml @@ -1,32 +1,56 @@ - - - - - + + + + + + + + + + + + + - Dutch White Asparagus Recipe - Food Republic - - - - + Dutch White Asparagus Recipe + + + + - - + + + + - - - + + @@ -34,14 +58,13 @@ + + + + + - - - - - - - - +
- +
@@ -124,7 +156,7 @@ Food Republic
- + - - + + + - + + + + + + +
- +
-
-
-
-
-
- - - -
-

Dutch White Asparagus Recipe

-
- - - - - -
-

+

+
+
+ + +
+ + + +
+

Dutch White Asparagus Recipe

+
+ +
+ + +
+

One of the great things about spring menus is all the tender, fresh green vegetable dishes. Longstanding Midtown dining spot Michael's New York, owned by restaurateur Michael McCarty, boasts a Dutch recipe we had to try: citrus-steamed Dutch white asparagus (they actually do a mix of white and green) with a wine-spiked butter sauce, a runny poached egg and a little Parmesan cheese. A little prosciutto never hurt anyone, either.

- -

- -
-
- -
- -
-
-
- Dutch White Asparagus Recipe
- -
-
-
Prep Time
-
20
-
minutes
-
-
-
Cook Time
-
40
-
minutes
-
-
-
Servings
-
0
-
servings
-
-
- -
-
-
-
- -
- Ingredients -
-
    -
  • 12 spears Dutch white asparagus
  • -
  • 1/2 each Meyer lemon
  • -
  • 2 cups water
  • -
  • 1 cup grated Parmesan cheese
  • -
  • 1/2 cup Chardonnay
  • -
  • 1/2 cup white wine vinegar
  • -
  • 2 sprigs fresh thyme
  • -
  • 1/2 cup shallots
  • -
  • small chunk of Parmesan rind
  • -
  • 4 tablespoons unsalted butter
  • -
  • 4 fresh eggs
  • -
  • 4 slices prosciutto
  • -
-
- Directions -
-
    -
  1. After peeling and trimming the asparagus, steam it in citrus water — water with Meyer lemon, orange and grapefruit slices — until fork tender.
  2. -
  3. In a pot add the Chardonnay, white wine vinegar, thyme, shallots and chunk of Parmesan rind; reduce about a quarter.
  4. -
  5. Remove from heat and slowly whisk in cubes of butter until sauce is thick and glossy.
  6. -
  7. Pour 2 tablespoons of beurre blanc on a plate, top it with a poached egg, steamed white asparagus, prosciutto and grated Parmesan.
  8. -
  9. Spring Asparagus Soup Recipe
  10. -
  11. Goat Cheese And Asparagus Macaroni Salad Recipe
  12. -
  13. Roasted Asparagus & Scrambled Eggs Recipe
  14. -
-
- Rate this recipe -
-
-
-
-
-
-
- - -
- - -
- - -
-
-
- - - -
+
+
+
+ +
+
+
Dutch White Asparagus Recipe
+ +
+
+
Prep Time
+
20
+
minutes
+
+
+
Cook Time
+
40
+
minutes
+
+
+
Servings
+
4
+
+
+
+ Dutch White Asparagus Recipe +
+
Total time: 1 hour
+
+
+
+
+
+
Ingredients
+
    +
  • 12 spears Dutch white asparagus
  • +
  • 1/2 each Meyer lemon
  • +
  • 2 cups water
  • +
  • 1 cup grated Parmesan cheese
  • +
  • 1/2 cup Chardonnay
  • +
  • 1/2 cup white wine vinegar
  • +
  • 2 sprigs fresh thyme
  • +
  • 1/2 cup shallots
  • +
  • small chunk of Parmesan rind
  • +
  • 4 tablespoons unsalted butter
  • +
  • 4 fresh eggs
  • +
  • 4 slices prosciutto
  • +
+ +
Directions
+
    +
  1. After peeling and trimming the asparagus, steam it in citrus water — water with Meyer lemon, orange and grapefruit slices — until fork tender.
  2. +
  3. In a pot add the Chardonnay, white wine vinegar, thyme, shallots and chunk of Parmesan rind; reduce about a quarter.
  4. +
  5. Remove from heat and slowly whisk in cubes of butter until sauce is thick and glossy.
  6. +
  7. Pour 2 tablespoons of beurre blanc on a plate, top it with a poached egg, steamed white asparagus, prosciutto and grated Parmesan.
  8. +
  9. Spring Asparagus Soup Recipe
  10. +
  11. Goat Cheese And Asparagus Macaroni Salad Recipe
  12. +
  13. Roasted Asparagus & Scrambled Eggs Recipe
  14. +
+ +
+ +
+
+
+ +
+
+ - -
-
- -
- -
-
- + +
+ +
+ + + + + + +
+
+ - - - + - - - + + - + \ No newline at end of file From 3f8bff4a897abcbae3f41edeb967769413892634 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:27:49 -0500 Subject: [PATCH 67/94] Refactor time handling for JulieGoodwin (#1443) * time refactor * naming --- recipe_scrapers/juliegoodwin.py | 34 +++++++++++-------- .../juliegoodwin.com.au/juliegoodwin_1.json | 2 ++ .../juliegoodwin.com.au/juliegoodwin_2.json | 2 ++ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/recipe_scrapers/juliegoodwin.py b/recipe_scrapers/juliegoodwin.py index 12553fd76..7bcbafe98 100644 --- a/recipe_scrapers/juliegoodwin.py +++ b/recipe_scrapers/juliegoodwin.py @@ -16,23 +16,29 @@ def author(self): def title(self): return normalize_string(self.soup.find("h1").get_text()) - def process_total_time(self, container): - if container: - prep_hours_match = re.search( - r"(\d+) hour", container.next_element.get_text() + def extract_time(self, keyword): + minutes = 0 + time_elements = self.soup.find_all(["h4", "h3"]) + for element in time_elements: + text = element.get_text(strip=True) + match = re.search( + rf"{keyword}\s*[\|=]?\s*(\d+)\s*(min|mins|minutes)", text, re.IGNORECASE ) - if prep_hours_match: - return 60 * int(prep_hours_match.group(1)) - prep_mins_match = re.search(r"(\d+) min", container.next_element.get_text()) - if prep_mins_match: - return int(prep_mins_match.group(1)) + if match: + minutes += int(match.group(1)) + return get_minutes(minutes) + + def prep_time(self): + return self.extract_time("Prep time") or 0 + + def cook_time(self): + return self.extract_time("Cooking time") or 0 def total_time(self): - prep = self.soup.find(string=re.compile("Prep time")) - mins = self.process_total_time(prep) - cooking = self.soup.find(string=re.compile("Cooking time")) - mins += self.process_total_time(cooking) - return get_minutes(mins) + prep_time = self.prep_time() + cook_time = self.cook_time() + total_mins = prep_time + cook_time + return total_mins def yields(self): container = self.soup.find("i", attrs={"class", "fa-cutlery"}) diff --git a/tests/test_data/juliegoodwin.com.au/juliegoodwin_1.json b/tests/test_data/juliegoodwin.com.au/juliegoodwin_1.json index 657075071..7e60c4063 100644 --- a/tests/test_data/juliegoodwin.com.au/juliegoodwin_1.json +++ b/tests/test_data/juliegoodwin.com.au/juliegoodwin_1.json @@ -22,5 +22,7 @@ ], "yields": "Makes 1 Slice = 12 Pieces", "total_time": 45, + "cook_time": 35, + "prep_time": 10, "image": "https://juliegoodwin.com.au/wordpress/wp-content/uploads/2016/03/slice.jpg" } diff --git a/tests/test_data/juliegoodwin.com.au/juliegoodwin_2.json b/tests/test_data/juliegoodwin.com.au/juliegoodwin_2.json index cfcdbf7ad..9233d2792 100644 --- a/tests/test_data/juliegoodwin.com.au/juliegoodwin_2.json +++ b/tests/test_data/juliegoodwin.com.au/juliegoodwin_2.json @@ -31,5 +31,7 @@ ], "yields": "Serves 6", "total_time": 35, + "cook_time": 20, + "prep_time": 15, "image": "https://juliegoodwin.com.au/wordpress/wp-content/uploads/2015/09/800-butter-chicken-2.jpg" } From e45440324a57ed55ec373aa725431d347a05a967 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:28:04 -0500 Subject: [PATCH 68/94] Refactor (#1445) --- recipe_scrapers/nhshealthierfamilies.py | 52 +-- .../nhs.uk/nhshealthierfamilies_1.json | 7 +- .../nhs.uk/nhshealthierfamilies_1.testhtml | 351 ++++++++--------- .../nhs.uk/nhshealthierfamilies_2.json | 7 +- .../nhs.uk/nhshealthierfamilies_2.testhtml | 353 +++++++++--------- 5 files changed, 375 insertions(+), 395 deletions(-) diff --git a/recipe_scrapers/nhshealthierfamilies.py b/recipe_scrapers/nhshealthierfamilies.py index 300a9d4c5..daaea329b 100644 --- a/recipe_scrapers/nhshealthierfamilies.py +++ b/recipe_scrapers/nhshealthierfamilies.py @@ -19,48 +19,28 @@ def title(self): title = title[:-7] return title - def _get_recipe_metadata(self): + def _get_recipe_content(self): container = self.soup.find("div", {"class": "bh-recipe__description"}) descriptions = container.findAll("p") - content = "".join([description.get_text() for description in descriptions]) + return "".join([description.get_text() for description in descriptions]) + + def prep_time(self): + content = self._get_recipe_content() prep_time = re.search(r"Prep: (\d+) mins", content) + return get_minutes(prep_time.group(0)) if prep_time else 0 + + def cook_time(self): + content = self._get_recipe_content() cook_time = re.search(r"Cook: (\d+) mins", content) - recipe_yields = re.search(r"Serves (\d+)", content) - return { - "prep_time": get_minutes(prep_time.group(0)) if prep_time else None, - "cook_time": get_minutes(cook_time.group(0)) if cook_time else None, - "yields": get_yields(recipe_yields.group(0)) if recipe_yields else None, - } + return get_minutes(cook_time.group(0)) if cook_time else 0 def total_time(self): - metadata = self._get_recipe_metadata() - return metadata["prep_time"] + metadata["cook_time"] + return self.prep_time() + self.cook_time() def yields(self): - metadata = self._get_recipe_metadata() - return metadata["yields"] - - def image(self): - return self.soup.find("img", {"class": "nhsuk-image__img"})["src"] - - def ingredients(self): - ingredients = [] - instructions_div = self.soup.find("div", {"class": "bh-recipe-instructions"}) - ul = instructions_div.find("ul") - - if ul: - for li in ul.findAll("li"): - ingredients.append(normalize_string(li.get_text())) - - # Stop when encountering an 'ol' element which is where instructions are stored. - for sibling in ul.find_next_siblings(): - if sibling.name == "ol": - break - if sibling.name == "ul": - for li in sibling.findAll("li"): - ingredients.append(normalize_string(li.get_text())) - - return ingredients + content = self._get_recipe_content() + recipe_yields = re.search(r"Serves (\d+)", content) + return get_yields(recipe_yields.group(0)) if recipe_yields else None def ingredient_groups(self): return group_ingredients( @@ -82,7 +62,3 @@ def instructions(self): return "\n".join( [normalize_string(instruction) for instruction in instructions] ) - - def description(self): - description_meta = self.soup.find("meta", {"name": "description"}) - return normalize_string(description_meta["content"]) diff --git a/tests/test_data/nhs.uk/nhshealthierfamilies_1.json b/tests/test_data/nhs.uk/nhshealthierfamilies_1.json index 5213e4e12..99a1944ff 100644 --- a/tests/test_data/nhs.uk/nhshealthierfamilies_1.json +++ b/tests/test_data/nhs.uk/nhshealthierfamilies_1.json @@ -26,9 +26,10 @@ "Meanwhile, cook the rice according to pack instructions.", "Season the chilli with pepper and serve with the boiled rice." ], - "category": null, "yields": "4 servings", - "description": "This classic chilli is packed with flavour. It also freezes well, so is perfect for batch-cooking.", + "description": "This classic chilli is packed with flavour. It also freezes well, so is perfect to batch-cook.", "total_time": 35, - "image": "https://assets.nhs.uk/campaigns-cms-prod/images/Chilli-con-carne_x7m8d91.width-320.jpg" + "cook_time": 25, + "prep_time": 10, + "image": "https://digitalcampaignsstorage.blob.core.windows.net/campaigns-cms-prod/images/Chilli-con-carne_x7m8d91.width-320.jpg" } diff --git a/tests/test_data/nhs.uk/nhshealthierfamilies_1.testhtml b/tests/test_data/nhs.uk/nhshealthierfamilies_1.testhtml index ae6efa5ae..debae96c2 100644 --- a/tests/test_data/nhs.uk/nhshealthierfamilies_1.testhtml +++ b/tests/test_data/nhs.uk/nhshealthierfamilies_1.testhtml @@ -6,7 +6,6 @@ - @@ -22,18 +21,18 @@ Easy Chilli Con Carne - Recipes - Healthier Families - NHS - + + + - - - - - + + + @@ -53,18 +52,18 @@ + + - - - + - + @@ -75,6 +74,8 @@ + + @@ -107,23 +108,23 @@ window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); - + gtag('config', 'G-1K4S0MRD2T'); - + - + Skip to main content - - + + @@ -149,114 +150,114 @@ + - - + + + + - - - - - - + + + - +
- - - - - - + + + + + +
- +
- - + +
- - - + + + @@ -273,8 +274,8 @@

Chilli con carne recipe

This classic chilli is packed with flavour. It also freezes well, so is perfect to batch-cook.

Prep: 10 mins
Cook: 25 mins
Serves 4

- - + +
@@ -282,34 +283,34 @@
- - + +

Per serving:

  • 2,042kJ / 488kcals
  • 30g protein
  • 5g fat, of which 1.5g saturates
  • 82g carbohydrate, of which 12g sugars
  • 7g fibre
  • 0.9g salt
- - + +
- +
Chilli made with beef, mushrooms, peppers and kidney beans served with rice @@ -320,58 +321,58 @@
- +

Ingredients

  • 300g extra-lean minced beef
  • 1 large onion, finely chopped
  • 2 garlic cloves, finely chopped
  • 400g chopped tomatoes
  • 2 tablespoons tomato purée
  • 2 teaspoons chilli powder
  • 1 teaspoon ground cumin
  • 1 red pepper, deseeded and chopped
  • 2 handfuls of cup or button mushrooms, sliced
  • 410g red kidney beans, drained
  • 150ml reduced-salt vegetable or chicken stock
  • 300g easy-cook white or brown rice
  • 1 pinch ground black pepper
- +

Method

    - - + +
  1. - +

    Heat a large saucepan and add the minced beef, a handful at a time, cooking it until browned. Add the onion and garlic, then cook for another 2 to 3 minutes.

    - +
    Information:

    Turkey mince also makes an excellent chilli – and it's lower in fat too. If you want to keep things vegetarian, substitute the minced beef with vegetarian mince, or try our tasty veggie chilli recipe.

    - +
  2. - - + +
  3. - +

    Add the chopped tomatoes, tomato purée, spices, red pepper, mushrooms, kidney beans and stock. Stir well, bring to the boil, then lower the heat and simmer gently for 15 to 20 minutes.

    - +
  4. - - + +
  5. - +

    Meanwhile, cook the rice according to pack instructions.

    - +
  6. - - + +
  7. - +

    Season the chilli with pepper and serve with the boiled rice.

    - +
    Information:

    Chilli makes a really versatile topping or filling, and is also great for reheating leftovers. So instead of rice, try serving with baked potatoes, topped with a spoonful of low-fat plain yoghurt and some chopped cucumber and tomatoes – or in a wholewheat wrap.

    - +
  8. - +
@@ -383,128 +384,128 @@ "@context": "https://schema.org", "@type": "Recipe", "description": "This classic chilli is packed with flavour. It also freezes well, so is perfect to batch-cook.", - "image": "https://assets.nhs.uk/campaigns-cms-prod/images/Chilli-con-carne_x7m8d91.width-320.jpg", + "image": "https://digitalcampaignsstorage.blob.core.windows.net/campaigns-cms-prod/images/Chilli-con-carne_x7m8d91.width-320.jpg", "recipeIngredient": ["300g extra-lean minced beef", "1 large onion, finely chopped", "2 garlic cloves, finely chopped", "400g chopped tomatoes", "2 tablespoons tomato pur\u00e9e", "2 teaspoons chilli powder", "1 teaspoon ground cumin", "1 red pepper, deseeded and chopped", "2 handfuls of cup or button mushrooms, sliced", "410g red kidney beans, drained", "150ml reduced-salt vegetable or chicken stock", "300g easy-cook white or brown rice", "1 pinch ground black pepper"], "name": "Chilli con carne recipe", "recipeInstructions": "Heat a large saucepan and add the minced beef, a handful at a time, cooking it until browned. Add the onion and garlic, then cook for another 2 to 3 minutes.Add the chopped tomatoes, tomato purée, spices, red pepper, mushrooms, kidney beans and stock. Stir well, bring to the boil, then lower the heat and simmer gently for 15 to 20 minutes.Meanwhile, cook the rice according to pack instructions.Season the chilli with pepper and serve with the boiled rice." } - - + +
- +
- - + +
- - + +
- +
- - + +
- - - + + + @@ -518,61 +519,61 @@
- +

- + Sign up for Healthy Steps emails - +

- - + +

Want the recipe for a healthier family? Join today and over 8 weeks you'll get easy tips from nutrition experts and parents, healthy swaps and tasty recipes on a budget.

- +
- - + +
- +
- - - + + +
- + + - - - - + + + diff --git a/tests/test_data/nhs.uk/nhshealthierfamilies_2.json b/tests/test_data/nhs.uk/nhshealthierfamilies_2.json index 74c8b6379..9313f11e6 100644 --- a/tests/test_data/nhs.uk/nhshealthierfamilies_2.json +++ b/tests/test_data/nhs.uk/nhshealthierfamilies_2.json @@ -39,9 +39,10 @@ "Meanwhile, sprinkle the breadcrumbs onto a large plate. Season with a little pepper. Dip each fish fillet in the beaten egg, then coat in the breadcrumbs. Place on the baking sheet, then transfer to the oven when you turn the potatoes, so that it cooks for 15 to 20 minutes. To check that the fish is cooked, it should flake easily when tested with a fork.", "Heat the mushy peas in a saucepan, then serve with the fish and chips." ], - "category": null, "yields": "4 servings", - "description": "Try our recipe for healthier, homemade fish and chips! Click to read the ingredients and a step-by-step guide to making it", + "description": "Make your own healthier version of fish and chips at home!", "total_time": 50, - "image": "https://assets.nhs.uk/campaigns-cms-prod/images/Recipes-square-healthy-fish-and-chips.width-320.jpg" + "cook_time": 40, + "prep_time": 10, + "image": "https://digitalcampaignsstorage.blob.core.windows.net/campaigns-cms-prod/images/Recipes-square-healthy-fish-and-chips.width-320.jpg" } diff --git a/tests/test_data/nhs.uk/nhshealthierfamilies_2.testhtml b/tests/test_data/nhs.uk/nhshealthierfamilies_2.testhtml index 946d1a8c0..448b212f4 100644 --- a/tests/test_data/nhs.uk/nhshealthierfamilies_2.testhtml +++ b/tests/test_data/nhs.uk/nhshealthierfamilies_2.testhtml @@ -6,7 +6,6 @@ - @@ -22,18 +21,18 @@ Healthy homemade fish and chips - Recipes - Healthier Families - NHS - + + + - - - - - + + + @@ -53,18 +52,18 @@ + + - - - + - + @@ -75,6 +74,8 @@ + + @@ -107,23 +108,23 @@ window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); - + gtag('config', 'G-1K4S0MRD2T'); - + - + Skip to main content - - + + @@ -149,114 +150,114 @@ + - - + + + + - - - - - - + + + - +
- - - - - - + + + + + +
- +
- - + +
- - - + + + @@ -273,8 +274,8 @@

Good old fish and chips recipe

Make your own healthier version of fish and chips at home!

Prep: 10 mins
Cook: 40 mins
Serves 4

- - + +
@@ -282,34 +283,34 @@
- - + +

Per serving:

  • 1,682kJ / 402kcal
  • 34g protein
  • 56g carbohydrate of which 3g sugars
  • 6g fat of which 1g saturates
  • 4g fibre
  • 1g salt
- - + +
- +
Homebaked chips and fillets of fish with breadcrumbs @@ -320,58 +321,58 @@
- -

Ingredients

  • 4 potatoes, scrubbed, each cut into 8 wedges
  • 1 tablespoon vegetable oil
  • 75g dried white or wholemeal breadcrumbs
  • 1 egg, beaten with 2 tbsp cold water
  • 4 fillets skinless white fish, like haddock, cod or pollock

Swappable or optional

  • 300g mushy peas
  • 1 pinch ground black pepper (optional)

Swap tip

You can use any frozen, fresh or canned peas if you don't have mushy ones.

- + +

Ingredients

  • 4 potatoes, scrubbed, each cut into 8 wedges
  • 1 tablespoon vegetable oil
  • 75g dried white or wholemeal breadcrumbs
  • 1 egg, beaten with 2 tbsp cold water
  • 4 fillets skinless white fish, like haddock, cod or pollock

Swappable or optional

  • 300g mushy peas
  • 1 pinch ground black pepper (optional)

Swap tip

You can use any frozen, fresh or canned peas if you don't have mushy ones.

+

Method

    - - + +
  1. - +

    Preheat the oven to 200C (fan 180C, gas mark 6). Lightly grease a baking sheet with a little vegetable oil.

    - +
  2. - - + +
  3. - +

    Put the potato wedges into a roasting tin. Add the remaining vegetable oil and toss to coat. Season with black pepper. Transfer to the oven to bake for 35 to 40 minutes, turning them over after 20 minutes.

    - +
    Information:

    Not peeling the potatoes means you get more fibre in your diet – and they're quicker to prepare.

    - +
  4. - - + +
  5. - +

    Meanwhile, sprinkle the breadcrumbs onto a large plate. Season with a little pepper. Dip each fish fillet in the beaten egg, then coat in the breadcrumbs. Place on the baking sheet, then transfer to the oven when you turn the potatoes, so that it cooks for 15 to 20 minutes. To check that the fish is cooked, it should flake easily when tested with a fork.

    - +
    Information:

    Look out for dried breadcrumbs flavoured with lemon or spices to add extra flavour to the fish, or add some finely grated lemon zest or a pinch of paprika to plain dried breadcrumbs.

    - +
  6. - - + +
  7. - +

    Heat the mushy peas in a saucepan, then serve with the fish and chips.

    - +
  8. - +
@@ -383,128 +384,128 @@ "@context": "https://schema.org", "@type": "Recipe", "description": "Make your own healthier version of fish and chips at home!", - "image": "https://assets.nhs.uk/campaigns-cms-prod/images/Recipes-square-healthy-fish-and-chips.width-320.jpg", + "image": "https://digitalcampaignsstorage.blob.core.windows.net/campaigns-cms-prod/images/Recipes-square-healthy-fish-and-chips.width-320.jpg", "recipeIngredient": ["4 potatoes, scrubbed, each cut into 8 wedges", "1 tablespoon vegetable oil", "75g dried white or wholemeal breadcrumbs", "1 egg, beaten with 2 tbsp cold water", "4 fillets skinless white fish, like haddock, cod or pollock", "300g mushy peas", "1 pinch\u00a0ground black pepper (optional)"], "name": "Good old fish and chips recipe", "recipeInstructions": "Preheat the oven to 200C (fan 180C, gas mark 6). Lightly grease a baking sheet with a little vegetable oil.Put the potato wedges into a roasting tin. Add the remaining vegetable oil and toss to coat. Season with black pepper. Transfer to the oven to bake for 35 to 40 minutes, turning them over after 20 minutes.Meanwhile, sprinkle the breadcrumbs onto a large plate. Season with a little pepper. Dip each fish fillet in the beaten egg, then coat in the breadcrumbs. Place on the baking sheet, then transfer to the oven when you turn the potatoes, so that it cooks for 15 to 20 minutes. To check that the fish is cooked, it should flake easily when tested with a fork.Heat the mushy peas in a saucepan, then serve with the fish and chips." } - - + +
- +
- - + +
- - + +
- +
- - + +
- - - + + + @@ -518,61 +519,61 @@
- +

- + Sign up for Healthy Steps emails - +

- - + +

Want the recipe for a healthier family? Join today and over 8 weeks you'll get easy tips from nutrition experts and parents, healthy swaps and tasty recipes on a budget.

- +
- - + +
- +
- - - + + +
- + + - - - - + + + From c6fd5ad4f43963c278ec9c51803d924ccf586e33 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:29:33 -0500 Subject: [PATCH 69/94] Fix additional details extraction in ATK scraper (#1320) * implement sudobash1's recommended fix * updated test data * cookscountry * cooksillustrated * rename * Test case for old format * Add fallback for old format w/ comments --- recipe_scrapers/americastestkitchen.py | 9 +- .../americastestkitchen.testhtml | 3705 --------- ...itchen.json => americastestkitchen_1.json} | 31 +- .../americastestkitchen_1.testhtml | 3832 ++++++++++ .../americastestkitchen_2.json | 107 + .../americastestkitchen_2.testhtml | 3832 ++++++++++ .../cookscountry.com/cookscountry.json | 2 +- .../cookscountry.com/cookscountry.testhtml | 6665 +++++++++-------- .../cooksillustrated.json | 4 +- .../cooksillustrated.testhtml | 6662 ++++++++-------- 10 files changed, 14595 insertions(+), 10254 deletions(-) delete mode 100644 tests/test_data/americastestkitchen.com/americastestkitchen.testhtml rename tests/test_data/americastestkitchen.com/{americastestkitchen.json => americastestkitchen_1.json} (83%) create mode 100644 tests/test_data/americastestkitchen.com/americastestkitchen_1.testhtml create mode 100644 tests/test_data/americastestkitchen.com/americastestkitchen_2.json create mode 100644 tests/test_data/americastestkitchen.com/americastestkitchen_2.testhtml diff --git a/recipe_scrapers/americastestkitchen.py b/recipe_scrapers/americastestkitchen.py index 589b9c952..a2ec71852 100644 --- a/recipe_scrapers/americastestkitchen.py +++ b/recipe_scrapers/americastestkitchen.py @@ -71,5 +71,10 @@ def _parse_ingredient_item(ingredient_item): @functools.cached_property def _get_additional_details(self): j = json.loads(self.soup.find(type="application/json").string) - name = list(j["props"]["initialState"]["content"]["documents"])[0] - return j["props"]["initialState"]["content"]["documents"][name] + # Handling for new page format + if "pageProps" in j["props"]: + return j["props"]["pageProps"]["data"] + else: + # Handling for old page format + name = list(j["props"]["initialState"]["content"]["documents"])[0] + return j["props"]["initialState"]["content"]["documents"][name] diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen.testhtml b/tests/test_data/americastestkitchen.com/americastestkitchen.testhtml deleted file mode 100644 index f698920be..000000000 --- a/tests/test_data/americastestkitchen.com/americastestkitchen.testhtml +++ /dev/null @@ -1,3705 +0,0 @@ - -Lasagna Bolognese, Simplified | America's Test Kitchen RecipeAmerica's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo

Lasagna Bolognese, Simplified

Could we adapt and simplify this northern Italian classic for the American kitchen?

SERVES 8

TIME 3 hours, plus 30 minutes cooling

Lasagna Bolognese, Simplified

Why This Recipe Works

Print

This is a members' feature.

\ No newline at end of file diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen.json b/tests/test_data/americastestkitchen.com/americastestkitchen_1.json similarity index 83% rename from tests/test_data/americastestkitchen.com/americastestkitchen.json rename to tests/test_data/americastestkitchen.com/americastestkitchen_1.json index fd113faaf..ee74b3170 100644 --- a/tests/test_data/americastestkitchen.com/americastestkitchen.json +++ b/tests/test_data/americastestkitchen.com/americastestkitchen_1.json @@ -72,13 +72,36 @@ ], "category": "Main Courses, Casseroles", "yields": "8 servings", - "description": "Could we adapt and simplify this northern Italian classic for the American kitchen?", + "description": "Could we adapt and simplify this northern Italian classic for the American kitchen? When we started thinking about a simple lasagna Bolognese recipe, there was no denying the appeal of no-boil noodles. After several tests, we found that a five-minute soak proved most effective for getting sturdy, al dente noodles that bound together the layers of ragu and béchamel without soaking up all the moisture. Stumbling through multiple rounds of meat sauce testing gave us the idea of combining the ragu and béchamel when both were lukewarm. The resulting sauce was thickened but easy to spread, with enough moisture for cooking the noodles in our simplified lasagna recipe.", "total_time": 210, "cuisine": "Europe, Italian", "ratings": 4.4, - "ratings_count": 80, + "ratings_count": 98, "nutrients": { - "calories": "5764 calories" + "calories": "721", + "fatContent": "40 grams", + "saturatedFatContent": "20 grams", + "unsaturatedFatContent": "14 grams", + "transFatContent": "1 grams", + "carbohydrateContent": "39 grams", + "sugarContent": "13 grams", + "proteinContent": "39 grams", + "sodiumContent": "1165 miligrams", + "cholesterolContent": "119 miligrams" }, - "image": "https://res.cloudinary.com/hksqkdlah/image/upload/ar_1:1,c_fill,dpr_2.0,f_auto,fl_lossy.progressive.strip_profile,g_faces:auto,q_auto:low,w_150/3801_so04-lasagnabolognes-article" + "image": "https://res.cloudinary.com/hksqkdlah/image/upload/ar_1:1,c_fill,dpr_2.0,f_auto,fl_lossy.progressive.strip_profile,g_faces:auto,q_auto:low,w_150/3801_so04-lasagnabolognes-article", + "keywords": [ + "Main Courses", + "Europe", + "Italian", + "Pasta", + "Grains", + "Rice & Beans", + "Eggs & Dairy", + "Meat", + "Cheese", + "Beef", + "Pork", + "Casseroles" + ] } diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen_1.testhtml b/tests/test_data/americastestkitchen.com/americastestkitchen_1.testhtml new file mode 100644 index 000000000..28aae8941 --- /dev/null +++ b/tests/test_data/americastestkitchen.com/americastestkitchen_1.testhtml @@ -0,0 +1,3832 @@ + +Lasagna Bolognese, Simplified | America's Test Kitchen Recipe
America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo

Lasagna Bolognese, Simplified

Could we adapt and simplify this northern Italian classic for the American kitchen?

SERVES 8

TIME 3 hours, plus 30 minutes cooling

Lasagna Bolognese, Simplified

Why This Recipe Works

Gather Your Ingredients

Meat Sauce (Ragù)
Béchamel
Noodles and Cheese

Key Equipment

Key Equipment - Food Processors
Key Equipment - Dutch Ovens
Key Equipment - All-Purpose Whisks

Before You Begin

*

For assembly, both the meat sauce and the bechamel should be just warm to the touch, not piping hot. Both sauces can be made, cooled, and refrigerated up to 2 days ahead, then gently reheated until warm. In terms of flavor and texture, we find that Barilla no-boil noodles are the closest to fresh, but this recipe will work with all major brands of no-boil noodles.

+

Instructions

1.

For the meat sauce: Process carrot, celery, and onion in food processor until finely chopped, about ten 1-second pulses, scraping down bowl as necessary; transfer mixture to small bowl. Wipe out food processor workbowl; process tomatoes and juice until finely chopped, six to eight 1-second pulses. Heat butter in heavy-bottomed Dutch oven over medium heat until foaming; add carrot, celery, and onion and cook, stirring occasionally, until softened but not browned, about 4 minutes. Add ground meats and cook, breaking meat into 1-inch pieces with wooden spoon, about 1 minute. Add milk and stir, breaking meat into 1/2-inch bits; bring to simmer and cook, stirring to break meat into small pieces, until almost all liquid has evaporated, 20 to 30 minutes. Using potato masher or wooden spoon, break up any remaining clumps of meat (no large pieces should remain). Add wine and bring to simmer; cook, stirring occasionally, until liquid has evaporated, 20 to 30 minutes. Stir in tomato paste until combined, about 1 minute; add chopped tomatoes, salt, and pepper. Bring to simmer, then reduce heat to medium-low and cook until sauce is slightly thickened, about 15 minutes. (You should have about 6 cups meat sauce.) Transfer meat sauce to bowl and cool until just warm to touch, about 30 minutes.

+

2.

For the béchamel: While meat sauce simmers, melt butter in medium saucepan over medium heat until foaming; add flour and cook, whisking constantly, until thoroughly combined, about 1 1/2 minutes; mixture should not brown. Gradually whisk in milk; increase heat to medium-high and bring to full boil, whisking frequently. Add salt, reduce heat to medium-low, and simmer 10 minutes, stirring occasionally with heatproof rubber spatula or wooden spoon, making sure to scrape bottom and corners of saucepan. (You should have about 3 1/3 cups.) Transfer béchamel to bowl and cool until just warm to touch, about 30 minutes.

+

3.

To assemble and bake: Adjust oven rack to middle position; heat oven to 425 degrees. Place noodles in 13- by 9-inch baking dish and cover with very hot tap water; soak 5 minutes, agitating noodles occasionally to prevent sticking. Remove noodles from water, place in single layer on kitchen towel, and pat dry. Wipe out baking dish and spray lightly with nonstick cooking spray. Stir béchamel to recombine; mix 3/4 cup warm béchamel into warm meat sauce until thoroughly combined.

+

4.

Distribute 1 cup béchamel-enriched meat sauce in baking dish. Place three noodles in single layer on top of sauce, arranging them close together, but not touching, at center of pan. Spread 1 1/4 cups béchamel-enriched meat sauce evenly over noodles, spreading sauce to edge of noodles but not to edge of dish (see illustration 1). Drizzle 1/3 cup béchamel evenly over meat sauce (illustration 2). Sprinkle 1/3 cup Parmesan evenly over béchamel. Repeat layering of noodles, béchamel-enriched meat sauce, bechamel, and cheese 3 more times. Place final 3 noodles on top and cover completely with remaining béchamel, spreading béchamel with rubber spatula and allowing it to spill over noodles (illustration 3). Sprinkle evenly with remaining Parmesan.

+

5.

Spray large sheet foil with nonstick cooking spray and cover lasagna; bake until bubbling, about 30 minutes. Remove foil, increase heat to 450 degrees, and continue to bake until surface is spotty brown, about 15 minutes. Cool 15 minutes; cut into pieces and serve.

+

Test Kitchen Techniques

FROM OUR TV SPONSORS

We are thankful to the sponsors who make it possible for us to bring you the America's Test Kitchen TV series on public television. Read more about why we have sponsors.

This is a members' feature.

America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo \ No newline at end of file diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen_2.json b/tests/test_data/americastestkitchen.com/americastestkitchen_2.json new file mode 100644 index 000000000..ee74b3170 --- /dev/null +++ b/tests/test_data/americastestkitchen.com/americastestkitchen_2.json @@ -0,0 +1,107 @@ +{ + "author": "America's Test Kitchen", + "canonical_url": "https://www.americastestkitchen.com/recipes/1629-lasagna-bolognese-simplified", + "site_name": "America's Test Kitchen", + "host": "americastestkitchen.com", + "language": "en", + "title": "Lasagna Bolognese, Simplified", + "ingredients": [ + "1 medium carrot, peeled and roughly chopped", + "1 medium rib celery, roughly chopped", + "1/2 small onion, roughly chopped", + "1 (28 ounce) can whole tomatoes with juice", + "2 tablespoons unsalted butter", + "8 ounces ground beef, preferably 90 percent lean", + "8 ounces ground pork", + "8 ounces ground veal", + "1 1/2 cups whole milk", + "1 1/2 cups dry white wine", + "2 tablespoons tomato paste", + "1 teaspoon table salt", + "1/4 teaspoon ground black pepper", + "4 tablespoons unsalted butter", + "1/4 cup unbleached all-purpose flour", + "4 cups whole milk", + "3/4 teaspoon table salt", + "15 sheets no-boil lasagna noodle (9 ounces)", + "4 ounces Parmesan cheese, grated (2 cups)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 medium carrot, peeled and roughly chopped", + "1 medium rib celery, roughly chopped", + "1/2 small onion, roughly chopped", + "1 (28 ounce) can whole tomatoes with juice", + "2 tablespoons unsalted butter", + "8 ounces ground beef, preferably 90 percent lean", + "8 ounces ground pork", + "8 ounces ground veal", + "1 1/2 cups whole milk", + "1 1/2 cups dry white wine", + "2 tablespoons tomato paste", + "1 teaspoon table salt", + "1/4 teaspoon ground black pepper" + ], + "purpose": "Meat Sauce (Ragù)" + }, + { + "ingredients": [ + "4 tablespoons unsalted butter", + "1/4 cup unbleached all-purpose flour", + "4 cups whole milk", + "3/4 teaspoon table salt" + ], + "purpose": "Béchamel" + }, + { + "ingredients": [ + "15 sheets no-boil lasagna noodle (9 ounces)", + "4 ounces Parmesan cheese, grated (2 cups)" + ], + "purpose": "Noodles and Cheese" + } + ], + "instructions_list": [ + "Note: For assembly, both the meat sauce and the bechamel should be just warm to the touch, not piping hot. Both sauces can be made, cooled, and refrigerated up to 2 days ahead, then gently reheated until warm. In terms of flavor and texture, we find that Barilla no-boil noodles are the closest to fresh, but this recipe will work with all major brands of no-boil noodles.", + "For the meat sauce: Process carrot, celery, and onion in food processor until finely chopped, about ten 1-second pulses, scraping down bowl as necessary; transfer mixture to small bowl. Wipe out food processor workbowl; process tomatoes and juice until finely chopped, six to eight 1-second pulses. Heat butter in heavy-bottomed Dutch oven over medium heat until foaming; add carrot, celery, and onion and cook, stirring occasionally, until softened but not browned, about 4 minutes. Add ground meats and cook, breaking meat into 1-inch pieces with wooden spoon, about 1 minute. Add milk and stir, breaking meat into 1/2-inch bits; bring to simmer and cook, stirring to break meat into small pieces, until almost all liquid has evaporated, 20 to 30 minutes. Using potato masher or wooden spoon, break up any remaining clumps of meat (no large pieces should remain). Add wine and bring to simmer; cook, stirring occasionally, until liquid has evaporated, 20 to 30 minutes. Stir in tomato paste until combined, about 1 minute; add chopped tomatoes, salt, and pepper. Bring to simmer, then reduce heat to medium-low and cook until sauce is slightly thickened, about 15 minutes. (You should have about 6 cups meat sauce.) Transfer meat sauce to bowl and cool until just warm to touch, about 30 minutes.", + "For the béchamel: While meat sauce simmers, melt butter in medium saucepan over medium heat until foaming; add flour and cook, whisking constantly, until thoroughly combined, about 1 1/2 minutes; mixture should not brown. Gradually whisk in milk; increase heat to medium-high and bring to full boil, whisking frequently. Add salt, reduce heat to medium-low, and simmer 10 minutes, stirring occasionally with heatproof rubber spatula or wooden spoon, making sure to scrape bottom and corners of saucepan. (You should have about 3 1/3 cups.) Transfer béchamel to bowl and cool until just warm to touch, about 30 minutes.", + "To assemble and bake: Adjust oven rack to middle position; heat oven to 425 degrees. Place noodles in 13- by 9-inch baking dish and cover with very hot tap water; soak 5 minutes, agitating noodles occasionally to prevent sticking. Remove noodles from water, place in single layer on kitchen towel, and pat dry. Wipe out baking dish and spray lightly with nonstick cooking spray. Stir béchamel to recombine; mix 3/4 cup warm béchamel into warm meat sauce until thoroughly combined.", + "Distribute 1 cup béchamel-enriched meat sauce in baking dish. Place three noodles in single layer on top of sauce, arranging them close together, but not touching, at center of pan. Spread 1 1/4 cups béchamel-enriched meat sauce evenly over noodles, spreading sauce to edge of noodles but not to edge of dish (see illustration 1). Drizzle 1/3 cup béchamel evenly over meat sauce (illustration 2). Sprinkle 1/3 cup Parmesan evenly over béchamel. Repeat layering of noodles, béchamel-enriched meat sauce, bechamel, and cheese 3 more times. Place final 3 noodles on top and cover completely with remaining béchamel, spreading béchamel with rubber spatula and allowing it to spill over noodles (illustration 3). Sprinkle evenly with remaining Parmesan.", + "Spray large sheet foil with nonstick cooking spray and cover lasagna; bake until bubbling, about 30 minutes. Remove foil, increase heat to 450 degrees, and continue to bake until surface is spotty brown, about 15 minutes. Cool 15 minutes; cut into pieces and serve." + ], + "category": "Main Courses, Casseroles", + "yields": "8 servings", + "description": "Could we adapt and simplify this northern Italian classic for the American kitchen? When we started thinking about a simple lasagna Bolognese recipe, there was no denying the appeal of no-boil noodles. After several tests, we found that a five-minute soak proved most effective for getting sturdy, al dente noodles that bound together the layers of ragu and béchamel without soaking up all the moisture. Stumbling through multiple rounds of meat sauce testing gave us the idea of combining the ragu and béchamel when both were lukewarm. The resulting sauce was thickened but easy to spread, with enough moisture for cooking the noodles in our simplified lasagna recipe.", + "total_time": 210, + "cuisine": "Europe, Italian", + "ratings": 4.4, + "ratings_count": 98, + "nutrients": { + "calories": "721", + "fatContent": "40 grams", + "saturatedFatContent": "20 grams", + "unsaturatedFatContent": "14 grams", + "transFatContent": "1 grams", + "carbohydrateContent": "39 grams", + "sugarContent": "13 grams", + "proteinContent": "39 grams", + "sodiumContent": "1165 miligrams", + "cholesterolContent": "119 miligrams" + }, + "image": "https://res.cloudinary.com/hksqkdlah/image/upload/ar_1:1,c_fill,dpr_2.0,f_auto,fl_lossy.progressive.strip_profile,g_faces:auto,q_auto:low,w_150/3801_so04-lasagnabolognes-article", + "keywords": [ + "Main Courses", + "Europe", + "Italian", + "Pasta", + "Grains", + "Rice & Beans", + "Eggs & Dairy", + "Meat", + "Cheese", + "Beef", + "Pork", + "Casseroles" + ] +} diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen_2.testhtml b/tests/test_data/americastestkitchen.com/americastestkitchen_2.testhtml new file mode 100644 index 000000000..28aae8941 --- /dev/null +++ b/tests/test_data/americastestkitchen.com/americastestkitchen_2.testhtml @@ -0,0 +1,3832 @@ + +Lasagna Bolognese, Simplified | America's Test Kitchen Recipe
America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo

Lasagna Bolognese, Simplified

Could we adapt and simplify this northern Italian classic for the American kitchen?

SERVES 8

TIME 3 hours, plus 30 minutes cooling

Lasagna Bolognese, Simplified

Why This Recipe Works

Gather Your Ingredients

Meat Sauce (Ragù)
Béchamel
Noodles and Cheese

Key Equipment

Key Equipment - Food Processors
Key Equipment - Dutch Ovens
Key Equipment - All-Purpose Whisks

Before You Begin

*

For assembly, both the meat sauce and the bechamel should be just warm to the touch, not piping hot. Both sauces can be made, cooled, and refrigerated up to 2 days ahead, then gently reheated until warm. In terms of flavor and texture, we find that Barilla no-boil noodles are the closest to fresh, but this recipe will work with all major brands of no-boil noodles.

+

Instructions

1.

For the meat sauce: Process carrot, celery, and onion in food processor until finely chopped, about ten 1-second pulses, scraping down bowl as necessary; transfer mixture to small bowl. Wipe out food processor workbowl; process tomatoes and juice until finely chopped, six to eight 1-second pulses. Heat butter in heavy-bottomed Dutch oven over medium heat until foaming; add carrot, celery, and onion and cook, stirring occasionally, until softened but not browned, about 4 minutes. Add ground meats and cook, breaking meat into 1-inch pieces with wooden spoon, about 1 minute. Add milk and stir, breaking meat into 1/2-inch bits; bring to simmer and cook, stirring to break meat into small pieces, until almost all liquid has evaporated, 20 to 30 minutes. Using potato masher or wooden spoon, break up any remaining clumps of meat (no large pieces should remain). Add wine and bring to simmer; cook, stirring occasionally, until liquid has evaporated, 20 to 30 minutes. Stir in tomato paste until combined, about 1 minute; add chopped tomatoes, salt, and pepper. Bring to simmer, then reduce heat to medium-low and cook until sauce is slightly thickened, about 15 minutes. (You should have about 6 cups meat sauce.) Transfer meat sauce to bowl and cool until just warm to touch, about 30 minutes.

+

2.

For the béchamel: While meat sauce simmers, melt butter in medium saucepan over medium heat until foaming; add flour and cook, whisking constantly, until thoroughly combined, about 1 1/2 minutes; mixture should not brown. Gradually whisk in milk; increase heat to medium-high and bring to full boil, whisking frequently. Add salt, reduce heat to medium-low, and simmer 10 minutes, stirring occasionally with heatproof rubber spatula or wooden spoon, making sure to scrape bottom and corners of saucepan. (You should have about 3 1/3 cups.) Transfer béchamel to bowl and cool until just warm to touch, about 30 minutes.

+

3.

To assemble and bake: Adjust oven rack to middle position; heat oven to 425 degrees. Place noodles in 13- by 9-inch baking dish and cover with very hot tap water; soak 5 minutes, agitating noodles occasionally to prevent sticking. Remove noodles from water, place in single layer on kitchen towel, and pat dry. Wipe out baking dish and spray lightly with nonstick cooking spray. Stir béchamel to recombine; mix 3/4 cup warm béchamel into warm meat sauce until thoroughly combined.

+

4.

Distribute 1 cup béchamel-enriched meat sauce in baking dish. Place three noodles in single layer on top of sauce, arranging them close together, but not touching, at center of pan. Spread 1 1/4 cups béchamel-enriched meat sauce evenly over noodles, spreading sauce to edge of noodles but not to edge of dish (see illustration 1). Drizzle 1/3 cup béchamel evenly over meat sauce (illustration 2). Sprinkle 1/3 cup Parmesan evenly over béchamel. Repeat layering of noodles, béchamel-enriched meat sauce, bechamel, and cheese 3 more times. Place final 3 noodles on top and cover completely with remaining béchamel, spreading béchamel with rubber spatula and allowing it to spill over noodles (illustration 3). Sprinkle evenly with remaining Parmesan.

+

5.

Spray large sheet foil with nonstick cooking spray and cover lasagna; bake until bubbling, about 30 minutes. Remove foil, increase heat to 450 degrees, and continue to bake until surface is spotty brown, about 15 minutes. Cool 15 minutes; cut into pieces and serve.

+

Test Kitchen Techniques

FROM OUR TV SPONSORS

We are thankful to the sponsors who make it possible for us to bring you the America's Test Kitchen TV series on public television. Read more about why we have sponsors.

This is a members' feature.

America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo \ No newline at end of file diff --git a/tests/test_data/cookscountry.com/cookscountry.json b/tests/test_data/cookscountry.com/cookscountry.json index 34ed1b6b2..10e857bf0 100644 --- a/tests/test_data/cookscountry.com/cookscountry.json +++ b/tests/test_data/cookscountry.com/cookscountry.json @@ -73,7 +73,7 @@ "total_time": 75, "cuisine": "Latin America & Caribbean, Mexican", "ratings": 4.2, - "ratings_count": 39, + "ratings_count": 56, "nutrients": { "calories": "687", "fatContent": "31 grams", diff --git a/tests/test_data/cookscountry.com/cookscountry.testhtml b/tests/test_data/cookscountry.com/cookscountry.testhtml index be399ece8..d1f084652 100644 --- a/tests/test_data/cookscountry.com/cookscountry.testhtml +++ b/tests/test_data/cookscountry.com/cookscountry.testhtml @@ -15,3203 +15,44 @@ j.async=true;j.src='//www.googletagmanager.com/gtm.js?id='+i+dl ; f.parentNode.insertBefore(j,f); - })(window,document,'script','dataLayer','GTM-MFMR9K');America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo \ No newline at end of file diff --git a/tests/test_data/cooksillustrated.com/cooksillustrated.json b/tests/test_data/cooksillustrated.com/cooksillustrated.json index 582c6db67..aeb86b2c8 100644 --- a/tests/test_data/cooksillustrated.com/cooksillustrated.json +++ b/tests/test_data/cooksillustrated.com/cooksillustrated.json @@ -21,8 +21,8 @@ "description": "Whisk butter into a little simmering water and—poof!—you've got beurre monté: liquid silk that pairs with any seasoning and gilds everything it touches. Beurre monté, emulsified melted butter, is a classic French preparation that can be drizzled over cooked meats, vegetables, pastas, and other dishes to add richness and a glossy appearance or used as a rich, creamy sauce base for pairing with a wide range of savory or sweet seasonings. Vigorously whisking cold butter into a measured amount of simmering water broke up the butterfat into tiny droplets that dispersed throughout the water, establishing a thick, creamy emulsion. Whisking oyster sauce plus orange zest and juice into the beurre monté produced a bold, rich, easy-to-make sauce that paired especially well with lean roasted or pan-seared proteins such as scallops, cod, pork tenderloin, or chicken breast; it was also great over pasta.", "total_time": 10, "cuisine": "French", - "ratings": 4.5, - "ratings_count": 26, + "ratings": 4.2, + "ratings_count": 44, "nutrients": { "calories": "207", "fatContent": "23 grams", diff --git a/tests/test_data/cooksillustrated.com/cooksillustrated.testhtml b/tests/test_data/cooksillustrated.com/cooksillustrated.testhtml index 0f6a57b99..83dd8e5b5 100644 --- a/tests/test_data/cooksillustrated.com/cooksillustrated.testhtml +++ b/tests/test_data/cooksillustrated.com/cooksillustrated.testhtml @@ -15,3203 +15,44 @@ j.async=true;j.src='//www.googletagmanager.com/gtm.js?id='+i+dl ; f.parentNode.insertBefore(j,f); - })(window,document,'script','dataLayer','GTM-MFMR9K');America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo \ No newline at end of file From c2c94101b53b934e2a6877c3a2c0fc4260bb5a4c Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Fri, 27 Dec 2024 15:19:12 +0200 Subject: [PATCH 70/94] Bump mypy version used --- .pre-commit-config.yaml | 2 +- pyproject.toml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f10bae483..23feed693 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: - id: black args: ["--target-version", "py39"] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.13.0 + rev: v1.14.0 hooks: - id: mypy additional_dependencies: [types-beautifulsoup4, types-requests] diff --git a/pyproject.toml b/pyproject.toml index 38426ae8c..e51e8d578 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ linters = [ "black == 24.10.0", # match what's in .pre-commit-config.yaml "flake8 == 7.1.1", # match what's in .pre-commit-config.yaml "pep8-naming == 0.14.1", # match what's in .pre-commit-config.yaml - "mypy == 1.13.0", # match what's in .pre-commit-config.yaml + "mypy == 1.14.0", # match what's in .pre-commit-config.yaml "types-beautifulsoup4", # needed for mypy "types-requests", # needed for mypy ] @@ -116,11 +116,12 @@ exclude_lines = [ [[tool.mypy.overrides]] module = "recipe_scrapers.*" disable_error_code = "union-attr" - +[[tool.mypy.overrides]] +module = "._abstract" +ignore_missing_imports = true [[tool.mypy.overrides]] module = "isodate" ignore_missing_imports = true - [[tool.mypy.overrides]] module = "extruct" ignore_missing_imports = true From ad0bd51db2296fb4516f92194c04a944d6a99902 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Fri, 27 Dec 2024 18:05:25 +0200 Subject: [PATCH 71/94] docs: Add contributing/setup.md section and adjustments with it --- docs/contributing/code-contribution.md | 95 ++--------- ...ation-contribution.md => documentation.md} | 46 +----- docs/contributing/how-to-contribute.md | 33 ++-- docs/contributing/how-to-develop-a-scraper.md | 16 +- .../in-depth-guide-html-scraping.md | 3 + .../in-depth-guide-ingredient-groups.md | 3 + .../in-depth-guide-scraper-functions.md | 3 + docs/contributing/setup.md | 154 ++++++++++++++++++ docs/getting-started/supported-sites.md | 2 +- mkdocs.yaml | 3 +- 10 files changed, 217 insertions(+), 141 deletions(-) rename docs/contributing/{documentation-contribution.md => documentation.md} (52%) create mode 100644 docs/contributing/setup.md diff --git a/docs/contributing/code-contribution.md b/docs/contributing/code-contribution.md index 53450baea..88791ab29 100644 --- a/docs/contributing/code-contribution.md +++ b/docs/contributing/code-contribution.md @@ -1,54 +1,18 @@ # Code Contribution !!! note "Prerequisites" - This guide assumes you have basic familiarity with Python development, including using `pip`, - `virtual environments`, and `git`. Teaching these core concepts is beyond the scope of this - documentation - please ensure you're comfortable with them before proceeding. - -!!! warning "Python Version Requirement" - We strongly recommend using Python 3.11 or above for all development work related to `recipe-scrapers`. - This version comes with `tomllib` support built-in, which is essential for the project's configuration handling. - -We welcome various types of code contributions to `recipe-scrapers`, including: - -- Bug fixes -- New recipe site scrapers -- Performance improvements -- Feature enhancements -- Test coverage improvements - -## Initial Setup - -Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers) on GitHub and follow these setup steps: - -!!! tip "Quick Setup" - ```bash - # Clone your fork - git clone https://github.com/YOUR-USERNAME/recipe-scrapers.git - cd recipe-scrapers - - # Set up Python environment - python -m venv .venv - source .venv/bin/activate # On Windows use: .venv\Scripts\activate - python -m pip install --upgrade pip - pip install -e ".[all]" - ``` - -!!! note "Virtual Environment" - Remember to activate your virtual environment each time you work on the project: - ```bash - source .venv/bin/activate # On Windows use: .venv\Scripts\activate - ``` + This guide assumes you are already familiar with our [setup guide](./setup.md). ## Development Workflow -Create a new branch for your changes: -```bash -git checkout -b feature/your-feature-name # for new features +Create a new branch for your code changes: + +```sh +git checkout -b fix/your-fix-name # for bug fixes # or -git checkout -b fix/your-fix-name # for bug fixes +git checkout -b site/website-name # for new site scrapers # or -git checkout -b site/website-name # for new site scrapers +git checkout -b feature/feature-name # for new features ``` After making your changes commit them: @@ -61,51 +25,20 @@ git push origin your-branch-name Then create a Pull Request back to the [main repository](https://github.com/hhursev/recipe-scrapers) from your fork. -### Pre-commit Hooks - -The project uses pre-commit hooks to ensure code quality and consistency. These hooks run -automatically when you commit changes, handling tasks like: - -- Code formatting (black, isort) -- Linting (flake8) -- Type checking -- Other code quality checks - -## What happens after a PR - -When you submit your PR: - -1. Our CI suite will run against your code to ensure everything works as expected. You can run the tests locally before submitting: - ```bash - python -m unittest - # or - unittest-parallel --level test - ``` - -2. Community members and core contributors will review your code. They may: - - Request changes or improvements - - Suggest alternative approaches - - Provide feedback on test coverage - - Ask for documentation updates - -3. Once approved, a core contributor will merge your PR - - Your contribution will be included in the next release - - Feel free to tackle any follow-up improvements in subsequent PRs - -Don't worry if your first PR needs some adjustments - this is normal and part of the collaborative development process! - - -## Development Guidelines (Coming Soon) +## Development Guidelines While we're working on comprehensive documentation, the codebase is designed to be self-explanatory. As a developer, you can understand our patterns and expectations by taking a look at existing scrapers in the `recipe_scrapers/` directory. + +## Hints + !!! tip "Generator Tool" If you're adding a new site scraper, you can use our generator command to create a template: - ```bash + ```sh python generate.py ``` @@ -114,7 +47,11 @@ by taking a look at existing scrapers in the `recipe_scrapers/` directory. - `ClassName`: The name of your new scraper class (e.g., `BBCGoodFood`) - `URL`: A sample recipe URL from the target site. This will be saved in `test_data/` for testing. + +## Examples + !!! warning "Work in Progress" + This contributing guide is currently being developed. Meanwhile, you can check these PRs as examples of good contribution standards: - [#1414](https://github.com/hhursev/recipe-scrapers/pull/1414/) - Adding a new site scraper diff --git a/docs/contributing/documentation-contribution.md b/docs/contributing/documentation.md similarity index 52% rename from docs/contributing/documentation-contribution.md rename to docs/contributing/documentation.md index c5e5c6120..4559ed522 100644 --- a/docs/contributing/documentation-contribution.md +++ b/docs/contributing/documentation.md @@ -1,43 +1,10 @@ # Contributing to Documentation !!! note "Prerequisites" - This guide assumes you have basic familiarity with Python development, including using `pip`, - `virtual environments`, and `git`. Teaching these core concepts is beyond the scope of this - documentation - please ensure you're comfortable with them before proceeding. - -!!! warning "Python Version Requirement" - We strongly recommend using Python 3.11 or above for all development work related to `recipe-scrapers`. - This version comes with `tomllib` support built-in, which is essential for the project's configuration handling. - -The documentation for `recipe-scrapers` is hosted at [docs.recipe-scrapers.com](https://docs.recipe-scrapers.com). -We welcome contributions to improve and expand our documentation! This guide will help you get started with making -documentation changes. - -## Initial Setup - -Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers) on GitHub and follow these setup steps: - -!!! tip "Quick Setup" - ```bash - # Clone your fork - git clone https://github.com/YOUR-USERNAME/recipe-scrapers.git - cd recipe-scrapers - - # Set up Python environment - python -m venv .venv - source .venv/bin/activate # On Windows use: .venv\Scripts\activate - python -m pip install --upgrade pip - pip install -e ".[all]" - ``` - -!!! note "Virtual Environment" - Remember to activate your virtual environment each time you work on the project: - ```bash - source .venv/bin/activate # On Windows use: .venv\Scripts\activate - ``` + This guide assumes you are already familiar with our [setup guide](./setup.md). Create a new branch for your documentation changes: -```bash +```sh git checkout -b docs/your-feature-name ``` @@ -45,7 +12,7 @@ git checkout -b docs/your-feature-name !!! example "Local Development" 1. From the project root directory, start the MkDocs development server: - ```bash + ```sh mkdocs serve ``` 2. Open your browser and navigate to `http://127.0.0.1:8000` @@ -62,20 +29,21 @@ The preview will automatically update as you make changes to the documentation f ## Submitting Your Changes 1. Commit your changes with a descriptive message: - ```bash + ```sh git add docs/ git commit -m "docs: describe your changes here" ``` 2. Push your changes to your fork: - ```bash + ```sh git push origin docs/your-feature-name ``` 3. Create a Pull Request (PR) from your fork to the main [recipe-scrapers](https://github.com/hhursev/recipe-scrapers) repository. !!! success "PR Preview" - When you create a PR, a special preview URL will be generated where your documentation changes can be reviewed. This will make it easy for maintainers to see your changes in action. + When you create a PR, a special preview URL will be generated where your documentation changes can be reviewed. + This will make it easy for maintainers to see your changes in action. ## Documentation Style Guidelines diff --git a/docs/contributing/how-to-contribute.md b/docs/contributing/how-to-contribute.md index 6e083d1bb..5fdf22b1c 100644 --- a/docs/contributing/how-to-contribute.md +++ b/docs/contributing/how-to-contribute.md @@ -1,32 +1,35 @@ # How to Contribute !!! success "Better For Everyone" - We welcome all forms of contribution to `recipe-scrapers`! - Whether you're reporting bugs, suggesting new sites to support, or contributing code, - your help makes this project better for everyone. + We welcome all contributions to `recipe-scrapers`! + Whether you're reporting bugs, suggesting features, improving documentation, + or contributing code, your help makes this project better for everyone. + ## Ways to Contribute ### Opening Issues -Found a bug? A scraper not working for a particular site? Please open an issue! -With the number of [Supported Sites](../getting-started/supported-sites.md) and their possible design changes, -bugs are inevitable and your reports help us maintain quality. +Found a bug or a scraper not working for a particular site? Please open an issue! +Given our large number of [Supported Sites](../getting-started/supported-sites.md) +and their frequent design changes, bugs are inevitable. Your reports help us +maintain quality and improve the project. -Want support for a new site? Feel free to request it by opening an issue. Please use our _issue templates_ whenever possible. +Want support for a new site? Open an issue using our _issue templates_. All issues +should be submitted through our [GitHub repository](https://github.com/hhursev/recipe-scrapers/issues). -All issues should be opened on our [GitHub repository](https://github.com/hhursev/recipe-scrapers/issues). +### Contributing to the Project -### Contributing Code +If you'd like to contribute to the project, whether it's fixing a bug, adding support +for a new site, improving documentation, or closing a raised issue, we're happy to help +you through the process. Check out our development guidelines [starting here](./setup.md). -If you'd like to contribute code, whether it's fixing a bug, adding support for a new site, or closing a raised issue -we're happy to help you through the process. Check out our development guidelines [starting here](./documentation-contribution.md). -## Our Contributors +## Our Community -This project thrives thanks to our amazing contributors. -Every contribution, whether big or small, helps make `recipe-scrapers` better for everyone. +This project thrives thanks to our amazing contributors. Every contribution, +whether big or small, helps make `recipe-scrapers` better for everyone. -## Wall of Fame +### Wall of Fame [![Contributors](https://contrib.rocks/image?repo=hhursev/recipe-scrapers)](https://github.com/hhursev/recipe-scrapers/graphs/contributors) diff --git a/docs/contributing/how-to-develop-a-scraper.md b/docs/contributing/how-to-develop-a-scraper.md index 65ee40c70..b3550c239 100644 --- a/docs/contributing/how-to-develop-a-scraper.md +++ b/docs/contributing/how-to-develop-a-scraper.md @@ -1,5 +1,9 @@ # How To Develop a New Scraper +!!! warning "Under Construction" + This section is being updated. Some information may be outdated or inaccurate. + + ## Find a website First, check if the website is already supported: @@ -21,7 +25,7 @@ print(SCRAPERS.get("bbcgoodfood.com")) Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers) on GitHub and follow these steps: !!! tip "Quick Setup" - ```bash + ```sh # Clone your fork git clone https://github.com/YOUR-USERNAME/recipe-scrapers.git cd recipe-scrapers @@ -35,12 +39,12 @@ Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers Create a new branch: -```bash +```sh git checkout -b site/website-name ``` !!! tip "Run Tests" - ```bash + ```sh python -m unittest # Optional: Parallel testing @@ -68,7 +72,7 @@ print(scraper.schema.data) # Empty dict if schema not supported ### 3. Generate Files -```bash +```sh python generate.py ``` @@ -123,7 +127,7 @@ Edit `tests/test_data//test.json`: ### 2. Run Tests -```bash +```sh python -m unittest -k ``` @@ -133,7 +137,7 @@ python -m unittest -k ## Submit Changes 1. Commit your work: -```bash +```sh git add -p # Review changes git commit -m "Add scraper for example.com" git push origin site/website-name diff --git a/docs/contributing/in-depth-guide-html-scraping.md b/docs/contributing/in-depth-guide-html-scraping.md index 5844a4b45..4b61e7f00 100644 --- a/docs/contributing/in-depth-guide-html-scraping.md +++ b/docs/contributing/in-depth-guide-html-scraping.md @@ -1,5 +1,8 @@ # In Depth Guide: HTML Scraping +!!! warning "Under Construction" + This section is being updated. Some information may be outdated or inaccurate. + The preferred method of scraping recipe information from a web page is to use the schema.org Recipe data. This is a machine readable, structured format intended to provide a standardised method of extracting information. However, whilst most recipe websites use the schema.org Recipe format, not all do, and for those websites that do, it does not always include all the information we are looking for. In these cases, we can use HTML scraping to extract the information from the HTML markup. ## `soup` diff --git a/docs/contributing/in-depth-guide-ingredient-groups.md b/docs/contributing/in-depth-guide-ingredient-groups.md index 9a88ffaf1..4b990eeca 100644 --- a/docs/contributing/in-depth-guide-ingredient-groups.md +++ b/docs/contributing/in-depth-guide-ingredient-groups.md @@ -1,5 +1,8 @@ # In Depth Guide: Ingredient Groups +!!! warning "Under Construction" + This section is being updated. Some information may be outdated or inaccurate. + Sometimes a website will format lists of ingredients using groups, where each group contains the ingredients needed for a particular aspect of the recipe. Recipe Schema has no way to represent these groupings, so all of the ingredients are presented as a single list and information about the groupings is lost. Some examples of recipes that have ingredient groups are: diff --git a/docs/contributing/in-depth-guide-scraper-functions.md b/docs/contributing/in-depth-guide-scraper-functions.md index e99ec9bee..f797fc642 100644 --- a/docs/contributing/in-depth-guide-scraper-functions.md +++ b/docs/contributing/in-depth-guide-scraper-functions.md @@ -1,5 +1,8 @@ # In Depth Guide: Scraper Functions +!!! warning "Under Construction" + This section is being updated. Some information may be outdated or inaccurate. + Each website scraper has a number of functions that return information about the recipe that has been scraped. Due to the variability in how recipes are written, not all of them are always applicable. These functions fall into three categories: 1. Mandatory functions diff --git a/docs/contributing/setup.md b/docs/contributing/setup.md new file mode 100644 index 000000000..b0e86352e --- /dev/null +++ b/docs/contributing/setup.md @@ -0,0 +1,154 @@ +# Setup + +Thank you for your interest in contributing to this project! + +Follow these steps to set up your environment for development. + +!!! note "Prerequisites" + This guide assumes you have basic familiarity with Python development, including using `pip`, + `virtual environments`, and `git`. These core concepts are beyond the scope of this documentation. + + +!!! warning "Python Version Requirement" + We strongly recommend using Python 3.11 or above for all development work related to `recipe-scrapers`. + This version includes built-in `tomllib` support, which is essential for the project's configuration handling. + + +We welcome various types of code contributions to `recipe-scrapers`, including: + +- Bug fixes +- New recipe site scrapers +- Performance improvements +- Feature enhancements +- Test coverage improvements + + +## Fork the Repository + +1. Navigate to [our repository on GitHub](https://github.com/hhursev/recipe-scrapers). +2. Click the "Fork" button in the top right corner to create your own copy of the repository. + + +## Clone Your Fork + +```sh +git clone https://github.com//recipe-scrapers.git +cd recipe-scrapers +``` + +## Set Upstream Remote + +!!! tip "Upstream Remote" + Setting the upstream remote allows you to sync changes from the original repository to your fork. + This is useful to keep your fork up-to-date with the latest changes. + +```sh +git remote add upstream https://github.com/hhursev/recipe-scrapers.git +``` + + +## Create a Virtual Environment + +It's recommended to use a virtual environment to manage dependencies. You can create one using `venv` + +```sh +python -m venv .venv +source venv/bin/activate # On Windows: `venv\Scripts\activate` +``` + +!!! tip "Virtual Environment" + Remember to activate your virtual environment each time you work on the project: + ```sh + source .venv/bin/activate # On Windows: .venv\Scripts\activate + ``` + +## Install Dependencies + +Install the required dependencies using `pip` + +```sh +pip install -e ".[all]" +``` + +Our pyproject.toml file lists the installed dependencies and their purposes. + + +## Development Workflow + +Create a new branch for your changes: +```sh +git checkout -b fix/your-fix-name # for bug fixes +# or +git checkout -b site/website-name # for new site scrapers +# or +git checkout -b docs/your-addition # for docs updates +# or +git checkout -b feature/feature-name # for new features +``` + +After making your changes, commit them: + +```sh +git add -p # Review changes before adding them +git commit -m "meaningful commit message" +git push origin your-branch-name +``` + +### Pre-commit Hooks + +The project uses pre-commit hooks to ensure code quality and consistency. These hooks run +automatically when you commit changes, handling tasks like: + +- Code formatting (black, isort) +- Linting (flake8) +- Type checking +- Other code quality checks + + +## Syncing Your Fork + +To keep your fork up-to-date with the original repository, you can fetch and merge changes from the upstream remote: + +```sh +git fetch upstream +git merge upstream/main +``` + +Then create a Pull Request back to the [main repository](https://github.com/hhursev/recipe-scrapers) from your fork. + + +If you have troubles check out [Submitting A Pull Request Section](#submitting-a-pull-request). + + +## Submitting a Pull Request + +1. Navigate to your fork on GitHub. +2. Click the "New pull request" button. +3. Ensure the base fork is the original repository and the base branch is `main`. +4. Fill out the pull request template and submit. + + +## Thank you for contributing! + +### What happens after a PR + +When you submit your PR: + +1. Our CI suite will run against your code to ensure everything works as expected. You can run the tests locally before submitting: +```sh +python -m unittest +# or +unittest-parallel --level test +``` + +2. Community members and core contributors will review your code. They may: + - Request changes or improvements + - Suggest alternative approaches + - Provide feedback on test coverage + - Ask for documentation updates + +3. Once approved, a core contributor will merge your PR + - Your contribution will be included in the next release + - Tackle any follow-up improvements in subsequent PRs + +Don't worry if your first PR needs some adjustments - this is normal and part of the collaborative development process! diff --git a/docs/getting-started/supported-sites.md b/docs/getting-started/supported-sites.md index 1cf3f4a58..02b79da09 100644 --- a/docs/getting-started/supported-sites.md +++ b/docs/getting-started/supported-sites.md @@ -5,7 +5,7 @@ - 📖 Check our [contributing guidelines](../contributing/how-to-contribute.md) - 🐛 Found a bug? [Open an issue](https://github.com/hhursev/recipe-scrapers/issues) - - 🚀 Ready to contribute? Submit a pull request! + - 🚀 Ready to contribute? [Submit a pull request](../contributing/setup.md)! ```python exec="on" import sys diff --git a/mkdocs.yaml b/mkdocs.yaml index 3984539a7..2f33d5c3b 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -41,7 +41,8 @@ nav: - Releases & License: getting-started/releases-and-license.md - Contributing: - How to Contribute: contributing/how-to-contribute.md - - Documentation Contribution: contributing/documentation-contribution.md + - Setup: contributing/setup.md + - Documentation: contributing/documentation.md - Code Contribution: contributing/code-contribution.md - How To Develop A Scraper: contributing/how-to-develop-a-scraper.md - In-Depth Guides: From 089c7afb180d9b789f991141ccbcfcbe588981ce Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Fri, 27 Dec 2024 18:24:11 +0200 Subject: [PATCH 72/94] docs: No longer than 100chars lines. Misc main-section naming updates --- docs/contributing/code-contribution.md | 8 +- docs/contributing/documentation.md | 7 +- .../{how-to-contribute.md => home.md} | 3 +- docs/contributing/how-to-develop-a-scraper.md | 9 +- docs/contributing/in-depth-guide-debugging.md | 3 +- .../in-depth-guide-html-scraping.md | 74 +++++++++++---- .../in-depth-guide-ingredient-groups.md | 92 ++++++++++++++----- .../in-depth-guide-scraper-functions.md | 86 +++++++++++------ docs/contributing/setup.md | 12 ++- docs/copyright-and-usage.md | 11 ++- docs/getting-started/examples.md | 4 +- docs/getting-started/releases-and-license.md | 6 +- docs/getting-started/supported-sites.md | 2 +- docs/index.md | 32 +++++-- docs/misc/migrating-from-v14.md | 13 ++- mkdocs.yaml | 4 +- 16 files changed, 259 insertions(+), 107 deletions(-) rename docs/contributing/{how-to-contribute.md => home.md} (92%) diff --git a/docs/contributing/code-contribution.md b/docs/contributing/code-contribution.md index 88791ab29..febded0e6 100644 --- a/docs/contributing/code-contribution.md +++ b/docs/contributing/code-contribution.md @@ -1,4 +1,4 @@ -# Code Contribution +# Code Contributions !!! note "Prerequisites" This guide assumes you are already familiar with our [setup guide](./setup.md). @@ -45,14 +45,16 @@ by taking a look at existing scrapers in the `recipe_scrapers/` directory. Where: - `ClassName`: The name of your new scraper class (e.g., `BBCGoodFood`) - - `URL`: A sample recipe URL from the target site. This will be saved in `test_data/` for testing. + - `URL`: A sample recipe URL from the target site. This will be saved in `test_data/` + for testing. ## Examples !!! warning "Work in Progress" - This contributing guide is currently being developed. Meanwhile, you can check these PRs as examples of good contribution standards: + This contributing guide is currently being developed. Meanwhile, you can check these + PRs as examples of good contribution standards: - [#1414](https://github.com/hhursev/recipe-scrapers/pull/1414/) - Adding a new site scraper - [#1432](https://github.com/hhursev/recipe-scrapers/pull/1432/) - Fixing broken functionality diff --git a/docs/contributing/documentation.md b/docs/contributing/documentation.md index 4559ed522..880f9af35 100644 --- a/docs/contributing/documentation.md +++ b/docs/contributing/documentation.md @@ -39,11 +39,12 @@ The preview will automatically update as you make changes to the documentation f git push origin docs/your-feature-name ``` -3. Create a Pull Request (PR) from your fork to the main [recipe-scrapers](https://github.com/hhursev/recipe-scrapers) repository. +3. Create a Pull Request (PR) from your fork to the main +[recipe-scrapers](https://github.com/hhursev/recipe-scrapers) repository. !!! success "PR Preview" - When you create a PR, a special preview URL will be generated where your documentation changes can be reviewed. - This will make it easy for maintainers to see your changes in action. + When you create a PR, a special preview URL will be generated where your documentation + changes can be reviewed. This will make it easy for maintainers to see your changes in action. ## Documentation Style Guidelines diff --git a/docs/contributing/how-to-contribute.md b/docs/contributing/home.md similarity index 92% rename from docs/contributing/how-to-contribute.md rename to docs/contributing/home.md index 5fdf22b1c..bafbe8605 100644 --- a/docs/contributing/how-to-contribute.md +++ b/docs/contributing/home.md @@ -16,7 +16,8 @@ and their frequent design changes, bugs are inevitable. Your reports help us maintain quality and improve the project. Want support for a new site? Open an issue using our _issue templates_. All issues -should be submitted through our [GitHub repository](https://github.com/hhursev/recipe-scrapers/issues). +should be submitted through our +[GitHub repository](https://github.com/hhursev/recipe-scrapers/issues). ### Contributing to the Project diff --git a/docs/contributing/how-to-develop-a-scraper.md b/docs/contributing/how-to-develop-a-scraper.md index b3550c239..ffef7e432 100644 --- a/docs/contributing/how-to-develop-a-scraper.md +++ b/docs/contributing/how-to-develop-a-scraper.md @@ -18,11 +18,13 @@ print(SCRAPERS.get("bbcgoodfood.com")) ``` !!! note "Track Your Progress" - Create an [issue](https://github.com/hhursev/recipe-scrapers/issues/new/choose) to track your work. + Create an [issue](https://github.com/hhursev/recipe-scrapers/issues/new/choose) to track + your work. ## Setup Repository -Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers) on GitHub and follow these steps: +Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers) on GitHub and +follow these steps: !!! tip "Quick Setup" ```sh @@ -57,7 +59,8 @@ git checkout -b site/website-name ### 1. Select Recipe URL !!! tip "Recipe Selection" - Choose a recipe with multiple instructions when possible. Single-instruction recipes may indicate parsing errors, unless [explicitly handled](https://github.com/hhursev/recipe-scrapers/blob/98ead6fc6e9653805b01539a3f46fbfb4e096136/tests/test_allrecipes.py#L147-L150). + Choose a recipe with multiple instructions when possible. Single-instruction recipes may + indicate parsing errors, unless [explicitly handled](https://github.com/hhursev/recipe-scrapers/blob/98ead6fc6e9653805b01539a3f46fbfb4e096136/tests/test_allrecipes.py#L147-L150). ### 2. Check Schema Support diff --git a/docs/contributing/in-depth-guide-debugging.md b/docs/contributing/in-depth-guide-debugging.md index e472804ab..ae6082460 100644 --- a/docs/contributing/in-depth-guide-debugging.md +++ b/docs/contributing/in-depth-guide-debugging.md @@ -1,6 +1,7 @@ # In Depth Guide: Debugging > **Draft** -> This in depth guide is intended to give more guidance on debugging scrapers during development and handling exceptions. +> This in depth guide is intended to give more guidance on debugging scrapers during +> development and handling exceptions. > >To be populated at a later date. diff --git a/docs/contributing/in-depth-guide-html-scraping.md b/docs/contributing/in-depth-guide-html-scraping.md index 4b61e7f00..9597c3f14 100644 --- a/docs/contributing/in-depth-guide-html-scraping.md +++ b/docs/contributing/in-depth-guide-html-scraping.md @@ -3,23 +3,38 @@ !!! warning "Under Construction" This section is being updated. Some information may be outdated or inaccurate. -The preferred method of scraping recipe information from a web page is to use the schema.org Recipe data. This is a machine readable, structured format intended to provide a standardised method of extracting information. However, whilst most recipe websites use the schema.org Recipe format, not all do, and for those websites that do, it does not always include all the information we are looking for. In these cases, we can use HTML scraping to extract the information from the HTML markup. +The preferred method of scraping recipe information from a web page is to use the schema.org +Recipe data. This is a machine readable, structured format intended to provide a standardised +method of extracting information. However, whilst most recipe websites use the schema.org Recipe +format, not all do, and for those websites that do, it does not always include all the information +we are looking for. In these cases, we can use HTML scraping to extract the information from +the HTML markup. ## `soup` -Each scraper has a `BeautifulSoup` object that can be accessed using the `self.soup` attribute. The `BeautifulSoup` object is a representation of the web page HTML that has been parsed into a format that we can query and extract information from. +Each scraper has a `BeautifulSoup` object that can be accessed using the `self.soup` attribute. +The `BeautifulSoup` object is a representation of the web page HTML that has been parsed into a +format that we can query and extract information from. -The [Beautiful Soup documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) is the best resource for learning how to use `BeautifulSoup` objects to interact with HTML documents. +The [Beautiful Soup documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) is the best resource for learning how to use `BeautifulSoup` +objects to interact with HTML documents. This guide covers a number of common patterns that are used in this library. ## `_schema_cls` and `_opengraph_cls` -It should rarely be necessary to override the default behaviour of schema.org and OpenGraph metadata retrieval; recipe websites should generally adhere to their respective standard formats when including metadata on their webpages. However, bugs/mistakes do happen - if you need to override the implementations provided by the `SchemaOrg` and `OpenGraph` classes, you can subclass from those and add a `_schema_cls` or `_opengraph_cls` attribute to your scraper class to instruct the library to use them instead. +It should rarely be necessary to override the default behaviour of schema.org and OpenGraph +metadata retrieval; recipe websites should generally adhere to their respective standard formats +when including metadata on their webpages. However, bugs/mistakes do happen - if you need to +override the implementations provided by the `SchemaOrg` and `OpenGraph` classes, you can subclass +from those and add a `_schema_cls` or `_opengraph_cls` attribute to your scraper class to instruct +the library to use them instead. ## Finding a single element -The `self.soup.find()` function returns the first element matching the arguments. This is useful if you are trying to extract some information that should only occur once, for example the prep time or total time. +The `self.soup.find()` function returns the first element matching the arguments. This is useful if +you are trying to extract some information that should only occur once, for example the prep time +or total time. ```python # To find a particular element @@ -36,14 +51,17 @@ self.soup.find(id="total-time") self.soup.find("h1", class_="title") ``` -`self.soup` returns a `bs4.element.Tag` object. Usually we just want the text from the selected element and the best way to do that is to use `.get_text()`. +`self.soup` returns a `bs4.element.Tag` object. Usually we just want the text from the selected +element and the best way to do that is to use `.get_text()`. ```python title_tag = self.soup.select("h1") # bs4.element.Tag object title_text = title_tag.get_text() # str ``` -`.get_text()` will get the text from all child elements, as it would appear in your browser, so there is no need to iterate through all the children, call `.get_text()` on each one, then join the results afterwards. +`.get_text()` will get the text from all child elements, as it would appear in your browser, so +there is no need to iterate through all the children, call `.get_text()` on each one, then join +the results afterwards. As an example, consider one of the ingredients in [this recipe](https://rainbowplantlife.com/instant-pot-jackfruit-curry/#wprm-recipe-container-5618). The markup looks like this: @@ -62,7 +80,8 @@ As an example, consider one of the ingredients in [this recipe](https://rainbowp ``` -We can select this element using its tag and class (we're pretending this recipe only has this one ingredient), and extract the text like so: +We can select this element using its tag and class (we're pretending this recipe only has this one +ingredient), and extract the text like so: ```python ingredient_tag = self.soup.find("li", class_="wprm-recipe-ingredient") @@ -74,7 +93,10 @@ The Beautiful Soup documentation for `find` is [here](https://www.crummy.com/sof ### Normalizing strings -A convenience function called `normalize_string()` is provided in the `_utils` package. This function will convert any characters escaped for HTML to their actual character (e.g. `&` to `&`) and remove unnecessary white space. It is best practice to always use this when extracting text from the HTML. +A convenience function called `normalize_string()` is provided in the `_utils` package. This +function will convert any characters escaped for HTML to their actual character (e.g. `&` +to `&`) and remove unnecessary white space. It is best practice to always use this when extracting +text from the HTML. ```python from ._utils import normalize_string @@ -86,7 +108,9 @@ ingredient_text = normalize_string(ingredient_tag.get_text()) ### Getting yields -A convenience function called `get_yields()` is provided in the `_utils` package. This function accepts a `str` or `bs4.element.Tag` and will return the yield, handling many of the common formats yields can appear in and normalizing them to a standard format. +A convenience function called `get_yields()` is provided in the `_utils` package. This function +accepts a `str` or `bs4.element.Tag` and will return the yield, handling many of the common +formats yields can appear in and normalizing them to a standard format. ```python from ._utils import get_yields @@ -101,7 +125,9 @@ yield_text = get_yields(yield_tag.get_text()) ### Getting times -A convenience function called `get_minutes()` is provided in the `_utils` package. This function accepts a `str` or `bs4.element.Tag` and will return the number of minutes as an `int`. This function handles a number of common formats that times can be expressed in. +A convenience function called `get_minutes()` is provided in the `_utils` package. This function +accepts a `str` or `bs4.element.Tag` and will return the number of minutes as an `int`. This +function handles a number of common formats that times can be expressed in. ```python from ._utils import get_minutes @@ -116,7 +142,10 @@ prep_time_value = get_minutes(prep_time_tag.get_text()) ## Finding multiple elements -Some information in a recipe, like the ingredients or instructions, come in the form of lists where we need to find multiple elements with the same attributes. We can use `self.soup.find_all()` for this. `find_all` uses the same arguments as `find`, it just returns a list of `bs4.element.Tag` objects with all the matching elements. +Some information in a recipe, like the ingredients or instructions, come in the form of lists where +we need to find multiple elements with the same attributes. We can use `self.soup.find_all()` for +this. `find_all` uses the same arguments as `find`, it just returns a list of `bs4.element.Tag` +objects with all the matching elements. Using the same site as above, we can find all the ingredients like so @@ -139,25 +168,34 @@ The Beautiful Soup documentation for `find_all` is [here](https://www.crummy.com ## Using CSS selectors -If you are already familiar with CSS selectors, then you can use `select()` to achieve the same result as `find_all()`, or `select_one()` to achieve the same result as `find`. +If you are already familiar with CSS selectors, then you can use `select()` to achieve the same +result as `find_all()`, or `select_one()` to achieve the same result as `find`. ```python -ingredient_tag = self.soup.select("li.wprm-recipe-ingredient") # Match all li elements with wprm-recipe-ingredient class +# Match all li elements with wprm-recipe-ingredient class +ingredient_tag = self.soup.select("li.wprm-recipe-ingredient") ``` -The Beautiful Soup documentation for `select` is [here](https://www.crummy.com/software/BeautifulSoup/bs4/doc/#css-selectors-through-the-css-property). MDN has a guide on CSS selectors [here](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors). +The Beautiful Soup documentation for `select` is [here](https://www.crummy.com/software/BeautifulSoup/bs4/doc/#css-selectors-through-the-css-property). MDN has a guide on +CSS selectors [here](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors). ## Finding elements using a partial attribute -Sometimes you might want to find elements using a part of an attribute. This is particularly helpful for websites that automatically generate CSS in a way that appends a random string to the end of class names. +Sometimes you might want to find elements using a part of an attribute. This is particularly +helpful for websites that automatically generate CSS in a way that appends a random string to +the end of class names. -An example of this is [cooking.nytimes.com](https://cooking.nytimes.com/recipes/1024605-cumin-and-cashew-yogurt-rice). If we wanted to select the yield element from this page, we could use the class `ingredients_recipeYield__DN65p`. However when the website is updated in the future, the `DN65p` at the end of the class name is likely to change, so we only want to use part of the class name. +An example of this is [cooking.nytimes.com](https://cooking.nytimes.com/recipes/1024605-cumin-and-cashew-yogurt-rice). If we wanted to select the yield element from +this page, we could use the class `ingredients_recipeYield__DN65p`. However when the website is +updated in the future, the `DN65p` at the end of the class name is likely to change, so we only +want to use part of the class name. There are two ways we can do this: ### Using `find` -Instead of using a string in the arguments we pass to `find`, we can use a regular expression instead. +Instead of using a string in the arguments we pass to `find`, we can use a regular expression +instead. ```python yield_tag = self.soup.find(class_=re.compile("ingredients_recipeYield")) diff --git a/docs/contributing/in-depth-guide-ingredient-groups.md b/docs/contributing/in-depth-guide-ingredient-groups.md index 4b990eeca..0512369d9 100644 --- a/docs/contributing/in-depth-guide-ingredient-groups.md +++ b/docs/contributing/in-depth-guide-ingredient-groups.md @@ -3,7 +3,10 @@ !!! warning "Under Construction" This section is being updated. Some information may be outdated or inaccurate. -Sometimes a website will format lists of ingredients using groups, where each group contains the ingredients needed for a particular aspect of the recipe. Recipe Schema has no way to represent these groupings, so all of the ingredients are presented as a single list and information about the groupings is lost. +Sometimes a website will format lists of ingredients using groups, where each group contains the +ingredients needed for a particular aspect of the recipe. Recipe Schema has no way to represent +these groupings, so all of the ingredients are presented as a single list and information about +the groupings is lost. Some examples of recipes that have ingredient groups are: @@ -11,13 +14,16 @@ Some examples of recipes that have ingredient groups are: * * -Not all websites use ingredient groups and those that do use ingredient groups will not use them for all recipes. +Not all websites use ingredient groups and those that do use ingredient groups will not use them +for all recipes. -This library allows a scraper to return the ingredients in the groups defined in the recipe if the functionality is added to that scraper. +This library allows a scraper to return the ingredients in the groups defined in the recipe if the +functionality is added to that scraper. ## `ingredient_groups()` -The `ingredient_groups()` function returns a list of `IngredientGroup` objects. Each `IngredientGroup` is a dataclass that represents a group of ingredients: +The `ingredient_groups()` function returns a list of `IngredientGroup` objects. Each +`IngredientGroup` is a dataclass that represents a group of ingredients: ```python @dataclass @@ -28,7 +34,8 @@ class IngredientGroup: ] = None # this group of ingredients is {purpose} (e.g. "For the dressing") ``` -The *purpose* is the ingredient group heading, such as *"For the dressing"*, *"For the sauce"* etc. The *ingredients* is the list of ingredients that comprise that group. +The *purpose* is the ingredient group heading, such as *"For the dressing"*, *"For the sauce"* etc. +The *ingredients* is the list of ingredients that comprise that group. This dataclass is defined in `_grouping_utils.py` and should be imported from there. @@ -36,19 +43,32 @@ This dataclass is defined in `_grouping_utils.py` and should be imported from th from ._grouping_utils import IngredientGroup ``` -The `ingredient_groups()` function has a default implementation in the `AbstractScraper` class that returns a single `IngredientGroup` object with `purpose` set to `None` and `ingredients` set to the output from the scraper's `ingredients()` function. +The `ingredient_groups()` function has a default implementation in the `AbstractScraper` class that +returns a single `IngredientGroup` object with `purpose` set to `None` and `ingredients` set to the +output from the scraper's `ingredients()` function. -Adding ingredient group support to a scraper involves overriding the `ingredient_groups` function for it. There are three important points to consider: +Adding ingredient group support to a scraper involves overriding the `ingredient_groups` function +for it. There are three important points to consider: -1. The schema.org Recipe format does not support groupings - so scraping from the HTML is required in the implementation. -1. The ingredients found in `ingredients()` and `ingredient_groups()` should be the same because we're presenting the same set of ingredients, just in a different way. There can sometimes be minor differences in the ingredients in the schema and the ingredients in the HTML which needs to be handled. -1. Not all recipes on a website will use ingredient groups, so the implementation must degrade gracefully in cases where groupings aren't available. For recipes that don't have ingredient groups, the output should be the same as default implementation (i.e. a single `IngredientGroup` with `purpose=None` and `ingredients=ingredients()`). +1. The schema.org Recipe format does not support groupings - so scraping from the HTML is required +in the implementation. +2. The ingredients found in `ingredients()` and `ingredient_groups()` should be the same because +we're presenting the same set of ingredients, just in a different way. There can sometimes be minor +differences in the ingredients in the schema and the ingredients in the HTML which needs to be +handled. +3. Not all recipes on a website will use ingredient groups, so the implementation must degrade +gracefully in cases where groupings aren't available. For recipes that don't have ingredient groups, +the output should be the same as default implementation +(i.e. a single `IngredientGroup` with `purpose=None` and `ingredients=ingredients()`). -In many cases the structure of how ingredients and group heading appear in the HTML is very similar. Some helper functions have been developed to make the implementation easier. +In many cases the structure of how ingredients and group heading appear in the HTML is very similar. +Some helper functions have been developed to make the implementation easier. ## _grouping_utils.py -The `_grouping_utils.py` file contains a helper function (`group_ingredients(...)`) that will handle the extraction of ingredients groups and their headings from the HTML, make sure the ingredients in the groups match those return from `.ingredients()`, and then return the groups. +The `_grouping_utils.py` file contains a helper function (`group_ingredients(...)`) +that will handle the extraction of ingredients groups and their headings from the HTML, make sure +the ingredients in the groups match those return from `.ingredients()`, and then return the groups. The `group_ingredients()` function takes four arguments: @@ -61,20 +81,29 @@ def group_ingredients( ) -> List[IngredientGroup]: ``` -* `ingredients_list` is the output from the `.ingredients()` function of the scraper class. This is used to make the ingredients found in the HTML match those returned by `.ingredients()`. -* `soup` is the `BeautifulSoup` object for the scraper. The ingredient groups are extracted from this. -* `group_heading` is the CSS selector for the group headings. This selector must only match the group headings in the recipe HTML. -* `group_element` is the CSS selector for the ingredients. This selector must only match the ingredients in the recipe HTML. +* `ingredients_list` is the output from the `.ingredients()` function of the scraper class. This is +* used to make the ingredients found in the HTML match those returned by `.ingredients()`. +* `soup` is the `BeautifulSoup` object for the scraper. The ingredient groups are extracted from +* this. +* `group_heading` is the CSS selector for the group headings. This selector must only match the +* group headings in the recipe HTML. +* `group_element` is the CSS selector for the ingredients. This selector must only match the +* ingredients in the recipe HTML. ### Example -Many recipe blogs use WordPress and the WordPress Recipe Manager plugin. This means they often use the same HTML elements and CSS classes to represent the same things. One such example is . +Many recipe blogs use WordPress and the WordPress Recipe Manager plugin. This means they often use +the same HTML elements and CSS classes to represent the same things. +One such example is . If we look at the recipe: -The group headings in this recipe are all `h4` headings inside an element with the class `wprm-recipe-ingredient-group`. Therefore we can select all ingredient group headings with the selector: `.wprm-recipe-ingredient-group h4` +The group headings in this recipe are all `h4` headings inside an element with the +class `wprm-recipe-ingredient-group`. Therefore we can select all ingredient group headings +with the selector: `.wprm-recipe-ingredient-group h4` -The ingredients are all elements with the class `wprm-recipe-ingredient`. Therefore we can select all ingredients with the selector: `.wprm-recipe-ingredient` +The ingredients are all elements with the class `wprm-recipe-ingredient`. Therefore we can select +all ingredients with the selector: `.wprm-recipe-ingredient` The implementation in the scraper looks like @@ -106,19 +135,32 @@ Some other examples of scrapers that support ingredient groups are: **What if `group_ingredients()` doesn't work?** -The `group_ingredients` function relies on being able to identify all the group headings with a single CSS selector and all the ingredients with a single CSS selector. However, this is not always possible - it depends on how the website lays out its HTML. +The `group_ingredients` function relies on being able to identify all the group headings with a +single CSS selector and all the ingredients with a single CSS selector. However, this is not always +possible - it depends on how the website lays out its HTML. -In these cases, supporting ingredient groups may still be possible. The `group_ingredients()` helper method is only that: an optional helper -- you can always implement custom grouping logic yourself by overriding `ingredient_groups()` directly in your scraper if you can't find suitable CSS selectors for the ingredients and groups. +In these cases, supporting ingredient groups may still be possible. The `group_ingredients()` helper +method is only that: an optional helper -- you can always implement custom grouping logic yourself +by overriding `ingredient_groups()` directly in your scraper if you can't find suitable CSS +selectors for the ingredients and groups. -An example of a scraper that supports ingredient groups without using the `group_ingredients()` helper is [NIHHealthyEating](https://github.com/hhursev/recipe-scrapers/blob/main/recipe_scrapers/nihhealthyeating.py). +An example of a scraper that supports ingredient groups without using the `group_ingredients()` +helper is [NIHHealthyEating](https://github.com/hhursev/recipe-scrapers/blob/main/recipe_scrapers/nihhealthyeating.py). ## Tests -Recipe websites often provide ingredient groupings on some, but not all, of their recipe webpages. When this is the case, we should add at least two test cases for our scraper: one to cover a recipe **with** ingredient groupings, and one to cover a recipe **without** them. +Recipe websites often provide ingredient groupings on some, but not all, of their recipe webpages. +When this is the case, we should add at least two test cases for our scraper: one to cover a +recipe **with** ingredient groupings, and one to cover a recipe **without** them. -Test cases **without** ingredient groupings in the HTML are simpler, because every scraper test case *automatically* inherits a test that checks to make sure the output of `.ingredients()` is consistent with the output from `.ingredient_groups()`, and that provides all the test coverage we need. +Test cases **without** ingredient groupings in the HTML are simpler, because every scraper test +case *automatically* inherits a test that checks to make sure the output of `.ingredients()` is +consistent with the output from `.ingredient_groups()`, and that provides all the test coverage +we need. -The test case **with** ingredient grouping should include an `ingredient_groups` item in the JSON data with each section of the ingredients separated out in the applicable test case like this example: +The test case **with** ingredient grouping should include an `ingredient_groups` item in the JSON +data with each section of the ingredients separated out in the applicable test case like this +example: ```json "ingredient_groups": [ diff --git a/docs/contributing/in-depth-guide-scraper-functions.md b/docs/contributing/in-depth-guide-scraper-functions.md index f797fc642..da6f725a3 100644 --- a/docs/contributing/in-depth-guide-scraper-functions.md +++ b/docs/contributing/in-depth-guide-scraper-functions.md @@ -3,19 +3,24 @@ !!! warning "Under Construction" This section is being updated. Some information may be outdated or inaccurate. -Each website scraper has a number of functions that return information about the recipe that has been scraped. Due to the variability in how recipes are written, not all of them are always applicable. These functions fall into three categories: +Each website scraper has a number of functions that return information about the recipe that has +been scraped. Due to the variability in how recipes are written, not all of them are always +applicable. These functions fall into three categories: 1. Mandatory functions - These functions can be expected to be available for all Scraper classes and combined provide the majority of the information for a recipe. + These functions can be expected to be available for all Scraper classes and combined provide the + majority of the information for a recipe. -1. Inherited functions +2. Inherited functions - These functions are always available for all Scraper classes. They are implemented in the `AbstractScraper` base class and rarely require overriding in the Scraper class. + These functions are always available for all Scraper classes. They are implemented in the + `AbstractScraper` base class and rarely require overriding in the Scraper class. -1. Optional functions +3. Optional functions - These functions provide extra information about a recipe, from the particular websites that support them. + These functions provide extra information about a recipe, from the particular websites that + support them. All of the examples below come from . @@ -28,7 +33,9 @@ All of the examples below come from str` -Returns the author of the recipe. This is typically a person's name but can sometimes be an organization or the name of the website the recipe came from. If the recipe does not explicitly define an author, this should return the name of the website. +Returns the author of the recipe. This is typically a person's name but can sometimes be an +organization or the name of the website the recipe came from. If the recipe does not explicitly +define an author, this should return the name of the website. ```py >>> scraper.author() @@ -37,16 +44,19 @@ Returns the author of the recipe. This is typically a person's name but can some ### `host() -> str` -Returns the host of the website the Scraper class is for. This is a constant `str` set in each Scraper class. +Returns the host of the website the Scraper class is for. This is a constant `str` set in each +Scraper class. -```python +```py >>> scraper.host() 'bbcgoodfood.com' ``` ### `description() -> str` -Returns a description of the recipe. This is normally a sentence or short paragraph describing the recipe. Often the website defines the description, but sometimes it has to be inferred from the page content. +Returns a description of the recipe. This is normally a sentence or short paragraph describing the +recipe. Often the website defines the description, but sometimes it has to be inferred from the +page content. ```py >>> scraper.description() @@ -55,7 +65,8 @@ Returns a description of the recipe. This is normally a sentence or short paragr ### `image() -> str` -Returns the URL to the main image associated with the recipe, usually a photograph of the completed recipe. +Returns the URL to the main image associated with the recipe, usually a photograph of the completed +recipe. ```py >>> scraper.image() @@ -64,7 +75,10 @@ Returns the URL to the main image associated with the recipe, usually a photogra ### `ingredients() -> List[str]` -Returns the ingredients needed to make the recipe as a `list` of `str`. Each element of the list is usually a single sentence stating an ingredient, the required amount and any additional comments. The elements of the list should mirror the ingredients written on the website and should not include non-ingredient sentences such as sub-headings. +Returns the ingredients needed to make the recipe as a `list` of `str`. Each element of the list is +usually a single sentence stating an ingredient, the required amount and any additional comments. +The elements of the list should mirror the ingredients written on the website and should not include +non-ingredient sentences such as sub-headings. ```py >>> scraper.ingredients() @@ -88,7 +102,8 @@ Returns the ingredients needed to make the recipe as a `list` of `str`. Each ele ### `instructions() -> str` -Returns a single `str` containing all instruction steps. Where a recipe has multiple instructions, each step is separated in the returned `str` by a newline character (`\n`). +Returns a single `str` containing all instruction steps. Where a recipe has multiple instructions, +each step is separated in the returned `str` by a newline character (`\n`). ```py >>> scraper.instructions() @@ -97,7 +112,8 @@ Returns a single `str` containing all instruction steps. Where a recipe has mult > [!IMPORTANT] > -> Occasionally, a recipe will have steps that have new lines within them. At the moment, this library cannot distinguish between a newline within a step and a newline between steps. +> Occasionally, a recipe will have steps that have new lines within them. At the moment, this +> librarycannot distinguish between a newline within a step and a newline between steps. ### `title() -> str` @@ -119,7 +135,8 @@ Returns the total time required to complete the recipe, in minutes. ### `yields() -> str` -Returns the number of items or servings the recipe will make. This `str` includes the quantity and unit of the yield, for example: 4 servings, 6 items, 12 cookies. +Returns the number of items or servings the recipe will make. This `str` includes the quantity and +unit of the yield, for example: 4 servings, 6 items, 12 cookies. ```py >>> scraper.yields() @@ -130,7 +147,9 @@ Returns the number of items or servings the recipe will make. This `str` include ### `canonical_url() -> str` -Returns the canonical URL for the scraped recipe. The canonical URL is the direct URL (defined by the website) at which the recipe can be found. This URL will generally not contain any query parameters or fragments, except those required to load the recipe. +Returns the canonical URL for the scraped recipe. The canonical URL is the direct URL (defined by +the website) at which the recipe can be found. This URL will generally not contain any query +parameters or fragments, except those required to load the recipe. ```py >>> scraper.canonical_url() @@ -139,13 +158,19 @@ Returns the canonical URL for the scraped recipe. The canonical URL is the direc ### `ingredient_groups() -> List[IngredientGroup]` -Returns a `list` of groups of ingredients. Some recipes on some websites will present the ingredients in groups, where each group contains the ingredients required for a particular aspect of the recipe. +Returns a `list` of groups of ingredients. Some recipes on some websites will present the +ingredients in groups, where each group contains the ingredients required for a particular aspect +of the recipe. -Each element of the returned `list` is an `IngredientGroup` object. An `IngredientGroup` object has a `purpose` (for example, *for the sauce*) and a `list` of ingredients. +Each element of the returned `list` is an `IngredientGroup` object. An `IngredientGroup` object has +a `purpose` (for example, *for the sauce*) and a `list` of ingredients. > [!IMPORTANT] > -> All scrapers inherit this function. By default, it returns a single group with purpose of `None` and the ingredients set to the output of `ingredients()`. This function should be overridden in scrapers for website that use ingredient groups. See [this guide](in-depth-guide-ingredient-groups.md) for help on implementing this. +> All scrapers inherit this function. By default, it returns a single group with purpose of `None` +> and the ingredients set to the output of `ingredients()`. This function should be overridden in +> scrapers for website that use ingredient groups. See [this guide](in-depth-guide-ingredient-groups.md) for help on implementing +> this. ```py >>> scraper.ingredient_groups() @@ -176,7 +201,8 @@ Each element of the returned `list` is an `IngredientGroup` object. An `Ingredie ### `instruction_list()` -Return a `list` of instructions. This `list` is generated by splitting the output of `instructions()` on newline characters. +Return a `list` of instructions. This `list` is generated by splitting the output of +`instructions()` on newline characters. ```py >>> scraper.instructions_list() @@ -203,7 +229,8 @@ For a comprehensive list of BCP 47 language codes, refer to this GitHub Gist: ### `links() -> List[Dict[str, str]]` -Returns a `list` of all links found in the page HTML defined in an `` element. For each link, the attributes of the HTML element are returned as a `dict`. +Returns a `list` of all links found in the page HTML defined in an `` element. For each link, +the attributes of the HTML element are returned as a `dict`. ```py >>> scraper.links() @@ -220,7 +247,8 @@ Returns a `list` of all links found in the page HTML defined in an `` element ### `site_name() -> str | None` -Returns the website name, as defined in the page's HTML. If the page does not define this, this function returns `None` +Returns the website name, as defined in the page's HTML. If the page does not define this, this +function returns `None` ```py >>> scraper.site_name() @@ -245,7 +273,9 @@ Returns the output of all functions implemented by this scraper as a `dict`. ### `category() -> str` -Semi-structured field that can contain a mix of cuisine type (for example, country names), mealtime (breakfast/dinner/etc) and dietary properties (gluten-free, vegetarian). The value is defined by the website, so it may overlap with other scraper functions (e.g. `cuisine()`). +Semi-structured field that can contain a mix of cuisine type (for example, country names), +mealtime (breakfast/dinner/etc) and dietary properties (gluten-free, vegetarian). The value is +defined by the website, so it may overlap with other scraper functions (e.g. `cuisine()`). ```py >>> scraper.category() @@ -272,7 +302,9 @@ Returns the cuisine of the recipe. ### `nutrients() -> Dict[str, str]` -Returns a `dict` of nutrition information. Each nutrition item is usually given per unit of yield, e.g. per servings, per item. The keys of the `dict` are the nutrients (including calories) and the values are the amount of that nutrient, including the unit. +Returns a `dict` of nutrition information. Each nutrition item is usually given per unit of yield, +e.g. per servings, per item. The keys of the `dict` are the nutrients (including calories) and the +values are the amount of that nutrient, including the unit. ```py >>> scraper.nutrients() @@ -299,7 +331,8 @@ Returns the time to prepare the ingredients for the recipe in minutes. ### `ratings() -> float` -Returns the recipe rating. When available, this is usually the average of all the ratings given to the recipe on the website. +Returns the recipe rating. When available, this is usually the average of all the ratings given to +the recipe on the website. ```py scraper.ratings() @@ -317,7 +350,8 @@ scraper.ratings_count() ### `reviews() -> List[Dict[str, str]]` -Returns a `list` of reviews about the recipe from the website. Each review is a `dict` containing the reviewer's name (`str`) and their review (`str`). +Returns a `list` of reviews about the recipe from the website. Each review is a `dict` containing +the reviewer's name (`str`) and their review (`str`). ### `equipment() -> List[str] | None` diff --git a/docs/contributing/setup.md b/docs/contributing/setup.md index b0e86352e..949d459f3 100644 --- a/docs/contributing/setup.md +++ b/docs/contributing/setup.md @@ -107,14 +107,16 @@ automatically when you commit changes, handling tasks like: ## Syncing Your Fork -To keep your fork up-to-date with the original repository, you can fetch and merge changes from the upstream remote: +To keep your fork up-to-date with the original repository, you can fetch and merge changes from +the upstream remote: ```sh git fetch upstream git merge upstream/main ``` -Then create a Pull Request back to the [main repository](https://github.com/hhursev/recipe-scrapers) from your fork. +Then create a Pull Request back to the [main repository](https://github.com/hhursev/recipe-scrapers) +from your fork. If you have troubles check out [Submitting A Pull Request Section](#submitting-a-pull-request). @@ -134,7 +136,8 @@ If you have troubles check out [Submitting A Pull Request Section](#submitting- When you submit your PR: -1. Our CI suite will run against your code to ensure everything works as expected. You can run the tests locally before submitting: +1. Our CI suite will run against your code to ensure everything works as expected. You can run the +2. tests locally before submitting: ```sh python -m unittest # or @@ -151,4 +154,5 @@ unittest-parallel --level test - Your contribution will be included in the next release - Tackle any follow-up improvements in subsequent PRs -Don't worry if your first PR needs some adjustments - this is normal and part of the collaborative development process! +Don't worry if your first PR needs some adjustments - this is normal and part of the collaborative +development process! diff --git a/docs/copyright-and-usage.md b/docs/copyright-and-usage.md index f17b2b349..73bd289aa 100644 --- a/docs/copyright-and-usage.md +++ b/docs/copyright-and-usage.md @@ -2,7 +2,9 @@ ## Overview -`recipe-scrapers` is a Python library that provides tools for extracting structured recipe data from websites. This document outlines our approach to copyright considerations and clarifies responsibilities for library maintainers and end users. +`recipe-scrapers` is a Python library that provides tools for extracting structured recipe data +from websites. This document outlines our approach to copyright considerations and clarifies +responsibilities for library maintainers and end users. ## Copyright Responsibility @@ -34,7 +36,8 @@ Many uses of `recipe-scrapers` may fall under fair use doctrine, particularly: - Transformative uses that add value to the original content - Non-commercial educational purposes -However, users should conduct their own legal analysis based on their specific use case and jurisdiction. +However, users should conduct their own legal analysis based on their specific use case and +jurisdiction. ## Best Practices for Users @@ -58,7 +61,9 @@ For contributors and maintainers: ## Disclaimer -`recipe-scrapers` is provided "as is" without warranty of any kind. The maintainers make no representations about the suitability, reliability, availability, timeliness, or accuracy of the software or its content extraction capabilities. +`recipe-scrapers` is provided "as is" without warranty of any kind. The maintainers make no +representations about the suitability, reliability, availability, timeliness, or accuracy of the +software or its content extraction capabilities. ## Additional Resources diff --git a/docs/getting-started/examples.md b/docs/getting-started/examples.md index a3dc2b667..3f18682ac 100644 --- a/docs/getting-started/examples.md +++ b/docs/getting-started/examples.md @@ -3,8 +3,8 @@ !!! important `recipe-scrapers` is designed to focus **exclusively on HTML parsing**. - This core principle guides our development and support. You'll need to implement your own solution for fetching - recipe HTML files and managing network requests. The library works best when you + This core principle guides our development and support. You'll need to implement your own solution + for fetching recipe HTML files and managing network requests. The library works best when you provide both the HTML content and its source domain. diff --git a/docs/getting-started/releases-and-license.md b/docs/getting-started/releases-and-license.md index 4306559cd..4fc422b91 100644 --- a/docs/getting-started/releases-and-license.md +++ b/docs/getting-started/releases-and-license.md @@ -23,4 +23,8 @@ pip install git+https://github.com/hhursev/recipe-scrapers.git@14.25.0 This project is licensed under the [MIT License](https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE). ### Test Data Notice -The `test_data` directory contains content from various recipe websites used for testing purposes only. This content is used under copyright exceptions including Fair Use (USA), Fair Dealing (UK, Canada, Australia), and other international copyright doctrines that permit limited use of copyrighted material for technical testing purposes. See the [test data license](https://github.com/hhursev/recipe-scrapers/blob/main/tests/test_data/LICENSE.md) for more details. +The `test_data` directory contains content from various recipe websites used for testing purposes +only. This content is used under copyright exceptions including Fair Use (USA), Fair Dealing +(UK, Canada, Australia), and other international copyright doctrines that permit limited use of +copyrighted material for technical testing purposes. See the [test data license](https://github.com/hhursev/recipe-scrapers/blob/main/tests/test_data/LICENSE.md) +for more details. diff --git a/docs/getting-started/supported-sites.md b/docs/getting-started/supported-sites.md index 02b79da09..afb3ab8d9 100644 --- a/docs/getting-started/supported-sites.md +++ b/docs/getting-started/supported-sites.md @@ -3,7 +3,7 @@ !!! success "Join Our Community" 🌟 Want to add your favorite recipe site? We'd love your help! - - 📖 Check our [contributing guidelines](../contributing/how-to-contribute.md) + - 📖 Check our [contributing guidelines](../contributing/home.md) - 🐛 Found a bug? [Open an issue](https://github.com/hhursev/recipe-scrapers/issues) - 🚀 Ready to contribute? [Submit a pull request](../contributing/setup.md)! diff --git a/docs/index.md b/docs/index.md index 952d22eaf..3da44e045 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,7 +10,10 @@ --- -`recipe-scrapers` is a Python package designed to extract recipe data from HTM content of cooking websites. It parses the HTML structure of recipe pages to provide a simple and consistent API for retrieving structured data like ingredients, instructions, cooking time, and more. Works with the python versions listed above. +`recipe-scrapers` is a Python package designed to extract recipe data from HTM content of +cooking websites. It parses the HTML structure of recipe pages to provide a simple and consistent +API for retrieving structured data like ingredients, instructions, cooking time, and more. +Works with the python versions listed above. ## Installation @@ -23,7 +26,8 @@ You can install `recipe-scrapers` using pip or your preferred Python package man !!! note - This should produce output about the installation process, with the final line reading: `Successfully installed recipe-scrapers-`. + This should produce output about the installation process, with the final line reading: + `Successfully installed recipe-scrapers-`. ## Overview @@ -52,7 +56,9 @@ Check out our [Examples](./getting-started/examples.md) section to see how to ge ## Core Functionality -`recipe-scrapers` long term aim is to focus **solely on HTML parsing** and not to handle networking operations. This design choice provides flexibility in how you retrieve HTML content and allows you to: +`recipe-scrapers` long term aim is to focus **solely on HTML parsing** and not to handle +networking operations. This design choice provides flexibility in how you retrieve HTML content +and allows you to: - Implement your own networking logic - Handle rate limiting @@ -61,11 +67,13 @@ Check out our [Examples](./getting-started/examples.md) section to see how to ge - Use your preferred HTTP client -## TLDR; +## Getting Started -👋 We suspect you've missed a few key links, such as us mentioning the [Examples](./getting-started/examples.md) and the [Supported Sites](./getting-started/supported-sites.md) section. +👋 We suspect you've missed a few key links, such as us mentioning the [Examples](./getting-started/examples.md) and +the [Supported Sites](./getting-started/supported-sites.md) section. -Thus, we drop this tiny Python snippet for you (using Python's built-in `urllib`) to showcase how you can use this package: +Thus, we drop this tiny Python snippet for you (using Python's built-in `urllib`) to showcase how +you can use this package: ```python from urllib.request import urlopen @@ -85,8 +93,10 @@ scraper.to_json() ## Why recipe-scrapers Exists Born from late-night coding sessions and a love for both food and programming, `recipe-scrapers` -evolved from a personal project into a community tool. It's open-sourced and under the [MIT license](https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE) -with a simple goal: let developers focus on building amazing food-related applications without reinventing the recipe-parsing wheel. +evolved from a personal project into a community tool. It's open-sourced and under +the [MIT license](https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE) +with a simple goal: let developers focus on building amazing food-related applications without +reinventing the recipe-parsing wheel. Today, our library helps power diverse projects across the cooking landscape: @@ -97,7 +107,9 @@ Today, our library helps power diverse projects across the cooking landscape: - Diet and nutrition trackers - Food blogs and recipe aggregators -We're excited to see what you'll create! Feel free to share your project in our [community showcase](https://github.com/hhursev/recipe-scrapers/issues/9) - we love seeing what others build with the library. +We're excited to see what you'll create! Feel free to share your project in our +[community showcase](https://github.com/hhursev/recipe-scrapers/issues/9) - we love seeing what others build with the library. !!! tip "Happy cooking with code!" - While building awesome stuff, remember to be mindful of websites' terms and fair usage - our [Copyright and Usage Guidelines](copyright-and-usage.md) will help you stay on track. + While building awesome stuff, remember to be mindful of websites' terms and fair usage - + our [Copyright and Usage Guidelines](copyright-and-usage.md) will help you stay on track. diff --git a/docs/misc/migrating-from-v14.md b/docs/misc/migrating-from-v14.md index e7795ea2c..df93a5904 100644 --- a/docs/misc/migrating-from-v14.md +++ b/docs/misc/migrating-from-v14.md @@ -5,13 +5,16 @@ ## Overview -Version 15 introduces important changes to the core API of recipe-scrapers, particularly regarding how recipes are scraped from websites. The main change is the deprecation of the `scrape_me` function in favor of more explicit HTML parsing methods. +Version 15 introduces important changes to the core API of recipe-scrapers, particularly regarding +how recipes are scraped from websites. The main change is the deprecation of the `scrape_me` +function in favor of more explicit HTML parsing methods. ## Key Changes ### 1. Deprecation of `scrape_me` -The `scrape_me` function, which was the primary method for scraping recipes in v14, is being deprecated. While it still works in v15, you'll receive deprecation warnings when using it: +The `scrape_me` function, which was the primary method for scraping recipes in v14, is being +deprecated. While it still works in v15, you'll receive deprecation warnings when using it: ```python # Old v14 approach (deprecated) @@ -38,7 +41,8 @@ scraper = scrape_html(html, org_url=url) ## Why This Change? -1. **Better Separation of Concerns**: The library now focuses solely on HTML parsing, letting you handle HTTP requests as you see fit +1. **Better Separation of Concerns**: The library now focuses solely on HTML parsing, letting +you handle HTTP requests as you see fit 2. **More Flexibility**: You can use your preferred HTTP client (requests, httpx, aiohttp, etc.) 3. **Better Error Handling**: Separate networking issues from parsing issues @@ -66,7 +70,8 @@ scraper = scrape_html(html, org_url=url) scraper = scrape_html(html, org_url=url) ``` -3. If you're using a web framework or need to handle many requests, consider using a more robust HTTP client: +3. If you're using a web framework or need to handle many requests, consider using a more +robust HTTP client: ```python # Example with requests import requests diff --git a/mkdocs.yaml b/mkdocs.yaml index 2f33d5c3b..998fd32e8 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -40,10 +40,10 @@ nav: - Migrating from v14: misc/migrating-from-v14.md - Releases & License: getting-started/releases-and-license.md - Contributing: - - How to Contribute: contributing/how-to-contribute.md + - Home: contributing/home.md - Setup: contributing/setup.md - Documentation: contributing/documentation.md - - Code Contribution: contributing/code-contribution.md + - Code Contributions: contributing/code-contribution.md - How To Develop A Scraper: contributing/how-to-develop-a-scraper.md - In-Depth Guides: - HTML Scraping: contributing/in-depth-guide-html-scraping.md From 918f897243c3bf45325e715417d9a5364cb51008 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Fri, 27 Dec 2024 19:19:48 +0200 Subject: [PATCH 73/94] Revamp GitHub issue templates - Enforce usage of templates by disabling blank issues - Add 4 streamlined templates: - New website requests - Website bug reports - Show and tell (with link to #9) - Generic template for other issues - Collect optional feedback about package usage and discovery --- .github/ISSUE_TEMPLATE/1_issue_new_webiste.md | 23 ++++++++++++++++ .github/ISSUE_TEMPLATE/2_issue_website_bug.md | 26 ++++++++++++++++++ .../ISSUE_TEMPLATE/3_issue_show_and_tell.md | 15 +++++++++++ .github/ISSUE_TEMPLATE/4_issue_other.md | 19 +++++++++++++ .github/ISSUE_TEMPLATE/config.yaml | 1 + .github/ISSUE_TEMPLATE/config.yml | 1 - .github/ISSUE_TEMPLATE/new_scraper.md | 13 --------- .github/ISSUE_TEMPLATE/scraper_bug_report.md | 27 ------------------- 8 files changed, 84 insertions(+), 41 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/1_issue_new_webiste.md create mode 100644 .github/ISSUE_TEMPLATE/2_issue_website_bug.md create mode 100644 .github/ISSUE_TEMPLATE/3_issue_show_and_tell.md create mode 100644 .github/ISSUE_TEMPLATE/4_issue_other.md create mode 100644 .github/ISSUE_TEMPLATE/config.yaml delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/new_scraper.md delete mode 100644 .github/ISSUE_TEMPLATE/scraper_bug_report.md diff --git a/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md b/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md new file mode 100644 index 000000000..df2d31eaa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md @@ -0,0 +1,23 @@ +--- +name: New website +about: Request support for a new recipe website +title: "I'd like to request support for " +labels: enhancement +assignees: '' + +--- + +Please verify the website is not listed in: https://docs.recipe-scrapers.com/getting-started/supported-sites/ + +Sample recipe URLs: +- https:// +- https:// + + + diff --git a/.github/ISSUE_TEMPLATE/2_issue_website_bug.md b/.github/ISSUE_TEMPLATE/2_issue_website_bug.md new file mode 100644 index 000000000..53b2417df --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_issue_website_bug.md @@ -0,0 +1,26 @@ +--- +name: Scraper bug +about: Report an issue with an existing scraper +title: "Scraper issue with " +labels: bug +assignees: '' + +--- + +Recipe URL with the issue: +- https:// + + +Which data is not being scraped correctly? +(e.g. ingredients, instructions, etc): + +What should be shown instead? + + + diff --git a/.github/ISSUE_TEMPLATE/3_issue_show_and_tell.md b/.github/ISSUE_TEMPLATE/3_issue_show_and_tell.md new file mode 100644 index 000000000..77ab19c82 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3_issue_show_and_tell.md @@ -0,0 +1,15 @@ +--- +name: Show and tell +about: Share what you've built using recipe-scrapers +title: "Built with recipe-scrapers: " +labels: show-and-tell +assignees: '' + +--- + +Tell us about your project built with recipe-scrapers! + +You can also share it as a comment in https://github.com/hhursev/recipe-scrapers/issues/9. + +Project details: + diff --git a/.github/ISSUE_TEMPLATE/4_issue_other.md b/.github/ISSUE_TEMPLATE/4_issue_other.md new file mode 100644 index 000000000..9c2a57114 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4_issue_other.md @@ -0,0 +1,19 @@ +--- +name: Other +about: For questions and issues that don't fit other categories +title: "" +labels: '' +assignees: '' + +--- + + + + + diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yaml new file mode 100644 index 000000000..3ba13e0ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yaml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 0086358db..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1 +0,0 @@ -blank_issues_enabled: true diff --git a/.github/ISSUE_TEMPLATE/new_scraper.md b/.github/ISSUE_TEMPLATE/new_scraper.md deleted file mode 100644 index 9b4160a3b..000000000 --- a/.github/ISSUE_TEMPLATE/new_scraper.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: New website scraper request -about: Add support for a new recipe website -title: '' -labels: enhancement -assignees: '' - ---- - -Please check that recipes published on the website you're requesting are public (we can't currently scrape recipes that require an account login), and add sample recipe URL(s) below: - -- https:// ... -- https:// ... diff --git a/.github/ISSUE_TEMPLATE/scraper_bug_report.md b/.github/ISSUE_TEMPLATE/scraper_bug_report.md deleted file mode 100644 index 9c7310184..000000000 --- a/.github/ISSUE_TEMPLATE/scraper_bug_report.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Scraper bug report -about: Report a scraper that is not working correctly -title: '' -labels: bug -assignees: '' - ---- - -**Pre-filing checks**: - -- [ ] I have searched for open issues that report the same problem -- [ ] I have checked that the bug affects the latest version of the library - -**The URL of the recipe(s) that are not being scraped correctly**: - -- https:// ... - -... - -**The results you expect to see**: - -... - -**The results (including any Python error messages) that you are seeing**: - -... From 8824f8331098b503d51437a45955e238bdbc7fba Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Fri, 27 Dec 2024 19:40:00 +0200 Subject: [PATCH 74/94] Update issue templates config and formatting.. use .yml --- .github/ISSUE_TEMPLATE/1_issue_new_webiste.md | 6 +++--- .github/ISSUE_TEMPLATE/2_issue_website_bug.md | 6 +++--- .github/ISSUE_TEMPLATE/4_issue_other.md | 9 +++++---- .github/ISSUE_TEMPLATE/{config.yaml => config.yml} | 0 4 files changed, 11 insertions(+), 10 deletions(-) rename .github/ISSUE_TEMPLATE/{config.yaml => config.yml} (100%) diff --git a/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md b/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md index df2d31eaa..3f671683d 100644 --- a/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md +++ b/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md @@ -14,10 +14,10 @@ Sample recipe URLs: - https:// - diff --git a/.github/ISSUE_TEMPLATE/2_issue_website_bug.md b/.github/ISSUE_TEMPLATE/2_issue_website_bug.md index 53b2417df..ef09d03ab 100644 --- a/.github/ISSUE_TEMPLATE/2_issue_website_bug.md +++ b/.github/ISSUE_TEMPLATE/2_issue_website_bug.md @@ -17,10 +17,10 @@ Which data is not being scraped correctly? What should be shown instead? - diff --git a/.github/ISSUE_TEMPLATE/4_issue_other.md b/.github/ISSUE_TEMPLATE/4_issue_other.md index 9c2a57114..b1fefd4bd 100644 --- a/.github/ISSUE_TEMPLATE/4_issue_other.md +++ b/.github/ISSUE_TEMPLATE/4_issue_other.md @@ -7,13 +7,14 @@ assignees: '' --- - +Describe your question or issue here - diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/config.yaml rename to .github/ISSUE_TEMPLATE/config.yml From f5188358f36d7cd9128cc7a804affa55e07867b0 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Fri, 27 Dec 2024 20:42:30 +0200 Subject: [PATCH 75/94] docs: move test data notice into the documentation Copyright and Usage section --- docs/test-data-notice.md | 57 ++++++++++++++++++++++++++++++++++++++ mkdocs.yaml | 8 ++++-- tests/test_data/LICENSE.md | 44 ----------------------------- 3 files changed, 62 insertions(+), 47 deletions(-) create mode 100644 docs/test-data-notice.md delete mode 100644 tests/test_data/LICENSE.md diff --git a/docs/test-data-notice.md b/docs/test-data-notice.md new file mode 100644 index 000000000..d5433e76a --- /dev/null +++ b/docs/test-data-notice.md @@ -0,0 +1,57 @@ +# License Notice for Test Data Directory + +This notice applies exclusively to the content within the +[test_data](https://github.com/hhursev/recipe-scrapers/tree/main/tests/test_data) directory. +This directory contains webpage content from various recipe websites, used strictly for testing +purposes. The test data is used under copyright exceptions including Fair Use (USA), Fair Dealing +(UK, Canada, Australia), and other international copyright doctrines that permit limited use +of copyrighted material for technical testing purposes. + +## Purpose of Use + +This content is used exclusively for: + +- Software testing +- Educational purposes +- Technical verification +- Functionality demonstration + +## Copyright Notice + +All recipe content, including but not limited to: + +- Recipe titles +- Ingredient lists +- Instructions +- Images +- Descriptions +- Other associated content + +remains the intellectual property of their respective original authors and websites. No claim of +ownership is made by this project over any of this content. + +## Attribution + +Each test file is named after its source website. The content within each file was obtained from +the corresponding website solely for testing the functionality of the recipe-scrapers library. + +## Limited Use Statement + +Our use of this content is strictly limited and justified because: + +1. It is used solely for testing software functionality +2. Only the minimum necessary content is stored +3. The content is not used for commercial purposes +4. The use does not negatively impact the market value of the original content +5. All content can be promptly removed upon copyright holder request +6. The use is consistent with educational and technical testing exceptions under various +international copyright laws + +## Content Removal and Privacy + +If you are a copyright holder of any content in this directory and wish to have it removed, you +can either open an issue in this repository or, if you wish to keep your privacy, contact us +through the email address listed in the [project's PyPI page](https://pypi.org/project/recipe-scrapers/) +under the Authors section. + +We'll sort it out promptly with our legal team. diff --git a/mkdocs.yaml b/mkdocs.yaml index 998fd32e8..7383ce498 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -33,14 +33,14 @@ theme: nav: - Getting Started: - - Home: index.md + - Getting Started: index.md - Examples: getting-started/examples.md - Supported Sites: getting-started/supported-sites.md - Advanced Usage: getting-started/advanced-usage.md - Migrating from v14: misc/migrating-from-v14.md - Releases & License: getting-started/releases-and-license.md - Contributing: - - Home: contributing/home.md + - Contributing: contributing/home.md - Setup: contributing/setup.md - Documentation: contributing/documentation.md - Code Contributions: contributing/code-contribution.md @@ -50,7 +50,9 @@ nav: - Scraper Functions: contributing/in-depth-guide-scraper-functions.md - Ingredient Groups: contributing/in-depth-guide-ingredient-groups.md - Debugging: contributing/in-depth-guide-debugging.md - - Copyright and Usage: copyright-and-usage.md + - Copyright and Usage: + - Copyright and Usage: copyright-and-usage.md + - Test Data Notice: test-data-notice.md markdown_extensions: - admonition diff --git a/tests/test_data/LICENSE.md b/tests/test_data/LICENSE.md deleted file mode 100644 index 686940bbb..000000000 --- a/tests/test_data/LICENSE.md +++ /dev/null @@ -1,44 +0,0 @@ -# License Notice for Test Data - -The files in this `test_data` directory contain content from various recipe websites used for testing purposes only. This content is used under copyright exceptions including Fair Use (USA), Fair Dealing (UK, Canada, Australia), and other international copyright doctrines that permit limited use of copyrighted material for technical testing purposes. - -## Purpose of Use - -This content is used exclusively for: - -- Software testing -- Educational purposes -- Technical verification -- Functionality demonstration - -## Copyright Notice - -All recipe content, including but not limited to: - -- Recipe titles -- Ingredient lists -- Instructions -- Images -- Descriptions -- Other associated content - -remains the intellectual property of their respective original authors and websites. No claim of ownership is made by this project over any of this content. - -## Attribution - -Each test file is named after its source website. The content within each file was obtained from the corresponding website solely for testing the functionality of the recipe-scrapers library. - -## Limited Use Statement - -Our use of this content is strictly limited and justified because: - -1. It is used solely for testing software functionality -2. Only the minimum necessary content is stored -3. The content is not used for commercial purposes -4. The use does not negatively impact the market value of the original content -5. All content can be promptly removed upon copyright holder request -6. The use is consistent with educational and technical testing exceptions under various international copyright laws - -## Content Removal and Privacy - -If you are a copyright holder of any content in this directory and wish to have it removed, you can either open an issue in this repository or, if you wish to keep your privacy, contact us through the email address listed in the [project's PyPI page](https://pypi.org/project/recipe-scrapers/) () under the Authors section. We'll sort it out promptly with our legal team. From d5e8518acb41ea2abf26763cd5ca2484aaa79474 Mon Sep 17 00:00:00 2001 From: Hristo Harsev Date: Fri, 27 Dec 2024 20:53:30 +0200 Subject: [PATCH 76/94] docs: simplify README and reduce duplication - Remove redundant list of supported websites in favor of docs reference - Focus README on core functionality and getting started - Point users to documentation for comprehensive site listings --- README.rst | 623 ++++------------------------------- pyproject.toml | 1 - tests/library/test_readme.py | 185 ----------- 3 files changed, 68 insertions(+), 741 deletions(-) delete mode 100644 tests/library/test_readme.py diff --git a/README.rst b/README.rst index 9154357c0..bd241764d 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,7 @@ +================= +recipe-scrapers +================= + .. image:: https://img.shields.io/github/stars/hhursev/recipe-scrapers?style=social :target: https://github.com/hhursev/recipe-scrapers/ :alt: Github @@ -20,600 +24,109 @@ :target: https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE :alt: License +------- ------- +A reliable python tool for scraping recipe data from popular cooking websites. Extract structured +recipe information including ingredients, instructions, cooking times, and nutritional data +with ease. Supports 400+ major recipe websites out of the box. -A simple scraping tool for recipe webpages. +Quick Links +----------- +- `Documentation `_ +- `Supported Sites `_ +- `Contributing Guide `_ +- `Issue Tracker `_ +- `Share Project Ideas `_ -Netiquette +Installing ---------- - -If you're using this library to collect large numbers of recipes from the web, please use the software responsibly and try to avoid creating high volumes of network traffic. - -Python's standard library provides a ``robots.txt`` `parser `_ that may be helpful to automatically follow common instructions specified by websites for web crawlers. - - -Getting Started ---------------- - -Start by using `Python's built-in package installer `_, ``pip``, to install the library: - .. code:: shell - python -m pip install recipe-scrapers - -This should produce output about the installation process, with the final line reading: ``Successfully installed recipe-scrapers-``. + pip install recipe-scrapers -To learn what the library can do, you can open a `Python interpreter session `_, and then begin typing -- and/or modifying -- the statements below: +Basic Usage +----------- .. code:: python from urllib.request import urlopen - from recipe_scrapers import scrape_html + # Example recipe URL url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" - html = urlopen(url).read().decode("utf-8") # retrieves the recipe webpage HTML - scraper = scrape_html(html, org_url=url) - scraper.title() - scraper.instructions() # etc. - # for a complete list of methods: - # help(scraper) - -Some Python HTTP clients that you can use to retrieve HTML include `requests`_, `httpx`_, and the `urllib.request module`_ included in Python's standard library. Please refer to their documentation to find out what options (timeout configuration, proxy support, etc) are available. - -.. _requests: https://pypi.org/project/requests/ - -.. _httpx: https://pypi.org/project/httpx/ - -.. _urllib.request module: https://docs.python.org/3/library/urllib.request.html - - -Scrapers available for: ------------------------ - -- `https://101cookbooks.com/ `_ -- `https://15gram.be `_ -- `https://40aprons.com/ `_ -- `https://www.750g.com `_ -- `https://abeautifulmess.com/ `_ -- `https://aberlehome.com/ `_ -- `https://abuelascounter.com/ `_ -- `https://www.acouplecooks.com `_ -- `https://addapinch.com/ `_ -- `http://www.afghankitchenrecipes.com/ `_ -- `https://aflavorjournal.com/ `_ -- `https://ah.nl/ `_ -- `https://www.ahealthysliceoflife.com/ `_ -- `https://akispetretzikis.com/ `_ -- `https://aldi-nord.de/ `_ - - `.es `__, `.fr `__, `.lu `__, `.nl `__, `.pl `__, `.pt `__ -- `https://aldi-sued.de/ `_ - - `.hu `__, `.it `__ -- `https://aldi-suisse.ch `_ -- `https://aldi.com.au/ `_ -- `https://alexandracooks.com/ `_ -- `https://alittlebityummy.com/ `_ -- `https://allrecipes.com/ `_ -- `https://allthehealthythings.com/ `_ -- `https://alltommat.se/ `_ -- `https://altonbrown.com/ `_ -- `https://amazingribs.com/ `_ -- `https://ambitiouskitchen.com/ `_ -- `https://ameessavorydish.com/ `_ -- `https://americastestkitchen.com/ `_ (*) -- `https://archanaskitchen.com/ `_ -- `https://www.argiro.gr/ `_ -- `https://www.arla.se/ `_ -- `https://www.atelierdeschefs.fr/ `_ -- `https://averiecooks.com/ `_ -- `https://www.bakels.com.au/ `_ - - `.co.uk `_ -- `https://baking-sense.com/ `_ -- `https://bakingmischief.com/ `_ -- `https://barefeetinthekitchen.com/ `_ -- `https://barefootcontessa.com/ `_ -- `https://barefootinthepines.com/ `_ -- `https://bbc.com/ `_ - - `.co.uk `__ -- `https://bbcgoodfood.com/ `_ -- `https://bestrecipes.com.au/ `_ -- `https://betterfoodguru.com/ `_ -- `https://bettybossi.ch/ `_ -- `https://bettycrocker.com/ `_ -- `https://beyondfrosting.com/ `_ -- `https://biancazapatka.com/ `_ -- `https://bigoven.com/ `_ -- `https://bitsofcarey.com/ `_ -- `https://blueapron.com/ `_ -- `https://bluejeanchef.com/ `_ -- `https://www.bodybuilding.com/ `_ -- `https://bonappetit.com/ `_ -- `https://bongeats.com/ `_ -- `https://books.ottolenghi.co.uk `_ (*) -- `https://bowlofdelicious.com/ `_ -- `https://breadtopia.com/ `_ -- `https://briceletbaklava.ch/ `_ -- `https://brokenovenbaking.com/ `_ -- `https://budgetbytes.com/ `_ -- `https://cafedelites.com/ `_ -- `https://cakemehometonight.com/ `_ -- `https://cambreabakes.com/ `_ -- `https://carlsbadcravings.com/ `_ -- `https://castironketo.net/ `_ -- `https://cdkitchen.com/ `_ -- `https://celebratingsweets.com/ `_ -- `https://chefjeanpierre.com/ `_ -- `https://chefkoch.de/ `_ -- `https://www.chefnini.com/ `_ -- `https://chefsavvy.com/ `_ -- `https://claudia.abril.com.br/ `_ -- `https://closetcooking.com/ `_ -- `https://colleenchristensennutrition.com/ `_ -- `https://comidinhasdochef.com/ `_ -- `https://cook-talk.com/ `_ -- `https://cookeatshare.com/ `_ -- `https://cookieandkate.com/ `_ -- `https://cookiesandcups.com/ `_ -- `https://cooking.nytimes.com/ `_ -- `https://cookingcircle.com/ `_ -- `https://cookinglight.com/ `_ -- `https://cookomix.com/ `_ -- `https://cookpad.com/ `_ -- `https://cookscountry.com/ `_ (*) -- `https://cooksillustrated.com/ `_ (*) -- `https://cookwell.com/ `_ -- `https://copykat.com/ `_ -- `https://www.costco.com/ `_ -- `https://countryliving.com/ `_ -- `https://creativecanning.com/ `_ -- `https://cucchiaio.it/ `_ -- `https://cuisineaz.com/ `_ -- `https://cybercook.com.br/ `_ -- `https://damndelicious.net/ `_ -- `https://www.davidlebovitz.com/ `_ -- `https://delish.com/ `_ -- `https://dinneratthezoo.com/ `_ -- `https://dinnerthendessert.com/ `_ -- `https://dish.co.nz/ `_ -- `https://dobruchut.aktuality.sk/ `_ -- `https://domesticate-me.com/ `_ -- `https://donalskehan.com/ `_ -- `https://downshiftology.com/ `_ -- `https://www.dr.dk/ `_ -- `https://www.eatingbirdfood.com/ `_ -- `https://www.eatingwell.com/ `_ -- `https://www.eatliverun.com/ `_ -- `https://eatsmarter.com/ `_ - - `.de `__ -- `https://eatthismuch.com/ `_ -- `https://eattolerant.de/ `_ -- `https://www.eatwell101.com `_ -- `https://eatwhattonight.com/ `_ -- `https://eggs.ca/ `_ -- `https://elavegan.com/ `_ -- `https://emmikochteinfach.de/ `_ -- `https://en.wikibooks.org/ `_ -- `https://epicurious.com/ `_ -- `https://www.errenskitchen.com/ `_ -- `https://ethanchlebowski.com/ `_ -- `https://www.evolvingtable.com/ `_ -- `https://www.familyfoodonthetable.com/ `_ -- `https://www.farmhouseonboone.com/ `_ -- `https://www.fattoincasadabenedetta.it/ `_ -- `https://felix.kitchen `_ -- `https://fifteenspatulas.com/ `_ -- `https://finedininglovers.com/ `_ -- `https://fitmencook.com/ `_ -- `https://fitslowcookerqueen.com `_ -- `https://food.com/ `_ -- `https://food52.com/ `_ -- `https://foodandwine.com/ `_ -- `https://foodfidelity.com/ `_ -- `https://foodnetwork.co.uk/ `_ - - `.com `__ -- `https://foodrepublic.com/ `_ -- `https://www.forksoverknives.com/ `_ -- `https://forktospoon.com/ `_ -- `https://franzoesischkochen.de/ `_ -- `https://www.gesund-aktiv.com/ `_ -- `https://gimmesomeoven.com/ `_ -- `https://glutenfreeonashoestring.com/ `_ -- `https://godt.no/ `_ -- `https://gonnawantseconds.com/ `_ -- `https://goodfooddiscoveries.com/ `_ -- `https://goodhousekeeping.com/ `_ -- `https://gourmettraveller.com.au/ `_ -- `https://www.grandfrais.com/ `_ -- `https://greatbritishchefs.com/ `_ -- `https://grimgrains.com/ `_ -- `http://www.grouprecipes.com/ `_ -- `https://halfbakedharvest.com/ `_ -- `https://handletheheat.com/ `_ -- `https://www.hassanchef.com/ `_ -- `https://headbangerskitchen.com/ `_ -- `https://healthyeating.nhlbi.nih.gov/ `_ -- `https://heatherchristo.com/ `_ -- `https://www.heb.com/ `_ -- `https://hellofresh.com/ `_ - - `.at `__, `.be `__, `.ca `__, `.ch `__, `.co.nz `__, `.co.uk `__, `.com.au `__, `.de `__, `.dk `__, `.es `__, `.fr `__, `.ie `__, `.it `__, `.lu `__, `.nl `__, `.no `__, `.se `__ -- `https://www.hersheyland.com/ `_ -- `https://hofer.at/ `_ - - `.si `__ -- `https://www.homechef.com/ `_ -- `https://hostthetoast.com/ `_ -- `https://hungryhappens.net/ `_ -- `https://www.ica.se/ `_ -- `https://www.im-worthy.com/ `_ -- `https://inbloombakery.com/ `_ -- `https://indianhealthyrecipes.com `_ -- `https://ingoodflavor.com `_ -- `https://www.innit.com/ `_ -- `https://insanelygoodrecipes.com `_ -- `https://inspiralized.com/ `_ -- `https://inspiredtaste.net/ `_ -- `https://irishcentral.com/ `_ -- `https://izzycooking.com/ `_ -- `https://jamieoliver.com/ `_ -- `https://jimcooksfoodgood.com/ `_ -- `https://www.jocooks.com/ `_ -- `https://joshuaweissman.com/ `_ -- `https://joyfoodsunshine.com/ `_ -- `https://joythebaker.com/ `_ -- `https://juliegoodwin.com.au/ `_ -- `https://justataste.com/ `_ -- `https://justbento.com/ `_ -- `https://www.justonecookbook.com/ `_ -- `https://kalejunkie.com/ `_ -- `https://kennymcgovern.com/ `_ -- `https://keukenliefde.nl/ `_ -- `https://www.kingarthurbaking.com `_ -- `https://kitchenaid.com.au/ `_ -- `https://kitchendivas.com `_ -- `https://www.kitchendreaming.com `_ -- `https://www.kitchensanctuary.com/ `_ -- `https://www.kitchenstories.com/ `_ -- `https://kochbar.de/ `_ -- `https://kochbucher.com/ `_ -- `http://koket.se/ `_ -- `https://kristineskitchenblog.com/ `_ -- `https://krollskorner.com/ `_ -- `https://kuchnia-domowa.pl/ `_ -- `https://kuchynalidla.sk/ `_ -- `https://www.kwestiasmaku.com/ `_ -- `https://lanascooking.com/ `_ -- `https://www.latelierderoxane.com `_ -- `https://leanandgreenrecipes.net `_ -- `https://www.lecker.de `_ -- `https://lecremedelacrumb.com/ `_ -- `https://leitesculinaria.com `_ -- `https://lekkerensimpel.com `_ -- `https://leukerecepten.nl/ `_ -- `https://lifestyleofafoodie.com `_ -- `https://littlespicejar.com/ `_ -- `https://littlesunnykitchen.com/ `_ -- `http://livelytable.com/ `_ -- `https://lovingitvegan.com/ `_ -- `https://www.maangchi.com `_ -- `https://www.madamecuisine.de `_ -- `https://madensverden.dk/ `_ -- `https://madsvin.com/ `_ -- `https://makeitdairyfree.com/ `_ -- `https://marmiton.org/ `_ -- `https://www.marthastewart.com/ `_ -- `https://matprat.no/ `_ -- `https://www.mccormick.com/ `_ -- `https://meganvskitchen.com/ `_ -- `https://meljoulwan.com/ `_ -- `https://www.melskitchencafe.com/ `_ -- `https://www.miljuschka.nl/ `_ -- `http://mindmegette.hu/ `_ -- `https://minimalistbaker.com/ `_ -- `https://ministryofcurry.com/ `_ -- `https://misya.info/ `_ -- `https://www.mob.co.uk/ `_ -- `https://mobkitchen.co.uk/ `_ -- `https://www.modernhoney.com/ `_ -- `https://www.momontimeout.com/ `_ -- `https://momswithcrockpots.com/ `_ -- `http://motherthyme.com/ `_ -- `https://www.moulinex.fr/ `_ -- `https://www.mundodereceitasbimby.com.pt/ `_ -- `https://mybakingaddiction.com/ `_ -- `https://myjewishlearning.com/ `_ -- `https://mykitchen101.com/ `_ -- `https://mykitchen101en.com/ `_ -- `https://mykoreankitchen.com/ `_ -- `https://www.myplate.gov/ `_ -- `https://myrecipes.com/ `_ -- `https://myvegetarianroots.com/ `_ -- `https://natashaskitchen.com/ `_ -- `https://www.nhs.uk/healthier-families/ `_ -- `https://nibbledish.com/ `_ -- `https://noracooks.com/ `_ -- `https://norecipes.com/ `_ -- `https://nosalty.hu/ `_ -- `https://www.notenoughcinnamon.com/ `_ -- `https://nourishedbynutrition.com/ `_ -- `https://www.nrk.no/ `_ -- `https://www.number-2-pencil.com/ `_ -- `https://nutritionbynathalie.com/blog `_ -- `https://nutritionfacts.org/ `_ -- `https://ohsheglows.com/ `_ -- `https://omnivorescookbook.com `_ -- `https://www.onceuponachef.com `_ -- `https://onesweetappetite.com/ `_ -- `https://owen-han.com/ `_ -- `https://www.paleorunningmomma.com/ `_ -- `https://www.panelinha.com.br/ `_ -- `https://paninihappy.com/ `_ -- `https://www.peelwithzeal.com/ `_ -- `https://www.persnicketyplates.com/ `_ -- `https://www.pickuplimes.com/ `_ -- `https://pinchofyum.com/ `_ -- `https://www.pingodoce.pt/ `_ -- `https://pinkowlkitchen.com/ `_ -- `https://www.platingpixels.com/ `_ -- `https://plowingthroughlife.com/ `_ -- `https://popsugar.com/ `_ -- `https://potatorolls.com/ `_ -- `https://practicalselfreliance.com/ `_ -- `https://pressureluckcooking.com/ `_ -- `https://www.primaledgehealth.com/ `_ -- `https://www.projectgezond.nl/ `_ -- `https://przepisy.pl/ `_ -- `https://purelypope.com/ `_ -- `https://purplecarrot.com/ `_ -- `https://quitoque.fr/ `_ -- `https://rachlmansfield.com/ `_ -- `https://rainbowplantlife.com/ `_ -- `https://realfood.tesco.com/ `_ -- `https://realsimple.com/ `_ -- `https://receitas.globo.com/ `_ -- `https://receitas.ig.com.br/ `_ -- `https://www.receitasnestle.com.br `_ -- `https://recept.se/ `_ -- `https://receptyprevas.sk/ `_ -- `https://recette.plus/ `_ -- `https://www.recipegirl.com/ `_ -- `https://recipeland.com/ `_ -- `https://reciperunner.com/ `_ -- `https://recipes.farmhousedelivery.com/ `_ -- `https://recipes.timesofindia.com/ `_ -- `https://recipetineats.com/ `_ -- `https://redhousespice.com/ `_ -- `https://reishunger.de/ `_ -- `https://rewe.de/ `_ -- `https://rezeptwelt.de/ `_ -- `https://ricetta.it/ `_ -- `https://ricette.giallozafferano.it/ `_ -- `https://www.ricetteperbimby.it/ `_ -- `https://rosannapansino.com `_ -- `https://rutgerbakt.nl/ `_ -- `https://www.saboresajinomoto.com.br/ `_ -- `https://sallys-blog.de `_ -- `https://sallysbakingaddiction.com `_ -- `https://saltpepperskillet.com/ `_ -- `https://sandwichtribunal.com/ `_ -- `https://www.saveur.com/ `_ -- `https://www.savorynothings.com/ `_ -- `https://schoolofwok.co.uk/ `_ -- `https://seriouseats.com/ `_ -- `https://shelikesfood.com/ `_ -- `https://simple-veganista.com/ `_ -- `https://simply-cookit.com/ `_ -- `https://simplyquinoa.com/ `_ -- `https://simplyrecipes.com/ `_ -- `https://simplywhisked.com/ `_ -- `https://skinnytaste.com/ `_ -- `https://smulweb.nl/ `_ -- `https://sobors.hu/ `_ -- `https://www.southerncastiron.com/ `_ -- `https://southernliving.com/ `_ -- `https://spainonafork.com/ `_ -- `https://spendwithpennies.com/ `_ -- `https://www.springlane.de `_ -- `https://stacyling.com/ `_ -- `https://www.staysnatched.com/ `_ -- `https://steamykitchen.com/ `_ -- `https://streetkitchen.hu/ `_ -- `https://www.strongrfastr.com `_ -- `https://sugarhero.com/ `_ -- `https://sunbasket.com/ `_ -- `https://sundpaabudget.dk/ `_ -- `https://www.sunset.com/ `_ -- `https://sweetcsdesigns.com/ `_ -- `https://sweetpeasandsaffron.com/ `_ -- `https://www.taste.com.au/ `_ -- `https://www.tasteatlas.com/ `_ -- `https://tasteofhome.com `_ -- `https://tastesbetterfromscratch.com `_ -- `https://tastesoflizzyt.com `_ -- `https://tasty.co `_ -- `https://tastykitchen.com/ `_ -- `https://theclevercarrot.com/ `_ -- `https://www.thecookierookie.com/ `_ -- `https://thecookingguy.com/ `_ -- `https://thefoodietakesflight.com/ `_ -- `https://theglutenfreeaustrian.com/ `_ -- `https://thehappyfoodie.co.uk/ `_ -- `https://thekitchencommunity.org/ `_ -- `https://www.thekitchenmagpie.com/ `_ -- `https://thekitchn.com/ `_ -- `https://theloopywhisk.com/ `_ -- `https://www.themagicalslowcooker.com/ `_ -- `https://themediterraneandish.com/ `_ -- `https://themodernproper.com/ `_ -- `https://www.thepalatablelife.com `_ -- `https://thepioneerwoman.com/ `_ -- `https://therecipecritic.com/ `_ -- `https://thesaltymarshmallow.com/ `_ -- `https://thespruceeats.com/ `_ -- `https://thevintagemixer.com/ `_ -- `https://thewoksoflife.com/ `_ -- `https://thinlicious.com/ `_ -- `https://tidymom.net `_ -- `https://tine.no/ `_ -- `https://tofoo.co.uk `_ -- `https://tudogostoso.com.br/ `_ -- `https://twopeasandtheirpod.com/ `_ -- `https://uitpaulineskeuken.nl/ `_ -- `https://unsophisticook.com/ `_ -- `https://usapears.org/ `_ -- `https://www.valdemarsro.dk/ `_ -- `https://vanillaandbean.com/ `_ -- `https://varecha.pravda.sk/ `_ -- `https://www.vegetarbloggen.no/ `_ -- `https://vegolosi.it/ `_ -- `https://vegrecipesofindia.com/ `_ -- `https://veroniquecloutier.com `_ -- `https://www.waitrose.com/ `_ -- `https://watchwhatueat.com/ `_ -- `https://wearenotmartha.com/ `_ -- `https://wedishitup.com/ `_ -- `https://www.weightwatchers.com/ `_ (*) -- `https://www.wellplated.com/ `_ -- `https://whatsgabycooking.com/ `_ -- `https://whole30.com/ `_ -- `https://www.wholefoodsmarket.com/ `_ - - `.co.uk `__ -- `https://www.williams-sonoma.com/ `_ -- `https://womensweeklyfood.com.au/ `_ -- `https://woop.co.nz/ `_ -- `https://yemek.com/ `_ -- `https://yummly.com/ `_ (*) -- `https://www.zaubertopf.de `_ -- `https://zeit.de/ (wochenmarkt) `_ -- `https://zenbelly.com/ `_ - -(*) offline saved files only - - -Contribute ----------- - -If you spot a design change (or something else) that makes the scraper unable to work for a given site - please fire an issue asap. - -If you are programmer PRs with fixes are warmly welcomed and acknowledged with a virtual beer. You can find documentation on how to develop scrapers `here `__. - - -If you want a scraper for a new site added ------------------------------------------- - -- Open an `Issue `_ providing us the site name, as well as a recipe link from it. -- You are a developer and want to code the scraper on your own: - - - If `Schema is available <#faq>`_ on the site - `you can go like this. `_ - - Otherwise, scrape the HTML - `like this `_ - - Generating a new scraper class: + # retrieve the recipe webpage HTML + html = urlopen(url).read().decode("utf-8") - .. code:: shell - - python generate.py - - - **ClassName**: The name of the new scraper class. - - **URL**: The URL of an example recipe from the target site. The content will be stored in ``test_data`` to be used with the test class. - - You can find a more detailed guide `here `__. - - -For Devs / Contribute ---------------------- + # pass the html alongside the url to our scrape_html function + scraper = scrape_html(html, org_url=url) -Assuming you have ``>=python3.9`` installed, navigate to the directory where you want this project to live in and drop these lines + # Extract recipe information + print(scraper.title()) # "Spinach and Feta Turkey Burgers" + print(scraper.total_time()) # 35 + print(scraper.yields()) # "4 servings" + print(scraper.ingredients()) # ['1 pound ground turkey', '1 cup fresh spinach...'] + print(scraper.instructions()) # 'Step 1: In a large bowl...' -.. code:: shell + # For a complete list of available methods: + help(scraper) - git clone git@github.com:hhursev/recipe-scrapers.git && - cd recipe-scrapers && - python -m venv .venv && - source .venv/bin/activate && - python -m pip install --upgrade pip && - pip install -e ".[dev]" && - pip install pre-commit && - pre-commit install && - python -m unittest -In case you want to run a single unittest for a newly developed scraper +HTTP Clients +------------ +Some Python HTTP clients you can use to retrieve HTML include: -.. code:: shell +- `requests`_: Popular and feature-rich +- `httpx`_: Modern, supports async/await +- `urllib.request`_: Included in Python's standard library - python -m unittest -k +Please refer to their documentation to find out what options (timeout configuration, proxy +support, etc) are available. +.. _requests: https://pypi.org/project/requests/ +.. _httpx: https://pypi.org/project/httpx/ +.. _urllib.request: https://docs.python.org/3/library/urllib.request.html -FAQ ---- -**What if the recipe site I want to extract information from is not listed above?** -You can give it a try with the ``wild_mode`` option! +Supported Sites +--------------- +We support a wide range of recipe websites out of the box. Check our +`supported sites list `_ +for the full list. -If there is Schema/Recipe available it will work just fine. +You can also get the full list programmatically with: .. code:: python - url = 'https://www.feastingathome.com/tomato-risotto/' - name = input('What is your name, risotto sampler?\n') - html = requests.get(url, headers={"User-Agent": f"Risotto Sampler {name}"}).content - scraper = scrape_html(html, org_url=url, wild_mode=True) + from recipe_scrapers import SCRAPERS - scraper.host() - scraper.title() - scraper.total_time() - scraper.image() - scraper.ingredients() - scraper.ingredient_groups() - scraper.instructions() - scraper.instructions_list() - scraper.yields() - scraper.to_json() - scraper.links() - scraper.nutrients() # not always available - scraper.canonical_url() # not always available - scraper.equipment() # not always available - scraper.cooking_method() # not always available - scraper.keywords() # not always available - scraper.dietary_restrictions() # not always available + SCRAPERS.keys() -Notes: -- ``scraper.links()`` returns a list of dictionaries containing all of the tag attributes. The attribute names are the dictionary keys. +Documentation +------------- +For detailed usage instructions, examples, and API reference, visit our +`documentation `_. -**How do I know if a website has a Recipe Schema?** +Contributing +------------ +We welcome contributions! Please read our +`contribution guide `_ to get started. -Run in python shell: -.. code:: python - - # first ensure you have the required packages: - # pip install "recipe-scrapers[online]" - - from recipe_scrapers import scrape_html - scraper = scrape_html(html=None, org_url='', online=True, wild_mode=True) - # if no error is raised - there's schema available: - scraper.title() - scraper.instructions() # etc. - - -Special thanks to: ------------------- - -All the `contributors that helped improving `_ the package. You are awesome! +Special Thanks +-------------- +To all the `contributors `_ who +help make this project better! .. image:: https://contrib.rocks/image?repo=hhursev/recipe-scrapers :target: https://github.com/hhursev/recipe-scrapers/graphs/contributors -Test Data Notice ----------------- - -All content in ``tests/test_data/`` is used for limited, non-commercial testing purposes and belongs to their respective copyright holders. See the ``tests/test_data/LICENSE.md`` for details. If you're a copyright holder with concerns, you can open an issue or contact us privately via the email in our PyPI page. - - -Extra: ------- -| You want to gather recipes data? -| You have an idea you want to implement? -| Check out `our "Share a project" wall `_ - it may save you time and spark ideas! +Share Your Project +------------------ +Have an idea for using recipe-scrapers? Check out +our `project ideas wall `_ for inspiration +or to share your own project! diff --git a/pyproject.toml b/pyproject.toml index e51e8d578..d80b127d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,7 +67,6 @@ docs = [ tests = [ "coverage >= 7.6.9", # Code coverage measurement tool "unittest-parallel >= 1.7.0", # Run unittest tests in parallel - "importlib-metadata >= 4.6 ; python_version < '3.10'", # used in test_readme ] linters = [ "pre-commit == 4.0.1", # latest from PyPI diff --git a/tests/library/test_readme.py b/tests/library/test_readme.py deleted file mode 100644 index 796455bac..000000000 --- a/tests/library/test_readme.py +++ /dev/null @@ -1,185 +0,0 @@ -import re -import sys -import unittest -from collections import defaultdict - -if sys.version_info >= (3, 10): - from importlib.metadata import PackageNotFoundError, metadata -else: - # TODO: Remove this branch once py3.10 is our minimum baseline; - # package description metadata (that we rely on for 'test_includes') is - # only available in importlib.metadata from py3.10 onwards - from importlib_metadata import PackageNotFoundError, metadata - -from typing import Optional - -from recipe_scrapers import SCRAPERS, AbstractScraper - -START_LIST = "-----------------------" -END_LIST = "(*) offline saved files only" - -ScraperIndex = dict[str, tuple[AbstractScraper, list[str]]] - - -def get_scraper_domains(): - scraper_domains = defaultdict(list) - for domain, scraper in SCRAPERS.items(): - primary_domain = scraper.host() - if domain == primary_domain: - scraper_domains[scraper].insert(0, domain) - else: - scraper_domains[scraper].append(domain) - return scraper_domains - - -def get_scraper_index() -> ScraperIndex: - scraper_index: ScraperIndex = {} - for scraper_instance, domains in get_scraper_domains().items(): - shared_prefix = get_shared_prefix(domains) - - if not shared_prefix: - # Treat all as primary domains - for domain in domains: - scraper_index[domain] = (scraper_instance, [domain]) - continue - - # Index the primary domain and include their secondary domains minus the shared prefix - primary_domain = scraper_instance.host() - secondary_domains = [ - domain[len(shared_prefix) :] if domain.startswith(shared_prefix) else domain - for domain in domains - if domain != shared_prefix - ] - scraper_index[primary_domain] = (scraper_instance, secondary_domains) - - # Produce the index sorted by primary domain name - return scraper_index - - -def get_shared_prefix(domains: list[str]) -> str: - """ - Find the longest-common-prefix of the domains - """ - if not domains: - return "" - - shared_prefix = domains[0] - for domain in domains[1:]: - while not domain.startswith(shared_prefix): - shared_prefix = shared_prefix[:-1] - if not shared_prefix: - return "" - - if "." in shared_prefix: - shared_prefix, _ = shared_prefix.rsplit(".", 1) - - return shared_prefix - - -def get_secondary_domains( - scraper_index: ScraperIndex, primary_domain: str -) -> list[str]: - _, suffixes = scraper_index[primary_domain] - return [suffix for suffix in suffixes if not primary_domain.endswith(suffix)] - - -def parse_primary_line(line: str) -> Optional[tuple[str, str]]: - match = re.search( - r"^- `https?://(?:www\.)?([^/\s]+)[^<]*]*>`_(?: \(\*\))?$", - line, - ) - if match: - groups = match.groups() - if len(groups) == 2: - return groups - return None - - -def parse_secondary_line(line: str) -> list[tuple[str, str]]: - return re.findall(r"`(\.[^\s]+)\s]+)[^>]*>`_", line) - - -def get_package_description() -> list[str]: - pkg_metadata = metadata("recipe_scrapers") - return pkg_metadata["Description"].splitlines() - - -def get_list_lines() -> list[str]: - list_lines: list[str] = [] - started_list = False - for line in get_package_description(): - stripped_line = line.strip() - if stripped_line == START_LIST: - started_list = True - continue - - if not started_list or not stripped_line: - continue - - if stripped_line == END_LIST: - break - - list_lines.append(line) - return list_lines - - -class TestReadme(unittest.TestCase): - - def test_includes(self): - scraper_index = get_scraper_index() - primary_domains = sorted(scraper_index.keys()) - - try: - lines = get_list_lines() - except PackageNotFoundError: - msg = ( - "Couldn't retrieve package metadata; is recipe_scrapers installed? " - "(if you're developing locally, try 'pip install -e .' for an editable install)" - ) - self.skipTest(msg) - - current_line_index = 0 - - for primary_host in primary_domains: - current_line = lines[current_line_index] - parse_result = parse_primary_line(current_line) - - if not parse_result: - self.fail(f"Invalid line: {current_line}") - - name_host, value_host = parse_result - self.assertEqual( - name_host, - value_host, - "The name and value hyperlink portions have different hosts.", - ) - self.assertEqual( - name_host, - primary_host, - f"The host ({name_host}) doesn't match the expected host ({primary_host})", - ) - - current_line_index += 1 - secondary_hosts = get_secondary_domains(scraper_index, primary_host) - - if secondary_hosts: - current_line = lines[current_line_index] - parse_result = parse_secondary_line(current_line) - - if not parse_result: - self.fail(f"Invalid line: {current_line}") - - sorted_secondary_hosts = sorted(secondary_hosts) - for i, secondary_host in enumerate(sorted_secondary_hosts): - if i >= len(parse_result): - self.fail( - f"Missing top level domain(s) for primary domain {primary_host}" - ) - - top_level_domain = parse_result[i][0] - self.assertEqual( - secondary_host, - top_level_domain, - f"Expected top level domain {secondary_host}, got {top_level_domain} for primary domain {primary_host}", - ) - current_line_index += 1 From 1436196d948dd15af6cf3620697db76519750b70 Mon Sep 17 00:00:00 2001 From: Brian Strauch Date: Sun, 29 Dec 2024 09:41:11 -0600 Subject: [PATCH 77/94] Update generate.py (#1451) * Currently, generate.py tries to insert new `from ... import ...` statements after the first line (See https://github.com/hhursev/recipe-scrapers/issues/1259 and https://github.com/hhursev/recipe-scrapers/pull/1427#issuecomment-2526395409). * It looks like the `node.level > 0` condition was added to skip the first item (`from __future__ import annotations`, which the generator considers to be a valid scraper class), but unfortunately `self.last_node = node` is still reached. The second time `__import()` is called, the first line is `self.last_node` and the new import is added beneath it. * This PR moves the `node.level > 0` condition up into the parent `if` statement to avoid `self.last_node = node` from being called. Luckily, this doesn't impact the `elif` beneath it. * I manually validated that we can insert a new scraper class named "AAA" and "ZZZ" --- generate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generate.py b/generate.py index ab8c7e138..ee6b32275 100644 --- a/generate.py +++ b/generate.py @@ -129,8 +129,8 @@ def _import(self, node): if isinstance(node, ast.Module) or isinstance(node, ast.Import): return True - if isinstance(node, ast.ImportFrom): - if node.module > self.module_name and node.level > 0: + if isinstance(node, ast.ImportFrom) and node.level > 0: + if node.module > self.module_name: offset = self._offset(node) import_statement = ( f"\nfrom .{self.module_name} import {self.class_name}" From 7004456af4646c22f0f3216a286612b46d631801 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sun, 5 Jan 2025 19:26:11 -0500 Subject: [PATCH 78/94] mealprepmanual (#1453) --- recipe_scrapers/__init__.py | 2 + recipe_scrapers/mealprepmanual.py | 31 + .../mealprepmanual.com/mealprepmanual_1.json | 73 + .../mealprepmanual_1.testhtml | 1413 ++++++++++++++++ .../mealprepmanual.com/mealprepmanual_2.json | 101 ++ .../mealprepmanual_2.testhtml | 1481 +++++++++++++++++ 6 files changed, 3101 insertions(+) create mode 100644 recipe_scrapers/mealprepmanual.py create mode 100644 tests/test_data/mealprepmanual.com/mealprepmanual_1.json create mode 100644 tests/test_data/mealprepmanual.com/mealprepmanual_1.testhtml create mode 100644 tests/test_data/mealprepmanual.com/mealprepmanual_2.json create mode 100644 tests/test_data/mealprepmanual.com/mealprepmanual_2.testhtml diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 5450e0b9e..ffa911df2 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -255,6 +255,7 @@ from .marthastewart import MarthaStewart from .matprat import Matprat from .mccormick import McCormick +from .mealprepmanual import MealPrepManual from .meganvskitchen import MeganVsKitchen from .meljoulwan import Meljoulwan from .melskitchencafe import MelsKitchenCafe @@ -580,6 +581,7 @@ MadameCuisine.host(): MadameCuisine, MakeItDairyFree.host(): MakeItDairyFree, McCormick.host(): McCormick, + MealPrepManual.host(): MealPrepManual, MeganVsKitchen.host(): MeganVsKitchen, Miljuschka.host(): Miljuschka, ModernHoney.host(): ModernHoney, diff --git a/recipe_scrapers/mealprepmanual.py b/recipe_scrapers/mealprepmanual.py new file mode 100644 index 000000000..93ea93d78 --- /dev/null +++ b/recipe_scrapers/mealprepmanual.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class MealPrepManual(AbstractScraper): + @classmethod + def host(cls): + return "mealprepmanual.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) diff --git a/tests/test_data/mealprepmanual.com/mealprepmanual_1.json b/tests/test_data/mealprepmanual.com/mealprepmanual_1.json new file mode 100644 index 000000000..e6a0f9bc1 --- /dev/null +++ b/tests/test_data/mealprepmanual.com/mealprepmanual_1.json @@ -0,0 +1,73 @@ +{ + "author": "Josh Cortis", + "canonical_url": "https://mealprepmanual.com/slow-cooker-big-boy-beef-stroganoff/", + "site_name": "The Meal Prep Manual", + "host": "mealprepmanual.com", + "language": "en-US", + "title": "Slow Cooker Big Boy Beef Stroganoff", + "ingredients": [ + "2½ lbs top round roast", + "½ cup cream cheese", + "2 cups beef broth", + "1 tbsp Worcestershire sauce", + "2 tsp garlic powder", + "2 tsp paprika", + "1 tsp salt", + "1 tsp pepper", + "1 medium onion", + "1 lb carrots", + "½ lb mushrooms", + "1½ lbs pasta (I used fusilli)", + "3 tbsp starch (tapioca or cornstarch)", + "¼ cup water", + "½ cup plain greek yogurt", + "1 tbsp dijon mustard", + "¼ cup chopped parsley for garnish (optional)" + ], + "instructions_list": [ + "For the Slow Cooker", + "Wash and cut all of your vegetables. Cut your onion into a small dice, the carrots into a large dice (about 1 inch pieces), and your mushrooms into a large dice as well.", + "Into the vessel of your slow cooker add the beef broth, Worcestershire sauce, onions, salt, pepper, garlic powder, and paprika. Stir to mix in the seasonings.", + "For the beef I used top round (London Broil). This is a cheap, lean piece of meat. Top sirloin is a more tender piece of beef of similar leanness but it is more expensive. Feel free to use either.", + "Lay the beef into the vessel and place it into the slow cooker. Cook on high for 4 hours or low for 6 hours.", + "When there are 30 minutes left of cook time, add in the mushrooms and carrots and stir to cover with the liquid.", + "For the Pasta", + "After you add in the vegetables you can start on your pasta. Bring a large pot of water to a boil and add the pasta of your choosing. I used fusilli.", + "Strain and set aside when finished cooking.", + "For the Sauce", + "After the slow cooker timer is finished, remove the lid and pull out the beef. Set it aside to break down.", + "Mix together 3 tbsp of tapioca starch (or cornstarch) with ¼ cup of cold water to make a slurry.", + "Drizzle the slurry into the slow cooker and stir constantly to thicken the sauce.", + "Next add in the cream cheese, Greek yogurt, and dijon mustard. Stir to melt the cheese and combine.", + "Break the beef down into bite sized pieces or shred it up. Add it to the sauce and mix.", + "Dump in your pasta and mix until all of the sauce is evenly distributed. Taste test and adjust with salt and pepper to meet your needs.", + "Plating", + "This recipe makes 5 servings. Divide the contents of the slow cooker evenly between your containers. Top with chopped parsley for garnish if you please." + ], + "category": "Main Dish", + "yields": "5 servings", + "description": "This Big Boy Beef Stroganoff is perfect for bulking season containing over 1000 calories and 80g of protein. It is made using a slow cooker to save you time and effort.", + "total_time": 260, + "cook_time": 240, + "prep_time": 20, + "cuisine": "meal prep", + "ratings": 5.0, + "ratings_count": 1, + "equipment": [ + "Slow cooker" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "1013 kcal", + "fatContent": "22 g", + "carbohydrateContent": "125 g", + "proteinContent": "80 g", + "fiberContent": "8.8 g" + }, + "image": "https://mealprepmanual.com/wp-content/uploads/2024/12/Big-Boy-Beef-Stroganoff-.jpg", + "keywords": [ + "beef", + "free", + "gluten free" + ] +} diff --git a/tests/test_data/mealprepmanual.com/mealprepmanual_1.testhtml b/tests/test_data/mealprepmanual.com/mealprepmanual_1.testhtml new file mode 100644 index 000000000..e43c874fb --- /dev/null +++ b/tests/test_data/mealprepmanual.com/mealprepmanual_1.testhtml @@ -0,0 +1,1413 @@ + + + + + + + + + + + + + + Slow Cooker Big Boy Beef Stroganoff - THE MEAL PREP MANUAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + +
+ + + +
+ + +
+ + +
+ + +
+
+
+
+
+
+
+

Slow Cooker Big Boy Beef Stroganoff

+
+
+
+
+
+
+
+ Big Boy Beef Stroganoff
+
+
+
+
+
+
+
+

Slow Cooker Big Boy Beef Stroganoff

+
+
+
+
+ + +
+
+
+
+
+ This Big Boy Beef Stroganoff is perfect for bulking season containing over 1000 calories and 80g of protein. It is made using a slow cooker to save you time and effort.
+
+
+
+
+
+
+
+ PREP TIME
+
+
+
+ 20 Minutes
+
+
+
+
+
+
+
+ COOK TIME
+
+
+
+ 4 Hours
+
+
+
+
+
+
+
+

Per Serving – Makes

+
+
+
+ 1013 Calories
+
+
+
+

125g C | 80g P | 22g F

+
+
+
+
+
+
+
+

How to Meal Prep Slow Cooker Big Boy Beef Stroganoff

+
+
+
+

A link to register for the MPM Club, a subscription service for a library of meal prep recipes

+
+
+
+

A link to register for the MPM Club, a subscription service for a library of meal prep recipes

+
+
+
+
+
Big Boy Beef Stroganoff
+
+
+

Slow Cooker Big Boy Beef Stroganoff

+
+
5 from 1 vote
+ + +
+
+
Course: Main Dish
Cuisine: meal prep
Keyword: beef, free, gluten free
+
Prep Time: 20 minutes
Cook Time: 4 hours
Total Time: 4 hours 20 minutes
+
Servings: 5 servings
+ +
Calories: 1013kcal
+ + +
+
This Big Boy Beef Stroganoff is perfect for bulking season containing over 1000 calories and 80g of protein. It is made using a slow cooker to save you time and effort.
+
+ + +Print Recipe + Pin Recipe + Share on Facebook + + + + +
+ +
+
+

Equipment

+ + +

Ingredients

  • lbs (1135 g) top round roast
  • ½ cup (150 g) cream cheese
  • 2 cups (600 g) beef broth
  • 1 tbsp (15 g) Worcestershire sauce
  • 2 tsp (6 g) garlic powder
  • 2 tsp (6 g) paprika
  • 1 tsp (6 g) salt
  • 1 tsp (3 g) pepper
  • 1 medium (200 g) onion
  • 1 lb (454 g) carrots
  • ½ lb (227 g) mushrooms
  • lbs (681 g) pasta I used fusilli
  • 3 tbsp (24 g) starch tapioca or cornstarch
  • ¼ cup (60 g) water
  • ½ cup (150 g) plain greek yogurt
  • 1 tbsp (15 g) dijon mustard
  • ¼ cup chopped parsley for garnish optional
+
+
+

Instructions

For the Slow Cooker

  • Wash and cut all of your vegetables. Cut your onion into a small dice, the carrots into a large dice (about 1 inch pieces), and your mushrooms into a large dice as well.
  • Into the vessel of your slow cooker add the beef broth, Worcestershire sauce, onions, salt, pepper, garlic powder, and paprika. Stir to mix in the seasonings.
  • For the beef I used top round (London Broil). This is a cheap, lean piece of meat. Top sirloin is a more tender piece of beef of similar leanness but it is more expensive. Feel free to use either.
  • Lay the beef into the vessel and place it into the slow cooker. Cook on high for 4 hours or low for 6 hours.
  • When there are 30 minutes left of cook time, add in the mushrooms and carrots and stir to cover with the liquid.

For the Pasta

  • After you add in the vegetables you can start on your pasta. Bring a large pot of water to a boil and add the pasta of your choosing. I used fusilli.
  • Strain and set aside when finished cooking.

For the Sauce

  • After the slow cooker timer is finished, remove the lid and pull out the beef. Set it aside to break down.
  • Mix together 3 tbsp of tapioca starch (or cornstarch) with ¼ cup of cold water to make a slurry.
  • Drizzle the slurry into the slow cooker and stir constantly to thicken the sauce.
  • Next add in the cream cheese, Greek yogurt, and dijon mustard. Stir to melt the cheese and combine.
  • Break the beef down into bite sized pieces or shred it up. Add it to the sauce and mix.
  • Dump in your pasta and mix until all of the sauce is evenly distributed. Taste test and adjust with salt and pepper to meet your needs.

Plating

  • This recipe makes 5 servings. Divide the contents of the slow cooker evenly between your containers. Top with chopped parsley for garnish if you please.
+
+
+ + +
+ +

Nutrition

Calories: 1013kcal | Carbohydrates: 125g | Protein: 80g | Fat: 22g | Fiber: 8.8g
+ + +
+ + + +

+ + + +

NUTRITIONAL INFO FOR THE Slow Cooker Big Boy Beef Stroganoff

+ + + +

The information in this table represents the estimate for the total nutrition of the recipe as it is written. If you wanted to split the recipe into more or less servings than what is originally listed you can use this table to determine the nutritional estimates.  If you update the number of servings in the “Servings” field of the recipe above, the information in these tables are no longer accurate as you have updated the ingredients.

+ + +
+
+
Servings
+
+ +
+
+
+
Carbs
+
625.8g
+
+
+
Protein
+
398.4g
+
+
+
Fat
+
107.8g
+
+
+
Calories
+
5067 cals
+
+
+
+
+
+
+
+ + +
+
+
+
+
+

Other recipes you might like

+
+ +
+
+ +
+ + + +

+ This Post Has One Comment +

+ +
    + +
  1. + +
    + + +
    +
    + Chris + + +
    + +
    + +
    + +
    +

    5 stars
    +Nice

    +
    +
    +
    + +
    + +
  2. +
+ + + + +
+
+
+ 5 from 1 vote
+
+
+

Leave a Reply

+ +
+ Recipe Rating +




+
+
+
+ +
+ +

+ +

+ +
+
+
+
+
+
+
+
+ + +
+ + +
+ + + + + + +
+ + + +
+ + + + + +
+ + + + + +
+ + + +
+ + +
+ + + + + + + + +
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+

Membership:

+
+
+
+
+
+

Status: Not logged in 

+
+
+
+
+
+

Renewal:

+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/mealprepmanual.com/mealprepmanual_2.json b/tests/test_data/mealprepmanual.com/mealprepmanual_2.json new file mode 100644 index 000000000..acad18d21 --- /dev/null +++ b/tests/test_data/mealprepmanual.com/mealprepmanual_2.json @@ -0,0 +1,101 @@ +{ + "author": "Josh Cortis", + "canonical_url": "https://mealprepmanual.com/sriracha-lime-chicken-bowls/", + "site_name": "The Meal Prep Manual", + "host": "mealprepmanual.com", + "language": "en-US", + "title": "Sriracha Lime Chicken Bowls", + "ingredients": [ + "2 lbs boneless skinless chicken thighs", + "1 lb broccoli (I use frozen)", + "1 large japanese sweet potato (any kind is fine)", + "5 stalks green onions", + "2 cups cooked rice", + "2 tbsp oil", + "3 tbsp sriracha", + "3 tbsp lime juice", + "2½ tbsp honey", + "2 tsp onion powder", + "2 tsp garlic powder", + "1 tsp salt", + "1 tsp pepper" + ], + "ingredient_groups": [ + { + "ingredients": [ + "2 lbs boneless skinless chicken thighs", + "1 lb broccoli (I use frozen)", + "1 large japanese sweet potato (any kind is fine)", + "5 stalks green onions", + "2 cups cooked rice", + "2 tbsp oil" + ], + "purpose": "For the Bowls" + }, + { + "ingredients": [ + "3 tbsp sriracha", + "3 tbsp lime juice", + "2½ tbsp honey", + "2 tsp onion powder", + "2 tsp garlic powder", + "1 tsp salt", + "1 tsp pepper" + ], + "purpose": "For the Sauce" + } + ], + "instructions_list": [ + "For the Rice", + "Cook enough rice to yield 2 cups (300g) of cooked rice. 1 cup of dry rice will make between 2-3 cups of rice depending on what kind you use.", + "For the Sauce", + "Mix the lime juice, sriracha, honey, onion powder, garlic powder, salt, and pepper together. Whisk to combine.", + "For the Chicken", + "Preheat your oven to 400 °F (204 °C).", + "Place the chicken thighs into a large bowl. Cut off any excess fat or skin from the thighs.", + "Pour roughly ½ of the sauce over the top of the chicken and mix it with the chicken until it is completely coated. Allowing it to marinate for 30 minutes to a couple of hours is best but if you want to just cook it immediately, that will do.", + "Line a sheet pan with foil and lay the chicken thighs smooth side down on the sheet pan, ensuring enough space between each thigh to promote proper browning.", + "Cook the chicken for 20-25 minutes then remove from oven and flip. Return to the oven for an additional 5-10 minutes.", + "Once finished, remove from the oven and allow it to rest before cutting.", + "For the Vegetables", + "While the chicken is cooking, wash and cut all of your vegetables.", + "Cut the green onion whites and greens into thin slices, separating them for their use later.", + "Cut the sweet potato into a medium to large dice, about ½ inch in size.", + "Add the potatoes to a large bowl and drizzle in 1 tbsp of oil and salt and pepper to your liking. Toss to coat.", + "Spread the potatoes out on an oiled sheet tray and place into the oven for 20-25 minutes, flipping around the 15 minute mark. I would recommend you place this tray above your chicken so the chicken isn't subjected to the steam from the potatoes.", + "While the potatoes are cooking, thaw out the broccoli in the microwave. Don't cook it or heat it, just thaw it to take out the chill and drain away any water that is released.", + "Place the thawed broccoli into a large bowl and add the scallion whites with 1 tbsp of oil and a bit of salt and pepper. Toss to coat.", + "Heat a large skillet over medium high heat and add in the broccoli and scallions. Cook for 3-5 minutes to develop some color on the broccoli but be careful to not overcook it as it will lose its texture and become mushy.", + "Construction", + "After the chicken has rested for a bit, cut it into a medium to large dice to match the size of the potatoes.", + "Add the chicken and potatoes to the skillet with the broccoli along with the remaining sauce. Stir to combine.", + "Add in 2 cups of cooked rice and mix again. Taste test and adjust with salt and pepper as needed.", + "Plating", + "This recipe makes 5 servings. Divide the contents of the skillet 5 ways. Garnish with green onion tops and a lime wedge if you wish." + ], + "category": "Main Dish", + "yields": "5 servings", + "description": "These Sriracha Lime Chicken Bowls have less than 500 calories and 41g of protein making them great for if you want to maintain a calorie deficit. They are made up of chicken, sweet potatoes, rice, and broccoli.", + "total_time": 60, + "cook_time": 40, + "prep_time": 20, + "cuisine": "Asian,meal prep", + "ratings": 5.0, + "ratings_count": 3, + "nutrients": { + "servingSize": "1 serving", + "calories": "498 kcal", + "fatContent": "14 g", + "carbohydrateContent": "52 g", + "proteinContent": "41 g", + "fiberContent": "5.7 g" + }, + "image": "https://mealprepmanual.com/wp-content/uploads/2024/09/Sriracha-Lime-Chicken-Bowls.jpg", + "keywords": [ + "chicken", + "free", + "gluten free", + "meal prep", + "under 500 calories" + ] +} diff --git a/tests/test_data/mealprepmanual.com/mealprepmanual_2.testhtml b/tests/test_data/mealprepmanual.com/mealprepmanual_2.testhtml new file mode 100644 index 000000000..92f1934e3 --- /dev/null +++ b/tests/test_data/mealprepmanual.com/mealprepmanual_2.testhtml @@ -0,0 +1,1481 @@ + + + + + + + + + + + + + + Sriracha Lime Chicken Bowls - THE MEAL PREP MANUAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + +
+ + + +
+ + +
+ + +
+ + +
+
+
+
+
+
+
+

Sriracha Lime Chicken Bowls

+
+
+
+
+
+
+
+ Sriracha Lime Chicken Bowls in a black meal prep container.
+
+
+
+
+
+
+
+

Sriracha Lime Chicken Bowls

+
+
+
+
+ + +
+
+
+
+
+ These Sriracha Lime Chicken Bowls have less than 500 calories and 41g of protein making them great for if you want to maintain a calorie deficit. They are made up of chicken, sweet potatoes, rice, and broccoli.
+
+
+
+
+
+
+
+ PREP TIME
+
+
+
+ 20 Minutes
+
+
+
+
+
+
+
+ COOK TIME
+
+
+
+ 40 Minutes
+
+
+
+
+
+
+
+

Per Serving – Makes 5

+
+
+
+ 498 Calories
+
+
+
+

52g C | 41g P | 14g F

+
+
+
+
+
+
+
+

How to Meal Prep Sriracha Lime Chicken Bowls

+
+
+
+

A link to register for the MPM Club, a subscription service for a library of meal prep recipes

+
+
+
+

A link to register for the MPM Club, a subscription service for a library of meal prep recipes

+
+
+
+
+
Sriracha Lime Chicken Bowls in a black meal prep container.
+
+
+

Sriracha Lime Chicken Bowls

+
+
5 from 3 votes
+ + +
+
+
Course: Main Dish
Cuisine: Asian, meal prep
Keyword: chicken, free, gluten free, meal prep, under 500 calories
+
Prep Time: 20 minutes
Cook Time: 40 minutes
Total Time: 1 hour
+
Servings: 5 servings
+ +
Calories: 498kcal
+ + +
+
These Sriracha Lime Chicken Bowls have less than 500 calories and 41g of protein making them great for if you want to maintain a calorie deficit. They are made up of chicken, sweet potatoes, rice, and broccoli.
+
+ + +Print Recipe + Pin Recipe + Share on Facebook + + + + +
+ +
+
+ + + +

Ingredients

For the Bowls

For the Sauce

+
+
+

Instructions

For the Rice

  • Cook enough rice to yield 2 cups (300g) of cooked rice. 1 cup of dry rice will make between 2-3 cups of rice depending on what kind you use.

For the Sauce

  • Mix the lime juice, sriracha, honey, onion powder, garlic powder, salt, and pepper together. Whisk to combine.

For the Chicken

  • Preheat your oven to 400 °F (204 °C).
  • Place the chicken thighs into a large bowl. Cut off any excess fat or skin from the thighs.
  • Pour roughly ½ of the sauce over the top of the chicken and mix it with the chicken until it is completely coated. Allowing it to marinate for 30 minutes to a couple of hours is best but if you want to just cook it immediately, that will do.
  • Line a sheet pan with foil and lay the chicken thighs smooth side down on the sheet pan, ensuring enough space between each thigh to promote proper browning.
  • Cook the chicken for 20-25 minutes then remove from oven and flip. Return to the oven for an additional 5-10 minutes.
  • Once finished, remove from the oven and allow it to rest before cutting.

For the Vegetables

  • While the chicken is cooking, wash and cut all of your vegetables.
  • Cut the green onion whites and greens into thin slices, separating them for their use later.
  • Cut the sweet potato into a medium to large dice, about ½ inch in size.
  • Add the potatoes to a large bowl and drizzle in 1 tbsp of oil and salt and pepper to your liking. Toss to coat.
  • Spread the potatoes out on an oiled sheet tray and place into the oven for 20-25 minutes, flipping around the 15 minute mark. I would recommend you place this tray above your chicken so the chicken isn't subjected to the steam from the potatoes.
  • While the potatoes are cooking, thaw out the broccoli in the microwave. Don't cook it or heat it, just thaw it to take out the chill and drain away any water that is released.
  • Place the thawed broccoli into a large bowl and add the scallion whites with 1 tbsp of oil and a bit of salt and pepper. Toss to coat.
  • Heat a large skillet over medium high heat and add in the broccoli and scallions. Cook for 3-5 minutes to develop some color on the broccoli but be careful to not overcook it as it will lose its texture and become mushy.

Construction

  • After the chicken has rested for a bit, cut it into a medium to large dice to match the size of the potatoes.
  • Add the chicken and potatoes to the skillet with the broccoli along with the remaining sauce. Stir to combine.
  • Add in 2 cups of cooked rice and mix again. Taste test and adjust with salt and pepper as needed.

Plating

  • This recipe makes 5 servings. Divide the contents of the skillet 5 ways. Garnish with green onion tops and a lime wedge if you wish.
+
+
+ + +
+ +

Nutrition

Calories: 498kcal | Carbohydrates: 52g | Protein: 41g | Fat: 14g | Fiber: 5.7g
+ + +
+ + + +

+ + + +

NUTRITIONAL INFO FOR THE Sriracha Lime Chicken Bowls

+ + + +

The information in this table represents the estimate for the total nutrition of the recipe as it is written. If you wanted to split the recipe into more or less servings than what is originally listed you can use this table to determine the nutritional estimates.  If you update the number of servings in the “Servings” field of the recipe above, the information in these tables are no longer accurate as you have updated the ingredients.

+ + +
+
+
Servings
+
+ +
+
+
+
Carbs
+
259.1g
+
+
+
Protein
+
204.9g
+
+
+
Fat
+
70.3g
+
+
+
Calories
+
2488.7 cals
+
+
+ + + +

+
+
+
+
+
+ + +
+
+
+
+
+

Other recipes you might like

+
+ +
+
+ +
+ + + +

+ This Post Has 3 Comments +

+ +
    + +
  1. + +
    + + +
    +
    + Bob + + +
    + +
    + +
    + +
    +

    5 stars
    +Very good, this guy is amazing. Even my mom loves him…. 👍

    +
    +
    +
    + +
    + +
  2. + +
  3. + +
    + + +
    +
    + Maria Lerma + + +
    + +
    + +
    + +
    +

    5 stars
    +dang Josh you really cooked w this one!! this recipe slaps

    +
    +
    +
    + +
    + +
  4. + +
  5. + +
    + + +
    +
    + Adam + + +
    + +
    + +
    + +
    +

    5 stars
    +This was a solid recipe. Can see myself making this one again for future mealprep.

    +
    +
    +
    + +
    + +
  6. +
+ + + + +
+
+
+ 5 from 3 votes
+
+
+

Leave a Reply

+ +
+ Recipe Rating +




+
+
+
+ +
+ +

+ +

+ +
+
+
+
+
+
+
+
+ + +
+ + +
+ + + + + + +
+ + + +
+ + + + + +
+ + + + + +
+ + + +
+ + +
+ + + + + + + + +
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+

Membership:

+
+
+
+
+
+

Status: Not logged in 

+
+
+
+
+
+

Renewal:

+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 158496cde6188a1288734b9da4ec53cea77abe38 Mon Sep 17 00:00:00 2001 From: Joey <7505194+jknndy@users.noreply.github.com> Date: Sun, 5 Jan 2025 20:33:16 -0500 Subject: [PATCH 79/94] preppykitchen (#1454) --- recipe_scrapers/__init__.py | 2 + recipe_scrapers/preppykitchen.py | 31 + .../preppykitchen.com/preppykitchen_1.json | 61 ++ .../preppykitchen_1.testhtml | 995 ++++++++++++++++++ .../preppykitchen.com/preppykitchen_2.json | 82 ++ .../preppykitchen_2.testhtml | 958 +++++++++++++++++ 6 files changed, 2129 insertions(+) create mode 100644 recipe_scrapers/preppykitchen.py create mode 100644 tests/test_data/preppykitchen.com/preppykitchen_1.json create mode 100644 tests/test_data/preppykitchen.com/preppykitchen_1.testhtml create mode 100644 tests/test_data/preppykitchen.com/preppykitchen_2.json create mode 100644 tests/test_data/preppykitchen.com/preppykitchen_2.testhtml diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index ffa911df2..485ffcc1b 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -314,6 +314,7 @@ from .popsugar import PopSugar from .potatorolls import PotatoRolls from .practicalselfreliance import PracticalSelfReliance +from .preppykitchen import PreppyKitchen from .pressureluckcooking import PressureLuckCooking from .primaledgehealth import PrimalEdgeHealth from .projectgezond import ProjectGezond @@ -600,6 +601,7 @@ PeelWithZeal.host(): PeelWithZeal, PinchOfYum.host(): PinchOfYum, PotatoRolls.host(): PotatoRolls, + PreppyKitchen.host(): PreppyKitchen, QuiToque.host(): QuiToque, Recept.host(): Recept, ReceptyPreVas.host(): ReceptyPreVas, diff --git a/recipe_scrapers/preppykitchen.py b/recipe_scrapers/preppykitchen.py new file mode 100644 index 000000000..2f5bc6fa7 --- /dev/null +++ b/recipe_scrapers/preppykitchen.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class PreppyKitchen(AbstractScraper): + @classmethod + def host(cls): + return "preppykitchen.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) diff --git a/tests/test_data/preppykitchen.com/preppykitchen_1.json b/tests/test_data/preppykitchen.com/preppykitchen_1.json new file mode 100644 index 000000000..b8ddb2497 --- /dev/null +++ b/tests/test_data/preppykitchen.com/preppykitchen_1.json @@ -0,0 +1,61 @@ +{ + "author": "John Kanell", + "canonical_url": "https://preppykitchen.com/rocky-road-cookies/", + "site_name": "Preppy Kitchen", + "host": "preppykitchen.com", + "language": "en-US", + "title": "Rocky Road Cookies Recipe", + "ingredients": [ + "1⅔ cups all-purpose flour (200g)", + "½ cup cocoa powder (50g)", + "1 teaspoon baking soda", + "½ teaspoon salt", + "¾ cup unsalted butter (softened (168g)", + "¾ cup light brown sugar (165g)", + "⅓ cup granulated sugar (66g)", + "1 large egg (room temperature)", + "2 teaspoons vanilla extract", + "1 cup mini marshmallows (divided (56g)", + "¾ cup semi-sweet chocolate chips (135g)", + "½ cup almonds (chopped (75g)" + ], + "instructions_list": [ + "Preheat the oven to 350°F.", + "In a medium mixing bowl, whisk to combine the flour, cocoa powder, baking soda and salt.", + "In the bowl of a stand mixer fitted with the paddle attachment (or in a large bowl, using a handheld electric mixer), cream the butter, light brown sugar, and granulated sugars on medium speed for about 3 minutes until lightened in color and fluffy.", + "Add the egg and vanilla and mix for 30 seconds, just until combined.", + "Add the flour mixture in three parts, mixing on low speed just until combined between each addition. WIth a spatula, fold in ¾ cup of the marshmallows (40g), the chocolate chips and almonds.", + "Scoop 1½ tablespoon-sized cookies (about 32g each) with a triggered cookie scoop or two spoons, onto parchment lined baking sheets, leaving about 2 inches of space between each cookie. Gently press 2 to 3 of the remaining ¼ cup of marshmallows (16g) into the top of each cookie.", + "Bake for 8 to 10 minutes or until the edges are set and the tops appear dry. Let cool on the pan for 5 minutes, then transfer to a cooling rack to cool completely." + ], + "category": "Dessert", + "yields": "28 servings", + "description": "Rocky Road Cookies with gooey marshmallows, melty chocolate chips, and crunchy nuts are about to be your new favorite treat!", + "total_time": 20, + "cook_time": 10, + "prep_time": 10, + "cuisine": "American", + "equipment": [ + "Stand mixer or handheld electric mixer" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "157 kcal", + "fatContent": "9 g", + "saturatedFatContent": "4 g", + "unsaturatedFatContent": "4 g", + "transFatContent": "0.2 g", + "carbohydrateContent": "19 g", + "sugarContent": "11 g", + "proteinContent": "2 g", + "sodiumContent": "88 mg", + "fiberContent": "1 g", + "cholesterolContent": "20 mg" + }, + "image": "https://preppykitchen.com/wp-content/uploads/2024/12/Rocky-Road-Cookies-Recipe-Card.jpg", + "keywords": [ + "how to make rocky road cookies", + "rocky road cookies", + "rocky road cookies recipe" + ] +} diff --git a/tests/test_data/preppykitchen.com/preppykitchen_1.testhtml b/tests/test_data/preppykitchen.com/preppykitchen_1.testhtml new file mode 100644 index 000000000..51180b2f8 --- /dev/null +++ b/tests/test_data/preppykitchen.com/preppykitchen_1.testhtml @@ -0,0 +1,995 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Rocky Road Cookies Recipe - Preppy Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Footer

+
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/preppykitchen.com/preppykitchen_2.json b/tests/test_data/preppykitchen.com/preppykitchen_2.json new file mode 100644 index 000000000..a9ea09877 --- /dev/null +++ b/tests/test_data/preppykitchen.com/preppykitchen_2.json @@ -0,0 +1,82 @@ +{ + "author": "John Kanell", + "canonical_url": "https://preppykitchen.com/mongolian-beef/", + "site_name": "Preppy Kitchen", + "host": "preppykitchen.com", + "language": "en-US", + "title": "Mongolian Beef Recipe", + "ingredients": [ + "⅓ cup soy sauce (80ml)", + "⅓ cup water (80ml)", + "⅓ cup light brown sugar (73g)", + "1 ½ tablespoons minced ginger", + "6 garlic cloves (minced)", + "1 pound flank steak (thinly sliced against the grain (450g)", + "⅓ cup cornstarch (37g)", + "3 tablespoons vegetable oil", + "10 dried red chilies (or ½ teaspoon crushed red pepper flakes), optional)", + "5 green onions (sliced into 1-inch pieces (2¾oucnes/80g)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "⅓ cup soy sauce (80ml)", + "⅓ cup water (80ml)", + "⅓ cup light brown sugar (73g)", + "1 ½ tablespoons minced ginger", + "6 garlic cloves (minced)" + ], + "purpose": "For the Sauce" + }, + { + "ingredients": [ + "1 pound flank steak (thinly sliced against the grain (450g)", + "⅓ cup cornstarch (37g)", + "3 tablespoons vegetable oil", + "10 dried red chilies (or ½ teaspoon crushed red pepper flakes), optional)", + "5 green onions (sliced into 1-inch pieces (2¾oucnes/80g)" + ], + "purpose": "For the Beef" + } + ], + "instructions_list": [ + "For the Sauce:", + "In a medium bowl, whisk together the soy sauce, water, brown sugar, ginger, and garlic. Set aside.", + "For the Beef:", + "In a large bowl, toss the steak with the cornstarch until well coated.", + "In a large skillet or wok, heat the oil over medium-high heat. Shake the beef strips to remove excess cornstarch, and then add the beef to the skillet. Cook, stirring occasionally, until the beef is browned and mostly cooked through, 3 to 4 minutes. Transfer the beef to a large bowl.", + "With the skillet still over medium-high heat, add the sauce to the skillet and cook, stirring occasionally, scraping any browned bits from the bottom of the skillet with a spoon, until the sauce is thickened, about 3 minutes. Stir in the beef, red chilies (if using), and green onions.", + "Cook, stirring often, until the beef is well coated and the green onions are softened, about 1 minute. Serve immediately over rice." + ], + "category": "Main Course", + "yields": "4 servings", + "description": "Quick and savory Mongolian Beef is a restaurant favorite you can make at home in less 20 minutes! Tender and juicy flank steak is the perfect cut of meat to sear before being coated in a homemade sauce. Serve this family-friendly dish with rice and your favorite vegetable.", + "total_time": 20, + "cook_time": 10, + "prep_time": 10, + "cuisine": "Chinese", + "equipment": [ + "Mixing Bowls", + "Large skillet or wok" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "385 kcal", + "fatContent": "16 g", + "saturatedFatContent": "4 g", + "unsaturatedFatContent": "11 g", + "transFatContent": "0.1 g", + "carbohydrateContent": "33 g", + "sugarContent": "19 g", + "proteinContent": "27 g", + "sodiumContent": "1152 mg", + "fiberContent": "1 g", + "cholesterolContent": "68 mg" + }, + "image": "https://preppykitchen.com/wp-content/uploads/2024/12/Mongolian-Beef-Recipe-Card.jpg", + "keywords": [ + "how to make Mongolian Beef", + "Mongolian Beef", + "Mongolian Beef recipe" + ] +} diff --git a/tests/test_data/preppykitchen.com/preppykitchen_2.testhtml b/tests/test_data/preppykitchen.com/preppykitchen_2.testhtml new file mode 100644 index 000000000..aa5cbc71c --- /dev/null +++ b/tests/test_data/preppykitchen.com/preppykitchen_2.testhtml @@ -0,0 +1,958 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Easy Mongolian Beef Recipe - Preppy Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Footer

+
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 878c0500509123b83a49e056b8fd14501dca6102 Mon Sep 17 00:00:00 2001 From: Tom Praschan <13141438+tom-anders@users.noreply.github.com> Date: Mon, 6 Jan 2025 15:21:22 +0100 Subject: [PATCH 80/94] docs: fix typo in contributing guide (#1457) --- docs/contributing/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/setup.md b/docs/contributing/setup.md index 949d459f3..7036022b1 100644 --- a/docs/contributing/setup.md +++ b/docs/contributing/setup.md @@ -53,7 +53,7 @@ It's recommended to use a virtual environment to manage dependencies. You can cr ```sh python -m venv .venv -source venv/bin/activate # On Windows: `venv\Scripts\activate` +source .venv/bin/activate # On Windows: `.venv\Scripts\activate` ``` !!! tip "Virtual Environment" From 5200083854b0d3ae81a6974433924315f8509cd2 Mon Sep 17 00:00:00 2001 From: fabrice1236 <87321357+fabrice1236@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:36:15 +0100 Subject: [PATCH 81/94] Add support for lacucinaitaliana.it and lacucinaitaliana.com (#1456) * Add support for lacucinaitaliana.it * Changed author parsing * Add support for the lacucinaitaliana english website * Minor formatting changes in test data * Re-order JSON keys * Fix formatting --- recipe_scrapers/__init__.py | 3 + recipe_scrapers/lacucinaitaliana.py | 10 + .../lacucinaitaliana.json | 28 + .../lacucinaitaliana.testhtml | 173 +++ .../lacucinaitaliana.it/lacucinaitaliana.json | 34 + .../lacucinaitaliana.testhtml | 1314 +++++++++++++++++ 6 files changed, 1562 insertions(+) create mode 100644 recipe_scrapers/lacucinaitaliana.py create mode 100644 tests/test_data/lacucinaitaliana.com/lacucinaitaliana.json create mode 100644 tests/test_data/lacucinaitaliana.com/lacucinaitaliana.testhtml create mode 100644 tests/test_data/lacucinaitaliana.it/lacucinaitaliana.json create mode 100644 tests/test_data/lacucinaitaliana.it/lacucinaitaliana.testhtml diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 485ffcc1b..02dc588bd 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -233,6 +233,7 @@ from .kuchniadomowa import KuchniaDomowa from .kuchynalidla import KuchynaLidla from .kwestiasmaku import KwestiaSmaku +from .lacucinaitaliana import LaCucinaItaliana from .lanascooking import LanasCooking from .latelierderoxane import LAtelierDeRoxane from .leanandgreenrecipes import LeanAndGreenRecipes @@ -576,6 +577,8 @@ KristinesKitchenBlog.host(): KristinesKitchenBlog, KrollsKorner.host(): KrollsKorner, KuchynaLidla.host(): KuchynaLidla, + LaCucinaItaliana.host(): LaCucinaItaliana, + LaCucinaItaliana.host(domain="com"): LaCucinaItaliana, LanasCooking.host(): LanasCooking, LittleSunnyKitchen.host(): LittleSunnyKitchen, LeitesCulinaria.host(): LeitesCulinaria, diff --git a/recipe_scrapers/lacucinaitaliana.py b/recipe_scrapers/lacucinaitaliana.py new file mode 100644 index 000000000..7ed8e361b --- /dev/null +++ b/recipe_scrapers/lacucinaitaliana.py @@ -0,0 +1,10 @@ +from ._abstract import AbstractScraper + + +class LaCucinaItaliana(AbstractScraper): + @classmethod + def host(cls, domain="it"): + return f"lacucinaitaliana.{domain}" + + def author(self): + return "La Cucina Italiana" diff --git a/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.json b/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.json new file mode 100644 index 000000000..ebf2f7b5d --- /dev/null +++ b/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.json @@ -0,0 +1,28 @@ +{ + "author": "La Cucina Italiana", + "canonical_url": "https://www.lacucinaitaliana.com/recipe/pasta/caserecce-with-broccoli-and-tuna", + "site_name": "La Cucina Italiana", + "host": "lacucinaitaliana.it", + "language": "en-US", + "title": "Casarecce Pasta With Broccoli and Tuna", + "ingredients": [ + "12OZ. casarecce or other short pasta", + "12OZ. broccoli crowns", + "5OZ. oil-packed tuna", + "2OZ. shallot, chopped", + "wild fennel", + "red chili pepper", + "2SPRIG thyme", + "extra-virgin olive oil", + "salt" + ], + "instructions_list": [ + "Boil the broccoli in a large pot of unsalted water until just crisp-tender, around 3 minutes. Drain with a slotted spoon. Add salt to the water and add pasta to cook until al dente.", + "In the meantime, chop thyme and wild fennel. Sauté broccoli and chopped shallot in oil. Add tuna, chili pepper, chopped thyme and fennel, salt and 2 ladles (around 1 cup) pasta cooking water. Cook for 10 minutes.", + "Drain the pasta when al dente and return to the warm pot. Stir in the sauce and sauté to coat. Serve immediately." + ], + "yields": "4 servings", + "description": "This simple pasta with tuna and broccoli is the perfect weeknight meal.", + "total_time": 30, + "image": "https://rms.condenast.it/rms/public/5d3/f03/de5/thumb_982_1200_670_0_0_auto.jpg" +} diff --git a/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.testhtml b/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.testhtml new file mode 100644 index 000000000..66d62d211 --- /dev/null +++ b/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.testhtml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Casarecce Pasta With Broccoli and Tuna Recipe - La Cucina Italiana + + + +
+ +
La Cucina Italiana

Casarecce Pasta With Broccoli and Tuna

+ Tested by La cucina Italiana
Editorial staff by Editorial staff
  • 4.2 / 5

new!

+ + diff --git a/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.json b/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.json new file mode 100644 index 000000000..90cfe2813 --- /dev/null +++ b/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.json @@ -0,0 +1,34 @@ +{ + "author": "La Cucina Italiana", + "canonical_url": "https://www.lacucinaitaliana.it/ricetta/dolcetti-fillo-frutta-secca-miele/", + "site_name": "La Cucina Italiana", + "host": "lacucinaitaliana.it", + "language": "it-IT", + "title": "Dolcetti di pasta fillo, frutta secca e miele", + "ingredients": [ + "250 g frutta secca mista (fichi secchi, datteri, uvetta ammorbiditain acqua, noci, mandorle,albicocche disidratate)", + "6 fogli di pasta fillo", + "miele", + "acqua di rose" + ], + "instructions_list": [ + "Sminuzzate la frutta secca e mescolatela ottenendo un granulato. Profumatelo con acqua di rose.", + "Disponete i fogli di fillo sovrapposti a due a due.", + "Spennellateli con il miele, quindi distribuitevi sopra il granulato.", + "Tagliate ogni doppio foglio in 4 strisce. Arricciate la pasta e arrotolatela a spirale, senza mai staccarvi dal piano di lavoro. Una volta ottenuta una chiocciolina per ogni striscia, adagiatela nell’incavo di uno stampo multiplo da muffin. Riempitelo tutto.", + "Infornate lo stampo a 200 °C per circa 15 minuti.", + "Sfornate e togliete i dolcetti dallo stampo, quindi serviteli con altro miele." + ], + "yields": "12 servings", + "description": "Scoprite come preparare i Dolcetti di pasta fillo, frutta secca e miele, una ricetta dal sapore orientale", + "total_time": 35, + "image": "https://media-assets.lacucinaitaliana.it/photos/67766a9c882f5b2b196e4cfc/16:9/w_1600,h_900,c_limit/Dolcetti%20di%20fillo,%20frutta%20secca%20e%20miele%20copia.jpg", + "keywords": [ + "dolcetti", + "miele api", + "frutta secca", + "vegetariana", + "facile", + "magazine" + ] +} diff --git a/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.testhtml b/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.testhtml new file mode 100644 index 000000000..c21c675e1 --- /dev/null +++ b/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.testhtml @@ -0,0 +1,1314 @@ +Ricetta Dolcetti di pasta fillo, frutta secca e miele | La Cucina Italiana
Skip to main content

Dolcetti di fillo, frutta secca e miele

Dolcetti che ci trasportano nelle atmosfere orientali dei viaggi di Marco Polo raccontati ne Il milione e anche al banchetto di nozze del mercante veneziano…
frutta secca
Chiara Cadeddu

Questi Dolcetti di fillo, frutta secca e miele ci piace immaginarli al banchetto delle nozze tra Marco Polo e Donata Badoer. Appena tornato a Venezia, liberato dalla provvida prigionia dei genovesi che gli ha permesso di dettare Il Milione, il mercante si sposa con una celebrazione in pompa magna in cui noi abbiamo sognato preparazioni che mescolano ingredienti esotici e nostrani, in omaggio alla vita avventurosa dello sposo.

Nel Milione il miele, anzi, il mèle, è spesso citato. Negli harem dei sultani dalle cento bellissime spose, le favorite che tessono le loro trame di potere e di passione sono ghiotte di pasticcini realizzati con fichi, datteri e frutta secca, dolcissimi e un tantino sensuali...

Scoprite anche queste ricette: Crostata al miele con noci e nocciole, Baklava Facile, Torrone, Torta di pasta fillo con fichi, miele e pistacchi, Biscotti al miele con marmellata di pere, Dolce di banane nocciole e miele, Brioche mignon all’anice e miele, Frittelle di mele cotogne e miele

  • Tempo

    35 minuti

  • Prodotto

    12 pezzi

Ingredienti

250

g frutta secca mista (fichi secchi, datteri, uvetta ammorbiditain acqua, noci, mandorle,albicocche disidratate)

6

fogli di pasta fillo

miele

acqua di rose

Procedimento

  1. Step 1

    Sminuzzate la frutta secca e mescolatela ottenendo un granulato. Profumatelo con acqua di rose.

    Step 2

    Disponete i fogli di fillo sovrapposti a due a due.

    Step 3

    Spennellateli con il miele, quindi distribuitevi sopra il granulato.

    Step 4

    Tagliate ogni doppio foglio in 4 strisce. Arricciate la pasta e arrotolatela a spirale, senza mai staccarvi dal piano di lavoro. Una volta ottenuta una chiocciolina per ogni striscia, adagiatela nell’incavo di uno stampo multiplo
    da muffin. Riempitelo tutto.

    Step 5

    Infornate lo stampo a 200 °C per circa 15 minuti.

    Step 6

    Sfornate e togliete i dolcetti dallo stampo, quindi serviteli con altro miele.

    Ricetta: Walter Pedrazzi, Foto: Chiara Cadeddu, Styling: Beatrice Prada

    +
    Chiara Cadeddu

Vota la ricetta Dolcetti di fillo, frutta secca e miele

\ No newline at end of file From f305b886576cfafe1df523a75d9fc99fd0ab21cf Mon Sep 17 00:00:00 2001 From: Tom Praschan <13141438+tom-anders@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:36:44 +0100 Subject: [PATCH 82/94] fix: update Rewe scraper (#1455) --- recipe_scrapers/rewe.py | 14 +- tests/test_data/rewe.de/rewe.json | 4 +- tests/test_data/rewe.de/rewe.testhtml | 443 +++++++++++++++++--------- 3 files changed, 301 insertions(+), 160 deletions(-) diff --git a/recipe_scrapers/rewe.py b/recipe_scrapers/rewe.py index ac6c0c2e8..5c5daafcd 100644 --- a/recipe_scrapers/rewe.py +++ b/recipe_scrapers/rewe.py @@ -48,13 +48,15 @@ def ingredients(self): ingredients = [] for item in list_items: - text = item.find("div", {"class": "ld-rds flex-[1_0_0%]"}) - ingredient_text = ( - text.get_text(" ", strip=True).replace("\n", "").replace(" ", " ") + amount = normalize_string( + item.find("div", class_="formattedAmountDiv").get_text() + ) + ingredient = item.find( + "span", {"class": "ld-rds break-words leading-6"} + ).get_text(" ", strip=True) + ingredients.append( + normalize_string(f"{amount + ' ' if amount != '0' else ''}{ingredient}") ) - ingredient_text = re.sub(r"\s+", " ", ingredient_text) - - ingredients.append(ingredient_text) return ingredients diff --git a/tests/test_data/rewe.de/rewe.json b/tests/test_data/rewe.de/rewe.json index 3821029b6..ab14bce3f 100644 --- a/tests/test_data/rewe.de/rewe.json +++ b/tests/test_data/rewe.de/rewe.json @@ -36,8 +36,8 @@ "yields": "4", "description": "Wir treiben es gerne bunt! Starte auch du mit einer ausgewogenen Familien-Mahlzeit durch. Hol dir das REWE Rezept für Wintergemüse-Gnocchi-Pfanne & Kräuterdip.", "total_time": 45, - "ratings": 4.63, - "ratings_count": 35, + "ratings": 4.69, + "ratings_count": 42, "nutrients": { "servingSize": "4 Portionen", "calories": "677 kcal" diff --git a/tests/test_data/rewe.de/rewe.testhtml b/tests/test_data/rewe.de/rewe.testhtml index 3ac4ff764..35e6fa48d 100644 --- a/tests/test_data/rewe.de/rewe.testhtml +++ b/tests/test_data/rewe.de/rewe.testhtml @@ -1,4 +1,4 @@ -Wintergemüse-Gnocchi-Pfanne mit Kräuterdip Rezept - REWE.de
  • 800 g +
    REWE Beste Wahl Gnocchi (Kühlregal)
  • 0  +
    Salz
  • 2  +
    rote Zwiebeln
  • 0.5  +
    Spitzkohl
  • 2  +
    Möhren
  • 1 Stange(n) +
    Lauch
  • 1  +
    Rote Bete (frisch)
  • 50 g +
    REWE Beste Wahl aromatische Walnüsse
  • 2 EL +
    Rohrzucker
  • 0.5 Bd. +
    Schnittlauch
  • 0.5 Bd. +
    Petersilie
  • 400 g +
    Quark (Halbfettstufe)
  • 0  +
    Pfeffer
  • 0  +
    Zitronensaft
  • 1 Prise(n) +
    Zucker
  • 3 EL +
    Rapsöl
  • 0  +
    Muskatnuss

Utensilien

Sparschäler, Hobel,

Utensilien

Sparschäler, Hobel,

Sammel Euros mit REWE Bonus

Lös dieses Guthaben jederzeit ein und spar beim Einkaufen

Leg gleich los und sicher dir deinen 5 € Start-Bonus

Gib uns dein Feedback

Hast du Feedback für unsere Redaktion? Hier kannst du uns Feedback zum Rezept geben.

Gib uns dein Feedback

Hast du Feedback für unsere Redaktion? Hier kannst du uns Feedback zum Rezept geben.

Bewertungen mit Kommentar

Hat's geschmeckt? Sag uns, wie dir unser Rezept gefallen hat.
Dieses Rezept wurde noch nicht kommentiert, mit deiner Bewertung mit Kommentar hilfst du anderen dabei, schneller zu finden, was sie mögen.
Du kannst deine Bewertung kommentieren, wenn du dich anmeldest.

Bewertungen mit Kommentar

Hat's geschmeckt? Sag uns, wie dir unser Rezept gefallen hat.
Dieses Rezept wurde noch nicht kommentiert, mit deiner Bewertung mit Kommentar hilfst du anderen dabei, schneller zu finden, was sie mögen.
Du kannst deine Bewertung kommentieren, wenn du dich anmeldest.
Frittata mit Feldsalat
  • Glutenfrei
1h 5min
Einfach
Gemüse-Crumble
3 Zutaten im Angebot
  • Vegetarisch
45min
Einfach
Rhabarber-Galettes mit Ziegenkäse
1 Zutat im Angebot
Grün-weißer Spargel-Reissalat mit Zitronen-Vinaigrette
1 Zutat im Angebot
  • Wenig Zucker
  • Vegetarisch
  • Glutenfrei
45min
Einfach

Frittata mit Feldsalat
  • Glutenfrei
1h 5min
Einfach
Gemüse-Crumble
  • Vegetarisch
45min
Einfach
Grün-weißer Spargel-Reissalat mit Zitronen-Vinaigrette
  • Vegetarisch
  • Glutenfrei
  • Wenig Zucker
45min
Einfach

Thunfisch Mousse
    15min
    Einfach
    Kartoffel-Wirsing-Taler mit Frischkäse-Dip
    • Vegetarisch
    • Kalorienarm
    1h 5min
    Einfach
    Gemüse-Rösti
    • Vegetarisch
    • Glutenfrei
    45min
    Einfach
    Herbstliches Ofengemüse mit Dip
    • Vegetarisch
    • Glutenfrei
    • Kalorienarm
    1h 10min
    Einfach