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

Svt #1447

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions recipe_scrapers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@
from .sunbasket import SunBasket
from .sundpaabudget import SundPaaBudget
from .sunset import Sunset
from .svt import Svt
from .sweetcsdesigns import SweetCsDesigns
from .sweetpeasandsaffron import SweetPeasAndSaffron
from .tasteatlas import TasteAtlas
Expand Down Expand Up @@ -604,6 +605,7 @@
Rewe.host(): Rewe,
RecipeLand.host(): RecipeLand,
RicettePerBimby.host(): RicettePerBimby,
Svt.host(): Svt,
SandwhichTribunal.host(): SandwhichTribunal,
SavoryNothings.host(): SavoryNothings,
SheLikesFood.host(): SheLikesFood,
Expand Down
133 changes: 133 additions & 0 deletions recipe_scrapers/svt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import json

from bs4 import BeautifulSoup

from ._abstract import AbstractScraper
from ._grouping_utils import IngredientGroup
from ._utils import normalize_string


class Svt(AbstractScraper):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

data_string = self.soup.find("script", id="__NEXT_DATA__").string
data = json.loads(data_string)
self.apollo = data["props"]["pageProps"]["__APOLLO_STATE__"]
recipe_id = self._get_recipe_id()
self.recipe_data = self.apollo[recipe_id]

@classmethod
def host(cls):
return "svt.se"

def title(self):
return self.recipe_data.get("title")

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

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

def cook_time(self):
return self.recipe_data.get("cookingTime")

def prep_time(self):
return self.recipe_data.get("preparationTime")

def yields(self):
portions_max = self.recipe_data.get("portionsMax")
if portions_max:
return f"{portions_max} servings"
portions_min = self.recipe_data.get("portionsMin")
if portions_min:
return f"{portions_min} servings"
return None

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

def ingredient_groups(self):
ingredient_groups = []
ingredient_list = self.recipe_data.get("ingredientList")
for group in ingredient_list:
group_purpose = group.get("headline")
group_ingredients = []
ingredients = group.get("ingredients")
for ingredient in ingredients:
name = ingredient.get("name")
amount = ingredient.get("amount")
unit = ingredient.get("unit")
ingredient_string = self._make_ingredient_string(name, amount, unit)
group_ingredients.append(ingredient_string)

ingredient_group = IngredientGroup(
ingredients=group_ingredients, purpose=group_purpose
)

ingredient_groups.append(ingredient_group)

return ingredient_groups

def ingredients(self):
ingredients = []
ingredient_groups = self.recipe_data.get("ingredientList")
for group in ingredient_groups:
group_ingredients = group.get("ingredients")
for ingredient in group_ingredients:
name = ingredient.get("name")
amount = ingredient.get("amount")
unit = ingredient.get("unit")
ingredient_string = self._make_ingredient_string(name, amount, unit)
ingredients.append(ingredient_string)
return ingredients

def instructions_list(self):
instructions_string = normalize_string(self.recipe_data.get("description"))
instructions_soup = BeautifulSoup(instructions_string, "html.parser")
instructions = [
element.text
for element in instructions_soup.children
if not element.text.isspace()
]
return instructions

def instructions(self):
return "\n".join(self.instructions_list())

def author(self):
chefs = self.recipe_data.get("chefs")
if not chefs:
return "SVT"
chef_ref = chefs[0]["__ref"]
chef = self.apollo[chef_ref]
return chef["title"]

def description(self):
return self.recipe_data.get("lead")

def _get_recipe_data(self):
data_string = self.soup.find("script", id="__NEXT_DATA__").string
data = json.loads(data_string)
apollo = data["props"]["pageProps"]["__APOLLO_STATE__"]
recipe_id = self._get_recipe_id(apollo)
return apollo[recipe_id]

def _get_recipe_id(self):
root_query = self.apollo["ROOT_QUERY"]
for key, value in root_query.items():
if key.startswith("route"):
return value["__ref"]
return None

