Repository: hhursev/recipe-scrapers
Pull request #1228 (2024-08-27 00:16:27)

Cleanup: removed schema calls and `instructions` keys

jayaddison: Optional: there seem to be a few more scrapers that have redundant `return self.schema.<field>()` calls - I don't know whether we need/want to remove all of them here, but if we do then there are a few more (`DobruChutAktualitySK` for example).
jknndy: Found several more on another pass through, this should be all the rest
jayaddison: I ran a `grep` to try to find any other remaining cases, and there aren't many, but it did find a small number.  Filtered output below (I've removed results where the `return` value is potentially modified by other code):

```sh
$ grep -r -B 2 "^        return self.schema." recipe_scrapers
...
--
recipe_scrapers/lekkerensimpel.py-
recipe_scrapers/lekkerensimpel.py-    def category(self):
recipe_scrapers/lekkerensimpel.py:        return self.schema.category()
...
--
recipe_scrapers/thecookingguy.py-
recipe_scrapers/thecookingguy.py-    def image(self):
recipe_scrapers/thecookingguy.py:        return self.schema.image()
...
--
recipe_scrapers/chefnini.py-
recipe_scrapers/chefnini.py-    def category(self):
recipe_scrapers/chefnini.py:        return self.schema.category()
```
jknndy: The `null` value in the JSON was causing an error but after removing the `null` keys everything is passing
jayaddison: Interesting.. I kinda feel that any `null` value in a test data file is only valid if either: it is asserting that the field is _always_ empty (i.e. non-implemented optional field, or mandatory field but with `FieldNotProvidedByWebsiteException` implementation) _or_ there is a separate test case that confirms a non-`null` value on some other recipe.

That would cover both `thecookingguy` and `chefnini` -- but because there is one `lekkerensimpel` recipe that _does_ have a `category` test result asserted, I think we should leave those `null` expectations in place for it.
jayaddison: Ok; it's the `schema.org` autofill plugin; [it handles the `NotImplementedError`, but re-raises it](https://github.com/hhursev/recipe-scrapers/blob/141470384b9e8a486f3a14255d37e3b608d3383a/recipe_scrapers/plugins/schemaorg_fill.py#L58-L66) if either: the page has no schema.org metadata, or there is not an implementation of the requested function (in the case of `category` -- there [is a `schemaorg` implementation for that field](https://github.com/hhursev/recipe-scrapers/blob/141470384b9e8a486f3a14255d37e3b608d3383a/recipe_scrapers/_schemaorg.py#L120-L124)).
jayaddison: Ah: I suppose this all implies that in fact, we do need a `category` implementation on `LekkerEnSimpel` -- because otherwise, as a non-mandatory field, non-empty test expectations aren't valid.  Sorry @jknndy - my mistake to remove it from that scraper.

I'm not sure whether to suggest re-adding it to `chefnini` and `thecookingguy` too... without test coverage that it works, it's difficult to confirm.
jayaddison: > I'm not sure whether to suggest re-adding it to `chefnini` and `thecookingguy` too... without test coverage that it works, it's difficult to confirm.

No; I think that only `lekkerensimpel` needs the `category` implementation re-added:

  * `chefnini`: test HTML does not appear to have the relevant schema.org metadata on the page, so let's remove the `self.schema.category` call.
  * `thecookingguy`: test HTML has `Recipe` schema.org data, but does not contain the `recipeCategory` field - so let's remove `self.schema.category` here too.

But to do that we need to resolve the source of the errors mentioned:

> The `null` value in the JSON was causing an error but after removing the `null` keys everything is passing

The reason those errors occur is potentially confusing (I find it confusing) behaviour in the `SchemaOrgFillPlugin`: if it does not find any relevant `schema.org` recipe metadata on the page, it re-raises any underlying exception from a called method.  In the case of `NotImplementedError`, that means that _some_ webpages for a recipe site could return results, while other webpages would raise a `NotImplementedError`.  That doesn't make much sense to me: whether a method is implemented or not doesn't vary based on the input HTML.

So I think I will open a separate issue and small pull request to resolve that separately, and that should allow us to restore the `category: null` expectations on `lekkerensimpel` tests 2 and 3 (which are genuine).
jayaddison: > So I think I will open a separate issue and small pull request to resolve that separately, and that should allow us to restore the `category: null` expectations on `lekkerensimpel` tests 2 and 3 (which are genuine).

Filed as issue #1229 with corresponding pull request #1230.
jayaddison: > So I think I will open a separate issue and small pull request to resolve that separately, and that should allow us to restore the `category: null` expectations on `lekkerensimpel` tests 2 and 3 (which are genuine).

Following the discussion in #1230 -- I don't think we should restore the `category: null` expectations to those tests.  Requesting the `category` field on those pages will begin raising an informative exception.  And the fact that we have `category` on _one_ of the tests means that we do have (some) coverage of that field for the scraper.

