Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scraper support for spisbedre.dk (#1486) #1487

Merged
merged 2 commits into from
Feb 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions recipe_scrapers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
143 changes: 143 additions & 0 deletions recipe_scrapers/spisbedre.py
Original file line number Diff line number Diff line change
@@ -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()
60 changes: 60 additions & 0 deletions tests/test_data/spisbedre.dk/spisbedre_1.json
Original file line number Diff line number Diff line change
@@ -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"
}
328 changes: 328 additions & 0 deletions tests/test_data/spisbedre.dk/spisbedre_1.testhtml

Large diffs are not rendered by default.

63 changes: 63 additions & 0 deletions tests/test_data/spisbedre.dk/spisbedre_2.json
Original file line number Diff line number Diff line change
@@ -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"
}
1,230 changes: 1,230 additions & 0 deletions tests/test_data/spisbedre.dk/spisbedre_2.testhtml

Large diffs are not rendered by default.