def _make_ingredient_string(self, name, amount, unit):
string = ""
if amount:
string += str(amount)
if unit:
string += unit
if string:
string += " "
string += name
return normalize_string(string)
53 changes: 53 additions & 0 deletions tests/test_data/svt.se/svt_1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"author": "Lisa Lemke",
"canonical_url": "svt.se",
"host": "svt.se",
"description": "Ugnspannkaka är en sådan där älskad rätt som dyker upp hos oss titt som tätt då den går snabbt, är älskad av alla och om du följer det här receptet svår att misslyckas med! Här gör jag den vegetarisk och min kompis Sebastian tipsade mig en gång om att kombinationen solroskärnor och kapris är ett perfekt substitut för fläsk. Men självklart kan du ersätta solroskärnor, kapris och liquid smoke med fläsk om du är sugen!",
"image": "https://backend.main-bvxea6i-nbs7p5fes6fzc.eu-5.platformsh.site/sites/default/files/images/23318806.jpg",
"ingredients": [
"6 ekologiska ägg",
"9dl mjölk, 3 %",
"4½dl vetemjöl",
"½tsk bakpulver",
"1⅓tsk salt",
"1dl kapris",
"1dl solroskärnor",
"1krm liquid smoke",
"smör till långpannan",
"lingonsylt till servering"
],
"ingredient_groups": [
{
"purpose": null,
"ingredients": [
"6 ekologiska ägg",
"9dl mjölk, 3 %",
"4½dl vetemjöl",
"½tsk bakpulver",
"1⅓tsk salt",
"1dl kapris",
"1dl solroskärnor",
"1krm liquid smoke",
"smör till långpannan",
"lingonsylt till servering"
]
}
],
"instructions": "1. Förbered gärna pannkakassmeten i god tid, med fördel redan på morgonen.\n2. Vispa samman mjöl, bakpulver och salt med hälften av mjölken tills du har en slät smet. Tillsätt äggen och resten av mjölken och vispa samman.\n3. Värm ugnen till 225 grader med en stor långpanna i ugnen så den får bli riktigt varm. Detta gör att ugnspannkakan blir ordentligt fluffig.\n4. Smält smör i långpannan och fördela över hela.\n5. Blanda kapris och solroskärnor med liquid smoke och låt detta sedan rosta i den heta pannan i någon minut tills solroskärnorna börjar få färg.\n6. Häll på pannkakassmeten (enklast när plåten fortfarande står kvar i ugnen) Låt grädda i ca 25-30 minuter eller tills pannkakan fluffat upp ordentligt och fått fin färg.\n7. Servera genast med lingonsylt och en god sallad. Tips\nHemligheten bakom en riktigt fluffig ugnspannkaka är att förbereda smeten i god tid och att grädda den i en ordentligt het långpanna! Överbliven ugnspannkaka går utmärkt att frysa in eller förvara i kylskåp där den håller 3-4 dagar.",
"instructions_list": [
"1. Förbered gärna pannkakassmeten i god tid, med fördel redan på morgonen.",
"2. Vispa samman mjöl, bakpulver och salt med hälften av mjölken tills du har en slät smet. Tillsätt äggen och resten av mjölken och vispa samman.",
"3. Värm ugnen till 225 grader med en stor långpanna i ugnen så den får bli riktigt varm. Detta gör att ugnspannkakan blir ordentligt fluffig.",
"4. Smält smör i långpannan och fördela över hela.",
"5. Blanda kapris och solroskärnor med liquid smoke och låt detta sedan rosta i den heta pannan i någon minut tills solroskärnorna börjar få färg.",
"6. Häll på pannkakassmeten (enklast när plåten fortfarande står kvar i ugnen) Låt grädda i ca 25-30 minuter eller tills pannkakan fluffat upp ordentligt och fått fin färg.",
"7. Servera genast med lingonsylt och en god sallad. Tips",
"Hemligheten bakom en riktigt fluffig ugnspannkaka är att förbereda smeten i god tid och att grädda den i en ordentligt het långpanna! Överbliven ugnspannkaka går utmärkt att frysa in eller förvara i kylskåp där den håller 3-4 dagar."
],
"language": "sv",
"site_name": "SVT recept",
"title": "Lisas ugnspannkaka med kapris",
"cook_time": 45,
"prep_time": null,
"yields": "6 servings"
}
22 changes: 22 additions & 0 deletions tests/test_data/svt.se/svt_1.testhtml

Large diffs are not rendered by default.