Patch:
diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py
index 361c378a..9b67ce5d 100644
--- a/recipe_scrapers/__init__.py
+++ b/recipe_scrapers/__init__.py
@@ -5,6 +5,7 @@ __all__ = (
     "ElementNotFoundInHtml",
     "FieldNotProvidedByWebsiteException",
     "NoSchemaFoundInWildMode",
+    "RecipeSchemaNotFound",
     "StaticValueException",
     "WebsiteNotImplementedError",
     "scrape_html",
@@ -26,6 +27,7 @@ from ._exceptions import (
     ElementNotFoundInHtml,
     FieldNotProvidedByWebsiteException,
     NoSchemaFoundInWildMode,
+    RecipeSchemaNotFound,
     StaticValueException,
     WebsiteNotImplementedError,
 )
diff --git a/recipe_scrapers/_exceptions.py b/recipe_scrapers/_exceptions.py
index 458e791e..680d0331 100644
--- a/recipe_scrapers/_exceptions.py
+++ b/recipe_scrapers/_exceptions.py
@@ -55,6 +55,15 @@ class SchemaOrgException(FillPluginException):
     ...
 
 
+class RecipeSchemaNotFound(SchemaOrgException):
+    """No recipe schema metadata found on the page"""
+
+    def __init__(self, url):
+        self.url = url
+        message = f"No Recipe Schema found at {self.url}."
+        super().__init__(message)
+
+
 class StaticValueException(RecipeScrapersExceptions):
     """Error to communicate that the scraper is returning a fixed/static value."""
 
diff --git a/recipe_scrapers/bakels.py b/recipe_scrapers/bakels.py
index a027232d..12e48032 100644
--- a/recipe_scrapers/bakels.py
+++ b/recipe_scrapers/bakels.py
@@ -13,9 +13,6 @@ class Bakels(AbstractScraper):
     def title(self):
         return self.soup.find("h1").get_text()
 
-    def image(self):
-        return self.schema.image()
-
     def ingredients(self):
         div = self.soup.find("div", id="tab-ingredients_1")
         if not div:
diff --git a/recipe_scrapers/bigoven.py b/recipe_scrapers/bigoven.py
index 1e6a31ad..b55a3db1 100644
--- a/recipe_scrapers/bigoven.py
+++ b/recipe_scrapers/bigoven.py
@@ -22,6 +22,3 @@ class BigOven(AbstractScraper):
     def instructions(self):
         ps = self.soup.find("div", {"class": "instructions"}).findAll("p")
         return "\n".join([normalize_string(p.text) for p in ps])
-
-    def ratings(self):
-        return self.schema.ratings()
diff --git a/recipe_scrapers/chefnini.py b/recipe_scrapers/chefnini.py
index f52d3fd3..9c69bf66 100644
--- a/recipe_scrapers/chefnini.py
+++ b/recipe_scrapers/chefnini.py
@@ -15,9 +15,6 @@ class Chefnini(AbstractScraper):
     def title(self):
         return self.soup.find("span", {"itemprop": "headline"}).get_text()
 
-    def category(self):
-        return self.schema.category()
-
     def total_time(self):
         raise FieldNotProvidedByWebsiteException(return_value=None)
 
diff --git a/recipe_scrapers/cookinglight.py b/recipe_scrapers/cookinglight.py
index f4f2cbed..da8e85e6 100644
--- a/recipe_scrapers/cookinglight.py
+++ b/recipe_scrapers/cookinglight.py
@@ -1,5 +1,5 @@
 from ._abstract import AbstractScraper
-from ._utils import get_yields, normalize_string
+from ._utils import normalize_string
 
 
 class CookingLight(AbstractScraper):
@@ -7,9 +7,6 @@ class CookingLight(AbstractScraper):
     def host(cls):
         return "cookinglight.com"
 
-    def yields(self):
-        return get_yields(self.schema.yields())
-
     def ingredients(self):
         ingredients = self.soup.find("div", {"class": "ingredients"}).ul.findAll("li")
         return "\n".join(
diff --git a/recipe_scrapers/dobruchutaktualitysk.py b/recipe_scrapers/dobruchutaktualitysk.py
index 0d18bc59..c4dd479f 100644
--- a/recipe_scrapers/dobruchutaktualitysk.py
+++ b/recipe_scrapers/dobruchutaktualitysk.py
@@ -12,27 +12,6 @@ class DobruChutAktualitySK(AbstractScraper):
         # site has no support for recipe keywords
         raise FieldNotProvidedByWebsiteException(return_value=None)
 
-    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):
         p_list = self.soup.find("div", {"class": "procedure-list"}).findChildren("p")
 
@@ -44,15 +23,6 @@ class DobruChutAktualitySK(AbstractScraper):
 
         return "\n".join(instructions)
 
-    def ratings(self):
-        return self.schema.ratings()
-
-    def cuisine(self):
-        return self.schema.cuisine()
-
-    def description(self):
-        return self.schema.description()
-
     def ingredient_groups(self):
         return group_ingredients(
             self.ingredients(),
diff --git a/recipe_scrapers/felixkitchen.py b/recipe_scrapers/felixkitchen.py
index a3a510a7..039c3665 100644
--- a/recipe_scrapers/felixkitchen.py
+++ b/recipe_scrapers/felixkitchen.py
@@ -30,9 +30,6 @@ class FelixKitchen(AbstractScraper):
         yields_strong = container_p.find("strong")
         return yields_strong.text
 
-    def image(self):
-        return self.schema.image()
-
     def ingredients(self):
         ingredients = []
 
diff --git a/recipe_scrapers/fifteengram.py b/recipe_scrapers/fifteengram.py
index 5d6325fc..e22385e7 100644
--- a/recipe_scrapers/fifteengram.py
+++ b/recipe_scrapers/fifteengram.py
@@ -11,24 +11,3 @@ class FifteenGram(AbstractScraper):
 
     def author(self):
         return "15gram"
-
-    def title(self):
-        return self.schema.title()
-
-    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 description(self):
-        return self.schema.description()
diff --git a/recipe_scrapers/gourmettraveller.py b/recipe_scrapers/gourmettraveller.py
index 1712c016..1b41a009 100644
--- a/recipe_scrapers/gourmettraveller.py
+++ b/recipe_scrapers/gourmettraveller.py
@@ -10,12 +10,6 @@ class GourmetTraveller(AbstractScraper):
     def host(cls):
         return "gourmettraveller.com.au"
 
-    def author(self):
-        return self.schema.author()
-
-    def title(self):
-        return self.schema.title()
-
     def category(self):
         recipe_category_span = self.soup.find(
             "span", {"class": "related-tags__label"}, string=re.compile("Recipe Course")
@@ -25,21 +19,6 @@ class GourmetTraveller(AbstractScraper):
         value = recipe_category_span.find_next_sibling("span")
         return normalize_string(value.text)
 
-    def total_time(self):
-        return self.schema.total_time()
-
-    def prep_time(self):
-        return self.schema.prep_time()
-
-    def cook_time(self):
-        return self.schema.cook_time()
-
-    def yields(self):
-        return self.schema.yields()
-
-    def image(self):
-        return self.schema.image()
-
     def ingredients(self):
         group_heading_divs = self.soup.find_all(
             "div", {"class": "recipe-ingredients__title"}
@@ -58,15 +37,6 @@ class GourmetTraveller(AbstractScraper):
 
         return ingredients
 
-    def instructions(self):
-        return self.schema.instructions()
-
-    def cuisine(self):
-        return self.schema.cuisine()
-
-    def description(self):
-        return self.schema.description()
-
     def ingredient_groups(self):
         return group_ingredients(
             self.ingredients(),
diff --git a/recipe_scrapers/halfbakedharvest.py b/recipe_scrapers/halfbakedharvest.py
index 24220228..2cbd21e3 100644
--- a/recipe_scrapers/halfbakedharvest.py
+++ b/recipe_scrapers/halfbakedharvest.py
@@ -7,9 +7,6 @@ class HalfBakedHarvest(AbstractScraper):
     def host(cls):
         return "halfbakedharvest.com"
 
-    def nutrients(self):
-        return self.schema.nutrients()
-
     def ingredient_groups(self):
         return group_ingredients(
             self.ingredients(),
diff --git a/recipe_scrapers/hellofresh.py b/recipe_scrapers/hellofresh.py
index 4e8feaee..771bd3d6 100644
--- a/recipe_scrapers/hellofresh.py
+++ b/recipe_scrapers/hellofresh.py
@@ -33,6 +33,3 @@ class HelloFresh(AbstractScraper):
         prep_time, cook_time = self.prep_time(), self.cook_time()
         if prep_time or cook_time:
             return (prep_time or 0) + (cook_time or 0)
-
-    def nutrients(self):
-        return self.schema.nutrients()
diff --git a/recipe_scrapers/jamieoliver.py b/recipe_scrapers/jamieoliver.py
index 59f3e0d8..6f4ce75e 100644
--- a/recipe_scrapers/jamieoliver.py
+++ b/recipe_scrapers/jamieoliver.py
@@ -7,9 +7,6 @@ class JamieOliver(AbstractScraper):
     def host(cls):
         return "jamieoliver.com"
 
-    def image(self):
-        return self.schema.image()
-
     def instructions(self):
         instructions = self.soup.find("ol", {"class": "recipeSteps"}).findAll("li")
         return "\n".join([normalize_string(inst.get_text()) for inst in instructions])
diff --git a/recipe_scrapers/jocooks.py b/recipe_scrapers/jocooks.py
index 30008688..3c5fe9ca 100644
--- a/recipe_scrapers/jocooks.py
+++ b/recipe_scrapers/jocooks.py
@@ -8,27 +8,6 @@ class JoCooks(AbstractScraper):
     def host(cls):
         return "jocooks.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 ingredient_groups(self):
         return group_ingredients(
             self.ingredients(),
@@ -37,21 +16,6 @@ class JoCooks(AbstractScraper):
             ".wprm-recipe-ingredient",
         )
 
-    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()
-
-    def nutrients(self):
-        return self.schema.nutrients()
-
     def equipment(self):
         equipment_items = [
             item.get_text()
diff --git a/recipe_scrapers/kitchensanctuary.py b/recipe_scrapers/kitchensanctuary.py
index 615fd306..d7af7d9c 100644
--- a/recipe_scrapers/kitchensanctuary.py
+++ b/recipe_scrapers/kitchensanctuary.py
@@ -8,33 +8,6 @@ class KitchenSanctuary(AbstractScraper):
     def host(cls):
         return "kitchensanctuary.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 prep_time(self):
-        return self.schema.prep_time()
-
-    def cook_time(self):
-        return self.schema.cook_time()
-
-    def yields(self):
-        return self.schema.yields()
-
-    def image(self):
-        return self.schema.image()
-
-    def ingredients(self):
-        return self.schema.ingredients()
-
     def ingredient_groups(self):
         ingredient_groups = self.soup.find_all(
             "div", {"class": "wprm-recipe-ingredient-group"}
@@ -68,15 +41,3 @@ class KitchenSanctuary(AbstractScraper):
             ingredient_index_base = ingredient_count
 
         return results
-
-    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/recipe_scrapers/lekkerensimpel.py b/recipe_scrapers/lekkerensimpel.py
index 5b95e55a..4d8a6ae9 100644
--- a/recipe_scrapers/lekkerensimpel.py
+++ b/recipe_scrapers/lekkerensimpel.py
@@ -17,9 +17,6 @@ class LekkerEnSimpel(AbstractScraper):
         title = self.soup.find("h1", {"class": "hero__title"}).text
         return normalize_string(title)
 
-    def category(self):
-        return self.schema.category()
-
     def image(self):
         image = self.soup.find("meta", {"property", "og:image"})
         return image["content"] if image else None
diff --git a/recipe_scrapers/mykoreankitchen.py b/recipe_scrapers/mykoreankitchen.py
index 1e266cef..f2a74592 100644
--- a/recipe_scrapers/mykoreankitchen.py
+++ b/recipe_scrapers/mykoreankitchen.py
@@ -8,27 +8,6 @@ class MyKoreanKitchen(AbstractScraper):
     def host(cls):
         return "mykoreankitchen.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 ingredient_groups(self):
         ingredient_groups = self.soup.find_all(
             "div", {"class": "wprm-recipe-ingredient-group"}
@@ -61,21 +40,3 @@ class MyKoreanKitchen(AbstractScraper):
             ingredient_index_base = ingredient_count
 
         return results
-
-    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()
-
-    def cook_time(self):
-        return self.schema.cook_time()
-
-    def prep_time(self):
-        return self.schema.prep_time()
diff --git a/recipe_scrapers/plugins/schemaorg_fill.py b/recipe_scrapers/plugins/schemaorg_fill.py
index d7e05e69..c2bf7ea1 100644
--- a/recipe_scrapers/plugins/schemaorg_fill.py
+++ b/recipe_scrapers/plugins/schemaorg_fill.py
@@ -1,7 +1,7 @@
 import functools
 import logging
 
-from recipe_scrapers._exceptions import FillPluginException
+from recipe_scrapers._exceptions import FillPluginException, RecipeSchemaNotFound
 from recipe_scrapers.settings import settings
 
 from ._interface import PluginInterface
@@ -57,7 +57,9 @@ class SchemaOrgFillPlugin(PluginInterface):
                 return decorated(self, *args, **kwargs)
             except (FillPluginException, NotImplementedError) as e:
                 function = getattr(self.schema, decorated.__name__)
-                if self.schema.data and function:
+                if not self.schema.data:
+                    raise RecipeSchemaNotFound(url=self.url)
+                if function:
                     logger.info(
                         f"{class_name}.{method_name}() seems to not be implemented but .schema is available! Attempting to return result from SchemaOrg."
                     )
diff --git a/recipe_scrapers/purplecarrot.py b/recipe_scrapers/purplecarrot.py
index edd8b44d..e759cf41 100644
--- a/recipe_scrapers/purplecarrot.py
+++ b/recipe_scrapers/purplecarrot.py
@@ -10,6 +10,3 @@ class PurpleCarrot(AbstractScraper):
         home_link = self.soup.find("a", {"href": "/", "title": True})
         if home_link:
             return home_link["title"]
-
-    def nutrients(self):
-        return self.schema.nutrients()
diff --git a/recipe_scrapers/receptyprevas.py b/recipe_scrapers/receptyprevas.py
index cf71585b..71334afb 100644
--- a/recipe_scrapers/receptyprevas.py
+++ b/recipe_scrapers/receptyprevas.py
@@ -7,36 +7,6 @@ class ReceptyPreVas(AbstractScraper):
     def host(cls):
         return "receptyprevas.sk"
 
-    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):
         description = []
         p_list = self.soup.find("div", {"class": "single-content-self"}).findChildren(
diff --git a/recipe_scrapers/thecookingguy.py b/recipe_scrapers/thecookingguy.py
index 650a1882..977c899a 100644
--- a/recipe_scrapers/thecookingguy.py
+++ b/recipe_scrapers/thecookingguy.py
@@ -9,21 +9,12 @@ class TheCookingGuy(AbstractScraper):
     def host(cls):
         return "thecookingguy.com"
 
-    def author(self):
-        return self.schema.author()
-
-    def title(self):
-        return self.schema.title()
-
     def total_time(self):
         raise FieldNotProvidedByWebsiteException(return_value=None)
 
     def yields(self):
         return get_yields(self.soup.find("div", class_="text-block-7").get_text())
 
-    def image(self):
-        return self.schema.image()
-
     def ingredients(self):
         ingredients = self.soup.find(
             "div", class_="w-layout-vflex card-text-holder ingredients"
diff --git a/recipe_scrapers/varechapravdask.py b/recipe_scrapers/varechapravdask.py
index bd94f67d..098dd680 100644
--- a/recipe_scrapers/varechapravdask.py
+++ b/recipe_scrapers/varechapravdask.py
@@ -5,36 +5,3 @@ class VarechaPravdaSK(AbstractScraper):
     @classmethod
     def host(cls):
         return "varecha.pravda.sk"
-
-    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()


Test patch:
diff --git a/recipe_scrapers/americastestkitchen.py b/recipe_scrapers/americastestkitchen.py
index 847decef..589b9c95 100644
--- a/recipe_scrapers/americastestkitchen.py
+++ b/recipe_scrapers/americastestkitchen.py
@@ -13,25 +13,13 @@ class AmericasTestKitchen(AbstractScraper):
     def host(cls):
         return "americastestkitchen.com"
 
-    def author(self):
-        return self.schema.author()
-
     def site_name(self):
         """Self-titled website"""
         return self.author()
 
-    def title(self):
-        return self.schema.title()
-
-    def description(self):
-        return self.schema.description()
-
     def total_time(self):
         return get_minutes(self._get_additional_details.get("recipeTimeNote"))
 
-    def image(self):
-        return self.schema.image()
-
     def ingredients(self):
         ingredients = []
         for group in self._get_additional_details.get("ingredientGroups"):
@@ -65,18 +53,6 @@ class AmericasTestKitchen(AbstractScraper):
             ]
         ).lstrip("\n")
 
-    def yields(self):
-        return self.schema.yields()
-
-    def nutrients(self):
-        return self.schema.nutrients()
-
-    def category(self):
-        return self.schema.category()
-
-    def ratings(self):
-        return self.schema.ratings()
-
     @staticmethod
     def _parse_ingredient_item(ingredient_item):
         fields = ingredient_item["fields"]
diff --git a/tests/library/test_exceptions.py b/tests/library/test_exceptions.py
index 37372ae5..dd7f1077 100644
--- a/tests/library/test_exceptions.py
+++ b/tests/library/test_exceptions.py
@@ -1,7 +1,9 @@
 import unittest
 
 from recipe_scrapers import (
+    AbstractScraper,
     NoSchemaFoundInWildMode,
+    RecipeSchemaNotFound,
     WebsiteNotImplementedError,
     scrape_html,
 )
@@ -17,3 +19,13 @@ class TestExceptions(unittest.TestCase):
 
         self.assertEqual(exception.url, "example.com")
         self.assertEqual(exception.message, "No Recipe Schema found at example.com.")
+
+    def test_no_schema_found_for_fill_plugin(self):
+        class TestScraper(AbstractScraper):
+            @classmethod
+            def host(cls):
+                return "example.com"
+
+        scraper = TestScraper(html="<html></html>", url="http://example.com/recipe")
+        with self.assertRaises(RecipeSchemaNotFound):
+            scraper.category()
diff --git a/tests/test_data/allrecipes.com/allrecipescurated.json b/tests/test_data/allrecipes.com/allrecipescurated.json
index 35731e2c..25366fa7 100644
--- a/tests/test_data/allrecipes.com/allrecipescurated.json
+++ b/tests/test_data/allrecipes.com/allrecipescurated.json
@@ -17,7 +17,6 @@
     "½ cup freshly grated Parmesan cheese",
     "½ cup crumbled feta cheese"
   ],
-  "instructions": "Stir together olive oil, garlic, and salt; toss with tomatoes, and allow to stand for 15 minutes. Preheat oven to 400 degrees F (200 degrees C).\nBrush each pizza crust with some of the tomato marinade. Sprinkle the pizzas evenly with Mozzarella and Fontina cheeses. Arrange tomatoes overtop, then sprinkle with shredded basil, Parmesan, and feta cheese.\nBake in preheated oven until the cheese is bubbly and golden brown, about 10 minutes.",
   "instructions_list": [
     "Stir together olive oil, garlic, and salt; toss with tomatoes, and allow to stand for 15 minutes. Preheat oven to 400 degrees F (200 degrees C).",
     "Brush each pizza crust with some of the tomato marinade. Sprinkle the pizzas evenly with Mozzarella and Fontina cheeses. Arrange tomatoes overtop, then sprinkle with shredded basil, Parmesan, and feta cheese.",
diff --git a/tests/test_data/books.ottolenghi.co.uk/ottolenghibooks_1.json b/tests/test_data/books.ottolenghi.co.uk/ottolenghibooks_1.json
index 2b72641f..63e122a5 100644
--- a/tests/test_data/books.ottolenghi.co.uk/ottolenghibooks_1.json
+++ b/tests/test_data/books.ottolenghi.co.uk/ottolenghibooks_1.json
@@ -35,7 +35,6 @@
       ]
     }
   ],
-  "instructions": "Preheat the oven to 160°C fan.\nDrain the chickpeas well and set them aside. Put 2 tablespoons of oil into a large, high-sided ovenproof sauté pan or cast-iron saucepan, for which you have a lid, and place on a medium-high heat. Once hot, add the garlic and cook for 90 seconds, until starting to colour. Add the Parmesan rinds, if using, the drained chickpeas, bicarbonate of soda, 1.2 litres of water and a very generous amount of coarsely cracked black pepper (give it about 40 grinds). Bring to the boil, skimming the scum from the surface as needed, then cover with the lid and bake in the oven for 75 minutes. Add ¾ teaspoon of salt and continue cooking, covered, for another 30 minutes, or until the chickpeas are very soft and the liquid has reduced by about half.\nMeanwhile, mix together the chillies, vinegar and a small pinch of salt in a small bowl. Set aside to pickle.\nTowards the last 10 minutes of cooking the chickpeas, put the last tablespoon of oil into a large frying pan on a medium-high heat and, once hot, cook the spinach, adding it to the pan in batches with ¼ teaspoon of salt until just wilted, about 4 minutes. Add the parsley and remove from the heat.\nWhen the chickpeas are ready, remove the lid and, while still hot from the oven but off the heat, add a quarter of the butter cubes and about 15g of grated Parmesan, mixing until the butter has melted into the sauce. Continue in this way, adding a quarter more of the butter and 15g more of Parmesan until you’ve used up all 100g of butter and 60g of cheese. Finally, add another very generous grind of coarsely ground black pepper. The sauce will have thickened significantly, coating the chickpeas nicely. Add a splash more water if you like it looser. Remove the Parmesan rinds, if using.\nTop with the spinach mixture, the pickled chillies and their liquid and a final sprinkling of Parmesan, serving any extra grated Parmesan alongside.",
   "instructions_list": [
     "Preheat the oven to 160°C fan.",
     "Drain the chickpeas well and set them aside. Put 2 tablespoons of oil into a large, high-sided ovenproof sauté pan or cast-iron saucepan, for which you have a lid, and place on a medium-high heat. Once hot, add the garlic and cook for 90 seconds, until starting to colour. Add the Parmesan rinds, if using, the drained chickpeas, bicarbonate of soda, 1.2 litres of water and a very generous amount of coarsely cracked black pepper (give it about 40 grinds). Bring to the boil, skimming the scum from the surface as needed, then cover with the lid and bake in the oven for 75 minutes. Add ¾ teaspoon of salt and continue cooking, covered, for another 30 minutes, or until the chickpeas are very soft and the liquid has reduced by about half.",
diff --git a/tests/test_data/books.ottolenghi.co.uk/ottolenghibooks_2.json b/tests/test_data/books.ottolenghi.co.uk/ottolenghibooks_2.json
index e390d501..0984387d 100644
--- a/tests/test_data/books.ottolenghi.co.uk/ottolenghibooks_2.json
+++ b/tests/test_data/books.ottolenghi.co.uk/ottolenghibooks_2.json
@@ -34,7 +34,6 @@
       "purpose": "Custard"
     }
   ],
-  "instructions": "Preheat the oven to 200°C fan.\nMix the rhubarb and strawberries with the sugar and arrange in a medium ovenproof dish: you want the fruit to fit snugly. Bake for 12–13 minutes, until the fruit has softened but still retains its shape and the sugar has melted. Don’t worry if there is a tiny amount of sugar that hasn’t melted: just give the fruit a gentle stir and the sugar will dissolve. Set aside to cool.\nLower the oven temperature to 170°C fan.\nFor the custard, place the egg yolks, cornflour, sugar and vanilla extract in a large bowl and whisk until smooth. Gradually pour in the double cream and whisk until combined. Pour the custard into a 25cm round high-sided ovenproof dish. Place the dish inside a larger ovenproof dish and fill the larger dish with boiling water so it rises about 1cm up the sides. Bake for 25 minutes, until the custard has set and is starting to brown on top. Remove from the oven, set aside to cool, then transfer to the fridge to chill.\nOnce chilled, spoon half the fruit and juice on top and serve with the remaining fruit and juice alongside.",
   "instructions_list": [
     "Preheat the oven to 200°C fan.",
     "Mix the rhubarb and strawberries with the sugar and arrange in a medium ovenproof dish: you want the fruit to fit snugly. Bake for 12–13 minutes, until the fruit has softened but still retains its shape and the sugar has melted. Don’t worry if there is a tiny amount of sugar that hasn’t melted: just give the fruit a gentle stir and the sugar will dissolve. Set aside to cool.",
diff --git a/tests/test_data/celebratingsweets.com/celebratingsweets_1.json b/tests/test_data/celebratingsweets.com/celebratingsweets_1.json
index 50abcc07..8b987069 100644
--- a/tests/test_data/celebratingsweets.com/celebratingsweets_1.json
+++ b/tests/test_data/celebratingsweets.com/celebratingsweets_1.json
@@ -17,7 +17,6 @@
     "6 ounces blueberries",
     "1/2 cup raspberry or strawberry jam (heated just enough to make it pourable (not hot))"
   ],
-  "instructions": "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.\nIn a large trifle dish (or individual glasses), layer the cake, whipped cream, berries, and jam. You can layer it anyway you like. I did the following (from the bottom up): whipped cream, cake, berries, whipped cream, cake, jam, whipped cream, berries.",
   "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.",
     "In a large trifle dish (or individual glasses), layer the cake, whipped cream, berries, and jam. You can layer it anyway you like. I did the following (from the bottom up): whipped cream, cake, berries, whipped cream, cake, jam, whipped cream, berries."
diff --git a/tests/test_data/celebratingsweets.com/celebratingsweets_2.json b/tests/test_data/celebratingsweets.com/celebratingsweets_2.json
index 8e6d0a93..952e2ee4 100644
--- a/tests/test_data/celebratingsweets.com/celebratingsweets_2.json
+++ b/tests/test_data/celebratingsweets.com/celebratingsweets_2.json
@@ -47,7 +47,6 @@
       "purpose": "Topping:"
     }
   ],
-  "instructions": "Cake:\nPreheat oven to 350°F. Lightly grease a 9-inch** square baking pan and set aside.\nIn a large bowl, whisk flour, brown sugar, cocoa, espresso powder, baking powder, and salt. Add milk, oil and vanilla and whisk until well combined and smooth. Using a rubber spatula, stir in chocolate chips.\nTransfer the batter to the prepared pan and spread into an even layer. Proceed with the topping.\nTopping:\nIn a bowl, combine cocoa powder and brown sugar, mixing until well combined (I use a fork). Sprinkle this mixture in an even layer over the top of the cake batter.\nSlowly and carefully pour the boiling water evenly over the top. TIP: I pour the water over the back of a large spoon and slowly move it around the pan while pouring. Do not stir or disturb the cake batter underneath.\nTransfer to the oven and bake for 25-30 minutes, until the cake layer (on top) is cooked through. The pudding sauce should be bubbling gently around the sides of the pan. Place on a wire rack to cool for about 10 minutes. Serve warm, scooping the cake into bowls and spooning the sauce over the top. Recommended garnishes: vanilla ice cream or whipped cream.",
   "instructions_list": [
     "Cake:",
     "Preheat oven to 350°F. Lightly grease a 9-inch** square baking pan and set aside.",
diff --git a/tests/test_data/chefnini.com/chefnini.json b/tests/test_data/chefnini.com/chefnini.json
index 9b7fc6d0..834861cb 100644
--- a/tests/test_data/chefnini.com/chefnini.json
+++ b/tests/test_data/chefnini.com/chefnini.json
@@ -27,7 +27,6 @@
     "9- Stoppez la cuisson lorsque la sauce est encore sirupeuse – trop tard, les pâtes seront sèches. Dosez l’eau de cuisson pour obtenir la consistance de sauce désirée.",
     "10- Servez aussitôt, poivrez et ajoutez un peu de noix de muscade râpée."
   ],
-  "category": null,
   "yields": "2 servings",
   "description": "En France, les pâtes carbonara sont très souvent cuisinées avec des oignons et de la crème liquide. C’est d’ailleurs de cette manière que je les ai découvertes. J’aimais bien mais j’ai toujours trouvé ça un peu écœurant et lourd.",
   "total_time": null,
diff --git a/tests/test_data/ingoodflavor.com/ingoodflavor_1.json b/tests/test_data/ingoodflavor.com/ingoodflavor_1.json
index c5d1b514..e3b91e87 100644
--- a/tests/test_data/ingoodflavor.com/ingoodflavor_1.json
+++ b/tests/test_data/ingoodflavor.com/ingoodflavor_1.json
@@ -15,7 +15,6 @@
     "1/2 tsp. black pepper",
     "10 oz. (about 5 cups) shredded sharp cheddar cheese"
   ],
-  "instructions": "Preheat oven to 375 degrees F.\nAdd olive oil to a preheated large skillet on medium heat. Add onion and garlic. Cook for 4 minutes, stirring frequently. Add ground linguica, breaking up chunks with a wooden spatula. Cook, stirring frequently for 3 minutes. Add sliced potatoes, seasoned salt, and black pepper. Cook, stirring frequently for 3 minutes.\nSpray a 9″ x 13″ baking dish with cooking spray. Spread 1/3 of the potato mixture on the bottom. Add 1/3 of the cheese. Repeat layering 1/3 of potatoes, 1/3 of cheese two more times, ending with the cheese.\nBake on the top half of the oven for 15-20 minutes or until cheese is bubbly.",
   "instructions_list": [
     "Preheat oven to 375 degrees F.",
     "Add olive oil to a preheated large skillet on medium heat. Add onion and garlic. Cook for 4 minutes, stirring frequently. Add ground linguica, breaking up chunks with a wooden spatula. Cook, stirring frequently for 3 minutes. Add sliced potatoes, seasoned salt, and black pepper. Cook, stirring frequently for 3 minutes.",
diff --git a/tests/test_data/ingoodflavor.com/ingoodflavor_2.json b/tests/test_data/ingoodflavor.com/ingoodflavor_2.json
index 1543131a..cb18d49f 100644
--- a/tests/test_data/ingoodflavor.com/ingoodflavor_2.json
+++ b/tests/test_data/ingoodflavor.com/ingoodflavor_2.json
@@ -47,7 +47,6 @@
       "purpose": "For the firecracker sauce:"
     }
   ],
