From ec73224d72186185e5096f9c835d7b155c558253 Mon Sep 17 00:00:00 2001 From: James Addison <55152140+jayaddison@users.noreply.github.com> Date: Tue, 14 Mar 2023 16:22:49 +0000 Subject: [PATCH] Fixup: repair sallys-blog to match updated website design (#744) --- README.rst | 1 + recipe_scrapers/__init__.py | 2 + .../plugins/opengraph_image_fetch.py | 2 +- recipe_scrapers/sallysblog.py | 56 +++++++++++++++++ tests/test_data/sallysblog.testhtml | 1 + tests/test_sallysblog.py | 63 +++++++++++++++++++ 6 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 recipe_scrapers/sallysblog.py create mode 100644 tests/test_data/sallysblog.testhtml create mode 100644 tests/test_sallysblog.py diff --git a/README.rst b/README.rst index 28228e701..2842fae04 100644 --- a/README.rst +++ b/README.rst @@ -262,6 +262,7 @@ Scrapers available for: - `https://rosannapansino.com `_ - `https://rutgerbakt.nl/ `_ - `https://sallysbakingaddiction.com `_ +- `https://sallys-blog.de `_ - `https://www.saveur.com/ `_ - `https://seriouseats.com/ `_ - `https://simple-veganista.com/ `_ diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index d4e7e2b05..5cbe2ef03 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -180,6 +180,7 @@ from .rosannapansino import RosannaPansino from .rutgerbakt import RutgerBakt from .sallysbakingaddiction import SallysBakingAddiction +from .sallysblog import SallysBlog from .saveur import Saveur from .seriouseats import SeriousEats from .simpleveganista import SimpleVeganista @@ -438,6 +439,7 @@ RosannaPansino.host(): RosannaPansino, RutgerBakt.host(): RutgerBakt, SallysBakingAddiction.host(): SallysBakingAddiction, + SallysBlog.host(): SallysBlog, Saveur.host(): Saveur, SeriousEats.host(): SeriousEats, SimpleVeganista.host(): SimpleVeganista, diff --git a/recipe_scrapers/plugins/opengraph_image_fetch.py b/recipe_scrapers/plugins/opengraph_image_fetch.py index ca6e4ced9..784091ebc 100644 --- a/recipe_scrapers/plugins/opengraph_image_fetch.py +++ b/recipe_scrapers/plugins/opengraph_image_fetch.py @@ -47,6 +47,6 @@ def decorated_method_wrapper(self, *args, **kwargs): image = self.soup.find( "meta", {"property": "og:image", "content": True} ) - return image.get("content") + return image.get("content") if image else None return decorated_method_wrapper diff --git a/recipe_scrapers/sallysblog.py b/recipe_scrapers/sallysblog.py new file mode 100644 index 000000000..053c36e95 --- /dev/null +++ b/recipe_scrapers/sallysblog.py @@ -0,0 +1,56 @@ +from ._abstract import AbstractScraper +from ._utils import get_minutes, normalize_string + + +class SallysBlog(AbstractScraper): + @classmethod + def host(cls): + return "sallys-blog.de" + + def title(self): + return normalize_string(self.soup.head.find("title").get_text()) + + def image(self): + raise NotImplementedError() # todo: probably better to return URLs than base64 content + + def total_time(self): + heading = self.soup.find("p", string="Zubereitungszeit") + timing = heading.find_next_sibling("h6") + return get_minutes(timing.text) + + def _servings_heading(self): + return self.soup.find("h4", string="Zutaten für:") + + def yields(self): + servings_heading = self._servings_heading() + servings = servings_heading.find_next_sibling("div").find("input") + return servings["value"] + + def _groupings(self): + servings_heading = self._servings_heading() + ingredients_area = servings_heading.next_sibling.next_sibling + return ingredients_area.find_all("div", recursive=False) + + def ingredients(self): + descriptions = [] + for grouping in self._groupings(): + ingredients = grouping.find_all("div", recursive=False) + for ingredient in ingredients: + descriptions.append(ingredient.text) + + return [normalize_string(description) for description in descriptions] + + def instructions(self): + grouping_titles = {grouping.find("h5").text for grouping in self._groupings()} + uppercase_titles = self.soup.find_all("h2", {"class": "uppercase"}) + + descriptions = [] + for title in uppercase_titles: + if title.text in grouping_titles or title.text.endswith("fertigstellen"): + instructions = title.find_next_sibling("div").find_all("p") + for instruction in instructions: + descriptions.append(instruction.text) + + return "\n".join( + [normalize_string(description) for description in descriptions] + ) diff --git a/tests/test_data/sallysblog.testhtml b/tests/test_data/sallysblog.testhtml new file mode 100644 index 000000000..880db906a --- /dev/null +++ b/tests/test_data/sallysblog.testhtml @@ -0,0 +1 @@ +20 Minuten Pasta / Brokkoli-Schinken-Nudeln / Sally und Murat kochen

20 Minuten Pasta / Brokkoli-Schinken-Nudeln / Sally und Murat kochen

Schnelle Rezepte zum Mittagessen oder Abendessen liebe ich. Dieses Pastagericht kannst du in etwa 20 Minuten zubereiten und auch hier Zutaten deiner Wahl verwenden. Als Gemüse verwende ich hier Brokkoli und Erbsen, aber auch Möhren, Zucchini oder andere Zutaten, die gerade im Kühlschrank liegen, dürfen gerne verwendet werden. Falls du das Gericht vegan zubereiten willst, tauschst du einfach die Butter gegen Olivenöl aus. Verwende statt Milch und Käse gerne eine pflanzliche Alternative und lasse den Schinken weg. Das Gericht kann auch als One-Pot-Gericht zubereitet werden, wenn du die Nudeln mit etwas mehr Wasser in der Soße garst. Allerdings finde ich es bei diesem Rezept besser zwei Töpfe zu verwenden, damit die Garzeiten besser kontrolliert werden können. Guten Appetit.

Käsesahnesoße

Schäle die Zwiebel und Knoblauchzehe und schneide sie fein. Erhitze die Butter in einer großen Pfanne und gib das Mehl hinzu. Brate es etwa 1 Minute an. Füge die Knoblauch- und Zwiebelwürfel hinzu und brate sie auch etwa 2-3 Minuten an. Lasse in der Zwischenzeit Wasser für die Nudeln aufkochen und salze es gut.

Lösche die Mehlschwitze mit der Gemüsebrühe und Milch ab und lasse die Soße aufkochen. Teile die Röschen des Brokkolis auf, schäle und schneide den Strunk fein. Gib die Strunkwürfel und die beiden Käsesorten grob zerkleinert in die Soße, würze sie mit Salz und Pfeffer und lasse sie mit Deckel etwa 2 Minuten köcheln.

Nudeln kochen

Koche in der Zwischenzeit auch die Nudeln im Salzwasser nach Packungsanleitung bissfest.

Brokkoli-Schinken-Nudeln fertigstellen

Schneide den Schinken in Würfel und gib ihn mit den Brokkoliröschen und den Erbsen in die Soße und lasse den Brokkoli etwa 3-4 Minuten in der Soße köcheln. Gib etwa 1 Schöpfkelle Nudelwasser in die Soße, gieße die Nudeln ab und vermische sie mit der Soße. Fertig ist das schnelle Nudelgericht. Viel Spaß beim Nachkochen, eure Sally!

Video Anleitung

Einkaufsliste erstellen?
Du möchtest die Zutaten dieses Rezepts als Einkaufsliste abspeichern? Diese und weitere nützlichen Funktionen findest du in meiner App fur Android-und iOS-Geräte:
Rezept Drucken?
Zubereitungszeit

Zubereitungszeit

20 Minuten

Zutaten für:

Portionen
Käsesahnesoße
1
Zwiebel
1
Knoblauchzehe
20 g
Butter
20 g
Mehl
300 g
Gemüsebrühe
200 g
Milch
500 g
Brokkoli
200 g
Gorgonzola
50 g
Parmesan
100 g
Schinken (z. B. Pute)
150 g
Erbsen (TK)
0,25 TL
Salz
0,25 TL
Pfeffer
Pasta
500 g
Nudeln (z. B. Orechiette)
\ No newline at end of file diff --git a/tests/test_sallysblog.py b/tests/test_sallysblog.py new file mode 100644 index 000000000..c47b96e10 --- /dev/null +++ b/tests/test_sallysblog.py @@ -0,0 +1,63 @@ +from recipe_scrapers.sallysblog import SallysBlog +from tests import ScraperTest + + +class TestSallysBlogScraper(ScraperTest): + scraper_class = SallysBlog + + def test_host(self): + self.assertEqual("sallys-blog.de", self.harvester_class.host()) + + def test_canonical_url(self): + self.assertEqual( + "https://sallys-blog.de/rezepte/20-minuten-pasta-brokkoli-schinken-nudeln", + self.harvester_class.canonical_url(), + ) + + def test_title(self): + self.assertEqual( + self.harvester_class.title(), + "20 Minuten Pasta / Brokkoli-Schinken-Nudeln / Sally und Murat kochen", + ) + + def test_total_time(self): + self.assertEqual(20, self.harvester_class.total_time()) + + def test_yields(self): + self.assertEqual("6", self.harvester_class.yields()) + + def test_image(self): + pass # todo + + def test_ingredients(self): + self.assertEqual( + [ + "1 Zwiebel", + "1 Knoblauchzehe", + "20 g Butter", + "20 g Mehl", + "300 g Gemüsebrühe", + "200 g Milch", + "500 g Brokkoli", + "200 g Gorgonzola", + "50 g Parmesan", + "100 g Schinken (z. B. Pute)", + "150 g Erbsen (TK)", + "0,25 TL Salz", + "0,25 TL Pfeffer", + "500 g Nudeln (z. B. Orechiette)", + ], + self.harvester_class.ingredients(), + ) + + def test_instructions(self): + return self.assertEqual( + "\n".join( + [ + "Schäle die Zwiebel und Knoblauchzehe und schneide sie fein. Erhitze die Butter in einer großen Pfanne und gib das Mehl hinzu. Brate es etwa 1 Minute an. Füge die Knoblauch- und Zwiebelwürfel hinzu und brate sie auch etwa 2-3 Minuten an. Lasse in der Zwischenzeit Wasser für die Nudeln aufkochen und salze es gut.", + "Lösche die Mehlschwitze mit der Gemüsebrühe und Milch ab und lasse die Soße aufkochen. Teile die Röschen des Brokkolis auf, schäle und schneide den Strunk fein. Gib die Strunkwürfel und die beiden Käsesorten grob zerkleinert in die Soße, würze sie mit Salz und Pfeffer und lasse sie mit Deckel etwa 2 Minuten köcheln.", + "Schneide den Schinken in Würfel und gib ihn mit den Brokkoliröschen und den Erbsen in die Soße und lasse den Brokkoli etwa 3-4 Minuten in der Soße köcheln. Gib etwa 1 Schöpfkelle Nudelwasser in die Soße, gieße die Nudeln ab und vermische sie mit der Soße. Fertig ist das schnelle Nudelgericht. Viel Spaß beim Nachkochen, eure Sally!", + ] + ), + self.harvester_class.instructions(), + )