69 changes: 69 additions & 0 deletions tests/test_data/svt.se/svt_2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"author": "Fredrik Borgskog",
"canonical_url": "svt.se",
"host": "svt.se",
"description": "Knäckig saffran och mandelkaka med päron, idén är att använda för hårt kokt eller överbliven knäck i denna kakan. Vid sidan av kakan kommer en lätt vispad vitchokladganache som smaksätts med vanilj och lite citronzest. Själva chokladganachen kan du vispa lite hårdare om önskas och spritsas upp på tex någon bakelse.",
"image": "https://backend.main-bvxea6i-nbs7p5fes6fzc.eu-5.platformsh.site/sites/default/files/2024-12/Saffranskakaka.jpg",
"ingredients": [
"165g smör (rumstempererat)",
"330g mandelmassa",
"180g ägg (ca 3 st stora)",
"35g havremjöl (funkar lika bra med vetemjöl)",
"0,5g mixad saffran (1pkt)",
"2g salt",
"1st stort skalat päron",
"20st små knäck",
"4g potatismjöl",
"130g mjölk",
"1st blötlagt gelatinblad",
"100g vitchoklad ca 28-32% kakaohalt",
"1nypa(or) salt",
"zest från en halv citron",
"75g grädde",
"1st skrapad och hackad vaniljstång"
],
"ingredient_groups": [
{
"purpose": "Saffranskaka",
"ingredients": [
"165g smör (rumstempererat)",
"330g mandelmassa",
"180g ägg (ca 3 st stora)",
"35g havremjöl (funkar lika bra med vetemjöl)",
"0,5g mixad saffran (1pkt)",
"2g salt",
"1st stort skalat päron",
"20st små knäck"
]
},
{
"purpose": "Vispad chokladganache",
"ingredients": [
"4g potatismjöl",
"130g mjölk",
"1st blötlagt gelatinblad",
"100g vitchoklad ca 28-32% kakaohalt",
"1nypa(or) salt",
"zest från en halv citron",
"75g grädde",
"1st skrapad och hackad vaniljstång"
]
}
],
"instructions": "Receptet passar till 4st små springformar (12cm) eller 1st stor (24cm).\nSaffranskaka:\nMixa smör och mandelmassa i en matberedare, gå sedan i med resterande ingredienser förutom päron och knäck, mixa ihop till en smet. Hacka nu ner knäcken i mindre bitar och dela ut i springformarna som är förberedda med bakplåtspapper i. Strimla upp päronen och lägg ovanpå knäcken. Dela ut saffranssmeten i formarna.Baka av på 180°C i 30min. Låt svalna och servera med botten uppåt.\nVispad chokladganache:\nBörja med att blanda ca 30g mjölk med potatismjölet. Koka upp resterande mjölk med vanilj, salt. Gå sedan i med potatismjölken. Koka upp under omrörning. Smält gelatinet i det. Sila det över chokladen. Mixa ihop till en kräm med stavmixer. Zesta i citron i choklad och häll i grädden. Mixa igen och sätt i kyl. Minst 8 tim kyltid.\nMontering:Börja med att vispa upp ganachen till en härlig konsistens. Dela kakan på hälften och och lägg upp och avsluta med ganachen.\nTips:Ganachen går bra att smaka upp på olika sätt och även bra användningsområde till att garnera bakelser eller tårtor.",
"instructions_list": [
"Receptet passar till 4st små springformar (12cm) eller 1st stor (24cm).",
"Saffranskaka:",
"Mixa smör och mandelmassa i en matberedare, gå sedan i med resterande ingredienser förutom päron och knäck, mixa ihop till en smet. Hacka nu ner knäcken i mindre bitar och dela ut i springformarna som är förberedda med bakplåtspapper i. Strimla upp päronen och lägg ovanpå knäcken. Dela ut saffranssmeten i formarna.Baka av på 180°C i 30min. Låt svalna och servera med botten uppåt.",
"Vispad chokladganache:",
"Börja med att blanda ca 30g mjölk med potatismjölet. Koka upp resterande mjölk med vanilj, salt. Gå sedan i med potatismjölken. Koka upp under omrörning. Smält gelatinet i det. Sila det över chokladen. Mixa ihop till en kräm med stavmixer. Zesta i citron i choklad och häll i grädden. Mixa igen och sätt i kyl. Minst 8 tim kyltid.",
"Montering:Börja med att vispa upp ganachen till en härlig konsistens. Dela kakan på hälften och och lägg upp och avsluta med ganachen.",
"Tips:Ganachen går bra att smaka upp på olika sätt och även bra användningsområde till att garnera bakelser eller tårtor."
],
"language": "sv",
"site_name": "SVT recept",
"title": "Saffran- och mandelkaka med vispad vitchokladganache",
"cook_time": 30,
"prep_time": null,
"yields": "8 servings"
}
6 changes: 6 additions & 0 deletions tests/test_data/svt.se/svt_2.testhtml

Large diffs are not rendered by default.

Loading