-  "instructions": "Instructions for pan frying are detailed here. See notes below for oven bake and air frying.\nFill large skillet or frying pan with 1 to 1 1/4-inch of oil. Make sure the oil is at least 1 1/2-inch below the top of the pan to prevent overflow. Preheat oil to 375° F while you prep the wings.\nPat wings (flats and drumettes) dry with paper towels.\nTo a large Ziploc bag or food storage container with a lid, add tapioca starch, salt, pepper, onion powder, and garlic powder. Close tight and shake to combine.\nAdd half of the wings. Shake well to coat with the tapioca starch mixture.\nShake off excess tapioca and place each wing in the hot oil. Fry for 5 minutes. Turn over. Continue to fry for 4-5 additional minutes or until the wing internal temperature reaches 165° F.\nTransfer to a baking sheet fitted with a cooling rack. Place in an a 170° F oven to keep warm.\nWhile the first batch fries, coat remaining half of the wings in the tapioca starch mixture.\nAllow the oil to come up to 375° F before frying the second batch of wings.\nFor the firecracker sauce:\nAdd all the sauce ingredients to a small saucepan. Blend well. Bring to a gently boil on medium heat, stirring occasionally. Reduce heat to a simmer for 1 minute. Reduce to low to warm, stirring occasionally.\nPour the desired amount of sauce over the wings. Toss to coat. Garnish with cilantro, optional. Serve immediately.\nMakes about 16 flats and drumettes or 4 appetizer servings.",
   "instructions_list": [
     "Instructions for pan frying are detailed here. See notes below for oven bake and air frying.",
     "Fill large skillet or frying pan with 1 to 1 1/4-inch of oil. Make sure the oil is at least 1 1/2-inch below the top of the pan to prevent overflow. Preheat oil to 375° F while you prep the wings.",
diff --git a/tests/test_data/kitchendreaming.com/kitchendreaming_1.json b/tests/test_data/kitchendreaming.com/kitchendreaming_1.json
index 0709ddf5..c98e47b7 100644
--- a/tests/test_data/kitchendreaming.com/kitchendreaming_1.json
+++ b/tests/test_data/kitchendreaming.com/kitchendreaming_1.json
@@ -21,7 +21,6 @@
     "1/2 cup chunky blue cheese dressing ( [See Note 5] - plus more for serving)",
     "fresh parsley for garnish"
   ],
