From 74c5de268029d2559a72a9cd798d0d93773abd48 Mon Sep 17 00:00:00 2001 From: Jacob Rasmussen <2988654+jacrasmussen@users.noreply.github.com> Date: Sun, 2 Feb 2025 23:50:46 +0100 Subject: [PATCH] Add scraper support for spisbedre.dk (#1486) (#1487) * Add scraper support for spisbedre.dk (#1486) * Reorder JSON unit tests --- recipe_scrapers/__init__.py | 2 + recipe_scrapers/spisbedre.py | 143 ++ tests/test_data/spisbedre.dk/spisbedre_1.json | 60 + .../spisbedre.dk/spisbedre_1.testhtml | 328 +++++ tests/test_data/spisbedre.dk/spisbedre_2.json | 63 + .../spisbedre.dk/spisbedre_2.testhtml | 1230 +++++++++++++++++ 6 files changed, 1826 insertions(+) create mode 100644 recipe_scrapers/spisbedre.py create mode 100644 tests/test_data/spisbedre.dk/spisbedre_1.json create mode 100644 tests/test_data/spisbedre.dk/spisbedre_1.testhtml create mode 100644 tests/test_data/spisbedre.dk/spisbedre_2.json create mode 100644 tests/test_data/spisbedre.dk/spisbedre_2.testhtml diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 11c06f155..5f784cccb 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -372,6 +372,7 @@ from .southernliving import SouthernLiving from .spainonafork import SpainOnAFork from .spendwithpennies import SpendWithPennies +from .spisbedre import SpisBedre from .springlane import Springlane from .stacyling import StacyLing from .staysnatched import StaySnatched @@ -633,6 +634,7 @@ SavoryNothings.host(): SavoryNothings, SheLikesFood.host(): SheLikesFood, SpainOnAFork.host(): SpainOnAFork, + SpisBedre.host(): SpisBedre, StacyLing.host(): StacyLing, StrongrFastr.host(): StrongrFastr, SugarHero.host(): SugarHero, diff --git a/recipe_scrapers/spisbedre.py b/recipe_scrapers/spisbedre.py new file mode 100644 index 000000000..29a6071dd --- /dev/null +++ b/recipe_scrapers/spisbedre.py @@ -0,0 +1,143 @@ +import json + +from ._abstract import AbstractScraper +from ._grouping_utils import IngredientGroup + + +class SpisBedre(AbstractScraper): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.recipe_json = json.loads( + self.soup.find("div", id="app").attrs["data-page"] + )["props"]["recipe"] + + @classmethod + def host(cls): + return "spisbedre.dk" + + def author(self): + return self.schema.author() + + def title(self): + return self.schema.title() + + def category(self): + return ", ".join([type["name"] for type in self.recipe_json.get("tags", [])]) + + def total_time(self): + return self.schema.total_time() + + def yields(self): + return self.schema.yields() + + def ingredients(self): + result = [] + for ingredient_group in self.ingredient_groups(): + result.extend(ingredient_group.ingredients) + return result + + def ingredient_groups(self): + result = [] + servings = self.recipe_json.get("serving_size", 1) + + def format_ingredient(servings, ingredient): + ingredient_elements = [] + + def ingredient_label(amount, inflection, ingredient, prefix, suffix): + label = [] + if ingredient is None: + return None + + if prefix: + label.append(prefix) + + if inflection in ["singular", "plural"]: + label.append(ingredient.get("name_" + inflection)) + elif amount and amount > 0 and amount < 2: + label.append(ingredient.get("name_singular")) + else: + label.append(ingredient.get("name_plural")) + + if suffix: + label.append(suffix) + + return " ".join(label) + + def unit_label(amount, inflection, texts): + label = [] + if amount is None or texts is None: + return None + + if texts.get("abbreviation"): + label.append(texts.get("abbreviation")) + elif inflection in ["singular", "plural"]: + label.append(texts.get("name_" + inflection)) + elif amount > 0 and amount < 2: + label.append(texts.get("name_singular")) + else: + label.append(texts.get("name_plural")) + + return " ".join(label) + + total_amount = amount = ingredient.get("amount") + if amount: + total_amount = amount * servings + if int(total_amount) == total_amount: + total_amount = int(total_amount) + ingredient_elements.append(str(total_amount)) + + # For some reason unit_id 21 isn't rendered on the site, so we filter it as well + if ingredient.get("unit_id") != 21: + unit = unit_label( + total_amount, + ingredient.get("unit_inflection"), + ingredient.get("unit"), + ) + if unit: + ingredient_elements.append(unit) + + label = ingredient_label( + total_amount, + ingredient.get("ingredient_inflection"), + ingredient.get("ingredient"), + ingredient.get("prefix"), + ingredient.get("suffix"), + ) + if label: + ingredient_elements.append(label) + + return " ".join(ingredient_elements) + + for group in self.recipe_json.get("grouped_ingredients", []): + current_group = {"ingredients": [], "purpose": group.get("title")} + for ingredient in group.get("ingredients", []): + formatted_ingredient = format_ingredient(servings, ingredient) + if formatted_ingredient: + current_group["ingredients"].append(formatted_ingredient) + + result.append(current_group) + + return [ + IngredientGroup( + ingredient_group["ingredients"], ingredient_group["purpose"] + ) + for ingredient_group in result + ] + + def instructions(self): + result = [] + for group in self.recipe_json.get("grouped_instructions", []): + for instruction in group.get("instructions", []): + if instruction.get("instruction"): + result.append(instruction.get("instruction")) + + return "\n".join(result) + + 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/spisbedre.dk/spisbedre_1.json b/tests/test_data/spisbedre.dk/spisbedre_1.json new file mode 100644 index 000000000..0f6c255c6 --- /dev/null +++ b/tests/test_data/spisbedre.dk/spisbedre_1.json @@ -0,0 +1,60 @@ +{ + "author": "Louisa Lorang", + "canonical_url": "https://spisbedre.dk/opskrifter/kyllingetaerte-med-butterdejslag", + "site_name": "SPIS BEDRE", + "host": "spisbedre.dk", + "language": "da", + "title": "Kyllingetærte med butterdejslåg", + "ingredients": [ + "2 stilke bladselleri", + "2 gulerødder", + "1 porre", + "2 fed hvidløg", + "2 spsk. olivenolie til stegning", + "salt og peber", + "50 g smør", + "50 g hvedemel", + "2 dl hønsebouillon", + "2 dl piskefløde", + "300 g kogt kyllingebrystfilet", + "200 g ærter fra frost", + "1 spsk. frisk timian", + "1 rulle butterdej", + "1 æg til pensling" + ], + "ingredient_groups": [ + { + "ingredients": [ + "2 stilke bladselleri", + "2 gulerødder", + "1 porre", + "2 fed hvidløg", + "2 spsk. olivenolie til stegning", + "salt og peber", + "50 g smør", + "50 g hvedemel", + "2 dl hønsebouillon", + "2 dl piskefløde", + "300 g kogt kyllingebrystfilet", + "200 g ærter fra frost", + "1 spsk. frisk timian", + "1 rulle butterdej", + "1 æg til pensling" + ], + "purpose": null + } + ], + "instructions_list": [ + "Rens bladselleri, og skær dem i tynde skiver. Skrub eller skræl gulerødderne, og skær dem i tern. Rens porre, og pil hvidløg. Hak begge dele fint.", + "Steg alle grøntsagerne i olie i en stor, dyb pande. De skal ikke tage farve, men falde let sammen. Krydr dem med salt og peber. Tag grøntsagerne af panden, og læg dem til side på en stor tallerken.", + "Smelt smør i den samme pande. Pisk mel i. Tilsæt langsomt bouillon under piskning. Pisk, til saucen er glat. Tilsæt fløde, og lad saucen simre i 4-5 minutter.", + "Tænd ovnen på 220°. Skær kyllingebrystfilet i strimler. Vend kyllingestrimler, grøntsager og ærter i saucen. Skyl og pluk timian. Kog saucen op, og smag til med timian, salt og peber.", + "Fordel fyldet i en tærteform. Rul butterdejen ud, og læg den forsigtigt over fyldet. Klem overskydende dej sammen rundt i kanten. Klip et par små huller i midten af butterdejslåget, så damp kan slippe ud.", + "Pisk æg med 1½ spsk. koldt vand, og pensl butterdejslåget. Bag tærten i ovnen i ca. 20 minutter, til den er gylden og lækker. Servér den lun, evt. med salat til." + ], + "category": "Hovedretter", + "yields": "4 servings", + "description": "Brug dine grøntsags- og kyllingerester i en lun tærte til middagsbordet. Det sprøde butterdejslåg er prikken over i'et.", + "total_time": 40, + "image": "https://spisbedre-production-app.imgix.net/images/recipes/kyllingetaerte-med-butterdejslag_15964.jpg?fit=crop&crop=focalpoint&fp-x=0.44097082638046&fp-y=0.66429758726712&fp-z=1.25" +} diff --git a/tests/test_data/spisbedre.dk/spisbedre_1.testhtml b/tests/test_data/spisbedre.dk/spisbedre_1.testhtml new file mode 100644 index 000000000..043387d62 --- /dev/null +++ b/tests/test_data/spisbedre.dk/spisbedre_1.testhtml @@ -0,0 +1,328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kyllingetærte med butterdejslåg | SPIS BEDRE + + + + + + + + + +

Kyllingetærte med butterdejslåg

Brug dine grøntsags- og kyllingerester i en lun tærte til middagsbordet. Det sprøde butterdejslåg er prikken over i'et.

Kyllingetærte med butterdejslåg
31-60 min.

(0)

March 8, 2023 af Louisa LorangFoto: Rikke Westesen

Ingredienser

personer

Sådan gør du

Tip!

Har du ikke en rest kylling, kan du koge to kyllingebryster. Som et vegetarisk alternativ kan du bruge blomkål.

Bedøm denne opskrift

Vælg det ønskede antal stjernerDu gav 0 stjernerGiv 0 stjernerÆndre til 0 stjerner

Måske du også kan li'

+ diff --git a/tests/test_data/spisbedre.dk/spisbedre_2.json b/tests/test_data/spisbedre.dk/spisbedre_2.json new file mode 100644 index 000000000..1a0a1da41 --- /dev/null +++ b/tests/test_data/spisbedre.dk/spisbedre_2.json @@ -0,0 +1,63 @@ +{ + "author": "Timm Vladimir", + "canonical_url": "https://spisbedre.dk/opskrifter/stegt-makrel-med-kartofler", + "site_name": "SPIS BEDRE", + "host": "spisbedre.dk", + "language": "da", + "title": "Stegt makrel med kartofler", + "ingredients": [ + "4 ferske makrelfileter", + "100 g smør", + "300 g stikkelsbær", + "1 dl vand", + "1 dl eddike", + "1 dl sukker", + "600 g små kartofler", + "1 bundt frisk dild", + "salt", + "2 hjertesalater", + "1 spsk. smagsneutral olie til stegning" + ], + "ingredient_groups": [ + { + "ingredients": [ + "4 ferske makrelfileter", + "100 g smør" + ], + "purpose": null + }, + { + "ingredients": [ + "300 g stikkelsbær", + "1 dl vand", + "1 dl eddike", + "1 dl sukker" + ], + "purpose": "Syltede stikkelsbær" + }, + { + "ingredients": [ + "600 g små kartofler", + "1 bundt frisk dild", + "salt", + "2 hjertesalater", + "1 spsk. smagsneutral olie til stegning" + ], + "purpose": "Tilbehør" + } + ], + "instructions_list": [ + "Skyl stikkelsbærrene, og hæld dem i et skoldet glas. Kog vand, eddike og sukker op i en lille gryde, og hæld den kogende lage over bærrene.", + "Luk glasset til, og lad bærrene stå 1-2 døgn.", + "Skrub kartoflerne, og læg dem i en gryde. Skyl dild, og skær stilkene fra (gem toppene til pynt). Læg stilkene ned til kartoflerne, hæld vand og lidt salt på, og kog kartoflerne, til de er møre.", + "Skyl hjertesalater, og skær dem over på langs. Steg dem i lidt olie på en pande i ca. 1 minut, til de har taget lidt farve.", + "Filetér makrellerne. Steg dem i lidt smør på en pande i ca. 3 minutter på skindsiden. Vend dem, og steg dem i 1 minut på kødsiden.", + "Smelt resten af smørret på panden, til det er brunet. Anret makrelfileterne på tallerkener sammen med kogte kartofler, stegt hjertesalat, brunet smør og dild. Servér de syltede stikkelsbær til." + ], + "category": "Hovedretter, Frokost, Dansk", + "yields": "4 servings", + "description": "Hvad enten der er tale om frokost eller aftensmad, kan du altid spise stegt makrel med møre kartofler toppet med surt og sødt.", + "total_time": 35, + "ratings": 4.0, + "image": "https://spisbedre-production-app.imgix.net/images/recipes/stegt-makrel-med-kartofler_324.jpg?fit=crop&crop=focalpoint&fp-x=0.5&fp-y=0.63232421875&fp-z=1" +} diff --git a/tests/test_data/spisbedre.dk/spisbedre_2.testhtml b/tests/test_data/spisbedre.dk/spisbedre_2.testhtml new file mode 100644 index 000000000..be471a0fb --- /dev/null +++ b/tests/test_data/spisbedre.dk/spisbedre_2.testhtml @@ -0,0 +1,1230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Stegt makrel med kartofler | SPIS BEDRE + + + + + + + + + + +
+ + +
+
+
+
+
+
+
+ + +
+ +
+
+ + + + + +
+
+ + +
+

Stegt makrel med kartofler

+

Hvad enten der er tale om frokost eller aftensmad, kan du altid spise stegt makrel med møre kartofler toppet med surt og sødt.

+
+ + + Stegt makrel med kartofler + +
+ + 31-60 min. +
+ + + + + +
+
+
+
+ + + +
+
+ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (1) + + +

+
+ May 31, 2018 af Timm Vladimir + + + Foto: Columbus Leth +
+ +
+
+
+ +
+ Bemærk: + Trækketid, stikkelsbær: 1-2 døgn. +
+
+
+
+

+ + Ingredienser + +

+
+ + + personer + +
+ +
+ + +
+
+ +
+
+
+
+
+
+

+ + Sådan gør du + +

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

Tip!

+
+ Fileteringen kan klares med en skarp kniv – eller med hjælp fra din fiskehandler. +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+

Bedøm denne opskrift

+ +
+ + + + + + + +
+ Vælg det ønskede antal stjerner + Du gav 0 stjerner + Giv 0 stjerner + Ændre til 0 stjerner +
+
+ + +
+
+ + +
+
+ +
+
+
+
+ +
+

+ + Måske du også kan li' + +

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