-  "instructions": "Preheat oven to 400 degrees F. Line a baking sheet with parchment paper or a silicone baking mat and set aside\nIn a large bowl, combine ground chicken, Panko, egg, garlic and onion powder, green onions, salt, and pepper. Mix until well combined. With a small scoop or your hands, roll the mixture into 1-inch meatballs, forming about 40 meatballs.\nPlace meatballs onto prepared baking sheet and bake for 4-5 minutes, or until all sides are browned.\nWhile the meatballs are in the oven, add the butter and hot sauce into the crock pot to melt; then whisk together.\nRemove the meatballs from the oven and place into the slow cooker and gently toss to combine with the sauce. Cover and cook on low heat for 2 hours.\nTo serve: Either insert a carrot or celery sticks into the meatballs for serving or serve them with the carrots and celery on the side allowing guests to chose their stick for an interactive appetizer.",
   "instructions_list": [
     "Preheat oven to 400 degrees F. Line a baking sheet with parchment paper or a silicone baking mat and set aside",
     "In a large bowl, combine ground chicken, Panko, egg, garlic and onion powder, green onions, salt, and pepper. Mix until well combined. With a small scoop or your hands, roll the mixture into 1-inch meatballs, forming about 40 meatballs.",
diff --git a/tests/test_data/kitchendreaming.com/kitchendreaming_2.json b/tests/test_data/kitchendreaming.com/kitchendreaming_2.json
index 64da3f46..16eade14 100644
--- a/tests/test_data/kitchendreaming.com/kitchendreaming_2.json
+++ b/tests/test_data/kitchendreaming.com/kitchendreaming_2.json
@@ -65,7 +65,6 @@
       "purpose": "For the sauce:"
     }
   ],
-  "instructions": "In a zip-top bag or bowl, combine chicken with all the ingredients for the chicken marinade; let marinate for 30 minutes to an hour (or overnight if time allows).\nHeat oil in a large skillet over medium-high heat. Cook chicken in small batches, making sure not to overcrowd the pan. Saute until browned - about 3 minutes on each side. Set aside while you prepare the sauce.\nHeat butter in the same pan. Saute the onions until they turn translucent while scraping up any browned bits stuck on the bottom of the pan.\nNext, add the garlic and ginger and saute for 1 minute until fragrant, then add ground coriander, cumin, and garam masala. Let spices bloom for about 20 seconds until fragrant. Stir occasionally.\nThen add the crushed tomatoes, chili powder, and salt. Let simmer for 10-15 minutes, stirring occasionally. Allow the sauce to thicken and become a deep red color.\nRemove from heat. Carefully pour the sauce into a blender and blend until smooth. If you have a smaller-sized blender, you may nee to do this in batches.\nPour the sauce back into the pan. Stir in the cream, sugar, and crushed fenugreek leaves. Add the chicken and any collected juices back into the pan and cook for an additional 5-10 minutes or until the chicken is cooked through.\nGarnish with chopped cilantro and serve with rice and Naan bread.",
   "instructions_list": [
     "In a zip-top bag or bowl, combine chicken with all the ingredients for the chicken marinade; let marinate for 30 minutes to an hour (or overnight if time allows).",
     "Heat oil in a large skillet over medium-high heat. Cook chicken in small batches, making sure not to overcrowd the pan. Saute until browned - about 3 minutes on each side. Set aside while you prepare the sauce.",
diff --git a/tests/test_data/leitesculinaria.com/leitesculinaria_1.json b/tests/test_data/leitesculinaria.com/leitesculinaria_1.json
index 272364b3..9b44d31f 100644
--- a/tests/test_data/leitesculinaria.com/leitesculinaria_1.json
+++ b/tests/test_data/leitesculinaria.com/leitesculinaria_1.json
@@ -15,7 +15,6 @@
     "1/2 cup distilled white vinegar (plus more as needed)",
     "Water (as needed)"
   ],
-  "instructions": "Process\nTo make the Sriracha, in the bowl of a food processor, combine the peppers, garlic, garlic powder, if desired, sugars, and salt. Pulse until a coarse purée forms.\nFerment\nTransfer to a glass jar, seal, and store at room temperature for 7 days, stirring daily. (It may get a little fizzy; that's to be expected.)\nSimmer\nAfter 1 week, pour the chile mixture into a small saucepan over medium heat. Add the vinegar and bring to a boil. Lower the heat and simmer gently for 5 minutes. [Editor's note: If you'd like to preserve the gut-friendly bacteria that has been brewing in your hot sauce, skip the simmering step and purée the pepper mixture and vinegar together in the next step.]\nCool\nLet the mixture cool and then purée it in a food processor for 2 to 3 minutes, until a smooth, uniform paste forms. If the mixture is too thick to blend properly, add a small amount of water.\nStrain\nPass the mixture through a fine-mesh strainer. Press on the solids with the back of a spoon to squeeze out every last bit of goodness you’ve been waiting a week to get.\nSeason\nTaste and adjust the seasoning and consistency of the final sauce, adding additional vinegar, water, salt, granulated sugar, or garlic powder to suit your taste. Transfer to a glass jar, close the lid tightly, and refrigerate for up to 6 months.",
   "instructions_list": [
     "Process",
     "To make the Sriracha, in the bowl of a food processor, combine the peppers, garlic, garlic powder, if desired, sugars, and salt. Pulse until a coarse purée forms.",
diff --git a/tests/test_data/leitesculinaria.com/leitesculinaria_2.json b/tests/test_data/leitesculinaria.com/leitesculinaria_2.json
index c02912d0..13ffbd8a 100644
--- a/tests/test_data/leitesculinaria.com/leitesculinaria_2.json
+++ b/tests/test_data/leitesculinaria.com/leitesculinaria_2.json
@@ -51,7 +51,6 @@
       "purpose": "For serving"
     }
   ],
-  "instructions": "Refrigerate\nThe day before cooking, in a large bowl, coat the beef with the crushed red pepper, cover, and refrigerate overnight.\nCombine\nAbout 4 hours before you intend to sit down at the table, scatter the onion slices, parsley, garlic, and bay leaves in the bottom of a Dutch oven. Tuck the allspice and cloves in a piece of cheesecloth tied together with kitchen twine or in a tea ball and toss them in the Dutch oven. If desired, season the beef with salt. Place the beef on top and dot with the butter or lard.\nStir\nIn a measuring glass or bowl, stir together the wine, tomato paste, and cinnamon and pour it over the beef.\nSimmer\nBring the mixture to a boil, reduce the heat to a very gentle simmer, cover, and cook until the meat is very tender, 3 to 3 1/2 hours, turning the pieces occasionally. For a more stew-like version, keep the lid on for the duration of cooking. For a more concentrated, glaze-like sauce version, about halfway through cooking, remove the lid to let some of the liquid evaporate so the sauce can concentrate in consistency and flavor.\nServe\nRemove the bay leaves and the cheesecloth pouch or teaball. If desired, serve the caçoila with boiled white potatoes, roasted red peppers, and cooked greens.",
   "instructions_list": [
     "Refrigerate",
     "The day before cooking, in a large bowl, coat the beef with the crushed red pepper, cover, and refrigerate overnight.",
diff --git a/tests/test_data/lekkerensimpel.com/lekkerensimpel_2.json b/tests/test_data/lekkerensimpel.com/lekkerensimpel_2.json
index b6c866b9..a8581140 100644
--- a/tests/test_data/lekkerensimpel.com/lekkerensimpel_2.json
+++ b/tests/test_data/lekkerensimpel.com/lekkerensimpel_2.json
@@ -22,7 +22,6 @@
     "Smelt een blokje boter in een pan en schep met een soeplepel 2-3 kleine pannenkoekjes in de pan.",
     "Bak de pannenkoekjes circa 2 minuten per kant. Ondertussen verwarm de Nutella en melk in een pannetje. Meng even goed door elkaar en zodra je een mooi glad sausje hebt, is het klaar. Serveer de American pancakes met wat gesmolten nutella en wat vers fruit."
   ],
-  "category": null,
   "description": "Wil je iemand (of jezelf) verwennen met een heel lekker ontbijtje? Bekijk dan dit recept voor American Pancakes met Nutella en fruit!",
   "image": "https://www.lekkerensimpel.com/wp-content/uploads/2016/08/IMG_7654.jpg"
 }
diff --git a/tests/test_data/lekkerensimpel.com/lekkerensimpel_3.json b/tests/test_data/lekkerensimpel.com/lekkerensimpel_3.json
index 0810c0a9..34d2429d 100644
--- a/tests/test_data/lekkerensimpel.com/lekkerensimpel_3.json
+++ b/tests/test_data/lekkerensimpel.com/lekkerensimpel_3.json
@@ -26,7 +26,6 @@
     "Volg ons ook op Pinterest en sla daar deze hartige taart met sperziebonen en gehakt op!",
     "Ook lekker: hartige taart met champignons en en spinazie. "
   ],
-  "category": null,
   "description": "Hartige taarten zijn lekker en leuk om te maken omdat je er zo goed mee kunt variëren. Wat dacht je van een hartige taart met gehakt?",
   "image": "https://www.lekkerensimpel.com/wp-content/uploads/2016/10/IMG_1300.jpg"
 }
diff --git a/tests/test_data/myvegetarianroots.com/myvegetarianroots_1.json b/tests/test_data/myvegetarianroots.com/myvegetarianroots_1.json
index 4bea8550..98203a13 100644
--- a/tests/test_data/myvegetarianroots.com/myvegetarianroots_1.json
+++ b/tests/test_data/myvegetarianroots.com/myvegetarianroots_1.json
@@ -18,7 +18,6 @@
     "2 inch Ginger Root",
     "2 cup Water"
   ],
-  "instructions": "Mix all lentils mentioned above, wash them few times and soak them for 6-8 hours.\nOnce soaked, drain all the water out. Wrap it in a muslin/cotton cloth. Place it in a strainer with a plate underneath it. Place the whole set up in a dark place. I like to place it in an oven (THAT IS NOT ON) for 12 hours to let them sprout.\nCheck the beans after 12 hours, move it around with you fingers. If you wish to sprout more, place the same setting in dark place for another 12 hours.\nOnce sprouted, rinse them with water. Drain all the water out.\nPlace drained sprouted beans in a blender/food processor with rest of the ingredients listed above. Keep blending till you get pancake like consistency. 2 cups of water as mentioned above should be enough to get the right consistency, but you can add more or less if you like. you can leave it grainy or smooth based on your preference.\nOnce the batter is ready, it's ready to make the chilla/wrap. You can either use it right away or refrigerate it up to 3 days and use it as you like!\nHeat up cast irons skillet/choice of tawa. Spray avocado oil or use any type of oil to grease the skillet/tawa.\nSpread a thin (or thick, as you like) layer of batter on greasy hot skillet/tawa. Spray/drizzle some more oil on top, cover and let it cook on medium heat (closer to high but not too high) for about a min or so, until you see charred brown marks on the side facing down.\nFlip it and cook on the other side for few more second, until it starts showing some brown spots.\nRepeat the same process for as mnay wraps/chilla you like to make.\nSimply enjoy it with choice of subzi/dal/pickle/yogurt. Or top it with crunchy veggie salad. Drizzle creamy tahini sauce & spicy garlicky red pepper sauce as mentioned in my Falafel recipe. Wrap it and enjoy like a wrap!",
   "instructions_list": [
     "Mix all lentils mentioned above, wash them few times and soak them for 6-8 hours.",
     "Once soaked, drain all the water out. Wrap it in a muslin/cotton cloth. Place it in a strainer with a plate underneath it. Place the whole set up in a dark place. I like to place it in an oven (THAT IS NOT ON) for 12 hours to let them sprout.",
diff --git a/tests/test_data/myvegetarianroots.com/myvegetarianroots_2.json b/tests/test_data/myvegetarianroots.com/myvegetarianroots_2.json
index 82400ef4..9cabe33a 100644
--- a/tests/test_data/myvegetarianroots.com/myvegetarianroots_2.json
+++ b/tests/test_data/myvegetarianroots.com/myvegetarianroots_2.json
@@ -98,7 +98,6 @@
       "purpose": "Other"
     }
   ],
-  "instructions": "Making Falafel\nMix all lentils mentioned above, wash them few times and soak them for 6-8 hours.\nOnce soaked for 6-8 hours, drain all the water our and grind them along with clean cilantro & parsley, serrano, garlic, ginger, coarsely ground coriander seeds.\nTry not to use any or too much water to grind it. The batter should be just a little grainy and thick so that you can form balls to deep fry. Please know that the falafel mix will start loosing moisture as time goes. I recommend you deep frying soon after grinding\nRight before you are ready to deep fry, mix in salt and baking soda.\nMake a bit smaller than golf ball sized balls, deep fry them in hot oil on medium heat until all sides are nicely brown and crispy.\nMake Creamy Tahini Sauce\nSimply blend everything listed under \"Creamy Tahini Sauce\". Blend it to creamy sauce consistency. Please know that this sauce will thicken as time goes. Take the sauce out in a mason jar and use the same blender without washing it to make the red sauce. Can be stored in a mason jar inside the fridge for upto 4-5 days.\nMake Spicy Red Garlicky Sauce\nSoak hot whole dry red chili in warm water for 10-15 min.\nUse the same unwashed blender you made the tahini sauce in to make red sauce. Red peppers have very high water content, using a tiny bit of creamy while sauce that is stuck in the blender will help the consistency of red sauce!\nBlend soaked hot whole dry red chili (without water), dark fresh red peppers (without seeds & stems), salt and garlic. Can be stored in a mason jar inside the fridge for upto 4-5 days.\nAssemble\nMix everything listed under \"Mixed Veggies/Salad\". Make sure all the veggies are well coated with Creamy Tahini Sauce. Use more or less tahini sauce as you like!\nWarm pita pocket for few second. Pack it half way through with \"Mixed Veggies/Salad\". Drizzle spicy red sauce, top it with falafel. Drizzle white & red sauces. Top it with more \"Mixed Veggies/Salad\" and enjoy!!",
   "instructions_list": [
     "Making Falafel",
     "Mix all lentils mentioned above, wash them few times and soak them for 6-8 hours.",
diff --git a/tests/test_data/peelwithzeal.com/peelwithzeal_1.json b/tests/test_data/peelwithzeal.com/peelwithzeal_1.json
index dada8e39..1e5dc147 100644
--- a/tests/test_data/peelwithzeal.com/peelwithzeal_1.json
+++ b/tests/test_data/peelwithzeal.com/peelwithzeal_1.json
@@ -19,7 +19,6 @@
     "2 tablespoons apple cider vinegar",
     "1 tablespoon paprika"
   ],
-  "instructions": "Preheat the oven to 350 degrees F.\nFry the bacon in a large skillet over medium-high heat until crisp. Remove the bacon from the pan and drain it on paper towels. Do not drain the pan.\nSaute\nAdd the onion to the pan with the bacon drippings and saute for 5 minutes. Add the garlic and stir for 30 seconds.\nMix\nStir in the beans, beef stock, molasses, ketchup, brown sugar, mustard, paprika, and cooked bacon, and mix well.\nBake\nPour into a large casserole and bake covered for about 20 minutes. Remove the lid and cook for an additional 25 minutes.",
   "instructions_list": [
     "Preheat the oven to 350 degrees F.",
     "Fry the bacon in a large skillet over medium-high heat until crisp. Remove the bacon from the pan and drain it on paper towels. Do not drain the pan.",
diff --git a/tests/test_data/peelwithzeal.com/peelwithzeal_2.json b/tests/test_data/peelwithzeal.com/peelwithzeal_2.json
index a267d336..caad9c8c 100644
--- a/tests/test_data/peelwithzeal.com/peelwithzeal_2.json
+++ b/tests/test_data/peelwithzeal.com/peelwithzeal_2.json
@@ -53,7 +53,6 @@
       "purpose": "Cajun Seasoning Blend"
     }
   ],
-  "instructions": "Mix\nStir together the cream cheese, mayo, lemon juice and zest, and spices.\nStir in the crab meat and green onions.\nServe\nTop with fresh parsley and serve with crackers, chips, or crostini.",
   "instructions_list": [
     "Mix",
     "Stir together the cream cheese, mayo, lemon juice and zest, and spices.",
diff --git a/tests/test_data/sandwichtribunal.com/sandwhichtribunal.json b/tests/test_data/sandwichtribunal.com/sandwhichtribunal.json
index b2caeb74..94363eb2 100644
--- a/tests/test_data/sandwichtribunal.com/sandwhichtribunal.json
+++ b/tests/test_data/sandwichtribunal.com/sandwhichtribunal.json
@@ -16,7 +16,6 @@
     "2 tsp cayenne pepper",
     "salt and pepper to taste"
   ],
-  "instructions": "Mix all ingredients together and taste. Season as needed and hold in refrigerator for at least 1 hour.\nServe with barbecue chicken, pork, or turkey",
   "instructions_list": [
     "Mix all ingredients together and taste. Season as needed and hold in refrigerator for at least 1 hour.",
     "Serve with barbecue chicken, pork, or turkey"
diff --git a/tests/test_data/weightwatchers.com/weightwatcherspublic_2.json b/tests/test_data/weightwatchers.com/weightwatcherspublic_2.json
index 2dacc8a5..9b46043d 100644
--- a/tests/test_data/weightwatchers.com/weightwatcherspublic_2.json
+++ b/tests/test_data/weightwatchers.com/weightwatcherspublic_2.json
@@ -13,7 +13,6 @@
     "2 Prise(n) Zimt",
     "2 Stück Erdbeeren, frisch"
   ],
-  "instructions": "Banane schälen und mit einer Gabel zerdrücken. Datteln hacken, mit Bananenmus, Ei, Haferflocken und Zimt verrühren und in eine Tasse füllen.\nTassen-Frühstück in der Mikrowelle bei 800 Watt 2–3 Minuten garen. Erdbeeren waschen, trocken tupfen, in Scheiben schneiden und Sarah’s Tassen-Frühstück mit Erdbeerscheiben garniert servieren.",
   "instructions_list": [
     "Banane schälen und mit einer Gabel zerdrücken. Datteln hacken, mit Bananenmus, Ei, Haferflocken und Zimt verrühren und in eine Tasse füllen.",
     "Tassen-Frühstück in der Mikrowelle bei 800 Watt 2–3 Minuten garen. Erdbeeren waschen, trocken tupfen, in Scheiben schneiden und Sarah’s Tassen-Frühstück mit Erdbeerscheiben garniert servieren."
diff --git a/tests/test_data/whatsgabycooking.com/whatsgabycooking.json b/tests/test_data/whatsgabycooking.com/whatsgabycooking.json
index d6c4cb76..1596b735 100644
--- a/tests/test_data/whatsgabycooking.com/whatsgabycooking.json
+++ b/tests/test_data/whatsgabycooking.com/whatsgabycooking.json
@@ -27,7 +27,6 @@
     "Limes",
     "Fresh Cilantro"
   ],
-  "instructions": "Slice the chicken breasts into thin strips, about the size of your finger. Combine the lime juice, olive oil, garlic, salt, cumin, chili powder and red pepper flakes in a bowl and whisk to combine. Add the chicken and marinate for 1 hour.\nHeat a large cast iron skillet over high heat. Add a tablespoon of olive oil. Add the chicken mixture, marinade included, and sauté until fully cooked. Using a pair of tongs, remove the chicken from the skillet and add the vegetables. Sauté until tender and charred. Add the chicken back into the cast iron skillet and toss to combine.\nServe in a bowl with rice, black beans, charred corn, chopped tomatoes, a big spoonful of guacamole and a wedge of lime.",
   "instructions_list": [
     "Slice the chicken breasts into thin strips, about the size of your finger. Combine the lime juice, olive oil, garlic, salt, cumin, chili powder and red pepper flakes in a bowl and whisk to combine. Add the chicken and marinate for 1 hour.",
     "Heat a large cast iron skillet over high heat. Add a tablespoon of olive oil. Add the chicken mixture, marinade included, and sauté until fully cooked. Using a pair of tongs, remove the chicken from the skillet and add the vegetables. Sauté until tender and charred. Add the chicken back into the cast iron skillet and toss to combine.",
diff --git a/tests/test_data/whatsgabycooking.com/whatsgabycooking_1.json b/tests/test_data/whatsgabycooking.com/whatsgabycooking_1.json
index cfa0593f..ab42fea2 100644
--- a/tests/test_data/whatsgabycooking.com/whatsgabycooking_1.json
+++ b/tests/test_data/whatsgabycooking.com/whatsgabycooking_1.json
@@ -15,7 +15,6 @@
     "1 lemon (juiced and zested)",
     "1/2 cup Tahini Sauce, plus more as needed"
   ],
-  "instructions": "Preheat the oven to 450 degrees F. Line a baking sheet with parchment paper. Spread the broccoli evenly on the baking sheet and drizzle with 2 tablespoons of olive oil. Using tongs, gently toss the florets in the oil to combine and season with 4 tablespoons of the tahini sauce, salt and pepper and red pepper flakes. Toss to combine.\nTransfer the baking sheet into the oven and roast for 15-20 minutes until the broccoli is just golden and slightly crispy.\nRemove the baking sheet from the oven and drizzle more 2-3 tablespoons more of the tahini sauce on top. Toss with the toasted buttered breadcrumbs, tons of freshly grated parmesan cheese, lemon juice and zest and serve as needed.",
   "instructions_list": [
     "Preheat the oven to 450 degrees F. Line a baking sheet with parchment paper. Spread the broccoli evenly on the baking sheet and drizzle with 2 tablespoons of olive oil. Using tongs, gently toss the florets in the oil to combine and season with 4 tablespoons of the tahini sauce, salt and pepper and red pepper flakes. Toss to combine.",
     "Transfer the baking sheet into the oven and roast for 15-20 minutes until the broccoli is just golden and slightly crispy.",
diff --git a/tests/test_data/whatsgabycooking.com/whatsgabycooking_2.json b/tests/test_data/whatsgabycooking.com/whatsgabycooking_2.json
index 091d7c80..df140b77 100644
--- a/tests/test_data/whatsgabycooking.com/whatsgabycooking_2.json
+++ b/tests/test_data/whatsgabycooking.com/whatsgabycooking_2.json
@@ -53,7 +53,6 @@
       "purpose": "For the Tzatziki"
     }
   ],
-  "instructions": "Preheat the oven to broil.\nIn a medium bowl, combine lamb with all of the meatball ingredients. Form the meat into golf ball sized balls. Place the meatballs two inches apart on the baking sheet, and position the baking sheet a few inches from the heat source. Broil for about 5-7 minutes, turning once halfway through. Alternatively you can bake these at 425 for 8-10 minutes.\nCombine the ingredients for the feta tzatziki. Serve alongside the meatballs for dipping.",
   "instructions_list": [
     "Preheat the oven to broil.",
     "In a medium bowl, combine lamb with all of the meatball ingredients. Form the meat into golf ball sized balls. Place the meatballs two inches apart on the baking sheet, and position the baking sheet a few inches from the heat source. Broil for about 5-7 minutes, turning once halfway through. Alternatively you can bake these at 425 for 8-10 minutes.",