diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 57702d326..000000000 --- a/.coveragerc +++ /dev/null @@ -1,13 +0,0 @@ -[run] -branch = True -source = recipe_scrapers -relative_files = True - -[report] -omit = recipe_scrapers/__version__.py - recipe_scrapers/plugins/template.py - recipe_scrapers/settings/template.py - -exclude_lines = - # Don't complain if tests don't hit defensive assertion code: - raise NotImplementedError diff --git a/.flake8 b/.flake8 index 76661ede4..3f0b0afb9 100644 --- a/.flake8 +++ b/.flake8 @@ -1,10 +1,43 @@ [flake8] -# FS002 comes from pugin "flake8-use-fstring" -# and would error on `str.format()` usage -ignore = E203, E501, W503, FS002, N818 +# Error codes we ignore: +# +# Ignored because Black handles code formatting: +# E203: Whitespace before ':' +# E501: Line too long (82 > 79 characters) +# W503: Line break occurred before a binary operator +# +# Other ignored rules: +# N818: Exception names should end in 'Error' +ignore = + E203, + E501, + W503, + N818 + +# To match Black's default max-line-length = 88 + +# McCabe complexity checker +# Standard is 10, we should aim to improve max-complexity = 21 -select = B,C,E,F,N,W,T4,B9 + +# Selected error codes: +# B: bugbear checks +# C: complexity checks +# E: pycodestyle errors +# F: pyflakes +# N: naming checks (from pep8-naming) +# W: pycodestyle warnings +# T4: mypy type checks +select = + B, + C, + E, + F, + N, + W, + T4 + exclude = ./.tox/ ./.venv/ diff --git a/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md b/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md new file mode 100644 index 000000000..3f671683d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_issue_new_webiste.md @@ -0,0 +1,23 @@ +--- +name: New website +about: Request support for a new recipe website +title: "I'd like to request support for " +labels: enhancement +assignees: '' + +--- + +Please verify the website is not listed in: https://docs.recipe-scrapers.com/getting-started/supported-sites/ + +Sample recipe URLs: +- https:// +- https:// + + +----- + +Optional information that helps us understand our users better: +- Which version of recipe-scrapers are you using? +- How did you discover the package? +- What's your use case for recipe-scrapers? +Feel free to delete this section. diff --git a/.github/ISSUE_TEMPLATE/2_issue_website_bug.md b/.github/ISSUE_TEMPLATE/2_issue_website_bug.md new file mode 100644 index 000000000..ef09d03ab --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_issue_website_bug.md @@ -0,0 +1,26 @@ +--- +name: Scraper bug +about: Report an issue with an existing scraper +title: "Scraper issue with " +labels: bug +assignees: '' + +--- + +Recipe URL with the issue: +- https:// + + +Which data is not being scraped correctly? +(e.g. ingredients, instructions, etc): + +What should be shown instead? + + +----- + +Optional information that helps us understand our users better: +- Which version of recipe-scrapers are you using? +- How did you discover the package? +- What's your use case for recipe-scrapers? +Feel free to delete this section. diff --git a/.github/ISSUE_TEMPLATE/3_issue_show_and_tell.md b/.github/ISSUE_TEMPLATE/3_issue_show_and_tell.md new file mode 100644 index 000000000..77ab19c82 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3_issue_show_and_tell.md @@ -0,0 +1,15 @@ +--- +name: Show and tell +about: Share what you've built using recipe-scrapers +title: "Built with recipe-scrapers: " +labels: show-and-tell +assignees: '' + +--- + +Tell us about your project built with recipe-scrapers! + +You can also share it as a comment in https://github.com/hhursev/recipe-scrapers/issues/9. + +Project details: + diff --git a/.github/ISSUE_TEMPLATE/4_issue_other.md b/.github/ISSUE_TEMPLATE/4_issue_other.md new file mode 100644 index 000000000..b1fefd4bd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4_issue_other.md @@ -0,0 +1,20 @@ +--- +name: Other +about: For questions and issues that don't fit other categories +title: "" +labels: '' +assignees: '' + +--- + + +Describe your question or issue here + + +----- + +Optional information that helps us understand our users better: +- Which version of recipe-scrapers are you using? +- How did you discover the package? +- What's your use case for recipe-scrapers? +Feel free to delete this section. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0086358db..3ba13e0ce 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1 @@ -blank_issues_enabled: true +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/new_scraper.md b/.github/ISSUE_TEMPLATE/new_scraper.md deleted file mode 100644 index 9b4160a3b..000000000 --- a/.github/ISSUE_TEMPLATE/new_scraper.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: New website scraper request -about: Add support for a new recipe website -title: '' -labels: enhancement -assignees: '' - ---- - -Please check that recipes published on the website you're requesting are public (we can't currently scrape recipes that require an account login), and add sample recipe URL(s) below: - -- https:// ... -- https:// ... diff --git a/.github/ISSUE_TEMPLATE/scraper_bug_report.md b/.github/ISSUE_TEMPLATE/scraper_bug_report.md deleted file mode 100644 index 9c7310184..000000000 --- a/.github/ISSUE_TEMPLATE/scraper_bug_report.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Scraper bug report -about: Report a scraper that is not working correctly -title: '' -labels: bug -assignees: '' - ---- - -**Pre-filing checks**: - -- [ ] I have searched for open issues that report the same problem -- [ ] I have checked that the bug affects the latest version of the library - -**The URL of the recipe(s) that are not being scraped correctly**: - -- https:// ... - -... - -**The results you expect to see**: - -... - -**The results (including any Python error messages) that you are seeing**: - -... diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index aa74d1880..2ea65d880 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -2,39 +2,28 @@ name: coverage on: push: - branches: - - main - - v14 + branches: [ main, v14 ] pull_request: - branches: - - main - - v14 + branches: [ main, v14 ] + types: [ opened, synchronize, reopened ] jobs: coverage: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: "3.x" - - name: run unittests - run: | - pip install tox - tox -e py - - name: (coveralls.io) Report code coverage - uses: AndreMiras/coveralls-python-action@develop + python-version: "3.12" + cache: pip + - name: Install test packages + run: pip install ".[tests]" + - name: Run tests with coverage + env: + PYTHONWARNINGS: "always:::recipe_scrapers,ignore:::recipe_scrapers.plugins.static_values" + run: coverage run -m unittest + - name: Report coverage to coveralls.io + uses: coverallsapp/github-action@v2 with: github-token: "SmlfzlVJy4ow55rduU7IU5GmmFCfAdGeq" - - if: github.event_name == 'push' - name: (codacy) Create coverage xml report - run: | - pip install coverage - coverage xml - - if: github.event_name == 'push' - name: (codacy) Report code coverage - uses: codacy/codacy-coverage-reporter-action@v1 - with: - project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} - coverage-reports: "coverage.xml" diff --git a/.github/workflows/linters.yaml b/.github/workflows/linters.yaml index 4449d24b4..5ec88b17e 100644 --- a/.github/workflows/linters.yaml +++ b/.github/workflows/linters.yaml @@ -2,24 +2,22 @@ name: linters on: push: - branches: - - main - - v14 + branches: [ main, v14 ] pull_request: - branches: - - main - - v14 + branches: [ main, v14 ] + types: [ opened, synchronize, reopened ] jobs: linters: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: "3.x" + python-version: "3.12" cache: pip - cache-dependency-path: .pre-commit-config.yaml - - run: pip install pre-commit - - run: pre-commit run --all-files + - name: Install linters related packages + run: pip install ".[linters]" + - name: Run pre-commit hooks + run: pre-commit run --all-files diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 7f10e4b63..89dd981df 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -6,11 +6,17 @@ on: jobs: publish: + name: Upload release to PyPI runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/recipe-scrapers + permissions: + id-token: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.x" - name: Build the package @@ -20,8 +26,6 @@ jobs: - name: Publish a Python distribution to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} verbose: true - name: Show build version used run: pip list | grep build diff --git a/.github/workflows/test_publish.yaml b/.github/workflows/test_publish.yaml deleted file mode 100644 index 8e03ef01d..000000000 --- a/.github/workflows/test_publish.yaml +++ /dev/null @@ -1,34 +0,0 @@ -name: test_publish - - -# Will attempt to build + publish package in test.pypi.org -# -# the build can be tested if it works as expected by installing the package with: -# pip install --index-url https://test.pypi.org/simple/ --no-deps recipe-scrapers -# -# or by inspecting the files: https://test.pypi.org/project/recipe-scrapers/#files -on: workflow_dispatch - -jobs: - test_publish: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.x" - - name: Build the package - run: | - python -m pip install --upgrade build - python -m build . - - name: Publish a Python distribution to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.TEST_PYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ - verbose: true - skip_existing: true - - name: Show build version used - run: pip list | grep build diff --git a/.github/workflows/unittests.yaml b/.github/workflows/unittests.yaml index 879b0f7fc..bcac524b7 100644 --- a/.github/workflows/unittests.yaml +++ b/.github/workflows/unittests.yaml @@ -2,13 +2,10 @@ name: unittests on: push: - branches: - - main - - v14 + branches: [ main, v14 ] pull_request: - branches: - - main - - v14 + branches: [ main, v14 ] + types: [ opened, synchronize, reopened ] jobs: test: @@ -19,16 +16,14 @@ jobs: python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: pip - - name: Install dependencies - run: python -m pip install .[dev] - - name: Install parallel test runner - run: python -m pip install unittest-parallel + - name: Install tests dependencies + run: pip install ".[tests]" - name: Run Tests env: PYTHONWARNINGS: "always:::recipe_scrapers,ignore:::recipe_scrapers.plugins.static_values" diff --git a/.markdownlint.json b/.markdownlint.json deleted file mode 100644 index bdbf52591..000000000 --- a/.markdownlint.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "_": "Adapted from: https://github.com/DavidAnson/markdownlint/blob/b2305efafb034b1f328845aec9928b5363ffd646/schema/.markdownlint.jsonc#L67-L85", - "_MD007": "// Indentation: use kramdown-compatible indentation : https://kramdown.gettalong.org/syntax.html#ordered-and-unordered-lists", - "MD007": { - "indent": 3 - }, - "_MD013": "// Line length : https://github.com/DavidAnson/markdownlint/blob/v0.34.0/doc/md013.md", - "MD013": { - "line_length": 800, - "heading_line_length": 80, - "code_block_line_length": 800, - "code_blocks": true, - "tables": true, - "headings": true, - "strict": false, - "stern": false - } -} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 883c6ac0c..23feed693 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ exclude: '.test(html|json)' repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: check-yaml - id: end-of-file-fixer @@ -12,35 +12,17 @@ repos: - "--no-sort-keys" - "--no-ensure-ascii" - repo: https://github.com/pycqa/flake8.git - rev: 7.0.0 + rev: 7.1.1 hooks: - id: flake8 - additional_dependencies: [flake8-use-fstring, pep8-naming] -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - args: ["--profile", "black", "--filter-files"] + additional_dependencies: ["pep8-naming==0.14.1"] - repo: https://github.com/psf/black - rev: 24.2.0 + rev: 24.10.0 hooks: - id: black + args: ["--target-version", "py39"] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.9.0 + rev: v1.14.0 hooks: - id: mypy additional_dependencies: [types-beautifulsoup4, types-requests] -- repo: https://github.com/asottile/pyupgrade - rev: v3.15.1 - hooks: - - id: pyupgrade - args: [--py39-plus] -- repo: https://github.com/sphinx-contrib/sphinx-lint - rev: v0.9.1 - hooks: - - id: sphinx-lint - args: ["-e", "all", "-d", "line-too-long"] -- repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.43.0 - hooks: - - id: markdownlint diff --git a/README.rst b/README.rst index ee5bc563e..b507e6bd3 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,7 @@ +================= +recipe-scrapers +================= + .. image:: https://img.shields.io/github/stars/hhursev/recipe-scrapers?style=social :target: https://github.com/hhursev/recipe-scrapers/ :alt: Github @@ -10,8 +14,8 @@ .. image:: https://pepy.tech/badge/recipe-scrapers :target: https://pepy.tech/project/recipe-scrapers :alt: Downloads -.. image:: https://github.com/hhursev/recipe-scrapers/workflows/unittests/badge.svg?branch=main - :target: https://github.com/hhursev/recipe-scrapers/actions/ +.. image:: https://github.com/hhursev/recipe-scrapers/actions/workflows/unittests.yaml/badge.svg?branch=main + :target: unittests :alt: GitHub Actions Unittests .. image:: https://coveralls.io/repos/hhursev/recipe-scraper/badge.svg?branch=main&service=github :target: https://coveralls.io/github/hhursev/recipe-scraper?branch=main @@ -19,584 +23,110 @@ .. image:: https://img.shields.io/github/license/hhursev/recipe-scrapers? :target: https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE :alt: License -.. image:: https://app.codacy.com/project/badge/Grade/3ee8da77aaa3475a8085ca22287dea89 - :target: https://app.codacy.com/gh/hhursev/recipe-scrapers/dashboard - :alt: Codacy Badge +------- ------- +A reliable python tool for scraping recipe data from popular cooking websites. Extract structured +recipe information including ingredients, instructions, cooking times, and nutritional data +with ease. Supports 400+ major recipe websites out of the box. -A simple scraping tool for recipe webpages. +Quick Links +----------- +- `Documentation `_ +- `Supported Sites `_ +- `Contributing Guide `_ +- `Issue Tracker `_ +- `Share Project Ideas `_ -Netiquette +Installing ---------- +.. code:: shell -If you're using this library to collect large numbers of recipes from the web, please use the software responsibly and try to avoid creating high volumes of network traffic. - -Python's standard library provides a ``robots.txt`` `parser `_ that may be helpful to automatically follow common instructions specified by websites for web crawlers. + pip install recipe-scrapers -Another parser option -- particularly if you find that many web requests from ``urllib.robotparser`` are blocked -- is the `robotexclusionrulesparser `_ library. +Basic Usage +----------- +.. code:: python -Getting Started ---------------- + from urllib.request import urlopen + from recipe_scrapers import scrape_html -Start by using `Python's built-in package installer `_, ``pip``, to install the library: + # Example recipe URL + url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" + # retrieve the recipe webpage HTML + html = urlopen(url).read().decode("utf-8") -.. code:: shell + # pass the html alongside the url to our scrape_html function + scraper = scrape_html(html, org_url=url) - python -m pip install recipe-scrapers + # Extract recipe information + print(scraper.title()) # "Spinach and Feta Turkey Burgers" + print(scraper.total_time()) # 35 + print(scraper.yields()) # "4 servings" + print(scraper.ingredients()) # ['1 pound ground turkey', '1 cup fresh spinach...'] + print(scraper.instructions()) # 'Step 1: In a large bowl...' -This should produce output about the installation process, with the final line reading: ``Successfully installed recipe-scrapers-``. + # For a complete list of available methods: + help(scraper) -To learn what the library can do, you can open a `Python interpreter session `_, and then begin typing -- and/or modifying -- the statements below (on the lines containing the ``>>>`` prompt): -.. code:: pycon +HTTP Clients +------------ +Some Python HTTP clients you can use to retrieve HTML include: - Python 4.0.4 (main, Oct 26 1985, 09:00:32) [GCC 22.3.4] on linux - Type "help", "copyright", "credits" or "license" for more information. - >>> from recipe_scrapers import scrape_html - >>> url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" - >>> name = input('What is your name, burger seeker?\n') - >>> html = requests.get(url, headers={"User-Agent": f"Burger Seeker {name}"}).content - >>> scraper = scrape_html(html, org_url=url) - >>> help(scraper) +- `requests`_: Popular and feature-rich +- `httpx`_: Modern, supports async/await +- `urllib.request`_: Included in Python's standard library -Some Python HTTP clients that you can use to retrieve HTML include `requests`_, `httpx`_, and the `urllib.request module`_ included in Python's standard library. Please refer to their documentation to find out what options (timeout configuration, proxy support, etc) are available. +Please refer to their documentation to find out what options (timeout configuration, proxy +support, etc) are available. .. _requests: https://pypi.org/project/requests/ - .. _httpx: https://pypi.org/project/httpx/ +.. _urllib.request: https://docs.python.org/3/library/urllib.request.html -.. _urllib.request module: https://docs.python.org/3/library/urllib.request.html - - -Scrapers available for: ------------------------ - -- `https://101cookbooks.com/ `_ -- `https://15gram.be `_ -- `https://40aprons.com/ `_ -- `https://www.750g.com `_ -- `https://abeautifulmess.com/ `_ -- `https://aberlehome.com/ `_ -- `https://abuelascounter.com/ `_ -- `https://www.acouplecooks.com `_ -- `https://addapinch.com/ `_ -- `http://www.afghankitchenrecipes.com/ `_ -- `https://aflavorjournal.com/ `_ -- `https://ah.nl/ `_ -- `https://akispetretzikis.com/ `_ -- `https://aldi-nord.de/ `_ - - `.es `__, `.fr `__, `.lu `__, `.nl `__, `.pl `__, `.pt `__ -- `https://aldi-sued.de/ `_ - - `.hu `__, `.it `__ -- `https://aldi-suisse.ch `_ -- `https://aldi.com.au/ `_ -- `https://alexandracooks.com/ `_ -- `https://alittlebityummy.com/ `_ -- `https://allrecipes.com/ `_ -- `https://allthehealthythings.com/ `_ -- `https://alltommat.se/ `_ -- `https://altonbrown.com/ `_ -- `https://amazingribs.com/ `_ -- `https://ambitiouskitchen.com/ `_ -- `https://americastestkitchen.com/ `_ (*) -- `https://archanaskitchen.com/ `_ -- `https://www.argiro.gr/ `_ -- `https://www.arla.se/ `_ -- `https://www.atelierdeschefs.fr/ `_ -- `https://averiecooks.com/ `_ -- `https://www.bakels.com.au/ `_ - - `.co.uk `_ -- `https://baking-sense.com/ `_ -- `https://bakingmischief.com/ `_ -- `https://barefeetinthekitchen.com/ `_ -- `https://barefootcontessa.com/ `_ -- `https://barefootinthepines.com/ `_ -- `https://bbc.com/ `_ - - `.co.uk `__ -- `https://bbcgoodfood.com/ `_ -- `https://bestrecipes.com.au/ `_ -- `https://betterfoodguru.com/ `_ -- `https://bettybossi.ch/ `_ -- `https://bettycrocker.com/ `_ -- `https://beyondfrosting.com/ `_ -- `https://biancazapatka.com/ `_ -- `https://bigoven.com/ `_ -- `https://bitsofcarey.com/ `_ -- `https://blueapron.com/ `_ -- `https://bluejeanchef.com/ `_ -- `https://www.bodybuilding.com/ `_ -- `https://bonappetit.com/ `_ -- `https://bongeats.com/ `_ -- `https://books.ottolenghi.co.uk `_ (*) -- `https://bowlofdelicious.com/ `_ -- `https://breadtopia.com/ `_ -- `https://briceletbaklava.ch/ `_ -- `https://brokenovenbaking.com/ `_ -- `https://budgetbytes.com/ `_ -- `https://cafedelites.com/ `_ -- `https://cakemehometonight.com/ `_ -- `https://cambreabakes.com/ `_ -- `https://carlsbadcravings.com/ `_ -- `https://castironketo.net/ `_ -- `https://cdkitchen.com/ `_ -- `https://celebratingsweets.com/ `_ -- `https://chefjeanpierre.com/ `_ -- `https://chefkoch.de/ `_ -- `https://www.chefnini.com/ `_ -- `https://chefsavvy.com/ `_ -- `https://claudia.abril.com.br/ `_ -- `https://closetcooking.com/ `_ -- `https://colleenchristensennutrition.com/ `_ -- `https://comidinhasdochef.com/ `_ -- `https://cook-talk.com/ `_ -- `https://cookeatshare.com/ `_ -- `https://cookieandkate.com/ `_ -- `https://cookiesandcups.com/ `_ -- `https://cooking.nytimes.com/ `_ -- `https://cookingcircle.com/ `_ -- `https://cookinglight.com/ `_ -- `https://cookomix.com/ `_ -- `https://cookpad.com/ `_ -- `https://cookscountry.com/ `_ (*) -- `https://cooksillustrated.com/ `_ (*) -- `https://cookwell.com/ `_ -- `https://copykat.com/ `_ -- `https://www.costco.com/ `_ -- `https://countryliving.com/ `_ -- `https://creativecanning.com/ `_ -- `https://cucchiaio.it/ `_ -- `https://cuisineaz.com/ `_ -- `https://cybercook.com.br/ `_ -- `https://damndelicious.net/ `_ -- `https://www.davidlebovitz.com/ `_ -- `https://delish.com/ `_ -- `https://dinneratthezoo.com/ `_ -- `https://dinnerthendessert.com/ `_ -- `https://dish.co.nz/ `_ -- `https://dobruchut.aktuality.sk/ `_ -- `https://domesticate-me.com/ `_ -- `https://donalskehan.com/ `_ -- `https://downshiftology.com/ `_ -- `https://www.dr.dk/ `_ -- `https://www.eatingbirdfood.com/ `_ -- `https://www.eatingwell.com/ `_ -- `https://www.eatliverun.com/ `_ -- `https://eatsmarter.com/ `_ - - `.de `__ -- `https://eatthismuch.com/ `_ -- `https://eattolerant.de/ `_ -- `https://www.eatwell101.com `_ -- `https://eatwhattonight.com/ `_ -- `https://elavegan.com/ `_ -- `https://emmikochteinfach.de/ `_ -- `https://en.wikibooks.org/ `_ -- `https://epicurious.com/ `_ -- `https://www.errenskitchen.com/ `_ -- `https://ethanchlebowski.com/ `_ -- `https://www.evolvingtable.com/ `_ -- `https://www.familyfoodonthetable.com/ `_ -- `https://www.farmhouseonboone.com/ `_ -- `https://www.fattoincasadabenedetta.it/ `_ -- `https://felix.kitchen `_ -- `https://fifteenspatulas.com/ `_ -- `https://finedininglovers.com/ `_ -- `https://fitmencook.com/ `_ -- `https://fitslowcookerqueen.com `_ -- `https://food.com/ `_ -- `https://food52.com/ `_ -- `https://foodandwine.com/ `_ -- `https://foodfidelity.com/ `_ -- `https://foodnetwork.co.uk/ `_ - - `.com `__ -- `https://foodrepublic.com/ `_ -- `https://www.forksoverknives.com/ `_ -- `https://forktospoon.com/ `_ -- `https://franzoesischkochen.de/ `_ -- `https://www.gesund-aktiv.com/ `_ -- `https://gimmesomeoven.com/ `_ -- `https://glutenfreeonashoestring.com/ `_ -- `https://godt.no/ `_ -- `https://gonnawantseconds.com/ `_ -- `https://goodfooddiscoveries.com/ `_ -- `https://goodhousekeeping.com/ `_ -- `https://gourmettraveller.com.au/ `_ -- `https://www.grandfrais.com/ `_ -- `https://greatbritishchefs.com/ `_ -- `https://grimgrains.com/ `_ -- `http://www.grouprecipes.com/ `_ -- `https://halfbakedharvest.com/ `_ -- `https://handletheheat.com/ `_ -- `https://www.hassanchef.com/ `_ -- `https://headbangerskitchen.com/ `_ -- `https://healthyeating.nhlbi.nih.gov/ `_ -- `https://heatherchristo.com/ `_ -- `https://www.heb.com/ `_ -- `https://hellofresh.com/ `_ - - `.at `__, `.be `__, `.ca `__, `.ch `__, `.co.nz `__, `.co.uk `__, `.com.au `__, `.de `__, `.dk `__, `.es `__, `.fr `__, `.ie `__, `.it `__, `.lu `__, `.nl `__, `.no `__, `.se `__ -- `https://www.hersheyland.com/ `_ -- `https://hofer.at/ `_ - - `.si `__ -- `https://www.homechef.com/ `_ -- `https://hostthetoast.com/ `_ -- `https://hungryhappens.net/ `_ -- `https://www.ica.se/ `_ -- `https://www.im-worthy.com/ `_ -- `https://inbloombakery.com/ `_ -- `https://indianhealthyrecipes.com `_ -- `https://ingoodflavor.com `_ -- `https://www.innit.com/ `_ -- `https://insanelygoodrecipes.com `_ -- `https://inspiralized.com/ `_ -- `https://irishcentral.com/ `_ -- `https://izzycooking.com/ `_ -- `https://jamieoliver.com/ `_ -- `https://jimcooksfoodgood.com/ `_ -- `https://www.jocooks.com/ `_ -- `https://joshuaweissman.com/ `_ -- `https://joyfoodsunshine.com/ `_ -- `https://joythebaker.com/ `_ -- `https://juliegoodwin.com.au/ `_ -- `https://justataste.com/ `_ -- `https://justbento.com/ `_ -- `https://www.justonecookbook.com/ `_ -- `https://kalejunkie.com/ `_ -- `https://kennymcgovern.com/ `_ -- `https://keukenliefde.nl/ `_ -- `https://www.kingarthurbaking.com `_ -- `https://kitchenaid.com.au/ `_ -- `https://kitchendivas.com `_ -- `https://www.kitchendreaming.com `_ -- `https://www.kitchensanctuary.com/ `_ -- `https://www.kitchenstories.com/ `_ -- `https://kochbar.de/ `_ -- `https://kochbucher.com/ `_ -- `http://koket.se/ `_ -- `https://kristineskitchenblog.com/ `_ -- `https://krollskorner.com/ `_ -- `https://kuchnia-domowa.pl/ `_ -- `https://kuchynalidla.sk/ `_ -- `https://www.kwestiasmaku.com/ `_ -- `https://www.latelierderoxane.com `_ -- `https://leanandgreenrecipes.net `_ -- `https://www.lecker.de `_ -- `https://lecremedelacrumb.com/ `_ -- `https://leitesculinaria.com `_ -- `https://lekkerensimpel.com `_ -- `https://leukerecepten.nl/ `_ -- `https://lifestyleofafoodie.com `_ -- `https://littlespicejar.com/ `_ -- `https://littlesunnykitchen.com/ `_ -- `http://livelytable.com/ `_ -- `https://lovingitvegan.com/ `_ -- `https://www.maangchi.com `_ -- `https://www.madamecuisine.de `_ -- `https://madensverden.dk/ `_ -- `https://madsvin.com/ `_ -- `https://marmiton.org/ `_ -- `https://www.marthastewart.com/ `_ -- `https://matprat.no/ `_ -- `https://www.mccormick.com/ `_ -- `https://meljoulwan.com/ `_ -- `https://www.melskitchencafe.com/ `_ -- `https://www.miljuschka.nl/ `_ -- `http://mindmegette.hu/ `_ -- `https://minimalistbaker.com/ `_ -- `https://ministryofcurry.com/ `_ -- `https://misya.info/ `_ -- `https://www.mob.co.uk/ `_ -- `https://mobkitchen.co.uk/ `_ -- `https://www.modernhoney.com/ `_ -- `https://www.momontimeout.com/ `_ -- `https://momswithcrockpots.com/ `_ -- `http://motherthyme.com/ `_ -- `https://www.moulinex.fr/ `_ -- `https://www.mundodereceitasbimby.com.pt/ `_ -- `https://mybakingaddiction.com/ `_ -- `https://myjewishlearning.com/ `_ -- `https://mykitchen101.com/ `_ -- `https://mykitchen101en.com/ `_ -- `https://mykoreankitchen.com/ `_ -- `https://www.myplate.gov/ `_ -- `https://myrecipes.com/ `_ -- `https://myvegetarianroots.com/ `_ -- `https://www.nhs.uk/healthier-families/ `_ -- `https://nibbledish.com/ `_ -- `https://norecipes.com/ `_ -- `https://nosalty.hu/ `_ -- `https://www.notenoughcinnamon.com/ `_ -- `https://nourishedbynutrition.com/ `_ -- `https://www.nrk.no/ `_ -- `https://www.number-2-pencil.com/ `_ -- `https://nutritionbynathalie.com/blog `_ -- `https://nutritionfacts.org/ `_ -- `https://ohsheglows.com/ `_ -- `https://omnivorescookbook.com `_ -- `https://www.onceuponachef.com `_ -- `https://onesweetappetite.com/ `_ -- `https://owen-han.com/ `_ -- `https://www.paleorunningmomma.com/ `_ -- `https://www.panelinha.com.br/ `_ -- `https://paninihappy.com/ `_ -- `https://www.peelwithzeal.com/ `_ -- `https://www.persnicketyplates.com/ `_ -- `https://www.pickuplimes.com/ `_ -- `https://pinchofyum.com/ `_ -- `https://www.pingodoce.pt/ `_ -- `https://pinkowlkitchen.com/ `_ -- `https://www.platingpixels.com/ `_ -- `https://plowingthroughlife.com/ `_ -- `https://popsugar.com/ `_ -- `https://potatorolls.com/ `_ -- `https://practicalselfreliance.com/ `_ -- `https://pressureluckcooking.com/ `_ -- `https://www.primaledgehealth.com/ `_ -- `https://www.projectgezond.nl/ `_ -- `https://przepisy.pl/ `_ -- `https://purelypope.com/ `_ -- `https://purplecarrot.com/ `_ -- `https://quitoque.fr/ `_ -- `https://rachlmansfield.com/ `_ -- `https://rainbowplantlife.com/ `_ -- `https://realfood.tesco.com/ `_ -- `https://realsimple.com/ `_ -- `https://receitas.globo.com/ `_ -- `https://receitas.ig.com.br/ `_ -- `https://www.receitasnestle.com.br `_ -- `https://recept.se/ `_ -- `https://receptyprevas.sk/ `_ -- `https://www.recipegirl.com/ `_ -- `https://reciperunner.com/ `_ -- `https://recipes.farmhousedelivery.com/ `_ -- `https://recipes.timesofindia.com/ `_ -- `https://recipetineats.com/ `_ -- `https://redhousespice.com/ `_ -- `https://reishunger.de/ `_ -- `https://rewe.de/ `_ -- `https://rezeptwelt.de/ `_ -- `https://ricetta.it/ `_ -- `https://ricette.giallozafferano.it/ `_ -- `https://www.ricetteperbimby.it/ `_ -- `https://rosannapansino.com `_ -- `https://rutgerbakt.nl/ `_ -- `https://www.saboresajinomoto.com.br/ `_ -- `https://sallys-blog.de `_ -- `https://sallysbakingaddiction.com `_ -- `https://saltpepperskillet.com/ `_ -- `https://sandwichtribunal.com/ `_ -- `https://www.saveur.com/ `_ -- `https://www.savorynothings.com/ `_ -- `https://seriouseats.com/ `_ -- `https://simple-veganista.com/ `_ -- `https://simply-cookit.com/ `_ -- `https://simplyquinoa.com/ `_ -- `https://simplyrecipes.com/ `_ -- `https://simplywhisked.com/ `_ -- `https://skinnytaste.com/ `_ -- `https://smulweb.nl/ `_ -- `https://sobors.hu/ `_ -- `https://www.southerncastiron.com/ `_ -- `https://southernliving.com/ `_ -- `https://spainonafork.com/ `_ -- `https://spendwithpennies.com/ `_ -- `https://www.springlane.de `_ -- `https://www.staysnatched.com/ `_ -- `https://steamykitchen.com/ `_ -- `https://streetkitchen.hu/ `_ -- `https://www.strongrfastr.com `_ -- `https://sunbasket.com/ `_ -- `https://sundpaabudget.dk/ `_ -- `https://www.sunset.com/ `_ -- `https://sweetcsdesigns.com/ `_ -- `https://sweetpeasandsaffron.com/ `_ -- `https://www.taste.com.au/ `_ -- `https://www.tasteatlas.com/ `_ -- `https://tasteofhome.com `_ -- `https://tastesbetterfromscratch.com `_ -- `https://tastesoflizzyt.com `_ -- `https://tasty.co `_ -- `https://tastykitchen.com/ `_ -- `https://theclevercarrot.com/ `_ -- `https://www.thecookierookie.com/ `_ -- `https://thecookingguy.com/ `_ -- `https://thefoodietakesflight.com/ `_ -- `https://theglutenfreeaustrian.com/ `_ -- `https://thehappyfoodie.co.uk/ `_ -- `https://thekitchencommunity.org/ `_ -- `https://www.thekitchenmagpie.com/ `_ -- `https://thekitchn.com/ `_ -- `https://theloopywhisk.com/ `_ -- `https://www.themagicalslowcooker.com/ `_ -- `https://themodernproper.com/ `_ -- `https://www.thepalatablelife.com `_ -- `https://thepioneerwoman.com/ `_ -- `https://therecipecritic.com/ `_ -- `https://thesaltymarshmallow.com/ `_ -- `https://thespruceeats.com/ `_ -- `https://thevintagemixer.com/ `_ -- `https://thewoksoflife.com/ `_ -- `https://thinlicious.com/ `_ -- `https://tidymom.net `_ -- `https://tine.no/ `_ -- `https://tofoo.co.uk `_ -- `https://tudogostoso.com.br/ `_ -- `https://twopeasandtheirpod.com/ `_ -- `https://uitpaulineskeuken.nl/ `_ -- `https://unsophisticook.com/ `_ -- `https://usapears.org/ `_ -- `https://www.valdemarsro.dk/ `_ -- `https://vanillaandbean.com/ `_ -- `https://varecha.pravda.sk/ `_ -- `https://www.vegetarbloggen.no/ `_ -- `https://vegolosi.it/ `_ -- `https://vegrecipesofindia.com/ `_ -- `https://www.waitrose.com/ `_ -- `https://watchwhatueat.com/ `_ -- `https://wearenotmartha.com/ `_ -- `https://www.weightwatchers.com/ `_ (*) -- `https://www.wellplated.com/ `_ -- `https://whatsgabycooking.com/ `_ -- `https://whole30.com/ `_ -- `https://www.wholefoodsmarket.com/ `_ - - `.co.uk `__ -- `https://www.williams-sonoma.com/ `_ -- `https://womensweeklyfood.com.au/ `_ -- `https://woop.co.nz/ `_ -- `https://yemek.com/ `_ -- `https://yummly.com/ `_ (*) -- `https://www.zaubertopf.de `_ -- `https://zeit.de/ (wochenmarkt) `_ -- `https://zenbelly.com/ `_ - -(*) offline saved files only - - -Contribute ----------- - -If you spot a design change (or something else) that makes the scraper unable to work for a given site - please fire an issue asap. - -If you are programmer PRs with fixes are warmly welcomed and acknowledged with a virtual beer. You can find documentation on how to develop scrapers `here `__. - - -If you want a scraper for a new site added ------------------------------------------- - -- Open an `Issue `_ providing us the site name, as well as a recipe link from it. -- You are a developer and want to code the scraper on your own: - - - If `Schema is available <#faq>`_ on the site - `you can go like this. `_ - - Otherwise, scrape the HTML - `like this `_ - - Generating a new scraper class: - - .. code:: shell - - python generate.py - - - **ClassName**: The name of the new scraper class. - - **URL**: The URL of an example recipe from the target site. The content will be stored in ``test_data`` to be used with the test class. - - You can find a more detailed guide `here `__. - - -For Devs / Contribute ---------------------- -Assuming you have ``>=python3.9`` installed, navigate to the directory where you want this project to live in and drop these lines - -.. code:: shell - - git clone git@github.com:hhursev/recipe-scrapers.git && - cd recipe-scrapers && - python -m venv .venv && - source .venv/bin/activate && - python -m pip install --upgrade pip && - pip install -e ".[dev]" && - pip install pre-commit && - pre-commit install && - python -m unittest - -In case you want to run a single unittest for a newly developed scraper - -.. code:: shell - - python -m unittest -k - - -FAQ ---- -**What if the recipe site I want to extract information from is not listed above?** - -You can give it a try with the ``wild_mode`` option! +Supported Sites +--------------- +We support a wide range of recipe websites out of the box. Check our +`supported sites list `_ +for the full list. -If there is Schema/Recipe available it will work just fine. +You can also get the full list programmatically with: .. code:: python - url = 'https://www.feastingathome.com/tomato-risotto/' - name = input('What is your name, risotto sampler?\n') - html = requests.get(url, headers={"User-Agent": f"Risotto Sampler {name}"}).content - scraper = scrape_html(html, org_url=url, wild_mode=True) - - scraper.host() - scraper.title() - scraper.total_time() - scraper.image() - scraper.ingredients() - scraper.ingredient_groups() - scraper.instructions() - scraper.instructions_list() - scraper.yields() - scraper.to_json() - scraper.links() - scraper.nutrients() # not always available - scraper.canonical_url() # not always available - scraper.equipment() # not always available - scraper.cooking_method() # not always available - scraper.keywords() # not always available - scraper.dietary_restrictions() # not always available - -Notes: - -- ``scraper.links()`` returns a list of dictionaries containing all of the tag attributes. The attribute names are the dictionary keys. - + from recipe_scrapers import SCRAPERS -**How do I know if a website has a Recipe Schema?** + SCRAPERS.keys() -Run in python shell: -.. code:: pycon +Documentation +------------- +For detailed usage instructions, examples, and API reference, visit our +`documentation `_. - Python 4.0.4 (main, Oct 26 1985, 09:00:32) [GCC 22.3.4] on linux - Type "help", "copyright", "credits" or "license" for more information. - >>> from recipe_scrapers import scrape_html - >>> scraper = scrape_html(html=None, org_url='', online=True, wild_mode=True) - >>> # if no error is raised - there's schema available: - >>> scraper.title() - >>> scraper.instructions() # etc. +Contributing +------------ +We welcome contributions! Please read our +`contribution guide `_ to get started. -Special thanks to: ------------------- -All the `contributors that helped improving `_ the package. You are awesome! +Special Thanks +-------------- +To all the `contributors `_ who +help make this project better! .. image:: https://contrib.rocks/image?repo=hhursev/recipe-scrapers :target: https://github.com/hhursev/recipe-scrapers/graphs/contributors -Test Data Notice ----------------- - -All content in ``tests/test_data/`` is used for limited, non-commercial testing purposes and belongs to their respective copyright holders. See the ``tests/test_data/LICENSE.md`` for details. If you're a copyright holder with concerns, you can open an issue or contact us privately via the email in our PyPI page. - - -Extra: ------- -| You want to gather recipes data? -| You have an idea you want to implement? -| Check out `our "Share a project" wall `_ - it may save you time and spark ideas! +Share Your Project +------------------ +Have an idea for using recipe-scrapers? Check out +our `project ideas wall `_ for inspiration +or to share your own project! diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index ec48b55ec..000000000 --- a/docs/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Scraper Development Guide - -## Goal - -This library has the goals of - -* making recipe information **accessible**, -* ensuring the author is **attributed** correctly, -* representing the recipes **accurately** and **authentically** - -Sometimes it is simple and straightforward to achieve all these goals, and sometimes it is more difficult (which is why this library exists). Where some interpretation or creativity is required to scrape a recipe, we should always keep those goals in mind. Occasionally, that might mean that we can't support a particular website. - -## Contents - -* [How To: Develop a New Scraper](how-to-develop-scraper.md) -* In Depth Guides: - * [Debugging](in-depth-guide-debugging.md) (coming soon) - * [HTML Scraping](in-depth-guide-html-scraping.md) - * [Ingredient Groups](in-depth-guide-ingredient-groups.md) - * [Scraper Functions](in-depth-guide-scraper-functions.md) diff --git a/docs/assets/.gitkeep b/docs/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/docs/contributing/code-contribution.md b/docs/contributing/code-contribution.md new file mode 100644 index 000000000..febded0e6 --- /dev/null +++ b/docs/contributing/code-contribution.md @@ -0,0 +1,62 @@ +# Code Contributions + +!!! note "Prerequisites" + This guide assumes you are already familiar with our [setup guide](./setup.md). + +## Development Workflow + +Create a new branch for your code changes: + +```sh +git checkout -b fix/your-fix-name # for bug fixes +# or +git checkout -b site/website-name # for new site scrapers +# or +git checkout -b feature/feature-name # for new features +``` + +After making your changes commit them: + +```bash +git add -p # Review changes before adding them +git commit -m "meaningful commit message" +git push origin your-branch-name +``` + +Then create a Pull Request back to the [main repository](https://github.com/hhursev/recipe-scrapers) from your fork. + + +## Development Guidelines + +While we're working on comprehensive documentation, the codebase is designed to +be self-explanatory. As a developer, you can understand our patterns and expectations +by taking a look at existing scrapers in the `recipe_scrapers/` directory. + + +## Hints + +!!! tip "Generator Tool" + If you're adding a new site scraper, you can use our generator command to create a template: + + ```sh + python generate.py + ``` + + Where: + + - `ClassName`: The name of your new scraper class (e.g., `BBCGoodFood`) + - `URL`: A sample recipe URL from the target site. This will be saved in `test_data/` + for testing. + + +## Examples + +!!! warning "Work in Progress" + + This contributing guide is currently being developed. Meanwhile, you can check these + PRs as examples of good contribution standards: + + - [#1414](https://github.com/hhursev/recipe-scrapers/pull/1414/) - Adding a new site scraper + - [#1432](https://github.com/hhursev/recipe-scrapers/pull/1432/) - Fixing broken functionality + - [#1434](https://github.com/hhursev/recipe-scrapers/pull/1434/) - Test improvements + - [#1345](https://github.com/hhursev/recipe-scrapers/pull/1345/) - CI Improvements diff --git a/docs/contributing/documentation.md b/docs/contributing/documentation.md new file mode 100644 index 000000000..880f9af35 --- /dev/null +++ b/docs/contributing/documentation.md @@ -0,0 +1,65 @@ +# Contributing to Documentation + +!!! note "Prerequisites" + This guide assumes you are already familiar with our [setup guide](./setup.md). + +Create a new branch for your documentation changes: +```sh +git checkout -b docs/your-feature-name +``` + +## Previewing Documentation Changes + +!!! example "Local Development" + 1. From the project root directory, start the MkDocs development server: + ```sh + mkdocs serve + ``` + 2. Open your browser and navigate to `http://127.0.0.1:8000` + +The preview will automatically update as you make changes to the documentation files. + +## Making Documentation Changes + +!!! info "Documentation Structure" + - Documentation source files are written in Markdown and located in the `docs/` directory + - Images and other assets should be placed in the `docs/assets/` directory + - The documentation structure is defined in `mkdocs.yaml` at the root of the repository + +## Submitting Your Changes + +1. Commit your changes with a descriptive message: + ```sh + git add docs/ + git commit -m "docs: describe your changes here" + ``` + +2. Push your changes to your fork: + ```sh + git push origin docs/your-feature-name + ``` + +3. Create a Pull Request (PR) from your fork to the main +[recipe-scrapers](https://github.com/hhursev/recipe-scrapers) repository. + +!!! success "PR Preview" + When you create a PR, a special preview URL will be generated where your documentation + changes can be reviewed. This will make it easy for maintainers to see your changes in action. + +## Documentation Style Guidelines + +!!! note "Style Guide" + - Use clear, concise language + - Include code examples where appropriate + - Follow the existing documentation structure + - Add screenshots or diagrams when they help explain concepts + - Ensure all links are working + - Use proper Markdown formatting + +## Need Help? + +!!! question "Getting Support" + If you have questions or need assistance with documentation contributions, please: + + - Open an [issue on GitHub](https://github.com/hhursev/recipe-scrapers/issues) + - Check existing documentation for reference diff --git a/docs/contributing/home.md b/docs/contributing/home.md new file mode 100644 index 000000000..bafbe8605 --- /dev/null +++ b/docs/contributing/home.md @@ -0,0 +1,36 @@ +# How to Contribute + +!!! success "Better For Everyone" + We welcome all contributions to `recipe-scrapers`! + Whether you're reporting bugs, suggesting features, improving documentation, + or contributing code, your help makes this project better for everyone. + + +## Ways to Contribute + +### Opening Issues + +Found a bug or a scraper not working for a particular site? Please open an issue! +Given our large number of [Supported Sites](../getting-started/supported-sites.md) +and their frequent design changes, bugs are inevitable. Your reports help us +maintain quality and improve the project. + +Want support for a new site? Open an issue using our _issue templates_. All issues +should be submitted through our +[GitHub repository](https://github.com/hhursev/recipe-scrapers/issues). + +### Contributing to the Project + +If you'd like to contribute to the project, whether it's fixing a bug, adding support +for a new site, improving documentation, or closing a raised issue, we're happy to help +you through the process. Check out our development guidelines [starting here](./setup.md). + + +## Our Community + +This project thrives thanks to our amazing contributors. Every contribution, +whether big or small, helps make `recipe-scrapers` better for everyone. + +### Wall of Fame + +[![Contributors](https://contrib.rocks/image?repo=hhursev/recipe-scrapers)](https://github.com/hhursev/recipe-scrapers/graphs/contributors) diff --git a/docs/contributing/how-to-develop-a-scraper.md b/docs/contributing/how-to-develop-a-scraper.md new file mode 100644 index 000000000..ffef7e432 --- /dev/null +++ b/docs/contributing/how-to-develop-a-scraper.md @@ -0,0 +1,149 @@ +# How To Develop a New Scraper + +!!! warning "Under Construction" + This section is being updated. Some information may be outdated or inaccurate. + + +## Find a website + +First, check if the website is already supported: + +- Check the [Supported Sites](../getting-started/supported-sites.md) +- Or verify programmatically: + +```python +from recipe_scrapers import SCRAPERS +# Check if site is supported +print(SCRAPERS.get("bbcgoodfood.com")) +``` + +!!! note "Track Your Progress" + Create an [issue](https://github.com/hhursev/recipe-scrapers/issues/new/choose) to track + your work. + +## Setup Repository + +Fork the [recipe-scrapers repository](https://github.com/hhursev/recipe-scrapers) on GitHub and +follow these steps: + +!!! tip "Quick Setup" + ```sh + # Clone your fork + git clone https://github.com/YOUR-USERNAME/recipe-scrapers.git + cd recipe-scrapers + + # Set up Python environment + python -m venv .venv + source .venv/bin/activate # On Windows use: .venv\Scripts\activate + python -m pip install --upgrade pip + pip install -e ".[all]" + ``` + +Create a new branch: + +```sh +git checkout -b site/website-name +``` + +!!! tip "Run Tests" + ```sh + python -m unittest + + # Optional: Parallel testing + pip install unittest-parallel + unittest-parallel --level test + ``` + +## Generate Scraper Files + +### 1. Select Recipe URL + +!!! tip "Recipe Selection" + Choose a recipe with multiple instructions when possible. Single-instruction recipes may + indicate parsing errors, unless [explicitly handled](https://github.com/hhursev/recipe-scrapers/blob/98ead6fc6e9653805b01539a3f46fbfb4e096136/tests/test_allrecipes.py#L147-L150). + +### 2. Check Schema Support + +Test if the site uses [Recipe Schema](https://schema.org/Recipe): + +```python +from recipe_scrapers import scrape_html + +scraper = scrape_html(html, url, wild_mode=True) +print(scraper.schema.data) # Empty dict if schema not supported +``` + +### 3. Generate Files + +```sh +python generate.py +``` + +This creates: + +- Scraper file in `recipe_scrapers/` +- Test files in `tests/test_data//` + +## Implementation + +=== "With Recipe Schema" + ```python + from recipe_scrapers import scrape_html + + scraper = scrape_html(html, url) + print(scraper.title()) + print(scraper.ingredients()) + ``` + +=== "Without Recipe Schema" + ```python + def title(self): + return self.soup.find('h1').get_text() + ``` + +!!! info "Resources" + - [Scraper Functions Guide](in-depth-guide-scraper-functions.md) + - [HTML Scraping Guide](in-depth-guide-html-scraping.md) + - [BeautifulSoup Documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) + +## Testing + +### 1. Update Test Data + +Edit `tests/test_data//test.json`: +```json +{ + "host": "", + "canonical_url": "...", + "site_name": "...", + "author": "...", + "language": "...", + "title": "...", + "ingredients": "...", + "instructions_list": "...", + "total_time": "...", + "yields": "...", + "image": "...", + "description": "..." +} +``` + +### 2. Run Tests + +```sh +python -m unittest -k +``` + +!!! warning "Edge Cases" + Test with multiple recipes to catch potential edge cases. + +## Submit Changes + +1. Commit your work: +```sh +git add -p # Review changes +git commit -m "Add scraper for example.com" +git push origin site/website-name +``` + +2. Create a pull request at [recipe-scrapers](https://github.com/hhursev/recipe-scrapers/pulls) diff --git a/docs/in-depth-guide-debugging.md b/docs/contributing/in-depth-guide-debugging.md similarity index 70% rename from docs/in-depth-guide-debugging.md rename to docs/contributing/in-depth-guide-debugging.md index e472804ab..ae6082460 100644 --- a/docs/in-depth-guide-debugging.md +++ b/docs/contributing/in-depth-guide-debugging.md @@ -1,6 +1,7 @@ # In Depth Guide: Debugging > **Draft** -> This in depth guide is intended to give more guidance on debugging scrapers during development and handling exceptions. +> This in depth guide is intended to give more guidance on debugging scrapers during +> development and handling exceptions. > >To be populated at a later date. diff --git a/docs/in-depth-guide-html-scraping.md b/docs/contributing/in-depth-guide-html-scraping.md similarity index 61% rename from docs/in-depth-guide-html-scraping.md rename to docs/contributing/in-depth-guide-html-scraping.md index 5844a4b45..9597c3f14 100644 --- a/docs/in-depth-guide-html-scraping.md +++ b/docs/contributing/in-depth-guide-html-scraping.md @@ -1,22 +1,40 @@ # In Depth Guide: HTML Scraping -The preferred method of scraping recipe information from a web page is to use the schema.org Recipe data. This is a machine readable, structured format intended to provide a standardised method of extracting information. However, whilst most recipe websites use the schema.org Recipe format, not all do, and for those websites that do, it does not always include all the information we are looking for. In these cases, we can use HTML scraping to extract the information from the HTML markup. +!!! warning "Under Construction" + This section is being updated. Some information may be outdated or inaccurate. + +The preferred method of scraping recipe information from a web page is to use the schema.org +Recipe data. This is a machine readable, structured format intended to provide a standardised +method of extracting information. However, whilst most recipe websites use the schema.org Recipe +format, not all do, and for those websites that do, it does not always include all the information +we are looking for. In these cases, we can use HTML scraping to extract the information from +the HTML markup. ## `soup` -Each scraper has a `BeautifulSoup` object that can be accessed using the `self.soup` attribute. The `BeautifulSoup` object is a representation of the web page HTML that has been parsed into a format that we can query and extract information from. +Each scraper has a `BeautifulSoup` object that can be accessed using the `self.soup` attribute. +The `BeautifulSoup` object is a representation of the web page HTML that has been parsed into a +format that we can query and extract information from. -The [Beautiful Soup documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) is the best resource for learning how to use `BeautifulSoup` objects to interact with HTML documents. +The [Beautiful Soup documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) is the best resource for learning how to use `BeautifulSoup` +objects to interact with HTML documents. This guide covers a number of common patterns that are used in this library. ## `_schema_cls` and `_opengraph_cls` -It should rarely be necessary to override the default behaviour of schema.org and OpenGraph metadata retrieval; recipe websites should generally adhere to their respective standard formats when including metadata on their webpages. However, bugs/mistakes do happen - if you need to override the implementations provided by the `SchemaOrg` and `OpenGraph` classes, you can subclass from those and add a `_schema_cls` or `_opengraph_cls` attribute to your scraper class to instruct the library to use them instead. +It should rarely be necessary to override the default behaviour of schema.org and OpenGraph +metadata retrieval; recipe websites should generally adhere to their respective standard formats +when including metadata on their webpages. However, bugs/mistakes do happen - if you need to +override the implementations provided by the `SchemaOrg` and `OpenGraph` classes, you can subclass +from those and add a `_schema_cls` or `_opengraph_cls` attribute to your scraper class to instruct +the library to use them instead. ## Finding a single element -The `self.soup.find()` function returns the first element matching the arguments. This is useful if you are trying to extract some information that should only occur once, for example the prep time or total time. +The `self.soup.find()` function returns the first element matching the arguments. This is useful if +you are trying to extract some information that should only occur once, for example the prep time +or total time. ```python # To find a particular element @@ -33,14 +51,17 @@ self.soup.find(id="total-time") self.soup.find("h1", class_="title") ``` -`self.soup` returns a `bs4.element.Tag` object. Usually we just want the text from the selected element and the best way to do that is to use `.get_text()`. +`self.soup` returns a `bs4.element.Tag` object. Usually we just want the text from the selected +element and the best way to do that is to use `.get_text()`. ```python title_tag = self.soup.select("h1") # bs4.element.Tag object title_text = title_tag.get_text() # str ``` -`.get_text()` will get the text from all child elements, as it would appear in your browser, so there is no need to iterate through all the children, call `.get_text()` on each one, then join the results afterwards. +`.get_text()` will get the text from all child elements, as it would appear in your browser, so +there is no need to iterate through all the children, call `.get_text()` on each one, then join +the results afterwards. As an example, consider one of the ingredients in [this recipe](https://rainbowplantlife.com/instant-pot-jackfruit-curry/#wprm-recipe-container-5618). The markup looks like this: @@ -59,7 +80,8 @@ As an example, consider one of the ingredients in [this recipe](https://rainbowp ``` -We can select this element using its tag and class (we're pretending this recipe only has this one ingredient), and extract the text like so: +We can select this element using its tag and class (we're pretending this recipe only has this one +ingredient), and extract the text like so: ```python ingredient_tag = self.soup.find("li", class_="wprm-recipe-ingredient") @@ -71,7 +93,10 @@ The Beautiful Soup documentation for `find` is [here](https://www.crummy.com/sof ### Normalizing strings -A convenience function called `normalize_string()` is provided in the `_utils` package. This function will convert any characters escaped for HTML to their actual character (e.g. `&` to `&`) and remove unnecessary white space. It is best practice to always use this when extracting text from the HTML. +A convenience function called `normalize_string()` is provided in the `_utils` package. This +function will convert any characters escaped for HTML to their actual character (e.g. `&` +to `&`) and remove unnecessary white space. It is best practice to always use this when extracting +text from the HTML. ```python from ._utils import normalize_string @@ -83,7 +108,9 @@ ingredient_text = normalize_string(ingredient_tag.get_text()) ### Getting yields -A convenience function called `get_yields()` is provided in the `_utils` package. This function accepts a `str` or `bs4.element.Tag` and will return the yield, handling many of the common formats yields can appear in and normalizing them to a standard format. +A convenience function called `get_yields()` is provided in the `_utils` package. This function +accepts a `str` or `bs4.element.Tag` and will return the yield, handling many of the common +formats yields can appear in and normalizing them to a standard format. ```python from ._utils import get_yields @@ -98,7 +125,9 @@ yield_text = get_yields(yield_tag.get_text()) ### Getting times -A convenience function called `get_minutes()` is provided in the `_utils` package. This function accepts a `str` or `bs4.element.Tag` and will return the number of minutes as an `int`. This function handles a number of common formats that times can be expressed in. +A convenience function called `get_minutes()` is provided in the `_utils` package. This function +accepts a `str` or `bs4.element.Tag` and will return the number of minutes as an `int`. This +function handles a number of common formats that times can be expressed in. ```python from ._utils import get_minutes @@ -113,7 +142,10 @@ prep_time_value = get_minutes(prep_time_tag.get_text()) ## Finding multiple elements -Some information in a recipe, like the ingredients or instructions, come in the form of lists where we need to find multiple elements with the same attributes. We can use `self.soup.find_all()` for this. `find_all` uses the same arguments as `find`, it just returns a list of `bs4.element.Tag` objects with all the matching elements. +Some information in a recipe, like the ingredients or instructions, come in the form of lists where +we need to find multiple elements with the same attributes. We can use `self.soup.find_all()` for +this. `find_all` uses the same arguments as `find`, it just returns a list of `bs4.element.Tag` +objects with all the matching elements. Using the same site as above, we can find all the ingredients like so @@ -136,25 +168,34 @@ The Beautiful Soup documentation for `find_all` is [here](https://www.crummy.com ## Using CSS selectors -If you are already familiar with CSS selectors, then you can use `select()` to achieve the same result as `find_all()`, or `select_one()` to achieve the same result as `find`. +If you are already familiar with CSS selectors, then you can use `select()` to achieve the same +result as `find_all()`, or `select_one()` to achieve the same result as `find`. ```python -ingredient_tag = self.soup.select("li.wprm-recipe-ingredient") # Match all li elements with wprm-recipe-ingredient class +# Match all li elements with wprm-recipe-ingredient class +ingredient_tag = self.soup.select("li.wprm-recipe-ingredient") ``` -The Beautiful Soup documentation for `select` is [here](https://www.crummy.com/software/BeautifulSoup/bs4/doc/#css-selectors-through-the-css-property). MDN has a guide on CSS selectors [here](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors). +The Beautiful Soup documentation for `select` is [here](https://www.crummy.com/software/BeautifulSoup/bs4/doc/#css-selectors-through-the-css-property). MDN has a guide on +CSS selectors [here](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors). ## Finding elements using a partial attribute -Sometimes you might want to find elements using a part of an attribute. This is particularly helpful for websites that automatically generate CSS in a way that appends a random string to the end of class names. +Sometimes you might want to find elements using a part of an attribute. This is particularly +helpful for websites that automatically generate CSS in a way that appends a random string to +the end of class names. -An example of this is [cooking.nytimes.com](https://cooking.nytimes.com/recipes/1024605-cumin-and-cashew-yogurt-rice). If we wanted to select the yield element from this page, we could use the class `ingredients_recipeYield__DN65p`. However when the website is updated in the future, the `DN65p` at the end of the class name is likely to change, so we only want to use part of the class name. +An example of this is [cooking.nytimes.com](https://cooking.nytimes.com/recipes/1024605-cumin-and-cashew-yogurt-rice). If we wanted to select the yield element from +this page, we could use the class `ingredients_recipeYield__DN65p`. However when the website is +updated in the future, the `DN65p` at the end of the class name is likely to change, so we only +want to use part of the class name. There are two ways we can do this: ### Using `find` -Instead of using a string in the arguments we pass to `find`, we can use a regular expression instead. +Instead of using a string in the arguments we pass to `find`, we can use a regular expression +instead. ```python yield_tag = self.soup.find(class_=re.compile("ingredients_recipeYield")) diff --git a/docs/in-depth-guide-ingredient-groups.md b/docs/contributing/in-depth-guide-ingredient-groups.md similarity index 55% rename from docs/in-depth-guide-ingredient-groups.md rename to docs/contributing/in-depth-guide-ingredient-groups.md index 9a88ffaf1..0512369d9 100644 --- a/docs/in-depth-guide-ingredient-groups.md +++ b/docs/contributing/in-depth-guide-ingredient-groups.md @@ -1,6 +1,12 @@ # In Depth Guide: Ingredient Groups -Sometimes a website will format lists of ingredients using groups, where each group contains the ingredients needed for a particular aspect of the recipe. Recipe Schema has no way to represent these groupings, so all of the ingredients are presented as a single list and information about the groupings is lost. +!!! warning "Under Construction" + This section is being updated. Some information may be outdated or inaccurate. + +Sometimes a website will format lists of ingredients using groups, where each group contains the +ingredients needed for a particular aspect of the recipe. Recipe Schema has no way to represent +these groupings, so all of the ingredients are presented as a single list and information about +the groupings is lost. Some examples of recipes that have ingredient groups are: @@ -8,13 +14,16 @@ Some examples of recipes that have ingredient groups are: * * -Not all websites use ingredient groups and those that do use ingredient groups will not use them for all recipes. +Not all websites use ingredient groups and those that do use ingredient groups will not use them +for all recipes. -This library allows a scraper to return the ingredients in the groups defined in the recipe if the functionality is added to that scraper. +This library allows a scraper to return the ingredients in the groups defined in the recipe if the +functionality is added to that scraper. ## `ingredient_groups()` -The `ingredient_groups()` function returns a list of `IngredientGroup` objects. Each `IngredientGroup` is a dataclass that represents a group of ingredients: +The `ingredient_groups()` function returns a list of `IngredientGroup` objects. Each +`IngredientGroup` is a dataclass that represents a group of ingredients: ```python @dataclass @@ -25,7 +34,8 @@ class IngredientGroup: ] = None # this group of ingredients is {purpose} (e.g. "For the dressing") ``` -The *purpose* is the ingredient group heading, such as *"For the dressing"*, *"For the sauce"* etc. The *ingredients* is the list of ingredients that comprise that group. +The *purpose* is the ingredient group heading, such as *"For the dressing"*, *"For the sauce"* etc. +The *ingredients* is the list of ingredients that comprise that group. This dataclass is defined in `_grouping_utils.py` and should be imported from there. @@ -33,19 +43,32 @@ This dataclass is defined in `_grouping_utils.py` and should be imported from th from ._grouping_utils import IngredientGroup ``` -The `ingredient_groups()` function has a default implementation in the `AbstractScraper` class that returns a single `IngredientGroup` object with `purpose` set to `None` and `ingredients` set to the output from the scraper's `ingredients()` function. +The `ingredient_groups()` function has a default implementation in the `AbstractScraper` class that +returns a single `IngredientGroup` object with `purpose` set to `None` and `ingredients` set to the +output from the scraper's `ingredients()` function. -Adding ingredient group support to a scraper involves overriding the `ingredient_groups` function for it. There are three important points to consider: +Adding ingredient group support to a scraper involves overriding the `ingredient_groups` function +for it. There are three important points to consider: -1. The schema.org Recipe format does not support groupings - so scraping from the HTML is required in the implementation. -1. The ingredients found in `ingredients()` and `ingredient_groups()` should be the same because we're presenting the same set of ingredients, just in a different way. There can sometimes be minor differences in the ingredients in the schema and the ingredients in the HTML which needs to be handled. -1. Not all recipes on a website will use ingredient groups, so the implementation must degrade gracefully in cases where groupings aren't available. For recipes that don't have ingredient groups, the output should be the same as default implementation (i.e. a single `IngredientGroup` with `purpose=None` and `ingredients=ingredients()`). +1. The schema.org Recipe format does not support groupings - so scraping from the HTML is required +in the implementation. +2. The ingredients found in `ingredients()` and `ingredient_groups()` should be the same because +we're presenting the same set of ingredients, just in a different way. There can sometimes be minor +differences in the ingredients in the schema and the ingredients in the HTML which needs to be +handled. +3. Not all recipes on a website will use ingredient groups, so the implementation must degrade +gracefully in cases where groupings aren't available. For recipes that don't have ingredient groups, +the output should be the same as default implementation +(i.e. a single `IngredientGroup` with `purpose=None` and `ingredients=ingredients()`). -In many cases the structure of how ingredients and group heading appear in the HTML is very similar. Some helper functions have been developed to make the implementation easier. +In many cases the structure of how ingredients and group heading appear in the HTML is very similar. +Some helper functions have been developed to make the implementation easier. ## _grouping_utils.py -The `_grouping_utils.py` file contains a helper function (`group_ingredients(...)`) that will handle the extraction of ingredients groups and their headings from the HTML, make sure the ingredients in the groups match those return from `.ingredients()`, and then return the groups. +The `_grouping_utils.py` file contains a helper function (`group_ingredients(...)`) +that will handle the extraction of ingredients groups and their headings from the HTML, make sure +the ingredients in the groups match those return from `.ingredients()`, and then return the groups. The `group_ingredients()` function takes four arguments: @@ -58,20 +81,29 @@ def group_ingredients( ) -> List[IngredientGroup]: ``` -* `ingredients_list` is the output from the `.ingredients()` function of the scraper class. This is used to make the ingredients found in the HTML match those returned by `.ingredients()`. -* `soup` is the `BeautifulSoup` object for the scraper. The ingredient groups are extracted from this. -* `group_heading` is the CSS selector for the group headings. This selector must only match the group headings in the recipe HTML. -* `group_element` is the CSS selector for the ingredients. This selector must only match the ingredients in the recipe HTML. +* `ingredients_list` is the output from the `.ingredients()` function of the scraper class. This is +* used to make the ingredients found in the HTML match those returned by `.ingredients()`. +* `soup` is the `BeautifulSoup` object for the scraper. The ingredient groups are extracted from +* this. +* `group_heading` is the CSS selector for the group headings. This selector must only match the +* group headings in the recipe HTML. +* `group_element` is the CSS selector for the ingredients. This selector must only match the +* ingredients in the recipe HTML. ### Example -Many recipe blogs use WordPress and the WordPress Recipe Manager plugin. This means they often use the same HTML elements and CSS classes to represent the same things. One such example is . +Many recipe blogs use WordPress and the WordPress Recipe Manager plugin. This means they often use +the same HTML elements and CSS classes to represent the same things. +One such example is . If we look at the recipe: -The group headings in this recipe are all `h4` headings inside an element with the class `wprm-recipe-ingredient-group`. Therefore we can select all ingredient group headings with the selector: `.wprm-recipe-ingredient-group h4` +The group headings in this recipe are all `h4` headings inside an element with the +class `wprm-recipe-ingredient-group`. Therefore we can select all ingredient group headings +with the selector: `.wprm-recipe-ingredient-group h4` -The ingredients are all elements with the class `wprm-recipe-ingredient`. Therefore we can select all ingredients with the selector: `.wprm-recipe-ingredient` +The ingredients are all elements with the class `wprm-recipe-ingredient`. Therefore we can select +all ingredients with the selector: `.wprm-recipe-ingredient` The implementation in the scraper looks like @@ -103,19 +135,32 @@ Some other examples of scrapers that support ingredient groups are: **What if `group_ingredients()` doesn't work?** -The `group_ingredients` function relies on being able to identify all the group headings with a single CSS selector and all the ingredients with a single CSS selector. However, this is not always possible - it depends on how the website lays out its HTML. +The `group_ingredients` function relies on being able to identify all the group headings with a +single CSS selector and all the ingredients with a single CSS selector. However, this is not always +possible - it depends on how the website lays out its HTML. -In these cases, supporting ingredient groups may still be possible. The `group_ingredients()` helper method is only that: an optional helper -- you can always implement custom grouping logic yourself by overriding `ingredient_groups()` directly in your scraper if you can't find suitable CSS selectors for the ingredients and groups. +In these cases, supporting ingredient groups may still be possible. The `group_ingredients()` helper +method is only that: an optional helper -- you can always implement custom grouping logic yourself +by overriding `ingredient_groups()` directly in your scraper if you can't find suitable CSS +selectors for the ingredients and groups. -An example of a scraper that supports ingredient groups without using the `group_ingredients()` helper is [NIHHealthyEating](https://github.com/hhursev/recipe-scrapers/blob/main/recipe_scrapers/nihhealthyeating.py). +An example of a scraper that supports ingredient groups without using the `group_ingredients()` +helper is [NIHHealthyEating](https://github.com/hhursev/recipe-scrapers/blob/main/recipe_scrapers/nihhealthyeating.py). ## Tests -Recipe websites often provide ingredient groupings on some, but not all, of their recipe webpages. When this is the case, we should add at least two test cases for our scraper: one to cover a recipe **with** ingredient groupings, and one to cover a recipe **without** them. +Recipe websites often provide ingredient groupings on some, but not all, of their recipe webpages. +When this is the case, we should add at least two test cases for our scraper: one to cover a +recipe **with** ingredient groupings, and one to cover a recipe **without** them. -Test cases **without** ingredient groupings in the HTML are simpler, because every scraper test case *automatically* inherits a test that checks to make sure the output of `.ingredients()` is consistent with the output from `.ingredient_groups()`, and that provides all the test coverage we need. +Test cases **without** ingredient groupings in the HTML are simpler, because every scraper test +case *automatically* inherits a test that checks to make sure the output of `.ingredients()` is +consistent with the output from `.ingredient_groups()`, and that provides all the test coverage +we need. -The test case **with** ingredient grouping should include an `ingredient_groups` item in the JSON data with each section of the ingredients separated out in the applicable test case like this example: +The test case **with** ingredient grouping should include an `ingredient_groups` item in the JSON +data with each section of the ingredients separated out in the applicable test case like this +example: ```json "ingredient_groups": [ diff --git a/docs/in-depth-guide-scraper-functions.md b/docs/contributing/in-depth-guide-scraper-functions.md similarity index 73% rename from docs/in-depth-guide-scraper-functions.md rename to docs/contributing/in-depth-guide-scraper-functions.md index e99ec9bee..da6f725a3 100644 --- a/docs/in-depth-guide-scraper-functions.md +++ b/docs/contributing/in-depth-guide-scraper-functions.md @@ -1,18 +1,26 @@ # In Depth Guide: Scraper Functions -Each website scraper has a number of functions that return information about the recipe that has been scraped. Due to the variability in how recipes are written, not all of them are always applicable. These functions fall into three categories: +!!! warning "Under Construction" + This section is being updated. Some information may be outdated or inaccurate. + +Each website scraper has a number of functions that return information about the recipe that has +been scraped. Due to the variability in how recipes are written, not all of them are always +applicable. These functions fall into three categories: 1. Mandatory functions - These functions can be expected to be available for all Scraper classes and combined provide the majority of the information for a recipe. + These functions can be expected to be available for all Scraper classes and combined provide the + majority of the information for a recipe. -1. Inherited functions +2. Inherited functions - These functions are always available for all Scraper classes. They are implemented in the `AbstractScraper` base class and rarely require overriding in the Scraper class. + These functions are always available for all Scraper classes. They are implemented in the + `AbstractScraper` base class and rarely require overriding in the Scraper class. -1. Optional functions +3. Optional functions - These functions provide extra information about a recipe, from the particular websites that support them. + These functions provide extra information about a recipe, from the particular websites that + support them. All of the examples below come from . @@ -25,7 +33,9 @@ All of the examples below come from str` -Returns the author of the recipe. This is typically a person's name but can sometimes be an organization or the name of the website the recipe came from. If the recipe does not explicitly define an author, this should return the name of the website. +Returns the author of the recipe. This is typically a person's name but can sometimes be an +organization or the name of the website the recipe came from. If the recipe does not explicitly +define an author, this should return the name of the website. ```py >>> scraper.author() @@ -34,16 +44,19 @@ Returns the author of the recipe. This is typically a person's name but can some ### `host() -> str` -Returns the host of the website the Scraper class is for. This is a constant `str` set in each Scraper class. +Returns the host of the website the Scraper class is for. This is a constant `str` set in each +Scraper class. -```python +```py >>> scraper.host() 'bbcgoodfood.com' ``` ### `description() -> str` -Returns a description of the recipe. This is normally a sentence or short paragraph describing the recipe. Often the website defines the description, but sometimes it has to be inferred from the page content. +Returns a description of the recipe. This is normally a sentence or short paragraph describing the +recipe. Often the website defines the description, but sometimes it has to be inferred from the +page content. ```py >>> scraper.description() @@ -52,7 +65,8 @@ Returns a description of the recipe. This is normally a sentence or short paragr ### `image() -> str` -Returns the URL to the main image associated with the recipe, usually a photograph of the completed recipe. +Returns the URL to the main image associated with the recipe, usually a photograph of the completed +recipe. ```py >>> scraper.image() @@ -61,7 +75,10 @@ Returns the URL to the main image associated with the recipe, usually a photogra ### `ingredients() -> List[str]` -Returns the ingredients needed to make the recipe as a `list` of `str`. Each element of the list is usually a single sentence stating an ingredient, the required amount and any additional comments. The elements of the list should mirror the ingredients written on the website and should not include non-ingredient sentences such as sub-headings. +Returns the ingredients needed to make the recipe as a `list` of `str`. Each element of the list is +usually a single sentence stating an ingredient, the required amount and any additional comments. +The elements of the list should mirror the ingredients written on the website and should not include +non-ingredient sentences such as sub-headings. ```py >>> scraper.ingredients() @@ -85,7 +102,8 @@ Returns the ingredients needed to make the recipe as a `list` of `str`. Each ele ### `instructions() -> str` -Returns a single `str` containing all instruction steps. Where a recipe has multiple instructions, each step is separated in the returned `str` by a newline character (`\n`). +Returns a single `str` containing all instruction steps. Where a recipe has multiple instructions, +each step is separated in the returned `str` by a newline character (`\n`). ```py >>> scraper.instructions() @@ -94,7 +112,8 @@ Returns a single `str` containing all instruction steps. Where a recipe has mult > [!IMPORTANT] > -> Occasionally, a recipe will have steps that have new lines within them. At the moment, this library cannot distinguish between a newline within a step and a newline between steps. +> Occasionally, a recipe will have steps that have new lines within them. At the moment, this +> librarycannot distinguish between a newline within a step and a newline between steps. ### `title() -> str` @@ -116,7 +135,8 @@ Returns the total time required to complete the recipe, in minutes. ### `yields() -> str` -Returns the number of items or servings the recipe will make. This `str` includes the quantity and unit of the yield, for example: 4 servings, 6 items, 12 cookies. +Returns the number of items or servings the recipe will make. This `str` includes the quantity and +unit of the yield, for example: 4 servings, 6 items, 12 cookies. ```py >>> scraper.yields() @@ -127,7 +147,9 @@ Returns the number of items or servings the recipe will make. This `str` include ### `canonical_url() -> str` -Returns the canonical URL for the scraped recipe. The canonical URL is the direct URL (defined by the website) at which the recipe can be found. This URL will generally not contain any query parameters or fragments, except those required to load the recipe. +Returns the canonical URL for the scraped recipe. The canonical URL is the direct URL (defined by +the website) at which the recipe can be found. This URL will generally not contain any query +parameters or fragments, except those required to load the recipe. ```py >>> scraper.canonical_url() @@ -136,13 +158,19 @@ Returns the canonical URL for the scraped recipe. The canonical URL is the direc ### `ingredient_groups() -> List[IngredientGroup]` -Returns a `list` of groups of ingredients. Some recipes on some websites will present the ingredients in groups, where each group contains the ingredients required for a particular aspect of the recipe. +Returns a `list` of groups of ingredients. Some recipes on some websites will present the +ingredients in groups, where each group contains the ingredients required for a particular aspect +of the recipe. -Each element of the returned `list` is an `IngredientGroup` object. An `IngredientGroup` object has a `purpose` (for example, *for the sauce*) and a `list` of ingredients. +Each element of the returned `list` is an `IngredientGroup` object. An `IngredientGroup` object has +a `purpose` (for example, *for the sauce*) and a `list` of ingredients. > [!IMPORTANT] > -> All scrapers inherit this function. By default, it returns a single group with purpose of `None` and the ingredients set to the output of `ingredients()`. This function should be overridden in scrapers for website that use ingredient groups. See [this guide](in-depth-guide-ingredient-groups.md) for help on implementing this. +> All scrapers inherit this function. By default, it returns a single group with purpose of `None` +> and the ingredients set to the output of `ingredients()`. This function should be overridden in +> scrapers for website that use ingredient groups. See [this guide](in-depth-guide-ingredient-groups.md) for help on implementing +> this. ```py >>> scraper.ingredient_groups() @@ -173,7 +201,8 @@ Each element of the returned `list` is an `IngredientGroup` object. An `Ingredie ### `instruction_list()` -Return a `list` of instructions. This `list` is generated by splitting the output of `instructions()` on newline characters. +Return a `list` of instructions. This `list` is generated by splitting the output of +`instructions()` on newline characters. ```py >>> scraper.instructions_list() @@ -200,7 +229,8 @@ For a comprehensive list of BCP 47 language codes, refer to this GitHub Gist: ### `links() -> List[Dict[str, str]]` -Returns a `list` of all links found in the page HTML defined in an `` element. For each link, the attributes of the HTML element are returned as a `dict`. +Returns a `list` of all links found in the page HTML defined in an `` element. For each link, +the attributes of the HTML element are returned as a `dict`. ```py >>> scraper.links() @@ -217,7 +247,8 @@ Returns a `list` of all links found in the page HTML defined in an `` element ### `site_name() -> str | None` -Returns the website name, as defined in the page's HTML. If the page does not define this, this function returns `None` +Returns the website name, as defined in the page's HTML. If the page does not define this, this +function returns `None` ```py >>> scraper.site_name() @@ -242,7 +273,9 @@ Returns the output of all functions implemented by this scraper as a `dict`. ### `category() -> str` -Semi-structured field that can contain a mix of cuisine type (for example, country names), mealtime (breakfast/dinner/etc) and dietary properties (gluten-free, vegetarian). The value is defined by the website, so it may overlap with other scraper functions (e.g. `cuisine()`). +Semi-structured field that can contain a mix of cuisine type (for example, country names), +mealtime (breakfast/dinner/etc) and dietary properties (gluten-free, vegetarian). The value is +defined by the website, so it may overlap with other scraper functions (e.g. `cuisine()`). ```py >>> scraper.category() @@ -269,7 +302,9 @@ Returns the cuisine of the recipe. ### `nutrients() -> Dict[str, str]` -Returns a `dict` of nutrition information. Each nutrition item is usually given per unit of yield, e.g. per servings, per item. The keys of the `dict` are the nutrients (including calories) and the values are the amount of that nutrient, including the unit. +Returns a `dict` of nutrition information. Each nutrition item is usually given per unit of yield, +e.g. per servings, per item. The keys of the `dict` are the nutrients (including calories) and the +values are the amount of that nutrient, including the unit. ```py >>> scraper.nutrients() @@ -296,7 +331,8 @@ Returns the time to prepare the ingredients for the recipe in minutes. ### `ratings() -> float` -Returns the recipe rating. When available, this is usually the average of all the ratings given to the recipe on the website. +Returns the recipe rating. When available, this is usually the average of all the ratings given to +the recipe on the website. ```py scraper.ratings() @@ -314,7 +350,8 @@ scraper.ratings_count() ### `reviews() -> List[Dict[str, str]]` -Returns a `list` of reviews about the recipe from the website. Each review is a `dict` containing the reviewer's name (`str`) and their review (`str`). +Returns a `list` of reviews about the recipe from the website. Each review is a `dict` containing +the reviewer's name (`str`) and their review (`str`). ### `equipment() -> List[str] | None` diff --git a/docs/contributing/setup.md b/docs/contributing/setup.md new file mode 100644 index 000000000..7036022b1 --- /dev/null +++ b/docs/contributing/setup.md @@ -0,0 +1,158 @@ +# Setup + +Thank you for your interest in contributing to this project! + +Follow these steps to set up your environment for development. + +!!! note "Prerequisites" + This guide assumes you have basic familiarity with Python development, including using `pip`, + `virtual environments`, and `git`. These core concepts are beyond the scope of this documentation. + + +!!! warning "Python Version Requirement" + We strongly recommend using Python 3.11 or above for all development work related to `recipe-scrapers`. + This version includes built-in `tomllib` support, which is essential for the project's configuration handling. + + +We welcome various types of code contributions to `recipe-scrapers`, including: + +- Bug fixes +- New recipe site scrapers +- Performance improvements +- Feature enhancements +- Test coverage improvements + + +## Fork the Repository + +1. Navigate to [our repository on GitHub](https://github.com/hhursev/recipe-scrapers). +2. Click the "Fork" button in the top right corner to create your own copy of the repository. + + +## Clone Your Fork + +```sh +git clone https://github.com//recipe-scrapers.git +cd recipe-scrapers +``` + +## Set Upstream Remote + +!!! tip "Upstream Remote" + Setting the upstream remote allows you to sync changes from the original repository to your fork. + This is useful to keep your fork up-to-date with the latest changes. + +```sh +git remote add upstream https://github.com/hhursev/recipe-scrapers.git +``` + + +## Create a Virtual Environment + +It's recommended to use a virtual environment to manage dependencies. You can create one using `venv` + +```sh +python -m venv .venv +source .venv/bin/activate # On Windows: `.venv\Scripts\activate` +``` + +!!! tip "Virtual Environment" + Remember to activate your virtual environment each time you work on the project: + ```sh + source .venv/bin/activate # On Windows: .venv\Scripts\activate + ``` + +## Install Dependencies + +Install the required dependencies using `pip` + +```sh +pip install -e ".[all]" +``` + +Our pyproject.toml file lists the installed dependencies and their purposes. + + +## Development Workflow + +Create a new branch for your changes: +```sh +git checkout -b fix/your-fix-name # for bug fixes +# or +git checkout -b site/website-name # for new site scrapers +# or +git checkout -b docs/your-addition # for docs updates +# or +git checkout -b feature/feature-name # for new features +``` + +After making your changes, commit them: + +```sh +git add -p # Review changes before adding them +git commit -m "meaningful commit message" +git push origin your-branch-name +``` + +### Pre-commit Hooks + +The project uses pre-commit hooks to ensure code quality and consistency. These hooks run +automatically when you commit changes, handling tasks like: + +- Code formatting (black, isort) +- Linting (flake8) +- Type checking +- Other code quality checks + + +## Syncing Your Fork + +To keep your fork up-to-date with the original repository, you can fetch and merge changes from +the upstream remote: + +```sh +git fetch upstream +git merge upstream/main +``` + +Then create a Pull Request back to the [main repository](https://github.com/hhursev/recipe-scrapers) +from your fork. + + +If you have troubles check out [Submitting A Pull Request Section](#submitting-a-pull-request). + + +## Submitting a Pull Request + +1. Navigate to your fork on GitHub. +2. Click the "New pull request" button. +3. Ensure the base fork is the original repository and the base branch is `main`. +4. Fill out the pull request template and submit. + + +## Thank you for contributing! + +### What happens after a PR + +When you submit your PR: + +1. Our CI suite will run against your code to ensure everything works as expected. You can run the +2. tests locally before submitting: +```sh +python -m unittest +# or +unittest-parallel --level test +``` + +2. Community members and core contributors will review your code. They may: + - Request changes or improvements + - Suggest alternative approaches + - Provide feedback on test coverage + - Ask for documentation updates + +3. Once approved, a core contributor will merge your PR + - Your contribution will be included in the next release + - Tackle any follow-up improvements in subsequent PRs + +Don't worry if your first PR needs some adjustments - this is normal and part of the collaborative +development process! diff --git a/docs/copyright-and-usage.md b/docs/copyright-and-usage.md new file mode 100644 index 000000000..73bd289aa --- /dev/null +++ b/docs/copyright-and-usage.md @@ -0,0 +1,74 @@ +# Copyright and Usage + +## Overview + +`recipe-scrapers` is a Python library that provides tools for extracting structured recipe data +from websites. This document outlines our approach to copyright considerations and clarifies +responsibilities for library maintainers and end users. + +## Copyright Responsibility + +### Library's Role + +`recipe-scrapers` is a tool that facilitates data extraction. The library itself: + +- Provides methods to access made available web content +- Transforms unstructured recipe data into structured formats +- Does not store, host, or redistribute any content +- Does not circumvent any technical access controls +- Makes no claims about the copyright status of accessed content + +### End User Responsibility + +Users of `recipe-scrapers` are responsible for: + +- Ensuring their use of scraped content complies with applicable laws +- Respecting website terms of service and *robots.txt* directives +- Obtaining necessary permissions for their intended use of scraped content +- Managing any copyright or licensing requirements for scraped content + +## Fair Use Considerations + +Many uses of `recipe-scrapers` may fall under fair use doctrine, particularly: + +- Personal recipe collection and organization +- Academic research and analysis +- Transformative uses that add value to the original content +- Non-commercial educational purposes + +However, users should conduct their own legal analysis based on their specific use case and +jurisdiction. + +## Best Practices for Users + +We recommend users: + +- Cache scraped content appropriately to minimize server load +- Include attribution when displaying scraped content +- Respect rate limits and *robots.txt* directives +- Consider websites' terms of service +- Implement appropriate error handling and fallbacks + +## Library Development Guidelines + +For contributors and maintainers: + +- Focus on structural improvements and bug fixes +- Maintain the library's role as a neutral tool +- Keep copyright considerations proportional and practical +- Balance legal compliance with usability +- Avoid features that could only serve infringing purposes + +## Disclaimer + +`recipe-scrapers` is provided "as is" without warranty of any kind. The maintainers make no +representations about the suitability, reliability, availability, timeliness, or accuracy of the +software or its content extraction capabilities. + +## Additional Resources + +For more information about web scraping and copyright: + +- [Stanford Libraries: Copyright and Fair Use](https://fairuse.stanford.edu/) +- [EFF: Legal Guide for Developers](https://www.eff.org/issues/coders) +- [Digital Media Law Project: Legal Risks in Scraping](https://www.dmlp.org/legal-guide) diff --git a/docs/getting-started/advanced-usage.md b/docs/getting-started/advanced-usage.md new file mode 100644 index 000000000..37f2c348a --- /dev/null +++ b/docs/getting-started/advanced-usage.md @@ -0,0 +1,56 @@ +# Advanced Usage + +!!! warning "Under Construction" + This whole page is currently under construction. + + Not worth your time at this point. + +!!! warning "Under Construction" + Just making sure the previous warning was not missed. + + This page is not worth your time at this point. + +## Overview + +This page covers the advanced internals of `recipe-scrapers`, including abstract +classes, schema.org parsing, utility functions, exception handling, and the +plugin system. These components are primarily useful for contributors and +developers looking to extend the library's functionality. + + +## Core Components + +??? abstract "Abstract Base Classes" + ::: recipe_scrapers._abstract + options: + heading_level: 3 + show_root_heading: false + show_source: true + +??? abstract "Schema.org Parser" + ::: recipe_scrapers._schemaorg + options: + heading_level: 3 + show_root_heading: false + show_source: true + +??? abstract "Utility Functions" + ::: recipe_scrapers._utils + options: + heading_level: 3 + show_root_heading: false + show_source: true + +??? abstract "Exception Handling" + ::: recipe_scrapers._exceptions + options: + heading_level: 3 + show_root_heading: false + show_source: true + +??? abstract "Plugin System" + ::: recipe_scrapers.plugins + options: + heading_level: 3 + show_root_heading: false + show_source: true diff --git a/docs/getting-started/examples.md b/docs/getting-started/examples.md new file mode 100644 index 000000000..3f18682ac --- /dev/null +++ b/docs/getting-started/examples.md @@ -0,0 +1,70 @@ +# Examples + +!!! important + `recipe-scrapers` is designed to focus **exclusively on HTML parsing**. + + This core principle guides our development and support. You'll need to implement your own solution + for fetching recipe HTML files and managing network requests. The library works best when you + provide both the HTML content and its source domain. + + +## Basic Usage + +Here's a simple example of how to use the library: + +```python title="Basic Usage Example" linenums="1" +from urllib.request import urlopen +from recipe_scrapers import scrape_html + +url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" +html = urlopen(url).read().decode("utf-8") # retrieves the recipe webpage HTML +scraper = scrape_html(html, org_url=url) + +# Extract recipe information +scraper.title() +scraper.instructions() +scraper.links() +scraper.to_json() +scraper.nutrients() + +# To see all available methods +help(scraper) +``` + +For optimal results, always provide both the HTML content and its original URL. +This helps the library correctly parse website-specific elements. + +## Available Methods + +Recipe websites vary in the amount of information they provide. While some offer +comprehensive details like nutritional information (`.nutrients()`), others may +not. + +### Core Methods + +These methods should be available for all supported websites: + +!!! warning "Under Construction" + This documentation section is currently being updated and improved. + +::: tests.MANDATORY_TESTS + options: + heading_level: 4 + + +### Optional Methods + +These additional methods are available for some websites: + +!!! warning "Under Construction" + This documentation section is currently being updated and improved. + +::: tests.OPTIONAL_TESTS + options: + heading_level: 4 + + +## Common Patterns + +!!! warning "Under Construction" + This documentation section is currently being updated and improved. diff --git a/docs/getting-started/releases-and-license.md b/docs/getting-started/releases-and-license.md new file mode 100644 index 000000000..4fc422b91 --- /dev/null +++ b/docs/getting-started/releases-and-license.md @@ -0,0 +1,30 @@ +# Releases & License + +## Releases + +- **PyPI**: All versions available on [PyPI](https://pypi.org/project/recipe-scrapers/#history) +- **GitHub**: All versions tagged in our [releases page](https://github.com/hhursev/recipe-scrapers/releases) with detailed changelogs + +## Installation + +Want a specific version? We've got all of them available: + +- **From PyPI**: +```console +pip install recipe-scrapers==14.25.0 # replace with desired version +``` + +- **From GitHub:** +```console +pip install git+https://github.com/hhursev/recipe-scrapers.git@14.25.0 +``` + +## License +This project is licensed under the [MIT License](https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE). + +### Test Data Notice +The `test_data` directory contains content from various recipe websites used for testing purposes +only. This content is used under copyright exceptions including Fair Use (USA), Fair Dealing +(UK, Canada, Australia), and other international copyright doctrines that permit limited use of +copyrighted material for technical testing purposes. See the [test data license](https://github.com/hhursev/recipe-scrapers/blob/main/tests/test_data/LICENSE.md) +for more details. diff --git a/docs/getting-started/supported-sites.md b/docs/getting-started/supported-sites.md new file mode 100644 index 000000000..afb3ab8d9 --- /dev/null +++ b/docs/getting-started/supported-sites.md @@ -0,0 +1,21 @@ +# Supported Websites + +!!! success "Join Our Community" + 🌟 Want to add your favorite recipe site? We'd love your help! + + - 📖 Check our [contributing guidelines](../contributing/home.md) + - 🐛 Found a bug? [Open an issue](https://github.com/hhursev/recipe-scrapers/issues) + - 🚀 Ready to contribute? [Submit a pull request](../contributing/setup.md)! + +```python exec="on" +import sys +sys.path.insert(0, '.') +from recipe_scrapers import SCRAPERS + +sites = sorted(SCRAPERS.keys()) + +print(f"## What we offer?") +print(f"We currently support over **{len(sites)} popular recipe websites** out of the box! And with our `wild_mode` option, you can potentially scrape many more sites that follow common patterns - making this probably the most extensive recipe scraping library available.\n") +print(f"## Supported Sites List\n") +print("\n".join(f"- [{host}](https://{host}/)" for host in sites)) +``` diff --git a/docs/how-to-develop-scraper.md b/docs/how-to-develop-scraper.md deleted file mode 100644 index 75d3b02f9..000000000 --- a/docs/how-to-develop-scraper.md +++ /dev/null @@ -1,226 +0,0 @@ -# How To: Develop a New Scraper - -## 1. Find a website - -If you have found a website you want to scrape the recipes from, first of all check to see if the website is already supported. - -The project [README](https://github.com/hhursev/recipe-scrapers/blob/main/README.rst) has a list of the hundreds of websites already supported. - -You can also check from within Python: - -```python ->>> from recipe_scrapers import SCRAPERS -``` - -`SCRAPERS` is a dict where the keys are the hostnames of the supported websites and the values are the scraper classes for each supported website. - -```python ->>> from recipe_scrapers import SCRAPERS ->>> SCRAPERS.get("bbcgoodfood.com") -recipe_scrapers.bbcgoodfood.BBCGoodFood -``` - -It's a good idea to file an [issue](https://github.com/hhursev/recipe-scrapers/issues/new/choose) on GitHub to track support for the website, and to indicate whether you are working on it. - -## 2. Fork the recipe-scrapers repository and clone - -If this is your first time contributing to this repository then you will need to create a fork of the repository and clone it to your computer. - -To create a fork, click the Fork button near the top of page on the project GitHub page. This will create a copy of the repository under your GitHub user. - -You can then clone the fork to your computer and set it up for development. - -**Clone the repository**, replacing \ with your username: - -```shell -git clone git@github.com:/recipe-scrapers.git -cd recipe-scrapers -``` - -**Create a virtual environment, activate and install dependencies**: - -```shell -python -m venv .venv --upgrade-deps -source .venv/bin/activate -pip install -e .[dev] -pip install pre-commit -pre-commit install -``` - -**Check that everything is working by running the tests**: - -```shell -python -m unittest -``` - -This will run all the tests for all the scrapers. You should not see any errors or failures. - -**OPTIONAL: To run the full test suite in parallel**: - -```shell -pip install unittest-parallel -unittest-parallel --level test -``` - -## 3. Identify a recipe and generate the scraper and test file - -To develop the scraper for the website, first identify a recipe. This will be used to create the test case that will validate that the scraper is working correctly. - -> [!TIP] -> Try to pick a recipe that involves more than one instruction, if you can. The test suite considers single-instruction recipes to indicate possible human error. If you need to, though, you can [indicate that that's expected](https://github.com/hhursev/recipe-scrapers/blob/98ead6fc6e9653805b01539a3f46fbfb4e096136/tests/test_allrecipes.py#L147-L150). - -Next, find out if the website supports [Recipe Schema](https://schema.org/Recipe). If the website does support Recipe Schema, this will make creating the scraper straightforward. If not, supporting the site will be more complex but still possible. - -```python ->>> from recipe_scrapers import scrape_html ->>> scraper = scrape_html(HTML, URL, wild_mode=True) ->>> scraper.schema.data -{'@context': 'https://schema.org', - '@type': 'Recipe', - ... -} -``` - -If Recipe Schema is available, then `scraper.schema.data` will return a dict containing information about the recipe. - -If Recipe Schema is not available, then `scraper.schema.data` will return an empty dict. - -Next, generate the scraper class and test files by running this command: - -```shell -python generate.py -``` - -This will generate a file for the scraper with name \ with basic code that you will need to modify. This will also download the recipe at \ and create a test case. - -You can find the generated scraper class in the `recipe_scrapers/` directory in a file the same as \ but all lower case. The generated scraper class will look something like this: - -```python -from ._abstract import AbstractScraper - -class ScraperName(AbstractScraper): - @classmethod - def host(cls): - return "websitehost.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 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() -``` - -The generated scraper class will automatically be populated with functions that assume the Recipe Schema is available, regardless of whether it is or not. - -## 4. Add functionality to the scraper - -If the website supports Recipe Schema, then this is mostly done for you already. You can check if the output from each function is what you would expect from the recipe by using the scraper. - -```python ->>> from recipe_scrapers import scrape_html ->>> scraper = scrape_html(HTML, URL) ->>> scraper.title() -"..." ->>> scraper.ingredients() -[ - "...", - "..." -] -# etc. -``` - -Some additional functionality may be required in the scraper functions to make the output match the recipe on the website. - -An in-depth guide on all the functions a scraper can support and what their output should be can be found [here](in-depth-guide-scraper-functions.md). The automatically generated scraper does not include all of these functions by default, so you may wish to add some of the additional functions listed if the website can support them. - -If the website does not support Recipe Schema, or the schema does not include all of the recipe information, then you can scrape the information out of the website HTML. Each scraper has a `bs4.BeautifulSoup` object made available in `self.soup` which contains the parsed HTML. This can be used to extract the recipe information needed. - -An example of a scraper that uses this approach is [Przepisy](https://github.com/hhursev/recipe-scrapers/blob/main/recipe_scrapers/przepisy.py). - -The [BeautifulSoup documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.html) is a good resource for getting started with extracting information from HTML. A guide of common patterns and best practice used in this library can be found [here](in-depth-guide-html-scraping). - -Some helper functions are available in the `_utils.py` file. These are functions that are commonly needed when extracting information from HTML, such as `normalize_string()`. - -## 5. Create the test - -A test case was automatically created when the scraper class was created. It can be found in the `tests/test_data/` directory, where `host` is the hostname of the website the scraper is for. - -The test case comprises two parts: - -1. testhtml file containing the html from the URL used to generate the scraper -1. json file containing the expected output from the scraper when the scraper is run on the testhtml file. - -The generated json file will look something like this, with only the host field populated: - -```json -{ - "host": "", - "canonical_url": "", - "site_name": "", - "author": "", - "language": "", - "title": "", - "ingredients": "", - "instructions_list": "", - "total_time": "", - "yields": "", - "image": "", - "description": "", -} -``` - -Each of the fields in this file has the same name as the related scraper function. You will need to add the correct output from the scraper to each of these fields. - -If the scraper implements any of the optional functions listed in the [Scraper Functions guide](in-depth-guide-scraper-functions.md), then you should add the appropriate fields to the json file. - -In some cases, a scraper is not able to support one or more of the mandatory functions because the website doesn't provide the information. In these cases, remove the field from the json file. What will happen is that the test case will check to see if the scraper raises an exception if any of the unsupported functions are called. - -You can check whether your scraper is passing the tests by running - -```shell -python -m unittest -k -``` - -Where `ClassName` is the name that you used earlier to generate the scraper. - -> [!TIP] -> It is also recommended that you manually test the scraper with a couple of different recipes from the website, to check that there aren't any special cases the scraper will need to handle. You don't need to create test cases for each of these. - -## 6. Update the README - -Add the website's domain to the supported scraper list in README.rst, ensuring alphabetical order. - -If your site supports multiple top level domains (e.g. `.com.au`, `.co.ul`, `.at`, etc.) then list these on an indented entry under the primary domain (the default value of `host()` when no arguments are provided). For an example of this, check out the `hellofresh` listings. - -## 7. Open a pull request - -Once you have finished developing the scraper and test case, you can commit the files to git and push them to GitHub. You should also update the README.rst to list the site, alphabetically, under the [Scrapers available for:](https://github.com/hhursev/recipe-scrapers#scrapers-available-for) header. - -After you have pushed the changes to GitHub, you can open a pull request in the [recipe-scrapers project](https://github.com/hhursev/recipe-scrapers/pulls). Your changes will undergo some automatic tests (no different to running the all the tests in the project, but this time on all supported platforms and using all supported Python versions) and be reviewed by other project contributors. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..3da44e045 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,115 @@ +# Recipe Scrapers + +[![Github](https://img.shields.io/github/stars/hhursev/recipe-scrapers?style=social)](https://github.com/hhursev/recipe-scrapers/) +[![Version](https://img.shields.io/pypi/v/recipe-scrapers.svg)](https://pypi.org/project/recipe-scrapers/) +[![Python Version](https://img.shields.io/pypi/pyversions/recipe-scrapers)](https://pypi.org/project/recipe-scrapers/) +[![Downloads](https://pepy.tech/badge/recipe-scrapers)](https://pepy.tech/project/recipe-scrapers) +[![GitHub Actions Unittests](https://github.com/hhursev/recipe-scrapers/workflows/unittests/badge.svg?branch=main)](https://github.com/hhursev/recipe-scrapers/actions/) +[![Coveralls](https://coveralls.io/repos/hhursev/recipe-scraper/badge.svg?branch=main&service=github)](https://coveralls.io/github/hhursev/recipe-scraper?branch=main) +[![License](https://img.shields.io/github/license/hhursev/recipe-scrapers)](https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE) + +--- + +`recipe-scrapers` is a Python package designed to extract recipe data from HTM content of +cooking websites. It parses the HTML structure of recipe pages to provide a simple and consistent +API for retrieving structured data like ingredients, instructions, cooking time, and more. +Works with the python versions listed above. + +## Installation + +You can install `recipe-scrapers` using pip or your preferred Python package manager: + +!!! tip "Install" + ``` console + pip install recipe-scrapers + ``` + +!!! note + + This should produce output about the installation process, with the final line reading: + `Successfully installed recipe-scrapers-`. + + +## Overview + +```python exec="on" +import sys +sys.path.insert(0, ".") +from recipe_scrapers import SCRAPERS + +print(f"There are **{len(SCRAPERS.keys())}** cooking websites currently supported.") +``` + +For a full list check our [Supported Sites](./getting-started/supported-sites.md) section. + +With `recipe-scrapers`, you should easily extract structured recipe data such as: + +- title +- ingredients +- instructions +- cooking and preparation times +- yields +- image +- and many more... + +Check out our [Examples](./getting-started/examples.md) section to see how to get started with the library. + +## Core Functionality + +`recipe-scrapers` long term aim is to focus **solely on HTML parsing** and not to handle +networking operations. This design choice provides flexibility in how you retrieve HTML content +and allows you to: + +- Implement your own networking logic +- Handle rate limiting +- Manage caching +- Control error handling +- Use your preferred HTTP client + + +## Getting Started + +👋 We suspect you've missed a few key links, such as us mentioning the [Examples](./getting-started/examples.md) and +the [Supported Sites](./getting-started/supported-sites.md) section. + +Thus, we drop this tiny Python snippet for you (using Python's built-in `urllib`) to showcase how +you can use this package: + +```python +from urllib.request import urlopen + +from recipe_scrapers import scrape_html + +url = "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/" +html = urlopen(url).read().decode("utf-8") # retrieves the recipe webpage HTML +scraper = scrape_html(html, org_url=url) +scraper.title() +scraper.instructions() +scraper.to_json() +# for a complete list of methods: +# help(scraper) +``` + +## Why recipe-scrapers Exists + +Born from late-night coding sessions and a love for both food and programming, `recipe-scrapers` +evolved from a personal project into a community tool. It's open-sourced and under +the [MIT license](https://github.com/hhursev/recipe-scrapers/blob/main/LICENSE) +with a simple goal: let developers focus on building amazing food-related applications without +reinventing the recipe-parsing wheel. + +Today, our library helps power diverse projects across the cooking landscape: + +- Meal prep and planning applications +- Smart shopping list generators +- Recipe collection managers +- Cooking time estimators +- Diet and nutrition trackers +- Food blogs and recipe aggregators + +We're excited to see what you'll create! Feel free to share your project in our +[community showcase](https://github.com/hhursev/recipe-scrapers/issues/9) - we love seeing what others build with the library. + +!!! tip "Happy cooking with code!" + While building awesome stuff, remember to be mindful of websites' terms and fair usage - + our [Copyright and Usage Guidelines](copyright-and-usage.md) will help you stay on track. diff --git a/docs/misc/migrating-from-v14.md b/docs/misc/migrating-from-v14.md new file mode 100644 index 000000000..df93a5904 --- /dev/null +++ b/docs/misc/migrating-from-v14.md @@ -0,0 +1,98 @@ +# Migrating from v14 to v15 + +!!! warning "Under Construction" + This documentation section is currently being updated and improved. + +## Overview + +Version 15 introduces important changes to the core API of recipe-scrapers, particularly regarding +how recipes are scraped from websites. The main change is the deprecation of the `scrape_me` +function in favor of more explicit HTML parsing methods. + +## Key Changes + +### 1. Deprecation of `scrape_me` + +The `scrape_me` function, which was the primary method for scraping recipes in v14, is being +deprecated. While it still works in v15, you'll receive deprecation warnings when using it: + +```python +# Old v14 approach (deprecated) +from recipe_scrapers import scrape_me +scraper = scrape_me('https://example.com/recipe') # Will show deprecation warning +``` + +### 2. New Recommended Approach + +The new approach separates HTML fetching from parsing: + +```python +# New v15 approach +from urllib.request import urlopen +from recipe_scrapers import scrape_html + +# Fetch HTML (you can use any HTTP client) +url = "https://example.com/recipe" +html = urlopen(url).read().decode("utf-8") + +# Parse HTML +scraper = scrape_html(html, org_url=url) +``` + +## Why This Change? + +1. **Better Separation of Concerns**: The library now focuses solely on HTML parsing, letting +you handle HTTP requests as you see fit +2. **More Flexibility**: You can use your preferred HTTP client (requests, httpx, aiohttp, etc.) +3. **Better Error Handling**: Separate networking issues from parsing issues + +## Migration Steps + +1. Replace `scrape_me` imports: + ```python + # Before + from recipe_scrapers import scrape_me + + # After + from recipe_scrapers import scrape_html + ``` + +2. Update scraping code: + ```python + # Before + scraper = scrape_me('https://example.com/recipe') + + # After + from urllib.request import urlopen + + url = 'https://example.com/recipe' + html = urlopen(url).read().decode("utf-8") + scraper = scrape_html(html, org_url=url) + ``` + +3. If you're using a web framework or need to handle many requests, consider using a more +robust HTTP client: + ```python + # Example with requests + import requests + from recipe_scrapers import scrape_html + + def get_recipe(url): + response = requests.get(url) + response.raise_for_status() + return scrape_html(response.text, org_url=url) + ``` + +## Timeline + +- v14.x.x: Still supported but will only receive critical bug fixes +- v15.x.x: Current stable version with new API +- Future versions: Will build upon the v15 API structure + +## Getting Help + +If you encounter issues during migration: + +1. Check the [GitHub issues](https://github.com/hhursev/recipe-scrapers/issues) for similar problems +2. Open a new issue if you find a bug +3. Join the community discussions for migration-related questions diff --git a/docs/test-data-notice.md b/docs/test-data-notice.md new file mode 100644 index 000000000..d5433e76a --- /dev/null +++ b/docs/test-data-notice.md @@ -0,0 +1,57 @@ +# License Notice for Test Data Directory + +This notice applies exclusively to the content within the +[test_data](https://github.com/hhursev/recipe-scrapers/tree/main/tests/test_data) directory. +This directory contains webpage content from various recipe websites, used strictly for testing +purposes. The test data is used under copyright exceptions including Fair Use (USA), Fair Dealing +(UK, Canada, Australia), and other international copyright doctrines that permit limited use +of copyrighted material for technical testing purposes. + +## Purpose of Use + +This content is used exclusively for: + +- Software testing +- Educational purposes +- Technical verification +- Functionality demonstration + +## Copyright Notice + +All recipe content, including but not limited to: + +- Recipe titles +- Ingredient lists +- Instructions +- Images +- Descriptions +- Other associated content + +remains the intellectual property of their respective original authors and websites. No claim of +ownership is made by this project over any of this content. + +## Attribution + +Each test file is named after its source website. The content within each file was obtained from +the corresponding website solely for testing the functionality of the recipe-scrapers library. + +## Limited Use Statement + +Our use of this content is strictly limited and justified because: + +1. It is used solely for testing software functionality +2. Only the minimum necessary content is stored +3. The content is not used for commercial purposes +4. The use does not negatively impact the market value of the original content +5. All content can be promptly removed upon copyright holder request +6. The use is consistent with educational and technical testing exceptions under various +international copyright laws + +## Content Removal and Privacy + +If you are a copyright holder of any content in this directory and wish to have it removed, you +can either open an issue in this repository or, if you wish to keep your privacy, contact us +through the email address listed in the [project's PyPI page](https://pypi.org/project/recipe-scrapers/) +under the Authors section. + +We'll sort it out promptly with our legal team. diff --git a/generate.py b/generate.py index ab8c7e138..ee6b32275 100644 --- a/generate.py +++ b/generate.py @@ -129,8 +129,8 @@ def _import(self, node): if isinstance(node, ast.Module) or isinstance(node, ast.Import): return True - if isinstance(node, ast.ImportFrom): - if node.module > self.module_name and node.level > 0: + if isinstance(node, ast.ImportFrom) and node.level > 0: + if node.module > self.module_name: offset = self._offset(node) import_statement = ( f"\nfrom .{self.module_name} import {self.class_name}" diff --git a/mkdocs.yaml b/mkdocs.yaml new file mode 100644 index 000000000..7383ce498 --- /dev/null +++ b/mkdocs.yaml @@ -0,0 +1,95 @@ +site_name: recipe-scrapers +site_url: https://docs.recipe-scrapers.com +site_description: Documentation for recipe-scrapers - Python package for scraping recipes data from the web +repo_url: https://github.com/hhursev/recipe-scrapers +repo_name: hhursev/recipe-scrapers + +theme: + name: material + palette: + - scheme: default + primary: teal + accent: teal + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - scheme: slate + primary: teal + accent: teal + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - navigation.instant + - navigation.tracking + - navigation.sections + - navigation.expand + - navigation.top + - search.suggest + - search.highlight + - navigation.top + - navigation.tabs + - navigation.tabs.sticky + +nav: + - Getting Started: + - Getting Started: index.md + - Examples: getting-started/examples.md + - Supported Sites: getting-started/supported-sites.md + - Advanced Usage: getting-started/advanced-usage.md + - Migrating from v14: misc/migrating-from-v14.md + - Releases & License: getting-started/releases-and-license.md + - Contributing: + - Contributing: contributing/home.md + - Setup: contributing/setup.md + - Documentation: contributing/documentation.md + - Code Contributions: contributing/code-contribution.md + - How To Develop A Scraper: contributing/how-to-develop-a-scraper.md + - In-Depth Guides: + - HTML Scraping: contributing/in-depth-guide-html-scraping.md + - Scraper Functions: contributing/in-depth-guide-scraper-functions.md + - Ingredient Groups: contributing/in-depth-guide-ingredient-groups.md + - Debugging: contributing/in-depth-guide-debugging.md + - Copyright and Usage: + - Copyright and Usage: copyright-and-usage.md + - Test Data Notice: test-data-notice.md + +markdown_extensions: + - admonition + - attr_list + - md_in_html + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.tabbed: + alternate_style: true + - tables + +plugins: + - search + - markdown-exec # used in supported-sites.md + - mkdocstrings: + default_handler: python + handlers: + python: + paths: [tests, recipe_scrapers] + options: + show_source: true + show_root_heading: true + heading_level: 1 + show_category_heading: true + docstring_style: google +# show_signature_annotations: true +# show_if_no_docstring: true +# show_root_full_path: true +# members: true +# show_private_members: true +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/hhursev/recipe-scrapers + - icon: fontawesome/brands/python + link: https://pypi.org/project/recipe-scrapers/ diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 0738deb4c..000000000 --- a/mypy.ini +++ /dev/null @@ -1,12 +0,0 @@ -[mypy] - -[mypy-recipe_scrapers.*] -disable_error_code = union-attr - -# Third-party libraries - -[mypy-isodate] -ignore_missing_imports = true - -[mypy-extruct] -ignore_missing_imports = true diff --git a/pyproject.toml b/pyproject.toml index a70094310..d80b127d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,15 +38,53 @@ dependencies = [ ] [project.optional-dependencies] +online = [ + "requests>=2.31.0", +] +# Documentation dependencies +# Install these to build and serve the documentation: +# pip install -e ".[docs]" +# +# Common commands: +# mkdocs serve # Start local docs server at http://127.0.0.1:8000 +# # The server auto-reloads when you change files in docs/ +docs = [ + "mkdocs >= 1.6.1", # Core documentation generator + "mkdocs-material >= 9.5.48", # Material theme for MkDocs + "mkdocstrings >= 0.27.0", # API documentation from docstrings + "mkdocstrings-python >= 1.12.2", # Python handler for mkdocstrings + "markdown-exec >= 1.10.0", # Execute code blocks in markdown +] +# Testing dependencies +# Install these to run tests and check coverage: +# pip install -e ".[test]" +# Common commands: +# python -m unittest # Run tests sequentially +# python -m unittest_parallel --level test # Run tests in parallel (speeed) +# coverage run -m unittest # Run tests with coverage +# coverage report # View coverage report in terminal +# coverage html # Generate HTML coverage report +tests = [ + "coverage >= 7.6.9", # Code coverage measurement tool + "unittest-parallel >= 1.7.0", # Run unittest tests in parallel +] +linters = [ + "pre-commit == 4.0.1", # latest from PyPI + "black == 24.10.0", # match what's in .pre-commit-config.yaml + "flake8 == 7.1.1", # match what's in .pre-commit-config.yaml + "pep8-naming == 0.14.1", # match what's in .pre-commit-config.yaml + "mypy == 1.14.0", # match what's in .pre-commit-config.yaml + "types-beautifulsoup4", # needed for mypy + "types-requests", # needed for mypy +] dev = [ - "coverage >=7.4.4", - "types-beautifulsoup4>=4.12.0", - "importlib-metadata>=4.6 ; python_version < '3.10'", + "recipe-scrapers[docs,tests,linters]", ] -online = [ - "requests >= 2.31.0", +all = [ + "recipe_scrapers[online,docs,tests,linters,dev]" ] + [tool.setuptools.packages.find] include = ["recipe_scrapers", "recipe_scrapers.*"] exclude = ["tests", "tests.*"] @@ -57,3 +95,32 @@ version = {attr = "recipe_scrapers.__version__.__version__"} [tool.setuptools.package-data] recipe_scrapers = ["py.typed"] + +[tool.coverage.run] +branch = true +source = ["recipe_scrapers"] +relative_files = true + +[tool.coverage.report] +omit = [ + "recipe_scrapers/__version__.py", + "recipe_scrapers/plugins/template.py", + "recipe_scrapers/settings/template.py" +] +exclude_lines = [ + "raise NotImplementedError" +] + +[tool.mypy] +[[tool.mypy.overrides]] +module = "recipe_scrapers.*" +disable_error_code = "union-attr" +[[tool.mypy.overrides]] +module = "._abstract" +ignore_missing_imports = true +[[tool.mypy.overrides]] +module = "isodate" +ignore_missing_imports = true +[[tool.mypy.overrides]] +module = "extruct" +ignore_missing_imports = true diff --git a/recipe_scrapers/__init__.py b/recipe_scrapers/__init__.py index 3b78a0a2d..11c06f155 100644 --- a/recipe_scrapers/__init__.py +++ b/recipe_scrapers/__init__.py @@ -41,6 +41,7 @@ from .addapinch import AddAPinch from .afghankitchenrecipes import AfghanKitchenRecipes from .aflavorjournal import AFlavorJournal +from .ahealthysliceoflife import AHealthySliceOfLife from .akispetretzikis import AkisPetretzikis from .albertheijn import AlbertHeijn from .aldi import Aldi @@ -55,6 +56,7 @@ from .altonbrown import AltonBrown from .amazingribs import AmazingRibs from .ambitiouskitchen import AmbitiousKitchen +from .ameessavorydish import AmeesSavoryDish from .americastestkitchen import AmericasTestKitchen from .archanaskitchen import ArchanasKitchen from .argiro import Argiro @@ -106,6 +108,7 @@ from .cookiesandcups import CookiesAndCups from .cookingcircle import CookingCircle from .cookinglight import CookingLight +from .cookingwithjanica import CookingWithJanica from .cookomix import Cookomix from .cookpad import CookPad from .cookscountry import CooksCountry @@ -118,7 +121,9 @@ from .creativecanning import CreativeCanning from .cucchiaio import Cucchiaio from .cuisineaz import CuisineAZ +from .culy import Culy from .cybercook import Cybercook +from .dagelijksekost import DagelijkseKost from .damndelicious import DamnDelicious from .davidlebovitz import DavidLebovitz from .delish import Delish @@ -138,6 +143,7 @@ from .eattolerant import EatTolerant from .eatwell101 import EatWell101 from .eatwhattonight import EatWhatTonight +from .eggsca import EggsCa from .elavegan import ElaVegan from .emmikochteinfach import EmmiKochtEinfach from .epicurious import Epicurious @@ -200,6 +206,7 @@ from .innit import Innit from .insanelygoodrecipes import InsanelyGoodRecipes from .inspiralized import Inspiralized +from .inspiredtaste import InspiredTaste from .irishcentral import IrishCentral from .izzycooking import IzzyCooking from .jamieoliver import JamieOliver @@ -209,10 +216,12 @@ from .joyfoodsunshine import Joyfoodsunshine from .joythebaker import JoyTheBaker from .juliegoodwin import JulieGoodwin +from .jumbo import Jumbo from .justataste import JustATaste from .justbento import JustBento from .justonecookbook import JustOneCookbook from .kalejunkie import KaleJunkie +from .kellyscleankitchen import KellysCleanKitchen from .kennymcgovern import KennyMcGovern from .keukenliefdenl import KeukenLiefdeNL from .kingarthur import KingArthur @@ -224,11 +233,14 @@ from .kochbar import Kochbar from .kochbucher import Kochbucher from .koket import Koket +from .kookjij import KookJij from .kristineskitchenblog import KristinesKitchenBlog from .krollskorner import KrollsKorner from .kuchniadomowa import KuchniaDomowa from .kuchynalidla import KuchynaLidla from .kwestiasmaku import KwestiaSmaku +from .lacucinaitaliana import LaCucinaItaliana +from .lanascooking import LanasCooking from .latelierderoxane import LAtelierDeRoxane from .leanandgreenrecipes import LeanAndGreenRecipes from .lecker import Lecker @@ -245,10 +257,13 @@ from .madamecuisine import MadameCuisine from .madensverden import MadensVerden from .madsvin import Madsvin +from .makeitdairyfree import MakeItDairyFree from .marmiton import Marmiton from .marthastewart import MarthaStewart from .matprat import Matprat from .mccormick import McCormick +from .mealprepmanual import MealPrepManual +from .meganvskitchen import MeganVsKitchen from .meljoulwan import Meljoulwan from .melskitchencafe import MelsKitchenCafe from .miljuschka import Miljuschka @@ -271,9 +286,11 @@ from .mykoreankitchen import MyKoreanKitchen from .myrecipes import MyRecipes from .myvegetarianroots import MyVegetarianRoots +from .natashaskitchen import NatashasKitchen from .nhshealthierfamilies import NHSHealthierFamilies from .nibbledish import NibbleDish from .nihhealthyeating import NIHHealthyEating +from .noracooks import NoraCooks from .norecipes import NoRecipes from .nosalty import NoSalty from .notenoughcinnamon import NotEnoughCinnamon @@ -284,6 +301,7 @@ from .nutritionfacts import NutritionFacts from .nytimes import NYTimes from .ohsheglows import OhSheGlows +from .okokorecepten import OkokoRecepten from .omnivorescookbook import OmnivoresCookbook from .onceuponachef import OnceUponAChef from .onehundredonecookbooks import OneHundredOneCookBooks @@ -304,6 +322,7 @@ from .popsugar import PopSugar from .potatorolls import PotatoRolls from .practicalselfreliance import PracticalSelfReliance +from .preppykitchen import PreppyKitchen from .pressureluckcooking import PressureLuckCooking from .primaledgehealth import PrimalEdgeHealth from .projectgezond import ProjectGezond @@ -318,7 +337,9 @@ from .receitasnestlebr import ReceitasNestleBR from .recept import Recept from .receptyprevas import ReceptyPreVas +from .recetteplus import RecettePlus from .recipegirl import RecipeGirl +from .recipeland import RecipeLand from .reciperunner import RecipeRunner from .recipetineats import RecipeTinEats from .redhousespice import RedHouseSpice @@ -336,7 +357,9 @@ from .sandwhichtribunal import SandwhichTribunal from .saveur import Saveur from .savorynothings import SavoryNothings +from .schoolofwok import SchoolOfWok from .seriouseats import SeriousEats +from .shelikesfood import SheLikesFood from .simpleveganista import SimpleVeganista from .simplycookit import SimplyCookit from .simplyquinoa import SimplyQuinoa @@ -350,10 +373,12 @@ from .spainonafork import SpainOnAFork from .spendwithpennies import SpendWithPennies from .springlane import Springlane +from .stacyling import StacyLing from .staysnatched import StaySnatched from .steamykitchen import SteamyKitchen from .streetkitchen import StreetKitchen from .strongrfastr import StrongrFastr +from .sugarhero import SugarHero from .sunbasket import SunBasket from .sundpaabudget import SundPaaBudget from .sunset import Sunset @@ -377,6 +402,7 @@ from .thekitchn import TheKitchn from .theloopywhisk import TheLoopyWhisk from .themagicalslowcooker import TheMagicalSlowCooker +from .themediterranedish import TheMediterraneDish from .themodernproper import TheModernProper from .thepalatablelife import ThePalatableLife from .thepioneerwoman import ThePioneerWoman @@ -391,6 +417,7 @@ from .tineno import TineNo from .tofoo import Tofoo from .tudogostoso import TudoGostoso +from .twentyfourkitchen import TwentyFourKitchen from .twopeasandtheirpod import TwoPeasAndTheirPod from .uitpaulineskeukennl import UitPaulinesKeukenNL from .unsophisticook import Unsophisticook @@ -402,9 +429,12 @@ from .vegetarbloggen import Vegetarbloggen from .vegolosi import Vegolosi from .vegrecipesofindia import VegRecipesOfIndia +from .veroniquecloutier import VeroniqueCloutier from .waitrose import Waitrose from .watchwhatueat import WatchWhatUEat +from .wdr import WDR from .wearenotmartha import WeAreNotMartha +from .wedishitup import WeDishItUp from .weightwatchers import WeightWatchers from .weightwatcherspublic import WeightWatchersPublic from .wellplated import WellPlated @@ -425,6 +455,7 @@ ABeautifulMess.host(): ABeautifulMess, ACoupleCooks.host(): ACoupleCooks, AFlavorJournal.host(): AFlavorJournal, + AHealthySliceOfLife.host(): AHealthySliceOfLife, ALittleBitYummy.host(): ALittleBitYummy, AberleHome.host(): AberleHome, Abril.host(): Abril, @@ -453,6 +484,7 @@ AmazingRibs.host(): AmazingRibs, AmbitiousKitchen.host(): AmbitiousKitchen, AmericasTestKitchen.host(): AmericasTestKitchen, + AmeesSavoryDish.host(): AmeesSavoryDish, ArchanasKitchen.host(): ArchanasKitchen, Argiro.host(): Argiro, Arla.host(): Arla, @@ -508,6 +540,7 @@ CookiesAndCups.host(): CookiesAndCups, CookingCircle.host(): CookingCircle, CookingLight.host(): CookingLight, + CookingWithJanica.host(): CookingWithJanica, Cookomix.host(): Cookomix, CooksCountry.host(): CooksCountry, CooksIllustrated.host(): CooksIllustrated, @@ -517,7 +550,9 @@ CreativeCanning.host(): CreativeCanning, Cucchiaio.host(): Cucchiaio, CuisineAZ.host(): CuisineAZ, + Culy.host(): Culy, Cybercook.host(): Cybercook, + DagelijkseKost.host(): DagelijkseKost, DamnDelicious.host(): DamnDelicious, DavidLebovitz.host(): DavidLebovitz, Delish.host(): Delish, @@ -528,6 +563,7 @@ DonalSkehan.host(): DonalSkehan, EatLiveRun.host(): EatLiveRun, EatThisMuch.host(): EatThisMuch, + EggsCa.host(): EggsCa, ElaVegan.host(): ElaVegan, EvolvingTable.host(): EvolvingTable, FamilyfoodOnTheTable.host(): FamilyfoodOnTheTable, @@ -541,21 +577,31 @@ HungryHappens.host(): HungryHappens, InBloomBakery.host(): InBloomBakery, InGoodFlavor.host(): InGoodFlavor, + InspiredTaste.host(): InspiredTaste, IrishCentral.host(): IrishCentral, JoCooks.host(): JoCooks, JoshuaWeissman.host(): JoshuaWeissman, JoyTheBaker.host(): JoyTheBaker, + Jumbo.host(): Jumbo, KaleJunkie.host(): KaleJunkie, + KellysCleanKitchen.host(): KellysCleanKitchen, KitchenAidAustralia.host(): KitchenAidAustralia, KitchenDivas.host(): KitchenDivas, KitchenDreaming.host(): KitchenDreaming, + KookJij.host(): KookJij, KristinesKitchenBlog.host(): KristinesKitchenBlog, KrollsKorner.host(): KrollsKorner, KuchynaLidla.host(): KuchynaLidla, + LaCucinaItaliana.host(): LaCucinaItaliana, + LaCucinaItaliana.host(domain="com"): LaCucinaItaliana, + LanasCooking.host(): LanasCooking, LittleSunnyKitchen.host(): LittleSunnyKitchen, LeitesCulinaria.host(): LeitesCulinaria, MadameCuisine.host(): MadameCuisine, + MakeItDairyFree.host(): MakeItDairyFree, McCormick.host(): McCormick, + MealPrepManual.host(): MealPrepManual, + MeganVsKitchen.host(): MeganVsKitchen, Miljuschka.host(): Miljuschka, ModernHoney.host(): ModernHoney, MomOnTimeout.host(): MomOnTimeout, @@ -564,29 +610,39 @@ MyJewishLearning.host(): MyJewishLearning, MyKoreanKitchen.host(): MyKoreanKitchen, MyVegetarianRoots.host(): MyVegetarianRoots, + NatashasKitchen.host(): NatashasKitchen, + NoraCooks.host(): NoraCooks, NotEnoughCinnamon.host(): NotEnoughCinnamon, NutritionFacts.host(): NutritionFacts, + OkokoRecepten.host(): OkokoRecepten, OneSweetAppetite.host(): OneSweetAppetite, OttolenghiBooks.host(): OttolenghiBooks, PeelWithZeal.host(): PeelWithZeal, PinchOfYum.host(): PinchOfYum, PotatoRolls.host(): PotatoRolls, + PreppyKitchen.host(): PreppyKitchen, QuiToque.host(): QuiToque, Recept.host(): Recept, ReceptyPreVas.host(): ReceptyPreVas, + RecettePlus.host(): RecettePlus, RecipeGirl.host(): RecipeGirl, Rewe.host(): Rewe, + RecipeLand.host(): RecipeLand, RicettePerBimby.host(): RicettePerBimby, SandwhichTribunal.host(): SandwhichTribunal, SavoryNothings.host(): SavoryNothings, + SheLikesFood.host(): SheLikesFood, SpainOnAFork.host(): SpainOnAFork, + StacyLing.host(): StacyLing, StrongrFastr.host(): StrongrFastr, + SugarHero.host(): SugarHero, TasteAtlas.host(): TasteAtlas, TheCookieRookie.host(): TheCookieRookie, TheCookingGuy.host(): TheCookingGuy, TheFoodieTakesFlight.host(): TheFoodieTakesFlight, TheGlutenFreeAustrian.host(): TheGlutenFreeAustrian, TheLoopyWhisk.host(): TheLoopyWhisk, + TheMediterraneDish.host(): TheMediterraneDish, ThePalatableLife.host(): ThePalatableLife, TheSaltyMarshmallow.host(): TheSaltyMarshmallow, Thinlicious.host(): Thinlicious, @@ -766,6 +822,7 @@ SallysBlog.host(): SallysBlog, SaltPepperSkillet.host(): SaltPepperSkillet, Saveur.host(): Saveur, + SchoolOfWok.host(): SchoolOfWok, SeriousEats.host(): SeriousEats, SimpleVeganista.host(): SimpleVeganista, SimplyCookit.host(): SimplyCookit, @@ -810,6 +867,7 @@ TineNo.host(): TineNo, Tofoo.host(): Tofoo, TudoGostoso.host(): TudoGostoso, + TwentyFourKitchen.host(): TwentyFourKitchen, TwoPeasAndTheirPod.host(): TwoPeasAndTheirPod, USAPears.host(): USAPears, USDAMyPlate.host(): USDAMyPlate, @@ -820,9 +878,12 @@ VegRecipesOfIndia.host(): VegRecipesOfIndia, Vegetarbloggen.host(): Vegetarbloggen, Vegolosi.host(): Vegolosi, + VeroniqueCloutier.host(): VeroniqueCloutier, + WDR.host(): WDR, Waitrose.host(): Waitrose, WatchWhatUEat.host(): WatchWhatUEat, WeAreNotMartha.host(): WeAreNotMartha, + WeDishItUp.host(): WeDishItUp, WeightWatchers.host(): WeightWatchers, WeightWatchersPublic.host(): WeightWatchersPublic, WellPlated.host(): WellPlated, diff --git a/recipe_scrapers/__version__.py b/recipe_scrapers/__version__.py index 85829d2f9..ff9f49ef4 100644 --- a/recipe_scrapers/__version__.py +++ b/recipe_scrapers/__version__.py @@ -1 +1 @@ -__version__ = "15.3.2" +__version__ = "15.4.0" diff --git a/recipe_scrapers/_schemaorg.py b/recipe_scrapers/_schemaorg.py index c1d6a4b70..8d44a0567 100644 --- a/recipe_scrapers/_schemaorg.py +++ b/recipe_scrapers/_schemaorg.py @@ -222,7 +222,9 @@ def ingredients(self): ingredients = [ingredients] return [ - normalize_string(ingredient) for ingredient in ingredients if ingredient + normalize_string(ingredient).replace("((", "(").replace("))", ")") + for ingredient in ingredients + if ingredient ] def nutrients(self): @@ -265,7 +267,11 @@ def _extract_howto_instructions_text(self, schema_item): return instructions_gist def instructions(self): - instructions = self.data.get("recipeInstructions") or "" + instructions = ( + self.data.get("recipeInstructions") + or self.data.get("RecipeInstructions") + or "" + ) if ( instructions diff --git a/recipe_scrapers/_utils.py b/recipe_scrapers/_utils.py index 438b6f970..6985e1dd1 100644 --- a/recipe_scrapers/_utils.py +++ b/recipe_scrapers/_utils.py @@ -224,9 +224,9 @@ def get_yields(element): return best_match if SERVE_REGEX_ITEMS.search(serve_text) is not None: - return "{} item{}".format(matched, "" if int(matched) == 1 else "s") + return f"{matched} item{'s' if int(matched) != 1 else ''}" - return "{} serving{}".format(matched, "" if int(matched) == 1 else "s") + return f"{matched} serving{'s' if int(matched) != 1 else ''}" def get_equipment(equipment_items): diff --git a/recipe_scrapers/ahealthysliceoflife.py b/recipe_scrapers/ahealthysliceoflife.py new file mode 100644 index 000000000..25ef58fb4 --- /dev/null +++ b/recipe_scrapers/ahealthysliceoflife.py @@ -0,0 +1,38 @@ +from ._abstract import AbstractScraper +from ._utils import normalize_string + + +class AHealthySliceOfLife(AbstractScraper): + @classmethod + def host(cls): + return "ahealthysliceoflife.com" + + def author(self): + return self.schema.author() + + def title(self): + return self.schema.title() + + def category(self): + return self.schema.category() + + def image(self): + return self.schema.image() + + def ingredients(self): + ingredients = self.soup.find( + "div", {"class": "tasty-recipes-ingredients-body"} + ).findAll("p") + return [normalize_string(ing.get_text().strip()) for ing in 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() diff --git a/recipe_scrapers/ameessavorydish.py b/recipe_scrapers/ameessavorydish.py new file mode 100644 index 000000000..e940e8511 --- /dev/null +++ b/recipe_scrapers/ameessavorydish.py @@ -0,0 +1,46 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment, normalize_string + + +class AmeesSavoryDish(AbstractScraper): + @classmethod + def host(cls): + return "ameessavorydish.com" + + def ingredients(self): + ingredients_list = [] + for element in self.soup.select(".wprm-recipe-ingredient:not(:has(strong))"): + ingredient_text = " ".join( + span.get_text(strip=True) + for span in element.select( + ".wprm-recipe-ingredient-amount, " + ".wprm-recipe-ingredient-unit, " + ".wprm-recipe-ingredient-name, " + ".wprm-recipe-ingredient-notes" + ) + ) + ingredients_list.append(ingredient_text) + return ingredients_list + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group .wprm-recipe-ingredient-name strong", + ".wprm-recipe-ingredient:not(:has(strong))", + ) + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + normalize_string(item.get_text()) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) diff --git a/recipe_scrapers/americastestkitchen.py b/recipe_scrapers/americastestkitchen.py index 589b9c952..a2ec71852 100644 --- a/recipe_scrapers/americastestkitchen.py +++ b/recipe_scrapers/americastestkitchen.py @@ -71,5 +71,10 @@ def _parse_ingredient_item(ingredient_item): @functools.cached_property def _get_additional_details(self): j = json.loads(self.soup.find(type="application/json").string) - name = list(j["props"]["initialState"]["content"]["documents"])[0] - return j["props"]["initialState"]["content"]["documents"][name] + # Handling for new page format + if "pageProps" in j["props"]: + return j["props"]["pageProps"]["data"] + else: + # Handling for old page format + name = list(j["props"]["initialState"]["content"]["documents"])[0] + return j["props"]["initialState"]["content"]["documents"][name] diff --git a/recipe_scrapers/cookingwithjanica.py b/recipe_scrapers/cookingwithjanica.py new file mode 100644 index 000000000..cfb5e34bb --- /dev/null +++ b/recipe_scrapers/cookingwithjanica.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class CookingWithJanica(AbstractScraper): + @classmethod + def host(cls): + return "cookingwithjanica.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/recipe_scrapers/cookwell.py b/recipe_scrapers/cookwell.py index f970324cd..5341f07be 100644 --- a/recipe_scrapers/cookwell.py +++ b/recipe_scrapers/cookwell.py @@ -1,7 +1,27 @@ from ._abstract import AbstractScraper +import re class CookWell(AbstractScraper): @classmethod def host(cls): return "cookwell.com" + + def nutrients(self): + nutrition_pattern = re.compile( + r'{\\"calories\\":(?P\d+),\\"carbohydrates\\":(?P\d+),\\"fat\\":(?P\d+),\\"protein\\":(?P\d+)}' + ) + + nutrition_script = self.soup.find("script", string=nutrition_pattern) + if nutrition_script: + match = nutrition_pattern.search(nutrition_script.string) + if match: + nutrition_info = match.groupdict() + return { + "calories": nutrition_info["calories"], + "carbohydrateContent": f'{nutrition_info["carbohydrates"]} g', + "fatContent": f'{nutrition_info["fat"]} g', + "proteinContent": f'{nutrition_info["protein"]} g', + } + + return self.schema.nutrients() diff --git a/recipe_scrapers/culy.py b/recipe_scrapers/culy.py new file mode 100644 index 000000000..e7c24a4c4 --- /dev/null +++ b/recipe_scrapers/culy.py @@ -0,0 +1,23 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class Culy(AbstractScraper): + @classmethod + def host(cls): + return "culy.nl" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".ingredients h3", + ".ingredients ul li[itemprop='ingredients'], .ingredients ul li", + ) + + def instructions(self): + instructions_list = self.soup.select("ol li") + cleaned_instructions = [ + instruction.get_text(strip=True) for instruction in instructions_list + ] + return "\n".join(cleaned_instructions) diff --git a/recipe_scrapers/dagelijksekost.py b/recipe_scrapers/dagelijksekost.py new file mode 100644 index 000000000..a459bf3d5 --- /dev/null +++ b/recipe_scrapers/dagelijksekost.py @@ -0,0 +1,109 @@ +from ._abstract import AbstractScraper +import json + + +def levenshtein_distance(s1, s2): + m, n = len(s1), len(s2) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + # Initialize DP table + for i in range(m + 1): + dp[i][0] = i + for j in range(n + 1): + dp[0][j] = j + + # Compute distances + for i in range(1, m + 1): + for j in range(1, n + 1): + cost = 0 if s1[i - 1] == s2[j - 1] else 1 + dp[i][j] = min( + dp[i - 1][j] + 1, # Deletion + dp[i][j - 1] + 1, # Insertion + dp[i - 1][j - 1] + cost, + ) # Substitution + + return dp[m][n] + + +def find_json(blocks): + for block in blocks: + if not block.string or "self.__next_f.push" not in block.string: + continue + start_idx = block.string.find('"f:') + end_idx = block.string.rfind('"') + if start_idx == -1 or end_idx == -1 or start_idx >= end_idx: + continue + json_content = block.string[start_idx + 3 : end_idx] + try: + unescaped_content = json_content.encode( + "latin-1", "backslashreplace" + ).decode("unicode-escape") + return json.loads(unescaped_content) + except json.JSONDecodeError: + continue + return None + + +def find_instructions(data): + results = [] + if isinstance(data, dict): + for key, value in data.items(): + if key == "instructions": + results.append(value) + elif isinstance(value, (dict, list)): + results.extend(find_instructions(value)) + elif isinstance(data, list): + for item in data: + if isinstance(item, (dict, list)): + results.extend(find_instructions(item)) + return results + + +def parse_instructions(instructions): + try: + return "\n".join([instructions[key] for key in sorted(instructions, key=int)]) + except (KeyError, ValueError): + return None + + +class DagelijkseKost(AbstractScraper): + @classmethod + def host(cls): + return "dagelijksekost.vrt.be" + + def canonical_url(self): + if "@id" in self.schema.data: + extracted_url = self.schema.data["@id"] + if extracted_url.startswith("http"): + return extracted_url + return self.url + + def instructions(self): + script_blocks = self.soup.find_all("script") + recipe_json = find_json(script_blocks) + instruction_candidates = find_instructions(recipe_json) + + short_instructions = self.schema.instructions() + + first_instruction = short_instructions.split("\n")[0] + if not first_instruction: + return short_instructions + + # Probably always matches exactly, but just in case, allow some fuzziness + dist = min(3, len(first_instruction) // 5) + + for instructions in instruction_candidates: + if "0" not in instructions: + continue + + if levenshtein_distance(first_instruction, instructions["0"]) > dist: + continue + + parsed_instructions = parse_instructions(instructions) + + if not parsed_instructions: + continue + + return parsed_instructions + + return short_instructions diff --git a/recipe_scrapers/dishnz.py b/recipe_scrapers/dishnz.py index e4496b3c4..d6b2da769 100644 --- a/recipe_scrapers/dishnz.py +++ b/recipe_scrapers/dishnz.py @@ -28,9 +28,7 @@ def yields(self): ) def image(self): - return "https://{}{}".format( - self.host(), self.soup.find("img", itemprop="image").attrs["src"] - ) + return f"https://{self.host()}{self.soup.find('img', itemprop='image').attrs['src']}" def ingredients(self): ingredients = [] diff --git a/recipe_scrapers/eggsca.py b/recipe_scrapers/eggsca.py new file mode 100644 index 000000000..7f1841ff9 --- /dev/null +++ b/recipe_scrapers/eggsca.py @@ -0,0 +1,56 @@ +from ._abstract import AbstractScraper +from ._exceptions import StaticValueException +from ._grouping_utils import IngredientGroup + + +class EggsCa(AbstractScraper): + @classmethod + def host(cls): + return "eggs.ca" + + def author(self): + raise StaticValueException(return_value="Eggs.ca") + + def ingredients(self): + return [ + " ".join( + [ + part.get_text(strip=True) + for part in ingredient.select( + ".ingredient__amount, .ingredient__ingredient" + ) + ] + ) + for ingredient in self.soup.select( + ".ingredients__sections .ingredient, .ingredients__wrap--simple .ingredient" + ) + ] + + def ingredient_groups(self): + all_ingredients = self.ingredients() + sections = self.soup.select(".ingredients__sections .ingredients__section") + if sections: + grouped_ingredients = [] + for section in sections: + section_ingredients = [ + " ".join( + [ + part.get_text(strip=True) + for part in ingredient.select( + ".ingredient__amount, .ingredient__ingredient" + ) + ] + ) + for ingredient in section.select(".ingredient") + ] + grouped_ingredients.append( + IngredientGroup( + ingredients=section_ingredients, + purpose=section.select_one( + ".ingredients__sectionHeading" + ).get_text(), + ) + ) + return grouped_ingredients + else: + return [IngredientGroup(ingredients=all_ingredients, purpose=None)] diff --git a/recipe_scrapers/foodrepublic.py b/recipe_scrapers/foodrepublic.py index 095e6307e..ed430b85a 100644 --- a/recipe_scrapers/foodrepublic.py +++ b/recipe_scrapers/foodrepublic.py @@ -1,5 +1,5 @@ from ._abstract import AbstractScraper -from ._utils import get_yields, normalize_string +from ._utils import get_yields class FoodRepublic(AbstractScraper): @@ -7,27 +7,6 @@ class FoodRepublic(AbstractScraper): def host(cls): return "foodrepublic.com" - def title(self): - title_div = self.soup.find("div", {"class": "recipe-card-title"}) - return title_div.get_text() - - def total_time(self): - prep_time_div = self.soup.find("div", {"class": "recipe-card-prep-time"}) - cook_time_div = self.soup.find("div", {"class": "recipe-card-cook-time"}) - - prep_time = ( - int(prep_time_div.find("div", {"class": "recipe-card-amount"}).text) - if prep_time_div - else 0 - ) - cook_time = ( - int(cook_time_div.find("div", {"class": "recipe-card-amount"}).text) - if cook_time_div - else 0 - ) - - return prep_time + cook_time - def yields(self): servings_div = self.soup.find("div", {"class": "recipe-card-servings"}) servings_amount = ( @@ -36,14 +15,3 @@ def yields(self): else "0" ) return get_yields(servings_amount) - - def ingredients(self): - ingredients = self.soup.select("ul.recipe-ingredients li") - - return [normalize_string(ingredient.get_text()) for ingredient in ingredients] - - def instructions(self): - instruction_list = self.soup.find("ol", {"class": "recipe-directions"}) - instructions = instruction_list.findAll("li") if instruction_list else [] - - return "\n".join([instruction.get_text() for instruction in instructions]) diff --git a/recipe_scrapers/inspiredtaste.py b/recipe_scrapers/inspiredtaste.py new file mode 100644 index 000000000..b154e4acd --- /dev/null +++ b/recipe_scrapers/inspiredtaste.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class InspiredTaste(AbstractScraper): + @classmethod + def host(cls): + return "inspiredtaste.net" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".ingredient_heading", + ".itr-ingredients p", + ) diff --git a/recipe_scrapers/jamieoliver.py b/recipe_scrapers/jamieoliver.py index 6f4ce75e4..6dccee576 100644 --- a/recipe_scrapers/jamieoliver.py +++ b/recipe_scrapers/jamieoliver.py @@ -1,4 +1,5 @@ from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients from ._utils import normalize_string @@ -8,5 +9,21 @@ def host(cls): return "jamieoliver.com" def instructions(self): - instructions = self.soup.find("ol", {"class": "recipeSteps"}).findAll("li") + method_heading = self.soup.find("h2", string="Method") + instructions_list = method_heading.find_next("ol") + instructions = instructions_list.find_all("li") return "\n".join([normalize_string(inst.get_text()) for inst in instructions]) + + def ingredients(self): + ingredients_list = self.soup.select(".ingredients-rich-text p.type-body") + return [ + normalize_string(ingredient.get_text()) for ingredient in ingredients_list + ] + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".ingredients-rich-text p.type-h5", + ".ingredients-rich-text p.type-body", + ) diff --git a/recipe_scrapers/juliegoodwin.py b/recipe_scrapers/juliegoodwin.py index 12553fd76..7bcbafe98 100644 --- a/recipe_scrapers/juliegoodwin.py +++ b/recipe_scrapers/juliegoodwin.py @@ -16,23 +16,29 @@ def author(self): def title(self): return normalize_string(self.soup.find("h1").get_text()) - def process_total_time(self, container): - if container: - prep_hours_match = re.search( - r"(\d+) hour", container.next_element.get_text() + def extract_time(self, keyword): + minutes = 0 + time_elements = self.soup.find_all(["h4", "h3"]) + for element in time_elements: + text = element.get_text(strip=True) + match = re.search( + rf"{keyword}\s*[\|=]?\s*(\d+)\s*(min|mins|minutes)", text, re.IGNORECASE ) - if prep_hours_match: - return 60 * int(prep_hours_match.group(1)) - prep_mins_match = re.search(r"(\d+) min", container.next_element.get_text()) - if prep_mins_match: - return int(prep_mins_match.group(1)) + if match: + minutes += int(match.group(1)) + return get_minutes(minutes) + + def prep_time(self): + return self.extract_time("Prep time") or 0 + + def cook_time(self): + return self.extract_time("Cooking time") or 0 def total_time(self): - prep = self.soup.find(string=re.compile("Prep time")) - mins = self.process_total_time(prep) - cooking = self.soup.find(string=re.compile("Cooking time")) - mins += self.process_total_time(cooking) - return get_minutes(mins) + prep_time = self.prep_time() + cook_time = self.cook_time() + total_mins = prep_time + cook_time + return total_mins def yields(self): container = self.soup.find("i", attrs={"class", "fa-cutlery"}) diff --git a/recipe_scrapers/jumbo.py b/recipe_scrapers/jumbo.py new file mode 100644 index 000000000..7f7f7a8c9 --- /dev/null +++ b/recipe_scrapers/jumbo.py @@ -0,0 +1,7 @@ +from ._abstract import AbstractScraper + + +class Jumbo(AbstractScraper): + @classmethod + def host(cls): + return "jumbo.com" diff --git a/recipe_scrapers/kellyscleankitchen.py b/recipe_scrapers/kellyscleankitchen.py new file mode 100644 index 000000000..6207f1b29 --- /dev/null +++ b/recipe_scrapers/kellyscleankitchen.py @@ -0,0 +1,72 @@ +import re + +from ._abstract import AbstractScraper +from ._utils import get_minutes, get_yields, normalize_string + + +class KellysCleanKitchen(AbstractScraper): + @classmethod + def host(cls): + return "kellyscleankitchen.com" + + def title(self): + return normalize_string( + self.soup.find("h1", class_="fusion-post-title").get_text() + ) + + def total_time(self): + total_time_element = self.soup.find( + "span", class_="white-text", string=re.compile("TOTAL TIME") + ) + if total_time_element: + total_time = total_time_element.get_text().split(":")[1] + return get_minutes(total_time) + + def yields(self): + servings_element = self.soup.find( + "div", class_="fusion-li-item-content", string=re.compile("SERVINGS") + ) + if servings_element: + servings = servings_element.get_text().split(":")[1] + return get_yields(servings) + + def ingredients(self): + ingredients_list = [] + ingredients_section = self.soup.find( + "h3", id=re.compile("ingredients.*") + ).find_next("ul") + if ingredients_section: + ingredients = ingredients_section.find_all("li") + ingredients_list = [ + normalize_string(ingredient.get_text()) for ingredient in ingredients + ] + return ingredients_list + + def instructions(self): + instructions_list = [] + steps = self.soup.find_all(class_="recipe-steps") + for step in steps: + instruction_text = normalize_string(step.find_next("p").get_text()) + if instruction_text: + instructions_list.append(instruction_text) + return "\n".join(instructions_list) + + def prep_time(self): + prep_time_element = self.soup.find( + "span", class_="white-text", string=re.compile("PREP TIME") + ) + if prep_time_element: + prep_time = prep_time_element.get_text().split(":")[1] + return get_minutes(prep_time) + + def cook_time(self): + cook_time_element = self.soup.find( + "span", class_="white-text", string=re.compile("COOK TIME") + ) + if cook_time_element: + cook_time = cook_time_element.get_text().split(":")[1] + return get_minutes(cook_time) + + def description(self): + description_text = self.soup.find("h1").find_next("p") + return normalize_string(description_text.get_text()) if description_text else "" diff --git a/recipe_scrapers/kookjij.py b/recipe_scrapers/kookjij.py new file mode 100644 index 000000000..a37a7ecd3 --- /dev/null +++ b/recipe_scrapers/kookjij.py @@ -0,0 +1,36 @@ +from ._abstract import AbstractScraper +from ._utils import normalize_string + + +class KookJij(AbstractScraper): + @classmethod + def host(cls): + return "kookjij.nl" + + def ingredients(self): + ingredients_elements = self.soup.select( + ".checkbox span[itemprop='ingredients']" + ) + ingredients_list = [ + ingredient.get_text() for ingredient in ingredients_elements + ] + return [normalize_string(ingredient) for ingredient in ingredients_list] + + def equipment(self): + equipment_elements = self.soup.select(".recipe-accessoires .checkbox label") + equipment_list = [ + equipment.get_text(strip=True) for equipment in equipment_elements + ] + return equipment_list + + def category(self): + return ", ".join( + category.get_text(strip=True) + for category in self.soup.select( + ".categories li[itemprop='recipeCategory'] a" + ) + ) + + def cuisine(self): + cuisine_element = self.soup.select_one('.row [itemprop="recipeCuisine"]') + return cuisine_element.get_text(strip=True) if cuisine_element else None diff --git a/recipe_scrapers/lacucinaitaliana.py b/recipe_scrapers/lacucinaitaliana.py new file mode 100644 index 000000000..7ed8e361b --- /dev/null +++ b/recipe_scrapers/lacucinaitaliana.py @@ -0,0 +1,10 @@ +from ._abstract import AbstractScraper + + +class LaCucinaItaliana(AbstractScraper): + @classmethod + def host(cls, domain="it"): + return f"lacucinaitaliana.{domain}" + + def author(self): + return "La Cucina Italiana" diff --git a/recipe_scrapers/lanascooking.py b/recipe_scrapers/lanascooking.py new file mode 100644 index 000000000..0bde6be42 --- /dev/null +++ b/recipe_scrapers/lanascooking.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class LanasCooking(AbstractScraper): + @classmethod + def host(cls): + return "lanascooking.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/recipe_scrapers/makeitdairyfree.py b/recipe_scrapers/makeitdairyfree.py new file mode 100644 index 000000000..8e2d2b486 --- /dev/null +++ b/recipe_scrapers/makeitdairyfree.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class MakeItDairyFree(AbstractScraper): + @classmethod + def host(cls): + return "makeitdairyfree.com" + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/recipe_scrapers/mealprepmanual.py b/recipe_scrapers/mealprepmanual.py new file mode 100644 index 000000000..93ea93d78 --- /dev/null +++ b/recipe_scrapers/mealprepmanual.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class MealPrepManual(AbstractScraper): + @classmethod + def host(cls): + return "mealprepmanual.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) diff --git a/recipe_scrapers/meganvskitchen.py b/recipe_scrapers/meganvskitchen.py new file mode 100644 index 000000000..bffde6c6c --- /dev/null +++ b/recipe_scrapers/meganvskitchen.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class MeganVsKitchen(AbstractScraper): + @classmethod + def host(cls): + return "meganvskitchen.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/recipe_scrapers/natashaskitchen.py b/recipe_scrapers/natashaskitchen.py new file mode 100644 index 000000000..add4d3c8b --- /dev/null +++ b/recipe_scrapers/natashaskitchen.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class NatashasKitchen(AbstractScraper): + @classmethod + def host(cls): + return "natashaskitchen.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/recipe_scrapers/nhshealthierfamilies.py b/recipe_scrapers/nhshealthierfamilies.py index 300a9d4c5..daaea329b 100644 --- a/recipe_scrapers/nhshealthierfamilies.py +++ b/recipe_scrapers/nhshealthierfamilies.py @@ -19,48 +19,28 @@ def title(self): title = title[:-7] return title - def _get_recipe_metadata(self): + def _get_recipe_content(self): container = self.soup.find("div", {"class": "bh-recipe__description"}) descriptions = container.findAll("p") - content = "".join([description.get_text() for description in descriptions]) + return "".join([description.get_text() for description in descriptions]) + + def prep_time(self): + content = self._get_recipe_content() prep_time = re.search(r"Prep: (\d+) mins", content) + return get_minutes(prep_time.group(0)) if prep_time else 0 + + def cook_time(self): + content = self._get_recipe_content() cook_time = re.search(r"Cook: (\d+) mins", content) - recipe_yields = re.search(r"Serves (\d+)", content) - return { - "prep_time": get_minutes(prep_time.group(0)) if prep_time else None, - "cook_time": get_minutes(cook_time.group(0)) if cook_time else None, - "yields": get_yields(recipe_yields.group(0)) if recipe_yields else None, - } + return get_minutes(cook_time.group(0)) if cook_time else 0 def total_time(self): - metadata = self._get_recipe_metadata() - return metadata["prep_time"] + metadata["cook_time"] + return self.prep_time() + self.cook_time() def yields(self): - metadata = self._get_recipe_metadata() - return metadata["yields"] - - def image(self): - return self.soup.find("img", {"class": "nhsuk-image__img"})["src"] - - def ingredients(self): - ingredients = [] - instructions_div = self.soup.find("div", {"class": "bh-recipe-instructions"}) - ul = instructions_div.find("ul") - - if ul: - for li in ul.findAll("li"): - ingredients.append(normalize_string(li.get_text())) - - # Stop when encountering an 'ol' element which is where instructions are stored. - for sibling in ul.find_next_siblings(): - if sibling.name == "ol": - break - if sibling.name == "ul": - for li in sibling.findAll("li"): - ingredients.append(normalize_string(li.get_text())) - - return ingredients + content = self._get_recipe_content() + recipe_yields = re.search(r"Serves (\d+)", content) + return get_yields(recipe_yields.group(0)) if recipe_yields else None def ingredient_groups(self): return group_ingredients( @@ -82,7 +62,3 @@ def instructions(self): return "\n".join( [normalize_string(instruction) for instruction in instructions] ) - - def description(self): - description_meta = self.soup.find("meta", {"name": "description"}) - return normalize_string(description_meta["content"]) diff --git a/recipe_scrapers/noracooks.py b/recipe_scrapers/noracooks.py new file mode 100644 index 000000000..d2b46301c --- /dev/null +++ b/recipe_scrapers/noracooks.py @@ -0,0 +1,40 @@ +from ._abstract import AbstractScraper + + +class NoraCooks(AbstractScraper): + @classmethod + def host(cls): + return "noracooks.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 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/okokorecepten.py b/recipe_scrapers/okokorecepten.py new file mode 100644 index 000000000..ec0aee46d --- /dev/null +++ b/recipe_scrapers/okokorecepten.py @@ -0,0 +1,64 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import IngredientGroup + + +class OkokoRecepten(AbstractScraper): + @classmethod + def host(cls): + return "okokorecepten.nl" + + def instructions(self): + instructions = [] + + voorbereiden_section = self.soup.find( + "h2", string=lambda text: "Voorbereiden" in text + ) + if voorbereiden_section: + for sibling in voorbereiden_section.find_next_siblings(): + if sibling.name == "h2": + break + if sibling.name == "p": + instructions.append(sibling.get_text(strip=True)) + + bereiden_section = self.soup.find("h2", string=lambda text: "Bereiden" in text) + if bereiden_section: + for sibling in bereiden_section.find_next_siblings(): + if sibling.name == "h2": + break + if sibling.name == "p": + instructions.append(sibling.get_text(strip=True)) + + return "\n".join(instructions) + + def ingredient_groups(self): + ingredient_groups = [] + ingredients_section = self.soup.find( + "h2", string=lambda text: "Ingrediënten" in text + ) + if not ingredients_section: + return None + + current_group = {"purpose": None, "ingredients": []} + + for sibling in ingredients_section.find_next_siblings(): + if sibling.name == "h2": + break + if sibling.name == "ul": + for li in sibling.find_all("li"): + if "tussenkop" in li.get("class", []): + if current_group["ingredients"]: + ingredient_groups.append(current_group) + current_group = { + "purpose": li.get_text(strip=True), + "ingredients": [], + } + else: + current_group["ingredients"].append(li.get_text(strip=True)) + + if current_group["ingredients"]: + ingredient_groups.append(current_group) + + return [ + IngredientGroup(ingredients=group["ingredients"], purpose=group["purpose"]) + for group in ingredient_groups + ] diff --git a/recipe_scrapers/preppykitchen.py b/recipe_scrapers/preppykitchen.py new file mode 100644 index 000000000..2f5bc6fa7 --- /dev/null +++ b/recipe_scrapers/preppykitchen.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class PreppyKitchen(AbstractScraper): + @classmethod + def host(cls): + return "preppykitchen.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) diff --git a/recipe_scrapers/recetteplus.py b/recipe_scrapers/recetteplus.py new file mode 100644 index 000000000..9369cd069 --- /dev/null +++ b/recipe_scrapers/recetteplus.py @@ -0,0 +1,22 @@ +from ._abstract import AbstractScraper +from ._utils import get_equipment + + +class RecettePlus(AbstractScraper): + @classmethod + def host(cls): + return "recette.plus" + + def equipment(self): + equipment_container = self.soup.find("ul", class_="ustensiles-list") + if not equipment_container: + return None + + equipment_items = [] + for item in equipment_container.find_all("li", class_="ustensiles-item"): + equipment_info = item.find("span", class_="ustensiles-info") + if equipment_info: + equipment_text = equipment_info.get_text().replace(" ", " ") + equipment_items.append(equipment_text) + + return get_equipment(equipment_items) diff --git a/recipe_scrapers/recipeland.py b/recipe_scrapers/recipeland.py new file mode 100644 index 000000000..a5f4504e3 --- /dev/null +++ b/recipe_scrapers/recipeland.py @@ -0,0 +1,55 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import IngredientGroup +from ._utils import normalize_string + + +class RecipeLand(AbstractScraper): + @classmethod + def host(cls): + return "recipeland.com" + + def _parse_ingredient_row(self, row): + amount = row.select_one(".amount") and row.select_one(".amount").get_text() + measure = row.select_one(".measure") and row.select_one(".measure").get_text() + ingredient_elem = row.select_one(".ingred") + ingredient = ingredient_elem and ingredient_elem.get_text() + + full_ingredient = f"{amount} {measure} {ingredient}" + return normalize_string(full_ingredient) + + def ingredients(self): + ingredient_rows = self.soup.select("#ingredient_list tbody tr") + return [ + self._parse_ingredient_row(row) + for row in ingredient_rows + if not row.select_one("th.i-head") + ] + + def ingredient_groups(self): + ingredient_rows = self.soup.select("#ingredient_list tbody tr") + groups = [] + current_group = None + grouped_ingredients = [] + + for row in ingredient_rows: + group_header = row.select_one("th.i-head") + if group_header: + if current_group or grouped_ingredients: + groups.append( + IngredientGroup( + ingredients=grouped_ingredients, purpose=current_group + ) + ) + current_group = group_header.get_text(strip=True) + grouped_ingredients = [] + else: + full_ingredient = self._parse_ingredient_row(row) + if full_ingredient: + grouped_ingredients.append(full_ingredient) + + if current_group or grouped_ingredients: + groups.append( + IngredientGroup(ingredients=grouped_ingredients, purpose=current_group) + ) + + return groups diff --git a/recipe_scrapers/rewe.py b/recipe_scrapers/rewe.py index ac6c0c2e8..5c5daafcd 100644 --- a/recipe_scrapers/rewe.py +++ b/recipe_scrapers/rewe.py @@ -48,13 +48,15 @@ def ingredients(self): ingredients = [] for item in list_items: - text = item.find("div", {"class": "ld-rds flex-[1_0_0%]"}) - ingredient_text = ( - text.get_text(" ", strip=True).replace("\n", "").replace(" ", " ") + amount = normalize_string( + item.find("div", class_="formattedAmountDiv").get_text() + ) + ingredient = item.find( + "span", {"class": "ld-rds break-words leading-6"} + ).get_text(" ", strip=True) + ingredients.append( + normalize_string(f"{amount + ' ' if amount != '0' else ''}{ingredient}") ) - ingredient_text = re.sub(r"\s+", " ", ingredient_text) - - ingredients.append(ingredient_text) return ingredients diff --git a/recipe_scrapers/schoolofwok.py b/recipe_scrapers/schoolofwok.py new file mode 100644 index 000000000..e590af7fd --- /dev/null +++ b/recipe_scrapers/schoolofwok.py @@ -0,0 +1,136 @@ +from collections import defaultdict + +from ._abstract import AbstractScraper +from ._grouping_utils import IngredientGroup +from ._utils import get_minutes, get_yields, normalize_string + + +class SchoolOfWok(AbstractScraper): + @classmethod + def host(cls): + return "schoolofwok.co.uk" + + def author(self): + return "School of Wok" + + def site_name(self): + return "School of Wok" + + def title(self): + return self.soup.find("h1").get_text() + + def cuisine(self): + categoryheader = self.soup.find( + string=lambda text: text and text.lower() == "cuisine" + ) + + return categoryheader.find_next("p").get_text() if categoryheader else None + + def total_time(self): + timeheader = self.soup.find(string=lambda text: text and text.lower() == "time") + + return get_minutes(timeheader.find_next("p").get_text()) if timeheader else None + + def yields(self): + servingheader = self.soup.find( + string=lambda text: text and text.lower() == "servings" + ) + + return ( + get_yields(servingheader.find_next("p").get_text()) + if servingheader + else None + ) + + def image(self): + return self.soup.find("img", {"alt": "recipe"}).get("src") + + def ingredients(self): + section = self.soup.find("section", {"id": "recipe-ingredients"}) + div_class = "flex flex-col gap-y-4 font-medium md:basis-1/2 xl:basis-2/5" + divs = section.findChildren("div", {"class": div_class}) + + if not divs: + return [] + + paragraphs = divs[0].find_all("p") + ingredients_list = [] + + if paragraphs: + for paragraph in paragraphs: + text = normalize_string(paragraph.get_text()) + if text and not paragraph.find("strong"): + ingredients_list.append(text) + else: + list_items = divs[0].find_all("li") + ingredients_list = [ + normalize_string(item.get_text()) for item in list_items + ] + + return ingredients_list + + def ingredient_groups(self): + section = self.soup.find("section", {"id": "recipe-ingredients"}) + div_class = "flex flex-col gap-y-4 font-medium md:basis-1/2 xl:basis-2/5" + divs = section.findChildren("div", {"class": div_class}) + + if not divs: + return [] + + paragraphs = divs[0].find_all("p") + groupings = defaultdict(list) + current_heading = None + + if paragraphs: + for paragraph in paragraphs: + normalized_ingredient = normalize_string(paragraph.get_text()) + if normalized_ingredient: + if paragraph.find("strong"): + current_heading = normalized_ingredient + else: + groupings[current_heading].append(normalized_ingredient) + else: + list_items = divs[0].find_all() + for item in list_items: + if ( + item.name == "h3" + and normalize_string(item.get_text()).lower() != "ingredients" + ): + current_heading = normalize_string(item.get_text()) + elif item.name == "li": + normalized_ingredient = normalize_string(item.get_text()) + if normalized_ingredient: + groupings[current_heading].append(normalized_ingredient) + + return [ + IngredientGroup(purpose=heading, ingredients=items) + for heading, items in groupings.items() + ] + + def instructions(self): + section = self.soup.find("section", {"id": "recipe-ingredients"}) + div_class = "flex flex-col gap-y-4 font-medium md:basis-1/2 xl:basis-2/5" + divs = section.findChildren("div", {"class": div_class}) + + if len(divs) < 2: + return "" + + instructions = divs[1].find_all("p") + instructionslist = [] + + for instruction in instructions: + normalizedinstruction = normalize_string(instruction.get_text()) + if normalizedinstruction: + if normalizedinstruction[0].isdigit(): + instructionslist.append(normalizedinstruction[3:]) + elif normalizedinstruction[0] == "•": + instructionslist.append(normalizedinstruction[2:]) + else: + instructionslist.append(normalizedinstruction) + + return "\n".join(instructionslist) + + def description(self): + return self.soup.find( + "p", {"class": "mb-2 pb-4 border-b border-b-white xl:text-lg"} + ).get_text() diff --git a/recipe_scrapers/shelikesfood.py b/recipe_scrapers/shelikesfood.py new file mode 100644 index 000000000..abfebc44f --- /dev/null +++ b/recipe_scrapers/shelikesfood.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class SheLikesFood(AbstractScraper): + @classmethod + def host(cls): + return "shelikesfood.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".tasty-recipes-ingredients p", + ".tasty-recipes-ingredients ul li", + ) diff --git a/recipe_scrapers/stacyling.py b/recipe_scrapers/stacyling.py new file mode 100644 index 000000000..3255f36f7 --- /dev/null +++ b/recipe_scrapers/stacyling.py @@ -0,0 +1,22 @@ +from ._abstract import AbstractScraper +from ._utils import get_equipment + + +class StacyLing(AbstractScraper): + @classmethod + def host(cls): + return "stacyling.com" + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text() + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) diff --git a/recipe_scrapers/sugarhero.py b/recipe_scrapers/sugarhero.py new file mode 100644 index 000000000..76e495288 --- /dev/null +++ b/recipe_scrapers/sugarhero.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class SugarHero(AbstractScraper): + @classmethod + def host(cls): + return "sugarhero.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/recipe_scrapers/themediterranedish.py b/recipe_scrapers/themediterranedish.py new file mode 100644 index 000000000..583d9d45a --- /dev/null +++ b/recipe_scrapers/themediterranedish.py @@ -0,0 +1,16 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients + + +class TheMediterraneDish(AbstractScraper): + @classmethod + def host(cls): + return "themediterraneandish.com" + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/recipe_scrapers/twentyfourkitchen.py b/recipe_scrapers/twentyfourkitchen.py new file mode 100644 index 000000000..fc8cfe3ea --- /dev/null +++ b/recipe_scrapers/twentyfourkitchen.py @@ -0,0 +1,46 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +import re + + +class TwentyFourKitchen(AbstractScraper): + @classmethod + def host(cls): + return "24kitchen.nl" + + def ingredient_groups(self): + groups = group_ingredients( + self.ingredients(), + self.soup, + ".ingredient-list-title", + ".recipe-ingredient", + ) + if ( + len(groups) == 1 + and groups[0].purpose + and groups[0].purpose.strip() == self.schema.title() + ): + groups[0].purpose = None + return groups + + def instructions(self): + instructions = [] + + # Instructions format #1 + preparation_steps = self.soup.select( + ".preparation-step .field--name-field-text" + ) + for step in preparation_steps: + text = step.get_text(strip=True) + if not text.lower().startswith("stap:"): + instructions.append(text) + + # Instructions format #2 + paragraph_steps = self.soup.select(".preparation-text p") + for step in paragraph_steps: + text = step.get_text(strip=True) + cleaned_instructions_text = re.sub(r"^Stap\s*\d+:?", "", text).strip() + if cleaned_instructions_text: + instructions.append(cleaned_instructions_text) + + return "\n".join(instructions) diff --git a/recipe_scrapers/veroniquecloutier.py b/recipe_scrapers/veroniquecloutier.py new file mode 100644 index 000000000..025a5b2fd --- /dev/null +++ b/recipe_scrapers/veroniquecloutier.py @@ -0,0 +1,129 @@ +from collections import defaultdict + +from ._abstract import AbstractScraper +from ._exceptions import FieldNotProvidedByWebsiteException +from ._grouping_utils import IngredientGroup +from ._utils import normalize_string + + +class VeroniqueCloutier(AbstractScraper): + @classmethod + def host(cls): + return "veroniquecloutier.com" + + def author(self): + return self.soup.find("strong").get_text() + + def title(self): + return self.soup.find("h1", {"class": "title -main -page-title"}).get_text() + + def total_time(self): + raise FieldNotProvidedByWebsiteException(return_value=None) + + def yields(self): + potion_line = self.soup.find( + string=lambda text: text + and ("portions" in text.lower() or "donne " in text.lower()) + ) + + if not potion_line: + return None + + parent_text = potion_line.parent.get_text() if potion_line.parent else None + french_numbers = { + "un": 1, + "deux": 2, + "trois": 3, + "quatre": 4, + "cinq": 5, + "six": 6, + "sept": 7, + "huit": 8, + "neuf": 9, + "dix": 10, + "onze": 11, + "douze": 12, + "treize": 13, + "quatorze": 14, + "quinze": 15, + } + special_cases = {"dizaine": 10, "douzaine": 12} + + for word in parent_text.split(): + word_lower = word.lower() + if word.isdigit(): + return f"{word} serving" if int(word) == 1 else f"{word} servings" + if word_lower in french_numbers: + number = french_numbers[word_lower] + return f"{number} serving" if number == 1 else f"{number} servings" + if word_lower in special_cases: + number = special_cases[word_lower] + return f"{number} serving" if number == 1 else f"{number} servings" + + return None + + def ingredients(self): + start = self.soup.find( + string=lambda text: text and text.lower() == "ingrédients" + ) + + ingredient_list = [] + for sibling in start.find_all_next(): + if sibling.string and "préparation" in sibling.string.lower(): + break + if sibling.name == "ul": + ingredient_list.extend(li.text for li in sibling.find_all("li")) + + return ingredient_list + + def ingredient_groups(self): + start = self.soup.find( + string=lambda text: text and text.lower() == "ingrédients" + ) + + found_ingredients = [] + groupings = defaultdict(list) + current_heading = None + for sibling in start.find_all_next(): + if sibling.string and "préparation" in sibling.string.lower(): + break + + if sibling.name == "p" and sibling.text.strip(): + current_heading = sibling.text.strip() + + if sibling.name == "ul" and current_heading: + groupings[current_heading].extend( + li.text for li in sibling.find_all("li") + ) + found_ingredients.extend(li.text for li in sibling.find_all("li")) + elif sibling.name == "ul": + found_ingredients.extend(li.text for li in sibling.find_all("li")) + + if not groupings: + return [IngredientGroup(ingredients=found_ingredients)] + + return [ + IngredientGroup(purpose=heading, ingredients=items) + for heading, items in groupings.items() + ] + + def instructions(self): + start = self.soup.find( + string=lambda text: text and text.lower() == "préparation" + ) + + instruction_list = [] + for sibling in start.find_all_next(): + if sibling.name == "div": + break + if sibling.name == "ol": + instruction_list.extend(li.text for li in sibling.find_all("li")) + elif sibling.name == "p" and sibling.text[0].isdigit(): + instruction_list.append(sibling.text[3:]) + + return "\n".join(instruction_list) + + def description(self): + return normalize_string( + self.soup.find("div", {"class": "post-excerpt"}).get_text() + ) diff --git a/recipe_scrapers/wdr.py b/recipe_scrapers/wdr.py new file mode 100644 index 000000000..eb757887d --- /dev/null +++ b/recipe_scrapers/wdr.py @@ -0,0 +1,45 @@ +from ._abstract import AbstractScraper +from ._utils import normalize_string +import re + + +class WDR(AbstractScraper): + @classmethod + def host(cls): + return "www1.wdr.de" + + def site_name(self): + return "WDR" + + def title(self): + return self.soup.find("meta", property="og:title")["content"] + + def ingredients(self): + header = self.soup.find("h2", string=re.compile(r"^Zutaten.*")) + + # find
  • siblings until the next

    tag: + ingredients = [] + for sibling in header.find_next_siblings(): + if sibling.name == "h2": + break + items = sibling.find_all("li") + if len(items) > 0: + ingredients.extend([normalize_string(li.get_text()) for li in items]) + return ingredients + + def image(self): + return f'https://{self.host()}{self.soup.find("picture").find_next("source")["srcset"]}' + + def instructions(self) -> str: + header = self.soup.find("h2", string="Zubereitung") + # Some recipes have the instructions in
  • tags, others in

    tags + return "\n".join( + [ + normalize_string(li.get_text()) + for li in header.findNextSibling().find_all("li") + ] + + [normalize_string(p.get_text()) for p in header.find_next_siblings("p")] + ) + + def description(self): + return self.soup.find("meta", {"name": "Description"})["content"] diff --git a/recipe_scrapers/wedishitup.py b/recipe_scrapers/wedishitup.py new file mode 100644 index 000000000..fcebfce89 --- /dev/null +++ b/recipe_scrapers/wedishitup.py @@ -0,0 +1,31 @@ +from ._abstract import AbstractScraper +from ._grouping_utils import group_ingredients +from ._utils import get_equipment + + +class WeDishItUp(AbstractScraper): + @classmethod + def host(cls): + return "wedishitup.com" + + def equipment(self): + equipment_container = self.soup.find( + "div", class_="wprm-recipe-equipment-container" + ) + if not equipment_container: + return None + equipment_items = [ + item.get_text(strip=True) + for item in equipment_container.find_all( + "div", class_="wprm-recipe-equipment-name" + ) + ] + return get_equipment(equipment_items) + + def ingredient_groups(self): + return group_ingredients( + self.ingredients(), + self.soup, + ".wprm-recipe-ingredient-group h4", + ".wprm-recipe-ingredient", + ) diff --git a/tests/library/test_readme.py b/tests/library/test_readme.py deleted file mode 100644 index 796455bac..000000000 --- a/tests/library/test_readme.py +++ /dev/null @@ -1,185 +0,0 @@ -import re -import sys -import unittest -from collections import defaultdict - -if sys.version_info >= (3, 10): - from importlib.metadata import PackageNotFoundError, metadata -else: - # TODO: Remove this branch once py3.10 is our minimum baseline; - # package description metadata (that we rely on for 'test_includes') is - # only available in importlib.metadata from py3.10 onwards - from importlib_metadata import PackageNotFoundError, metadata - -from typing import Optional - -from recipe_scrapers import SCRAPERS, AbstractScraper - -START_LIST = "-----------------------" -END_LIST = "(*) offline saved files only" - -ScraperIndex = dict[str, tuple[AbstractScraper, list[str]]] - - -def get_scraper_domains(): - scraper_domains = defaultdict(list) - for domain, scraper in SCRAPERS.items(): - primary_domain = scraper.host() - if domain == primary_domain: - scraper_domains[scraper].insert(0, domain) - else: - scraper_domains[scraper].append(domain) - return scraper_domains - - -def get_scraper_index() -> ScraperIndex: - scraper_index: ScraperIndex = {} - for scraper_instance, domains in get_scraper_domains().items(): - shared_prefix = get_shared_prefix(domains) - - if not shared_prefix: - # Treat all as primary domains - for domain in domains: - scraper_index[domain] = (scraper_instance, [domain]) - continue - - # Index the primary domain and include their secondary domains minus the shared prefix - primary_domain = scraper_instance.host() - secondary_domains = [ - domain[len(shared_prefix) :] if domain.startswith(shared_prefix) else domain - for domain in domains - if domain != shared_prefix - ] - scraper_index[primary_domain] = (scraper_instance, secondary_domains) - - # Produce the index sorted by primary domain name - return scraper_index - - -def get_shared_prefix(domains: list[str]) -> str: - """ - Find the longest-common-prefix of the domains - """ - if not domains: - return "" - - shared_prefix = domains[0] - for domain in domains[1:]: - while not domain.startswith(shared_prefix): - shared_prefix = shared_prefix[:-1] - if not shared_prefix: - return "" - - if "." in shared_prefix: - shared_prefix, _ = shared_prefix.rsplit(".", 1) - - return shared_prefix - - -def get_secondary_domains( - scraper_index: ScraperIndex, primary_domain: str -) -> list[str]: - _, suffixes = scraper_index[primary_domain] - return [suffix for suffix in suffixes if not primary_domain.endswith(suffix)] - - -def parse_primary_line(line: str) -> Optional[tuple[str, str]]: - match = re.search( - r"^- `https?://(?:www\.)?([^/\s]+)[^<]*]*>`_(?: \(\*\))?$", - line, - ) - if match: - groups = match.groups() - if len(groups) == 2: - return groups - return None - - -def parse_secondary_line(line: str) -> list[tuple[str, str]]: - return re.findall(r"`(\.[^\s]+)\s]+)[^>]*>`_", line) - - -def get_package_description() -> list[str]: - pkg_metadata = metadata("recipe_scrapers") - return pkg_metadata["Description"].splitlines() - - -def get_list_lines() -> list[str]: - list_lines: list[str] = [] - started_list = False - for line in get_package_description(): - stripped_line = line.strip() - if stripped_line == START_LIST: - started_list = True - continue - - if not started_list or not stripped_line: - continue - - if stripped_line == END_LIST: - break - - list_lines.append(line) - return list_lines - - -class TestReadme(unittest.TestCase): - - def test_includes(self): - scraper_index = get_scraper_index() - primary_domains = sorted(scraper_index.keys()) - - try: - lines = get_list_lines() - except PackageNotFoundError: - msg = ( - "Couldn't retrieve package metadata; is recipe_scrapers installed? " - "(if you're developing locally, try 'pip install -e .' for an editable install)" - ) - self.skipTest(msg) - - current_line_index = 0 - - for primary_host in primary_domains: - current_line = lines[current_line_index] - parse_result = parse_primary_line(current_line) - - if not parse_result: - self.fail(f"Invalid line: {current_line}") - - name_host, value_host = parse_result - self.assertEqual( - name_host, - value_host, - "The name and value hyperlink portions have different hosts.", - ) - self.assertEqual( - name_host, - primary_host, - f"The host ({name_host}) doesn't match the expected host ({primary_host})", - ) - - current_line_index += 1 - secondary_hosts = get_secondary_domains(scraper_index, primary_host) - - if secondary_hosts: - current_line = lines[current_line_index] - parse_result = parse_secondary_line(current_line) - - if not parse_result: - self.fail(f"Invalid line: {current_line}") - - sorted_secondary_hosts = sorted(secondary_hosts) - for i, secondary_host in enumerate(sorted_secondary_hosts): - if i >= len(parse_result): - self.fail( - f"Missing top level domain(s) for primary domain {primary_host}" - ) - - top_level_domain = parse_result[i][0] - self.assertEqual( - secondary_host, - top_level_domain, - f"Expected top level domain {secondary_host}, got {top_level_domain} for primary domain {primary_host}", - ) - current_line_index += 1 diff --git a/tests/test_data/24kitchen.nl/twentyfourkitchen_1.json b/tests/test_data/24kitchen.nl/twentyfourkitchen_1.json new file mode 100644 index 000000000..98070abb4 --- /dev/null +++ b/tests/test_data/24kitchen.nl/twentyfourkitchen_1.json @@ -0,0 +1,42 @@ +{ + "author": "24Kitchen", + "canonical_url": "https://www.24kitchen.nl/recepten/vegan-oliebollen", + "site_name": "24Kitchen", + "host": "24kitchen.nl", + "language": "nl", + "title": "Vegan oliebollen", + "ingredients": [ + "500 gr bloem", + "500 ml plantaardige melk", + "7 gr gedroogde gist", + "50 gr plantaardige magarine", + "1 el fijne kristalsuiker", + "1 tl zout", + "zonnebloemolie (om in te frituren)", + "poedersuiker" + ], + "instructions_list": [ + "Verwarm de plantaardige melk in pan op laag vuur tot handwarm (lauwwarm). Voeg de gist en de suiker toe. Doe de plantaardige margarine erbij en laat smelten. Laat staan tot het mengsel begint te schuimen.", + "Zeef de bloem en mix het zout er doorheen. Voeg het schuimige gistmengsel toe en mix goed door.", + "Dek het beslag af met een vochtige theedoek en zet weg op een warme, tochtvrije plek. Laat het beslag 1 uur rijzen of tot het in volume verdubbeld is.", + "Verwarm de olie tot 180°C.", + "Roer het beslag door. Schep met een ijslepel bolletjes beslag in de hete olie. Bak zoveel oliebollen tegelijk als er in de pan passen zonder dat ze elkaar raken.", + "Bak de oliebollen in 6-8 minuten goudbruin en gaar. Draai ze halverwege om.", + "Laat de oliebollen uitlekken op keukenpapier en bestrooi ze met poedersuiker voor het serveren.", + "Verwarm de plantaardige melk in pan op laag vuur tot handwarm (lauwwarm). Voeg de gist en de suiker toe. Doe de plantaardige margarine erbij en laat smelten. Laat staan tot het mengsel begint te schuimen.", + "Zeef de bloem en mix het zout er doorheen. Voeg het schuimige gistmengsel toe en mix goed door.", + "Liever krentenbollen? Voeg gewelde krenten, stukjes appel of sinaasappel- of citroenschil toe aan je beslag.", + "Dek het beslag af met een vochtige theedoek en zet weg op een warme, tochtvrije plek. Laat het beslag 1 uur rijzen of tot het in volume verdubbeld is.", + "Verwarm de olie tot 180°C.", + "Roer het beslag door. Schep met een ijslepel bolletjes beslag in de hete olie. Bak zoveel oliebollen tegelijk als er in de pan passen zonder dat ze elkaar raken.", + "Bak de oliebollen in 6-8 minuten goudbruin en gaar. Draai ze halverwege om.", + "Laat de oliebollen uitlekken op keukenpapier en bestrooi ze met poedersuiker voor het serveren." + ], + "yields": "4 servings", + "description": "Deze vegan oliebollen zijn knapperig van buiten, luchtig van binnen én hartststikke plantaardig. Probeer het recept van oliebollen-koning Hidde de Brabander.", + "total_time": 30, + "prep_time": 30, + "ratings": 5.0, + "ratings_count": 1, + "image": "https://www.24kitchen.nl/files/styles/social_media_share/public/2024-12/AdobeStock_340976387.jpeg?itok=FYrCCyX9" +} diff --git a/tests/test_data/24kitchen.nl/twentyfourkitchen_1.testhtml b/tests/test_data/24kitchen.nl/twentyfourkitchen_1.testhtml new file mode 100644 index 000000000..d3c9c9f72 --- /dev/null +++ b/tests/test_data/24kitchen.nl/twentyfourkitchen_1.testhtml @@ -0,0 +1,3434 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vegan oliebollen recept | 24Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + +

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

    De voordelen van een 24K account

    + +
    + +
      +
    • + + Recepten bewaren +
    • +
    • + + Exclusieve content en aanbiedingen +
    • +
    • + + Gratis e-books +
    • +
    + +
    + + + + +
    + +
    +
    + +
    +
    + +
    + + + + + + + + +
    + + + + + +
    +
    + + + + + + +
    + +
    + +
    + + + + + + + + +
    + + + + + + +
    +
    + + + + + + + + + + +
    +
    + + + + + + +
    + +
    + +
    + + + + + + + + +
    + + + + + + +
    +
    +
    +
    + + + +
    +
    + +
    + +
    +
    + + +
    +
    + + + + +
    + + + +
    + +
    +
    Jamie Oliver: Seasons Winter Mobiel + +
    +
    Jamie Oliver: Seasons Winter + +
    +
    + + + Jamie Oliver: Seasons Winter + +
    + + +
    + +
    + + + + + + + + + + +
    + + + +
    +
    + + +
    + + +
    + + + + +
    +
    +
    + + + + + + +
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + +
    +
    +
    +
    + + +
    +
    +
    +

    vegan oliebollen

    + + +
    + +

    Deze vegan oliebollen zijn knapperig van buiten, luchtig van binnen én hartststikke plantaardig. Probeer het recept van oliebollen-koning Hidde de Brabander.

    + +
    + + +
    + + + 30 min voorbereidingstijd + +
    +
    + + + 60 min wachttijd + +
    + +
    + + +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    + +
    + +
    + + +
    + + + + + + + + + + + vegan oliebollen + + + +
    + + +
    + + + +
    + +
    + +
    +
    +
    +
    +
    +
    +
    + + +
    + + +
    + + + +
    +
    +

    Een recept van

    +
    + +
    +
    + +
    + +
    +

    Hidde de Brabander

    + + +
    +
    + +
    Miniatuurvoorbeeld + + +
    + +
    +
    + +
    +
    + +
    +
    + +

    "Vegan oliebollen maken is een eitje! Vervang de roomboter door margarine en de melk door een plantaardig alternatief als amandel- of havermelk."

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

    Bereidingswijze

    +
    + +
    +
    +

    + Vegan oliebollen +

    + + +
      +
    1. +
      + +

      Verwarm de plantaardige melk in pan op laag vuur tot handwarm (lauwwarm). Voeg de gist en de suiker toe. Doe de plantaardige margarine erbij en laat smelten. Laat staan tot het mengsel begint te schuimen. 

      + +
      + +
    2. +
    3. +
      + +

      Zeef de bloem en mix het zout er doorheen. Voeg het schuimige gistmengsel toe en mix goed door. 

      + +
      + + + +
      + + +

      + +

      + +
      + +

      Liever krentenbollen? Voeg gewelde krenten, stukjes appel of sinaasappel- of citroenschil toe aan je beslag.

      + +
      + +
      +
      + +
      + +
    4. +
    5. +
      + +

      Dek het beslag af met een vochtige theedoek en zet weg op een warme, tochtvrije plek. Laat het beslag 1 uur rijzen of tot het in volume verdubbeld is. 

      + +
      + +
    6. +
    7. +
      + +

      Verwarm de olie tot 180°C.

      + +
      + +
    8. +
    9. +
      + +

      Roer het beslag door. Schep met een ijslepel bolletjes beslag in de hete olie. Bak zoveel oliebollen tegelijk als er in de pan passen zonder dat ze elkaar raken.

      + +
      + +
    10. +
    11. +
      + +

      Bak de oliebollen in 6-8 minuten goudbruin en gaar. Draai ze halverwege om.

      + +
      + +
    12. +
    13. +
      + +

      Laat de oliebollen uitlekken op keukenpapier en bestrooi ze met poedersuiker voor het serveren.

      + +
      + +
    14. +
    + + +
    + + + +
    + +
    + +
    + +
    + +
    +
    +

    Hoe laat je oliebollendeeg goed rijzen?

    + +

    Gist heeft tijd en warmte nodig om te rijzen. Een aantal tips:
    - zorg dat het zout in het deeg de gist niet direct raakt
    - zorg dat de lauwwarme melk niet warmer wordt dan 35°C, anders gaat de gist dood
    - zet het deeg afgedekt weg (onder een vochtige theedoek of vershoudfolie), om uitdroging te voorkomen
    - zet het deeg op een warme plek in huis, uit de tocht

    + +
    +
    + + + + + + + + + + + + deeg rijzen + + + + +
    +
    + + +
    +
    +

    Op welke temperatuur frituur je oliebollen?

    + +

    Zorg dat de olie 180°C is om oliebollen te frituren. Is de olie kouder, nemen de oliebollen te veel olie op en worden ze compact en vettig. Is de olie te heet verbrand de buitenkant en blijft de binnenkant rauw. Probeer niet te veel oliebollen tegelijk te frituren, om te voorkomen dat de temperatuur van de olie te snel daalt.

    + +
    +
    + + + + + + + + + + + + oliebollen bakken + + + + +
    +
    + + +
    +
    +

    Oliebollen te vet?

    + +

    Zijn je oliebollen toch te vet? Check dan de temperatuur en zorg dat de olie 180°C is. Gebruik daarnaast schone olie, zorg dat het beslag niet te dun is en laat de oliebollen uitlekken op keukenpapier om overtollige olie te verwijderen.

    + +
    +
    + + + + + + + + + + + + Oliebollen opwarmen + + + + +
    +
    + + +
    +
    +

    Hoelang moet het deeg rijzen?

    + +

    Afhankelijk van de sterkte van je gist, en de omgevingstemperatuur moet het deeg voor oliebollen tussen 1 uur en 1,5 uur rijzen. Gebruik dit als leidraad: kijk vooral of het deeg in omvang verdubbeld is. Zodra dat het geval is, is het deeg voldoende gerezen.

    + +
    +
    + + + + + + + + + + + + vegan oliebollen + + + + +
    +
    + + +
    +
    +

    Hoe test je of de olie heet genoeg is?

    + +

    De olie moet 180°C zijn om de oliebollen in te frituren. Geen thermometer? Gooi dan een stukje brood in het vet, als het direct borrelt, is de olie goed heet.

    + +
    +
    + + + + + + + + + + + + Italiaanse oliebollen + + + + +
    +
    + + +
    +
    +

    Hoe maak ik mooie ronde oliebollen?

    + +

    Voor ronde oliebollen gebruik je een ijsschep. Doop de ijsschep in de olie voordat je het beslag oplepelt, zodat het niet aan de lepel plakt. Zorg daarnaast voor een beslag dat niet te dun (maar ook niet te dik is). 

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

    Laat weten wat je van dit recept vindt

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

    + Reacties op het recept

    + + + +
    +

    + 0 reacties

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

    Ook lekker

    + + + + + + + +
    + + + +
    +
    + + + +
    +
    + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/24kitchen.nl/twentyfourkitchen_2.json b/tests/test_data/24kitchen.nl/twentyfourkitchen_2.json new file mode 100644 index 000000000..4d0ddb981 --- /dev/null +++ b/tests/test_data/24kitchen.nl/twentyfourkitchen_2.json @@ -0,0 +1,92 @@ +{ + "author": "24Kitchen", + "canonical_url": "https://www.24kitchen.nl/recepten/winterse-pompoenpizza", + "site_name": "24Kitchen", + "host": "24kitchen.nl", + "language": "nl", + "title": "Winterse pompoenpizza met gegrilde bavette", + "ingredients": [ + "100 g pompoen", + "120 ml lauwwarm water", + "17 g verse gist (of 7 g gedroogde gist uit een zakje)", + "1 tl suiker", + "250 g bloem", + "1 tl kurkuma", + "1 el olijfolie", + "300 g bavette", + "1 el bbq rub", + "100 g kastanjechampignons", + "1 kleine rode ui", + "2 el crème fraîche", + "2 el zure room", + "1 tl witte peper", + "100 g blauwe kaas", + "2 takjes tijm", + "rucola om te garneren", + "BBQ met deksel voor direct grillen", + "keukenmachine met deeghaken", + "pizzasteen", + "pizzaschep" + ], + "ingredient_groups": [ + { + "ingredients": [ + "100 g pompoen", + "120 ml lauwwarm water", + "17 g verse gist (of 7 g gedroogde gist uit een zakje)", + "1 tl suiker", + "250 g bloem", + "1 tl kurkuma", + "1 el olijfolie" + ], + "purpose": "Pizzadeeg" + }, + { + "ingredients": [ + "300 g bavette", + "1 el bbq rub", + "100 g kastanjechampignons", + "1 kleine rode ui", + "2 el crème fraîche", + "2 el zure room", + "1 tl witte peper", + "100 g blauwe kaas", + "2 takjes tijm", + "rucola om te garneren" + ], + "purpose": "Topping" + }, + { + "ingredients": [ + "BBQ met deksel voor direct grillen", + "keukenmachine met deeghaken", + "pizzasteen", + "pizzaschep" + ], + "purpose": "Extra nodig" + } + ], + "instructions_list": [ + "Schil en snijd de pompoen in blokjes en kook in circa 10 minuten gaar.Benieuwd hoe je makkelijk en snel pompoen moet snijden?Pureer met een pureestamper of in de keukenmachine. Laat de pompoenpuree afkoelen.", + "Los de gist in een andere kom met de suiker al roerend op in het lauwe water. Voeg 200 g bloem, zout, kurkuma, gistmengsel en 1 eetlepel pompoenpuree toe aan de kom van de mixer. Laat het geheel circa 10 minuten mengen en kneden in de mixer tot een egaal deeg.", + "Voeg de olijfolie toe en meng nog even goed door. (voeg, als het te droog is, wat olijfolie en/of water toe en als het te vochtig is wat extra bloem). Vet een kom in met wat olijfolie en laat het deeg op een warme plek, afgedekt met een vochtige theedoek, circa 2 uur rijzen.", + "Bereid de BBQ voor op een temperatuur van 120 ºC. Smeer de bavette in met een dun laagje olie en wrijf het vlees in met een eetlepel bbq rub. Gril het vlees om en om een paar minuten boven hete kolen totdat het een mooie grill kleur heeft gekregen. Laat daarna circa 10 minuten rusten.", + "Breng de bbq naar een temperatuur van 280 á 290 ºC.", + "Snijd de champignons in plakjes en de ui in dunne, halveringen. Snijd de bavette tegen de draad in plakjes", + "Bestrooi je werkblad met wat bloem en rol je pizzadeeg hierop uit tot ca. 2 mm. dikte. Let op: je kunt van dit deeg 2 ronde pizza’s maken of een grote, langwerpige.", + "Meng voor de saus de crème fraîche, zure room, witte peper en de rest van de bbq rub.Verdeel de saus over het pizzadeeg en verdeel tot 1 cm van de randen.", + "Bestrooi, als je pizzasteen de juiste temperatuur heeft, een pizzaschep met bloem en schuif het deeg erop. Beleg de pizza met de ui, kastanjechampignons. Verbrokkel de blauwe kaas erover. Bak de pizza circa 3-4 minuten. Beleg met de bavette. Sluit de deksel en laat de bavette nog circa 30 seconden meegaren.", + "Ris de tijm. Verdeel een beetje pompoenpuree en de tijm over de pizza’s. Bestrooi met peper en zout. Garneer met de rucola.", + "Inspiratie nodig om aan de slag te gaan met pompoenen?" + ], + "category": "Hoofdgerecht", + "yields": "4 servings", + "description": "Waarom pizza afhalen of bestellen als je deze waanzinnige pompoenpizza met gegrilde bavette makkelijk zelf kunt maken?", + "total_time": 150, + "cook_time": 120, + "prep_time": 30, + "cuisine": "Italiaans", + "ratings": 2.43, + "ratings_count": 44, + "image": "https://www.24kitchen.nl/files/styles/social_media_share/public/2021-12/Winterse%20Pompoenpizza%20met%20Gegrilde%20Bavette_10139.jpg?itok=G99n24zn" +} diff --git a/tests/test_data/24kitchen.nl/twentyfourkitchen_2.testhtml b/tests/test_data/24kitchen.nl/twentyfourkitchen_2.testhtml new file mode 100644 index 000000000..f5cf70594 --- /dev/null +++ b/tests/test_data/24kitchen.nl/twentyfourkitchen_2.testhtml @@ -0,0 +1,3342 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pompoenpizza I 24Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +
    + + +
    +
    + +
    + + + + + +

    De voordelen van een 24K account

    + +
    + +
      +
    • + + Recepten bewaren +
    • +
    • + + Exclusieve content en aanbiedingen +
    • +
    • + + Gratis e-books +
    • +
    + +
    + + + + +
    + +
    +
    + +
    +
    + +
    + + + + + + + + +
    + + + + + +
    +
    + + + + + + +
    + +
    + +
    + + + + + + + + +
    + + + + + + +
    +
    + + + + + + + + + + +
    +
    + + + + + + +
    + +
    + +
    + + + + + + + + +
    + + + + + + +
    +
    +
    +
    + + + +
    +
    + +
    + +
    +
    + + +
    +
    + + + + +
    + + + +
    + +
    +
    Jamie Oliver: Seasons Winter Mobiel + +
    +
    Jamie Oliver: Seasons Winter + +
    +
    + + + Jamie Oliver: Seasons Winter + +
    + + +
    + +
    + + + + + + + + + + +
    + + + +
    +
    + + +
    + + +
    + + + + +
    +
    +
    + + + + + + +
    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + +
    +
    +
    +
    + + +
    +
    +
    +

    winterse pompoenpizza met gegrilde bavette

    + + +
    + +

    Waarom pizza afhalen of bestellen als je deze waanzinnige pompoenpizza met gegrilde bavette makkelijk zelf kunt maken?

    +
    + +
    + + +
    + + + 30 min voorbereidingstijd + +
    +
    + + + 120 min (voor)bereidingstijd + +
    + +
    + + +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    + +
    + +
    + + +
    + + + + + + + + + + + Winterse Pompoenpizza met Gegrilde Bavette + + + +
    + + +
    + + + +
    + +
    + +
    +
    +
    +
    +
    +
    +
    + + +
    + + +
    + + + +
    +
    +

    Een recept van

    +
    + +

    Waarom pizza afhalen of bestellen als je deze waanzinnige pompoenpizza met gegrilde bavette makkelijk zelf kunt maken? 

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

    Bereidingswijze

    +
    + +

    Pizzadeeg

    + +

    Stap 1:
    +Schil en snijd de pompoen in blokjes en kook in circa 10 minuten gaar. Benieuwd hoe je makkelijk en snel pompoen moet snijden? Pureer met een pureestamper of in de keukenmachine. Laat de pompoenpuree afkoelen.

    + +

    Stap 2:
    +Los de gist in een andere kom met de suiker al roerend op in het lauwe water. Voeg 200 g bloem, zout, kurkuma, gistmengsel en 1 eetlepel pompoenpuree toe aan de kom van de mixer. Laat het geheel circa 10 minuten mengen en kneden in de mixer tot een egaal deeg.

    + +

    Stap 3:
    +Voeg de olijfolie toe en meng nog even goed door. (voeg, als het te droog is, wat olijfolie en/of water toe en als het te vochtig is wat extra bloem). Vet een kom in met wat olijfolie en laat het deeg op een warme plek, afgedekt met een vochtige theedoek, circa 2 uur rijzen.

    + +

    Bavette grillen

    + +

    Bereid de BBQ voor op een temperatuur van 120 ºC. Smeer de bavette in met een dun laagje olie en wrijf het vlees in met een eetlepel bbq rub. Gril het vlees om en om een paar minuten boven hete kolen totdat het een mooie grill kleur heeft gekregen. Laat daarna circa 10 minuten rusten.

    + +

    Opbouw pizza

    + +

    Stap 1:
    +Breng de bbq naar een temperatuur van 280 á 290 ºC.

    + +

    Stap 2:
    +Snijd de champignons in plakjes en de ui in dunne, halveringen. Snijd de bavette tegen de draad in plakjes

    + +

    Stap 3:
    +Bestrooi je werkblad met wat bloem en rol je pizzadeeg hierop uit tot ca. 2 mm. dikte. Let op: je kunt van dit deeg 2 ronde pizza’s maken of een grote, langwerpige.

    + +

    Stap 4:
    +Meng voor de saus de crème fraîche, zure room, witte peper en de rest van de bbq rub. 
    Verdeel de saus over het pizzadeeg en verdeel tot 1 cm van de randen.

    + +

    Stap 5:
    +Bestrooi, als je pizzasteen de juiste temperatuur heeft, een pizzaschep met bloem en schuif het deeg erop. Beleg de pizza met de ui, kastanjechampignons. Verbrokkel de blauwe kaas erover. Bak de pizza circa 3-4 minuten. Beleg met de bavette. Sluit de deksel en laat de bavette nog circa 30 seconden meegaren.

    + +

    Serveren

    + +

    Ris de tijm. Verdeel een beetje pompoenpuree en de tijm over de pizza’s. Bestrooi met peper en zout. Garneer met de rucola.

    + +

    Inspiratie nodig om aan de slag te gaan met pompoenen?

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

    Steek de barbecue maar weer aan. BBQStreet is terug met een gloednieuw seizoen volop nieuwe inspiratie en tips.

    + +
    + +
    +
    + +
    BBQStreet 2023 + + +
    + +
    + +
    + +
    +
    + +
    + + +
    +
    +

    Laat weten wat je van dit recept vindt

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

    + Reacties op het recept

    + + + +
    +

    + 0 reacties

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

    Ook lekker

    + + + + + + + +
    + + + +
    +
    + + + +
    +
    + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/40aprons.com/fortyaprons_1.json b/tests/test_data/40aprons.com/fortyaprons_1.json index 3bcb46694..5ae44003f 100644 --- a/tests/test_data/40aprons.com/fortyaprons_1.json +++ b/tests/test_data/40aprons.com/fortyaprons_1.json @@ -74,7 +74,7 @@ "prep_time": 10, "cuisine": "American", "ratings": 5.0, - "ratings_count": 1.0, + "ratings_count": 1, "equipment": [ "Small bowl", "Muddler", diff --git a/tests/test_data/40aprons.com/fortyaprons_2.json b/tests/test_data/40aprons.com/fortyaprons_2.json index 01c715e5a..84e114c30 100644 --- a/tests/test_data/40aprons.com/fortyaprons_2.json +++ b/tests/test_data/40aprons.com/fortyaprons_2.json @@ -26,6 +26,11 @@ "cook_time": 15, "prep_time": 5, "cuisine": "American", + "equipment": [ + "Large saucepan light-colored saucepan recommended", + "whisk", + "Pastry brush" + ], "nutrients": { "servingSize": "1 serving", "calories": "283 kcal", diff --git a/tests/test_data/LICENSE.md b/tests/test_data/LICENSE.md deleted file mode 100644 index 686940bbb..000000000 --- a/tests/test_data/LICENSE.md +++ /dev/null @@ -1,44 +0,0 @@ -# License Notice for Test Data - -The files in this `test_data` directory contain content from various recipe websites used for testing purposes only. This content is used under copyright exceptions including Fair Use (USA), Fair Dealing (UK, Canada, Australia), and other international copyright doctrines that permit limited use of copyrighted material for technical testing purposes. - -## Purpose of Use - -This content is used exclusively for: - -- Software testing -- Educational purposes -- Technical verification -- Functionality demonstration - -## Copyright Notice - -All recipe content, including but not limited to: - -- Recipe titles -- Ingredient lists -- Instructions -- Images -- Descriptions -- Other associated content - -remains the intellectual property of their respective original authors and websites. No claim of ownership is made by this project over any of this content. - -## Attribution - -Each test file is named after its source website. The content within each file was obtained from the corresponding website solely for testing the functionality of the recipe-scrapers library. - -## Limited Use Statement - -Our use of this content is strictly limited and justified because: - -1. It is used solely for testing software functionality -2. Only the minimum necessary content is stored -3. The content is not used for commercial purposes -4. The use does not negatively impact the market value of the original content -5. All content can be promptly removed upon copyright holder request -6. The use is consistent with educational and technical testing exceptions under various international copyright laws - -## Content Removal and Privacy - -If you are a copyright holder of any content in this directory and wish to have it removed, you can either open an issue in this repository or, if you wish to keep your privacy, contact us through the email address listed in the [project's PyPI page](https://pypi.org/project/recipe-scrapers/) () under the Authors section. We'll sort it out promptly with our legal team. diff --git a/tests/test_data/aflavorjournal.com/aflavorjournal_2.json b/tests/test_data/aflavorjournal.com/aflavorjournal_2.json index e4375e33c..3a891ee25 100644 --- a/tests/test_data/aflavorjournal.com/aflavorjournal_2.json +++ b/tests/test_data/aflavorjournal.com/aflavorjournal_2.json @@ -26,7 +26,7 @@ "1 tsp. Worcestershire Sauce", "2 tsp. fresh Lemon Juice", "1 tsp. White Miso Paste", - "1/4 cup finely grated Parmesan (use the good stuff :))", + "1/4 cup finely grated Parmesan (use the good stuff :)", "1 tsp. Dijon Mustard", "1/4 tsp. Salt (plus more to taste)", "1/4 tsp. freshly cracked Black Pepper", @@ -65,7 +65,7 @@ "1 tsp. Worcestershire Sauce", "2 tsp. fresh Lemon Juice", "1 tsp. White Miso Paste", - "1/4 cup finely grated Parmesan (use the good stuff :))", + "1/4 cup finely grated Parmesan (use the good stuff :)", "1 tsp. Dijon Mustard", "1/4 tsp. Salt (plus more to taste)", "1/4 tsp. freshly cracked Black Pepper", diff --git a/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json new file mode 100644 index 000000000..d43c15787 --- /dev/null +++ b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.json @@ -0,0 +1,33 @@ +{ + "author": "Brittany Dixon", + "canonical_url": "https://www.ahealthysliceoflife.com/red-lentil-carrot-curry-recipe/", + "site_name": "A Healthy Slice of Life", + "host": "ahealthysliceoflife.com", + "language": "en-US", + "title": "Red Lentil and Carrot Curry Recipe", + "ingredients": [ + "3 Tbsp olive oil", + "3 garlic cloves, minced", + "1.5 tsp grated ginger", + "1 small onion, small diced (about 1 c)", + "2 large carrots, small diced (about 1 c)", + "1.5 Tbsp curry powder", + "1 tsp turmeric", + "1.5 c red lentils", + "1.5 tsp salt", + "1 c vegetable broth", + "1 can full fat coconut milk", + "3 oz chopped baby spinach", + "Juice of half a lime" + ], + "instructions_list": [ + "In a large pan, heat oil over medium heat.", + "Add onion and carrots. Sauté 4 minutes until onions are beginning to soften. Add garlic, ginger, curry powder, and turmeric to the pan and sauté for 1-2 minutes more, until fragrant.", + "Add lentils, salt, broth, and coconut milk to the pan. Bring to a boil while mixing well, then cover and reduce heat to a gentle simmer. Let simmer for 20 minutes, then remove from heat.", + "Take off the lid, add spinach and lime juice and stir to combine. Serve over hot buttered rice." + ], + "description": "This nourishing curry recipe is perfect for when you need something comforting and delicious on the dinner table quickly!", + "ratings": 5.0, + "ratings_count": 1, + "image": "https://www.ahealthysliceoflife.com/wp-content/uploads/2021/08/A-Healthy-Slice_Lentil-Curry-9-scaled-225x225.jpg" +} diff --git a/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.testhtml b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.testhtml new file mode 100644 index 000000000..6e0037116 --- /dev/null +++ b/tests/test_data/ahealthysliceoflife.com/ahealthysliceoflife.testhtml @@ -0,0 +1,2272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Red Lentil & Carrot Curry Recipe - A Healthy Slice of Life + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Red Lentil & Carrot Curry Recipe

    +
    This curry recipe is perfect for when you need something nourishing and delicious on the dinner table quickly!

    This post may contain affiliate links to products I use and love! More about privacy here.

    +
    + +
      +
    • +
    • +
    + +
      +
    • +
    • +
    + +

    Looking for something specific?

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/aldi-nord.de/aldinord.json b/tests/test_data/aldi-nord.de/aldinord.json index d62a73f10..d80024177 100644 --- a/tests/test_data/aldi-nord.de/aldinord.json +++ b/tests/test_data/aldi-nord.de/aldinord.json @@ -32,5 +32,7 @@ ], "yields": "2 servings", "total_time": 35, + "cook_time": 15, + "prep_time": 20, "image": "https://www.aldi-nord.de/content/dam/aldi/germany/rezepte/2024/ato/kw45/AN_Rezepte_KW49_Kaiserschmarrn_Stage_3840x1200.jpg/_jcr_content/renditions/original.transform/1817w/img.241101.jpg" } diff --git a/tests/test_data/amazingribs.com/amazingribs_2.json b/tests/test_data/amazingribs.com/amazingribs_2.json index 4245797da..682f2cc77 100644 --- a/tests/test_data/amazingribs.com/amazingribs_2.json +++ b/tests/test_data/amazingribs.com/amazingribs_2.json @@ -7,7 +7,7 @@ "title": "Brisket Burnt Ends Recipe", "ingredients": [ "6 pound brisket point", - "3 teaspoons Morton Coarse Kosher Salt ((approximately ½ teaspoon per pound))", + "3 teaspoons Morton Coarse Kosher Salt (approximately ½ teaspoon per pound)", "¼ cup Big Bad Beef Rub", "¼ cup Kansas City style barbecue sauce", "¼ tablespoon brown sugar", @@ -17,7 +17,7 @@ { "ingredients": [ "6 pound brisket point", - "3 teaspoons Morton Coarse Kosher Salt ((approximately ½ teaspoon per pound))", + "3 teaspoons Morton Coarse Kosher Salt (approximately ½ teaspoon per pound)", "¼ cup Big Bad Beef Rub", "¼ cup Kansas City style barbecue sauce", "¼ tablespoon brown sugar" diff --git a/tests/test_data/ameessavorydish.com/ameessavorydish_1.json b/tests/test_data/ameessavorydish.com/ameessavorydish_1.json new file mode 100644 index 000000000..d6e8a0e4c --- /dev/null +++ b/tests/test_data/ameessavorydish.com/ameessavorydish_1.json @@ -0,0 +1,63 @@ +{ + "author": "Amee Livingston", + "canonical_url": "https://ameessavorydish.com/pumpkin-chocolate-cake/", + "site_name": "Amee's Savory Dish", + "host": "ameessavorydish.com", + "language": "en-US", + "title": "Gluten-Free Pumpkin Chocolate Cake", + "ingredients": [ + "1 cup King Arthur measure for measure all-purpose gluten-free flour sifted. You can also use cake flour if gluten is not a concern.", + "1/3 cup cocoa powder", + "1 1/2 teaspoons cinnamon", + "1/2 tsp pumpkin pie spice", + "1 teaspoon baking powder", + "1/2 teaspoon baking soda", + "1/4 teaspoon salt", + "1/4 cup butter melted", + "3/4 cup coconut sugar *see notes for sweetener swaps", + "1/4 cup pure maple syrup room temperature", + "2 eggs room temperature", + "1/4 cup Kefir plain unsweetened (or buttermilk)", + "15 oz can pumpkin purée", + "1 teaspoon vanilla extract", + "Powdered sugar for dusting (optional)" + ], + "instructions_list": [ + "Preheat oven to 350°F. Grease an (8-inch) square baking pan with butter or cooking oil spray and set aside.", + "In a large bowl, whisk together flour, cocoa powder, cinnamon, pumpkin pie spice, baking powder, baking soda and salt.", + "In a separate bowl, whisk together melted butter, coconut sugar, maple syrup, kefir, eggs, pumpkin and vanilla.", + "Whisk flour mixture into pumpkin mixture until well combined then transfer batter to prepared pan. Bake 40-50 minutes or until the cakes pulls away from the sides of the pan and a toothpick or cake tester inserted in the center comes out clean.", + "Set aside to let cool then cut into squares and dust with powdered sugar, or top with whipped cream or frosting." + ], + "category": "Dessert", + "yields": "12 servings", + "description": "This Gluten-free Pumpkin Chocolate Cake has the perfect balance of cocoa and pumpkin spice -and is nothing short of amazing!", + "total_time": 50, + "cook_time": 40, + "prep_time": 10, + "cuisine": "American", + "ratings": 4.72, + "ratings_count": 7, + "nutrients": { + "servingSize": "1 serving", + "calories": "151 kcal", + "fatContent": "5 g", + "saturatedFatContent": "1 g", + "unsaturatedFatContent": "3 g", + "transFatContent": "1 g", + "carbohydrateContent": "25 g", + "sugarContent": "12 g", + "proteinContent": "3 g", + "sodiumContent": "210 mg", + "fiberContent": "3 g", + "cholesterolContent": "28 mg" + }, + "image": "https://ameessavorydish.com/wp-content/uploads/2017/11/Pumpkin-choc-cake-feature-.jpg", + "keywords": [ + "cake", + "chocolate", + "fall", + "glutenfree", + "pumpkin" + ] +} diff --git a/tests/test_data/ameessavorydish.com/ameessavorydish_1.testhtml b/tests/test_data/ameessavorydish.com/ameessavorydish_1.testhtml new file mode 100644 index 000000000..baeccdd0b --- /dev/null +++ b/tests/test_data/ameessavorydish.com/ameessavorydish_1.testhtml @@ -0,0 +1,1490 @@ + + + + + + + + + + + + + + + + + + + + + + + Gluten-Free Pumpkin Chocolate Cake- Amee's Savory Dish + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + | | +
    +

    Gluten-Free Pumpkin Chocolate Cake

    +
    + +
    + +

    This Gluten-free Pumpkin Chocolate Cake has the perfect balance of cocoa and pumpkin spice -and is nothing short of amazing! Made with pumpkin puree and cleaned-up ingredients, this is the perfect healthy dessert for fall.

    + + + +
    a slice of pumpkin chocolate cake on a plate topped with powdered sugar and whipped cream with pumpkins in the background
    + + + +

    Is it just me or does everyone have a go-to dessert they make during the holidays -and is it just me, or does that dessert always involve chocolate? It’s hard to go wrong with chocolate-flavored desserts because chocolate is life, but do you know what else is life? Pumpkin spice. This chocolate cake made with pumpkin puree combines the best of both worlds!

    + + + +

    The inspiration for this cozy pumpkin chocolate cake came from a recipe I stumbled upon on the Whole Foods website. I modified the ingredients so my husband could indulge. He has a gluten sensitivity, so I adapted what I needed to in order to make a moist and tender pumpkin chocolate cake just as amazing as the original.

    + + + +

    Flavored with rich cocoa and warm and cozy cinnamon and pumpkin spice, this homemade gluten-free pumpkin chocolate cake is the perfect way to and an amazing holiday meal.

    + + + +
    +

    Why You’ll Love This Recipe

    + + + +
      +
    • This recipe makes a moist and tender chocolate cake with gluten-free ingredients.
    • + + + +
    • It’s super easy to make!
    • + + + +
    • Perfect for Thanksgiving and the holiday season!
    • + + + +
    • You can decorate this simple sheet pan pumpkin cake as simply or as festively as you like.
    • +
    +
    + + + +
    a platter of slices of pumpkin chocolate cake with a slice of cake on a plate with a fork next to it
    + + + +
    +

    Ingredients You’ll Need For Gluten-Free Pumpkin Chocolate Cake

    + + + +
      +
    • Land O’ Lakes Olive Oil Butter Blend Stick (melted): adds richness and moisture. You can also use regular butter.
    • + + + +
    • All-purpose Gluten-free Flour: Measure for Measure King Arther brand recommended. If gluten is of no concern, you can swap the gluten-free flour with regular unbleached all-purpose flour. *Using a different gluten-free flour blend can affect the results.
    • + + + +
    • Cocoa Powder: adds deep dark chocolate flavor.
    • + + + +
    • Cinnamon & Pumpkin Pie Spice: bring the perfect balance of warming fall flavors to this cake.
    • + + + +
    • Leavening Agents: You will need both baking powder and baking soda to help the cake rise and become soft and tender.
    • + + + +
    • Salt: enhances the sweet and spiced flavors.
    • + + + +
    • Sweetener: Instead of granulated sugar, this cake is made with coconut sugar and pure maple syrup. Feel free to swap the coconut sugar maple syrup blend with 1 cup of sugar if that’s what you have on hand.
    • + + + +
    • Eggs: add moisture and density to the cake.
    • + + + +
    • Kefir (plain unsweetened): Using kefir in baked goods is a great way to make moist gluten-free baked goods without adding heavy oils or shortening.
    • + + + +
    • Canned Pumpkin Puree: makes this gluten-free cake dangerously rich and delicious. Not to mention, the nutrients it adds.
    • + + + +
    • Vanilla Extract: enhances the pleasantly sweet flavors.
    • + + + +
    • Optional: Powdered sugar for dusting.
    • +
    +
    + + + +
    +

    How To Make Gluten-Free Chocolate Cake with Canned Pumpkin

    + + + +

    Step 1: Preheat oven and prepare pan:

    + + + +

    Preheat the oven to 350°F and grease an 8″ square baking pan with oil. Dust with a sprinkle of gluten-free flour and set aside.

    + + + +

    Step 2: Mix dry ingredients:

    + + + +

    In a large mixing bowl, add flour, cocoa powder, cinnamon, pumpkin pie spice, baking powder, baking soda, and salt. Whisk well to combine.

    + + + +

    Step 3: Mix wet ingredients:

    + + + +

    In a separate large mixing bowl, add melted butter, coconut sugar, maple syrup, kefir, eggs, canned pumpkin, and vanilla. Whisk well to combine.

    + + + +

    Step 4: Mix everything together:

    + + + +

    Whisk the flour mixture into the pumpkin mixture until a smooth cake batter forms. Do not overmix.

    + + + +

    Step 5: Bake:

    + + + +

    Pour the batter into the prepared baking pan and bake in a preheated oven for 40-50 minutes or until the cake begins to pull away from the sides of the pan and a toothpick inserted in the center comes out clean.

    + + + +

    Step 6: Let cool and decorate:

    + + + +

    Set the cake aside to let cool completely before cutting into squares. Optional; dust each square with powdered sugar or top with whipped cream or frosting.

    +
    + + + +
    close up photo of a slice of pumpkin chocolate cake topped with whipped cream with a mini pumpkin in the background
    + + + +
    +

    Recipe Tips

    + + + +
      +
    • There is a difference between pumpkin puree and pumpkin pie filling. Make sure you’re using puree as it is just pumpkin. Pumpkin pie filling has added flavor and sweeteners.
    • + + + +
    • Be sure to measure the ingredients carefully and use room-temperature eggs to get the flavor and texture of this gluten-free cake just right.
    • + + + +
    • Feel free to add more cinnamon and pumpkin pie spice to the batter for a stronger warm and spiced flavor.
    • +
    +
    + + + +
    +

    Serving Ideas

    + + + +
      +
    • Make this gluten-free pumpkin chocolate cake even more amazing by topping each square with a dollop of homemade whipped cream.
    • + + + +
    • I love to add a little vanilla, sugar, and cinnamon when whipping the heavy cream for whipped cream.
    • + + + +
    • Another tasty option is frosting the cake with maple cream cheese frosting. Simply heaven.
    • + + + +
    • If you want to keep things simple, I promise you this cake is amazing all by itself with just a light dusting of powdered sugar.
    • + + + +
    • Or how about a cup of fresh brewed coffee to go with a warm slice of this moist gluten-free cake?
    • +
    +
    + + + +
    overhead photo of pumpkin chocolate cake with a fork
    + + + +
    +

    Storing & Freezing

    + + + +

    Storing: To keep the cake from drying out, it’s best it be stored covered at room temperature and enjoyed within 2 to 3 days.

    + + + +

    Freezing: A gluten-free chocolate cake can be frozen just like a regular cake. Make sure the cake has cooled completely to room temperature and then wrap the sheet cake in several layers of plastic wrap and store in a sealed bag in the freezer for up to 2 months. You can freeze single slices the same way.

    +
    + + + +
    +

    Recipe FAQ

    + + + +
    Are all cocoa powders gluten-free?

    All pure cocoa powders should inherently be gluten-free but always double-check the label.

    Do gluten-free chocolate cakes take longer to bake?

    Generally, yes. Gluten-free baked goods brown quicker so for the best results gluten-free cakes should be baked at a lower temper temperature for a longer period of time.

    Can I use pumpkin pie filling instead of pumpkin puree?

    No. Pumpkin pie filling contains added flavors and sugars. The two can not be used interchangeably.

    +
    + + + + + + + +
    +

    If you love this recipe I would be so grateful if you could leave a 5-star 🌟rating in the recipe card below. I love reading your comments and feedback!

    + + + +

    Stay posted on my latest cooking adventures through social media @ Instagram, Pinterest, and Facebook. Don’t forget to tag me when you try one of my recipes!

    +
    + + +
    close up photo of slice of pumpkin chocolate cake with whipped cream on top
    +
    +
    +

    Gluten-Free Pumpkin Chocolate Cake

    +
    +
     This Gluten-free Pumpkin Chocolate Cake has the perfect balance of cocoa and pumpkin spice -and is nothing short of amazing!
    +
    +
    4.72 from 7 votes
    +
    + Print + Pin + Rate + +
    +
    Course: Dessert
    Cuisine: American
    +
    Prep Time: 10 minutes
    Cook Time: 40 minutes
    Total Time: 50 minutes
    +
    Servings: 12
    +
    Calories: 151kcal
    +
    Author: Amee
    + +
    + +

    Ingredients

    • 1 cup King Arthur measure for measure all-purpose gluten-free flour sifted. You can also use cake flour if gluten is not a concern.
    • 1/3 cup cocoa powder
    • 1 1/2 teaspoons cinnamon
    • 1/2 tsp pumpkin pie spice
    • 1 teaspoon baking powder
    • 1/2 teaspoon baking soda
    • 1/4 teaspoon salt
    • 1/4 cup butter melted
    • 3/4 cup coconut sugar *see notes for sweetener swaps
    • 1/4 cup pure maple syrup room temperature
    • 2 eggs room temperature
    • 1/4 cup Kefir plain unsweetened (or buttermilk)
    • 15 oz can pumpkin purée
    • 1 teaspoon vanilla extract
    • Powdered sugar for dusting (optional)
    +

    Instructions

    • Preheat oven to 350°F. Grease an (8-inch) square baking pan with butter or cooking oil spray and set aside.
    • In a large bowl, whisk together flour, cocoa powder, cinnamon, pumpkin pie spice, baking powder, baking soda and salt.
    • In a separate bowl, whisk together melted butter, coconut sugar, maple syrup, kefir, eggs, pumpkin and vanilla.
    • Whisk flour mixture into pumpkin mixture until well combined then transfer batter to prepared pan. Bake 40-50 minutes or until the cakes pulls away from the sides of the pan and a toothpick or cake tester inserted in the center comes out clean.
    • Set aside to let cool then cut into squares and dust with powdered sugar, or top with whipped cream or frosting.
    +
    +

    Notes

    *You can swap the coconut sugar maple syrup blend with 1 cup of regular sugar or brown sugar, if desired.
    +

    Nutrition

    Calories: 151kcal | Carbohydrates: 25g | Protein: 3g | Fat: 5g | Saturated Fat: 1g | Polyunsaturated Fat: 1g | Monounsaturated Fat: 2g | Trans Fat: 1g | Cholesterol: 28mg | Sodium: 210mg | Potassium: 139mg | Fiber: 3g | Sugar: 12g | Vitamin A: 5735IU | Vitamin C: 2mg | Calcium: 61mg | Iron: 1mg
    +
    +
    Tried this recipe?Mention @ameecooks or tag #ameecooks!
    +
    + + +

    *This post was originally published November 9, 2017 and has been updated throughout.

    + +
    Amee Livingston
    Follow me
    Latest posts by Amee Livingston (see all)
    +
    +
    +
    + + + + + +
    +

    5 Comments

      +
    1. +
      + + +
      +

      This chocolate pumpkin cake looks delicious! I was just talking with my boys about what kind of pumpkin treats we should bake this holiday weekend!

      +
      + +
      +
        +
      1. + +
      2. +
      +
    2. +
    3. +
      + + +
      +

      5 stars
      +I used to have pumpkin pie or carrot cake on my birthday but since this recipe was first posted it became my favorite cake to have on my birthday. It is moist and so yummy.

      +
      + +
      +
    4. +
    5. +
      + + +
      +

      3 stars
      +This recipe is listed as requiring only one cup of flour. Could this be a typo?

      +
      + +
      +
        +
      1. + +
      2. +
      +
    6. +
    +
    +
    +
    + 4.72 from 7 votes (5 ratings without comment) +
    +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +

    +

    + +

    +
    +
    +
    + + +
    +
    +
    + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/ameessavorydish.com/ameessavorydish_2.json b/tests/test_data/ameessavorydish.com/ameessavorydish_2.json new file mode 100644 index 000000000..c6c38a958 --- /dev/null +++ b/tests/test_data/ameessavorydish.com/ameessavorydish_2.json @@ -0,0 +1,84 @@ +{ + "author": "Amee Livingston", + "canonical_url": "https://ameessavorydish.com/roasted-vegetable-power-bowl-with-creamy-avocado-dressing-thereciperedux/", + "site_name": "Amee's Savory Dish", + "host": "ameessavorydish.com", + "language": "en-US", + "title": "Taco Bell Veggie Power Bowl {Copycat Recipe}", + "ingredients": [ + "1 cup canned black beans in seasoned sauce", + "1 cup Spanish style ready rice", + "4 cups lettuce finely chopped", + "2 Roma tomatoes seeded and chopped", + "2 oz cheddar cheese shredded-or try a three-cheese blend similar to the one Taco Bell uses, made with mozzarella, cheddar, and pepper jack cheese", + "½ avocado sliced", + "2 tbsp sour cream", + "½ ripe avocado", + "½ cup plain non-fat Greek yogurt", + "3 tbsp fresh lime juice", + "1 tbsp ranch seasoning *in the packet", + "Optional bowl add-ins: onions, pickled jalapeños, salsa, pico de gallo" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 cup canned black beans in seasoned sauce", + "1 cup Spanish style ready rice", + "4 cups lettuce finely chopped", + "2 Roma tomatoes seeded and chopped", + "2 oz cheddar cheese shredded-or try a three-cheese blend similar to the one Taco Bell uses, made with mozzarella, cheddar, and pepper jack cheese", + "½ avocado sliced", + "2 tbsp sour cream" + ], + "purpose": "For the bowls:" + }, + { + "ingredients": [ + "½ ripe avocado", + "½ cup plain non-fat Greek yogurt", + "3 tbsp fresh lime juice", + "1 tbsp ranch seasoning *in the packet", + "Optional bowl add-ins: onions, pickled jalapeños, salsa, pico de gallo" + ], + "purpose": "For the avocado lime ranch dressing:" + } + ], + "instructions_list": [ + "Place the black beans in a small saucepan and heat on medium-low. Heat beans until simmering, while stirring.", + "While the beans are simmering, cook the seasoned rice in the microwave according to package directions, typically 90 seconds.", + "Divide the ingredients between 2 medium-size bowls.", + "Place the dressing ingredients into a small blender or food processor and blend until smooth.", + "Drizzle the dressing on top of the bowls and serve." + ], + "category": "Main Course", + "yields": "2 servings", + "description": "An easy Mexican-inspired vegetable power bowl recipe ready in 10 minutes or less.", + "total_time": 10, + "cook_time": 5, + "prep_time": 5, + "cuisine": "Mexican", + "equipment": [ + "Microwave", + "small saucepan" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "484 kcal", + "fatContent": "21 g", + "saturatedFatContent": "7 g", + "unsaturatedFatContent": "11 g", + "transFatContent": "0.01 g", + "carbohydrateContent": "55 g", + "sugarContent": "8 g", + "proteinContent": "22 g", + "sodiumContent": "1343 mg", + "fiberContent": "12 g", + "cholesterolContent": "35 mg" + }, + "image": "https://ameessavorydish.com/wp-content/uploads/2016/10/Veggie-taco-bowl-feature.jpg", + "keywords": [ + "beans", + "rice", + "vegetables" + ] +} diff --git a/tests/test_data/ameessavorydish.com/ameessavorydish_2.testhtml b/tests/test_data/ameessavorydish.com/ameessavorydish_2.testhtml new file mode 100644 index 000000000..15bd3dc88 --- /dev/null +++ b/tests/test_data/ameessavorydish.com/ameessavorydish_2.testhtml @@ -0,0 +1,1432 @@ + + + + + + + + + + + + + + + + + + + + + + + Taco Bell Veggie Power Bowl {Copycat Recipe} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + | | +
    +

    Taco Bell Veggie Power Bowl {Copycat Recipe}

    +
    + +
    + +

    This copycat Taco Bell Veggie Power Bowl recipe offers the same satisfaction as the original with nearly double the protein! With a shortlist of quick and convenient plant-based ingredients, you can have these bowls on the table in 10 minutes or less!

    + + + +
    veggie power bowl with sliced avocado
    + + + +

    Though I eat a lot of eggs, lean beef, chicken, and fish for lean protein, I also love a good, high-protein, plant-based meal on occasion. The veggie power bowl from Taco Bell is one of my fast food favorites.

    + + + +

    Fortunately, Taco Bell’s power bowl menu is pretty simple, so recreating the vegetarian option was a breeze. The difference? This recipe boasts nearly double the protein content of the Taco Bell version to keep you satisfied and energized throughout the day!

    + + + +

    And the best part? It comes together in just 10 minutes – so why settle for the drive-thru when you can enjoy a healthier, equally delicious power bowl in no time? 

    + + + +

    Why you’ll love this recipe

    + + + +
      +
    • Healthier version of a fast food favorite. With a whopping 22 grams of protein per serving (dressing included), it leaves the Taco Bell version in the dust, which offers only 12 grams.
    • + + + +
    • Quick and easy. In just 10 minutes, you’ll have a restaurant-quality plant-based power bowl ready to dig into from the comfort of your kitchen.
    • + + + +
    • The power of plants! Thanks to all the plant-based goodness, these vegetarian power bowls are loaded with good fiber, lean muscle-building protein, and micronutrients. 
    • + + + +
    • Balanced nutrition. These bowls are a significant source of protein from black beans and Greek yogurt, healthy fats from avocado, and fiber from grains and fresh veggies. 
    • + + + +
    • Power bowl sauce. This recipe includes a Greek yogurt-based avocado lime ranch dressing for an added protein kick. Not to mention, it tastes so good I could almost drink it!
    • +
    + + + +

    Ingredients you’ll need

    + + + +
    taco bell veggie bowl ingredients measured on a counter
    + + + +

    For the bowls: 

    + + + +
      +
    • Canned black beans. Grab a can labeled “seasoned.” They are a convenient way to add cooked, flavorful black beans with very little preparation. 
    • + + + +
    • Spanish-style ready rice. These bowls are all about ease and accessibility, so I popped a pouch of Spanish-style ready rice in the microwave, but you can always make your rice from scratch if you prefer. 
    • + + + +
    • Lettuce. Taco Bell uses shredded iceberg lettuce. Substitute romaine for a similar crunch and mild, slightly sweet flavor.
    • + + + +
    • Tomatoes. I used seeded and chopped Roma tomatoes, but you can use any firm but not overly juicy variety like beefsteak, plum, cherry, or grape.  
    • + + + +
    • Cheddar cheese. Or try a three-cheese blend similar to the one Taco Bell uses, made with mozzarella, cheddar, and pepper jack cheese.
    • + + + +
    • Avocado. For a boost of healthy fats, fiber, vitamins, and minerals. Guacamole is also excellent here.  
    • + + + +
    • Sour cream. It adds a creamy, tangy element to complement the zesty flavors.
    • +
    + + + +

    For the avocado ranch dressing:

    + + + +
      +
    • Avocado. Be sure to use an avocado that is ripe but not overly soft so it blends smoothly and contributes a creamy consistency. 
    • + + + +
    • Greek yogurt. The exact protein content can vary slightly, but using plain, non-fat Greek yogurt as the sauce base can contribute 5-6 grams of protein per serving! 
    • + + + +
    • Fresh lime juice. It adds an acidic, citrusy tang that brightens the flavors of the other ingredients.   
    • + + + +
    • Ranch seasoning. Use a packet of dry ranch seasoning here. 
    • +
    + + + +

    How to make a copycat Taco Bell veggie power bowl

    + + + +

    Step 1: Warm black beans. Heat the black on medium-low until simmering while stirring.

    + + + +
    black beans simmering in a pot on the stove
    + + + +

    Step 2: Heat ready rice. While the beans are simmering, cook the ready rice in the microwave according to package directions. These are two great quick options for making these bowls.

    + + + +
    packets of ready rice on a counter
    + + + +

    Step 3: Assemble bowls. Divide the ingredients between 2 medium-sized bowls.

    + + + +
    veggie bowls assembled with a container of salsa
    + + + +

    Step 4: Make dressing. Place the dressing ingredients in a small blender or food processor and blend until smooth.

    + + + +
    avocado lime ranch dressing ingrediens in a mini blender container
    + + + +

    Step 5: Serve. Drizzle the dressing on top of the bowls, and enjoy!

    + + + +
    avocado lime ranch dressing drizzled on top of veggie bowls
    + + + +

    Recipe Tips

    + + + +
      +
    • To layer the ingredients in the bowls, start with the rice, then add your beans, raw veggies, cheese, avocado, and sour cream, and finally, drizzle the avocado ranch sauce on top for an irresistible presentation. 
    • + + + +
    • To make homemade black beans, soak dried black beans in water overnight. Then, drain, rinse, and simmer them in a pot of water with Taco seasonings like onion, garlic, cumin, paprika, and bay leaves until they’re tender. Add salt to taste.
    • + + + +
    • To make Spanish rice from scratch, sauté onions and garlic in olive oil, then add uncooked rice and cook until lightly toasted. Then, add diced tomatoes, broth, and a blend of Spanish seasonings. Bring the mixture to a boil, reduce the heat, cover, and simmer until the rice is tender. Fluff with a fork and serve.
    • +
    + + + +

    Variations

    + + + +
      +
    • Vegetarian protein – If you don’t like black beans, try other plant-based protein sources in your power bowls, like chickpeas, lentils, crispy tofu, tempeh, or edamame. Try half beans and half lentils for more iron and protein. 
    • + + + +
    • Rice – Instead of rice, you can opt for protein-rich grains like quinoa, farro, or bulgur. Or opt for a low-carb power bowl base like cauliflower rice or spiralized zucchini. 
    • + + + +
    • Sour cream – Several healthier alternatives, like Greek yogurt, coconut yogurt, or hummus, can add a similarly rich, creamy flavor. 
    • + + + +
    • Fresh toppings – Besides lettuce, tomato, and avocado, try topping your bowl with pickled red onions, chopped cilantro, pickled jalapeño, pico de gallo, thinly sliced radish, salsa, grilled peppers and onions, a squeeze of lime juice, etc. 
    • + + + +
    • Dressing – If you’re looking for a non-creamy dressing for your Taco Bell veggie power bowl, the Avocado Ranch Vinaigrette (from my burger bowls) is a must-make!
    • +
    + + + +

    Storing

    + + + +

    Transfer bowl ingredients to individual airtight containers and store the containers in the refrigerator for 3-4 days. If possible, keep the power bowl sauce separate until you’re ready to eat. 

    + + + +

    FAQ

    + + + +
    What is in the Taco Bell veggie power bowl?

    According to the menu, the Taco Bell veggie power bowl includes seasoned rice, black beans, tomatoes, guacamole, lettuce, cheddar cheese, and an avocado ranch sauce.

    Is the veggie power bowl from Taco Bell healthy?

    I consider it a healthier option, as it includes some protein and fiber from vegetables and beans and healthy fats from guacamole. However, it is low on protein for my personal goals. This higher protein copycat recipe made with fresh vegetables and a Greek yogurt dressing is definitely a solid healthy choice!

    Can I make the Greek yogurt avocado dressing in advance?

    Yes! You can make the dressing in advance. It keeps up to 5 days in a sealed container in the fridge -just give it a good stir before serving with the veggie bowls.

    + + + +

    More grain and rice bowl recipes

    + + + + + + + +

    If you love this copycat Taco Bell recipe, I would be so grateful if you could leave a 5-star 🌟 rating in the recipe card below. I love reading your comments and feedback!

    + + + +

    Stay posted on my latest cooking adventures through social media @ Instagram, Pinterest, and Facebook. Also, don’t forget to tag me when you try one of my recipes!

    + + + +
    veggie bowl with rice, beans, tomatoes, cheese, avocado and sour cream with avocado dressing drizzle
    + + +
    veggie bowl with rice, beans, tomatoes, cheese, avocado and sour cream with avocado dressing drizzle
    +
    +
    +

    Taco Bell Veggie Power Bowl {Copycat Recipe}

    +
    +
    An easy Mexican-inspired vegetable power bowl recipe ready in 10 minutes or less.
    +
    +
    No ratings yet
    +
    + Print + Pin + Rate + +
    +
    Course: Main Course
    Cuisine: Mexican
    +
    Prep Time: 5 minutes
    Cook Time: 5 minutes
    Total Time: 10 minutes
    +
    Servings: 2 servings
    +
    Calories: 484kcal
    +
    Author: Amee
    + +
    +

    Equipment

    • Microwave
    • small saucepan
    +

    Ingredients

    • For the bowls:
    • 1 cup canned black beans in seasoned sauce
    • 1 cup Spanish style ready rice
    • 4 cups lettuce finely chopped
    • 2 Roma tomatoes seeded and chopped
    • 2 oz cheddar cheese shredded-or try a three-cheese blend similar to the one Taco Bell uses, made with mozzarella, cheddar, and pepper jack cheese
    • ½ avocado sliced
    • 2 tbsp sour cream
    • For the avocado lime ranch dressing:
    • ½ ripe avocado
    • ½ cup plain non-fat Greek yogurt
    • 3 tbsp fresh lime juice
    • 1 tbsp ranch seasoning *in the packet
    • Optional bowl add-ins: onions, pickled jalapeños, salsa, pico de gallo
    +

    Instructions

    • Place the black beans in a small saucepan and heat on medium-low. Heat beans until simmering, while stirring.
    • While the beans are simmering, cook the seasoned rice in the microwave according to package directions, typically 90 seconds.
    • Divide the ingredients between 2 medium-size bowls.
    • Place the dressing ingredients into a small blender or food processor and blend until smooth.
    • Drizzle the dressing on top of the bowls and serve.
    +
    +

    Notes

    +
      +
    • To make homemade black beans, soak dried black beans in water overnight. Then, drain, rinse, and simmer them in a pot of water with Taco seasonings like onion, garlic, cumin, paprika, and bay leaves until they’re tender. Add salt to taste.
    • +
      +
    • To make Spanish rice from scratch, sauté onions and garlic in olive oil, then add uncooked rice and cook until lightly toasted. Then, add diced tomatoes, broth, and a blend of Spanish seasonings. Bring the mixture to a boil, reduce the heat, cover, and simmer until the rice is tender. Fluff with a fork and serve.
    • +
    +
    +

    Nutrition

    Calories: 484kcal | Carbohydrates: 55g | Protein: 22g | Fat: 21g | Saturated Fat: 7g | Polyunsaturated Fat: 2g | Monounsaturated Fat: 9g | Trans Fat: 0.01g | Cholesterol: 35mg | Sodium: 1343mg | Potassium: 1104mg | Fiber: 12g | Sugar: 8g | Vitamin A: 1653IU | Vitamin C: 27mg | Calcium: 369mg | Iron: 4mg
    +
    +
    Tried this recipe?Mention @ameecooks or tag #ameecooks!
    +
    +
    Amee Livingston
    Follow me
    Latest posts by Amee Livingston (see all)
    +
    +
    +
    + + + + + +
    +

    4 Comments

      +
    1. + +
    2. +
    3. + +
        +
      1. + +
          +
        1. +
          + + +
          +

          You can plug the recipe ingredients into an app, like My Fitness Pal, if you need calorie counts. I don’t do calorie counts on my recipes. I try to focus more on nutrient density and portion size.

          +
          + +
          +
        2. +
        +
      2. +
      +
    4. +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +

    +

    + +

    +
    +
    +
    + + +
    +
    +
    + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen.testhtml b/tests/test_data/americastestkitchen.com/americastestkitchen.testhtml deleted file mode 100644 index f698920be..000000000 --- a/tests/test_data/americastestkitchen.com/americastestkitchen.testhtml +++ /dev/null @@ -1,3705 +0,0 @@ - -Lasagna Bolognese, Simplified | America's Test Kitchen RecipeAmerica's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo

    Lasagna Bolognese, Simplified

    Could we adapt and simplify this northern Italian classic for the American kitchen?

    SERVES 8

    TIME 3 hours, plus 30 minutes cooling

    Lasagna Bolognese, Simplified

    Why This Recipe Works

    Print

    This is a members' feature.

    \ No newline at end of file diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen.json b/tests/test_data/americastestkitchen.com/americastestkitchen_1.json similarity index 83% rename from tests/test_data/americastestkitchen.com/americastestkitchen.json rename to tests/test_data/americastestkitchen.com/americastestkitchen_1.json index fd113faaf..ee74b3170 100644 --- a/tests/test_data/americastestkitchen.com/americastestkitchen.json +++ b/tests/test_data/americastestkitchen.com/americastestkitchen_1.json @@ -72,13 +72,36 @@ ], "category": "Main Courses, Casseroles", "yields": "8 servings", - "description": "Could we adapt and simplify this northern Italian classic for the American kitchen?", + "description": "Could we adapt and simplify this northern Italian classic for the American kitchen? When we started thinking about a simple lasagna Bolognese recipe, there was no denying the appeal of no-boil noodles. After several tests, we found that a five-minute soak proved most effective for getting sturdy, al dente noodles that bound together the layers of ragu and béchamel without soaking up all the moisture. Stumbling through multiple rounds of meat sauce testing gave us the idea of combining the ragu and béchamel when both were lukewarm. The resulting sauce was thickened but easy to spread, with enough moisture for cooking the noodles in our simplified lasagna recipe.", "total_time": 210, "cuisine": "Europe, Italian", "ratings": 4.4, - "ratings_count": 80, + "ratings_count": 98, "nutrients": { - "calories": "5764 calories" + "calories": "721", + "fatContent": "40 grams", + "saturatedFatContent": "20 grams", + "unsaturatedFatContent": "14 grams", + "transFatContent": "1 grams", + "carbohydrateContent": "39 grams", + "sugarContent": "13 grams", + "proteinContent": "39 grams", + "sodiumContent": "1165 miligrams", + "cholesterolContent": "119 miligrams" }, - "image": "https://res.cloudinary.com/hksqkdlah/image/upload/ar_1:1,c_fill,dpr_2.0,f_auto,fl_lossy.progressive.strip_profile,g_faces:auto,q_auto:low,w_150/3801_so04-lasagnabolognes-article" + "image": "https://res.cloudinary.com/hksqkdlah/image/upload/ar_1:1,c_fill,dpr_2.0,f_auto,fl_lossy.progressive.strip_profile,g_faces:auto,q_auto:low,w_150/3801_so04-lasagnabolognes-article", + "keywords": [ + "Main Courses", + "Europe", + "Italian", + "Pasta", + "Grains", + "Rice & Beans", + "Eggs & Dairy", + "Meat", + "Cheese", + "Beef", + "Pork", + "Casseroles" + ] } diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen_1.testhtml b/tests/test_data/americastestkitchen.com/americastestkitchen_1.testhtml new file mode 100644 index 000000000..28aae8941 --- /dev/null +++ b/tests/test_data/americastestkitchen.com/americastestkitchen_1.testhtml @@ -0,0 +1,3832 @@ + +Lasagna Bolognese, Simplified | America's Test Kitchen Recipe
    America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo

    Lasagna Bolognese, Simplified

    Could we adapt and simplify this northern Italian classic for the American kitchen?

    SERVES 8

    TIME 3 hours, plus 30 minutes cooling

    Lasagna Bolognese, Simplified

    Why This Recipe Works

    Gather Your Ingredients

    Meat Sauce (Ragù)
    Béchamel
    Noodles and Cheese

    Key Equipment

    Key Equipment - Food Processors
    Key Equipment - Dutch Ovens
    Key Equipment - All-Purpose Whisks

    Before You Begin

    *

    For assembly, both the meat sauce and the bechamel should be just warm to the touch, not piping hot. Both sauces can be made, cooled, and refrigerated up to 2 days ahead, then gently reheated until warm. In terms of flavor and texture, we find that Barilla no-boil noodles are the closest to fresh, but this recipe will work with all major brands of no-boil noodles.

    +

    Instructions

    1.

    For the meat sauce: Process carrot, celery, and onion in food processor until finely chopped, about ten 1-second pulses, scraping down bowl as necessary; transfer mixture to small bowl. Wipe out food processor workbowl; process tomatoes and juice until finely chopped, six to eight 1-second pulses. Heat butter in heavy-bottomed Dutch oven over medium heat until foaming; add carrot, celery, and onion and cook, stirring occasionally, until softened but not browned, about 4 minutes. Add ground meats and cook, breaking meat into 1-inch pieces with wooden spoon, about 1 minute. Add milk and stir, breaking meat into 1/2-inch bits; bring to simmer and cook, stirring to break meat into small pieces, until almost all liquid has evaporated, 20 to 30 minutes. Using potato masher or wooden spoon, break up any remaining clumps of meat (no large pieces should remain). Add wine and bring to simmer; cook, stirring occasionally, until liquid has evaporated, 20 to 30 minutes. Stir in tomato paste until combined, about 1 minute; add chopped tomatoes, salt, and pepper. Bring to simmer, then reduce heat to medium-low and cook until sauce is slightly thickened, about 15 minutes. (You should have about 6 cups meat sauce.) Transfer meat sauce to bowl and cool until just warm to touch, about 30 minutes.

    +

    2.

    For the béchamel: While meat sauce simmers, melt butter in medium saucepan over medium heat until foaming; add flour and cook, whisking constantly, until thoroughly combined, about 1 1/2 minutes; mixture should not brown. Gradually whisk in milk; increase heat to medium-high and bring to full boil, whisking frequently. Add salt, reduce heat to medium-low, and simmer 10 minutes, stirring occasionally with heatproof rubber spatula or wooden spoon, making sure to scrape bottom and corners of saucepan. (You should have about 3 1/3 cups.) Transfer béchamel to bowl and cool until just warm to touch, about 30 minutes.

    +

    3.

    To assemble and bake: Adjust oven rack to middle position; heat oven to 425 degrees. Place noodles in 13- by 9-inch baking dish and cover with very hot tap water; soak 5 minutes, agitating noodles occasionally to prevent sticking. Remove noodles from water, place in single layer on kitchen towel, and pat dry. Wipe out baking dish and spray lightly with nonstick cooking spray. Stir béchamel to recombine; mix 3/4 cup warm béchamel into warm meat sauce until thoroughly combined.

    +

    4.

    Distribute 1 cup béchamel-enriched meat sauce in baking dish. Place three noodles in single layer on top of sauce, arranging them close together, but not touching, at center of pan. Spread 1 1/4 cups béchamel-enriched meat sauce evenly over noodles, spreading sauce to edge of noodles but not to edge of dish (see illustration 1). Drizzle 1/3 cup béchamel evenly over meat sauce (illustration 2). Sprinkle 1/3 cup Parmesan evenly over béchamel. Repeat layering of noodles, béchamel-enriched meat sauce, bechamel, and cheese 3 more times. Place final 3 noodles on top and cover completely with remaining béchamel, spreading béchamel with rubber spatula and allowing it to spill over noodles (illustration 3). Sprinkle evenly with remaining Parmesan.

    +

    5.

    Spray large sheet foil with nonstick cooking spray and cover lasagna; bake until bubbling, about 30 minutes. Remove foil, increase heat to 450 degrees, and continue to bake until surface is spotty brown, about 15 minutes. Cool 15 minutes; cut into pieces and serve.

    +

    Test Kitchen Techniques

    FROM OUR TV SPONSORS

    We are thankful to the sponsors who make it possible for us to bring you the America's Test Kitchen TV series on public television. Read more about why we have sponsors.

    This is a members' feature.

    America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo \ No newline at end of file diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen_2.json b/tests/test_data/americastestkitchen.com/americastestkitchen_2.json new file mode 100644 index 000000000..ee74b3170 --- /dev/null +++ b/tests/test_data/americastestkitchen.com/americastestkitchen_2.json @@ -0,0 +1,107 @@ +{ + "author": "America's Test Kitchen", + "canonical_url": "https://www.americastestkitchen.com/recipes/1629-lasagna-bolognese-simplified", + "site_name": "America's Test Kitchen", + "host": "americastestkitchen.com", + "language": "en", + "title": "Lasagna Bolognese, Simplified", + "ingredients": [ + "1 medium carrot, peeled and roughly chopped", + "1 medium rib celery, roughly chopped", + "1/2 small onion, roughly chopped", + "1 (28 ounce) can whole tomatoes with juice", + "2 tablespoons unsalted butter", + "8 ounces ground beef, preferably 90 percent lean", + "8 ounces ground pork", + "8 ounces ground veal", + "1 1/2 cups whole milk", + "1 1/2 cups dry white wine", + "2 tablespoons tomato paste", + "1 teaspoon table salt", + "1/4 teaspoon ground black pepper", + "4 tablespoons unsalted butter", + "1/4 cup unbleached all-purpose flour", + "4 cups whole milk", + "3/4 teaspoon table salt", + "15 sheets no-boil lasagna noodle (9 ounces)", + "4 ounces Parmesan cheese, grated (2 cups)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 medium carrot, peeled and roughly chopped", + "1 medium rib celery, roughly chopped", + "1/2 small onion, roughly chopped", + "1 (28 ounce) can whole tomatoes with juice", + "2 tablespoons unsalted butter", + "8 ounces ground beef, preferably 90 percent lean", + "8 ounces ground pork", + "8 ounces ground veal", + "1 1/2 cups whole milk", + "1 1/2 cups dry white wine", + "2 tablespoons tomato paste", + "1 teaspoon table salt", + "1/4 teaspoon ground black pepper" + ], + "purpose": "Meat Sauce (Ragù)" + }, + { + "ingredients": [ + "4 tablespoons unsalted butter", + "1/4 cup unbleached all-purpose flour", + "4 cups whole milk", + "3/4 teaspoon table salt" + ], + "purpose": "Béchamel" + }, + { + "ingredients": [ + "15 sheets no-boil lasagna noodle (9 ounces)", + "4 ounces Parmesan cheese, grated (2 cups)" + ], + "purpose": "Noodles and Cheese" + } + ], + "instructions_list": [ + "Note: For assembly, both the meat sauce and the bechamel should be just warm to the touch, not piping hot. Both sauces can be made, cooled, and refrigerated up to 2 days ahead, then gently reheated until warm. In terms of flavor and texture, we find that Barilla no-boil noodles are the closest to fresh, but this recipe will work with all major brands of no-boil noodles.", + "For the meat sauce: Process carrot, celery, and onion in food processor until finely chopped, about ten 1-second pulses, scraping down bowl as necessary; transfer mixture to small bowl. Wipe out food processor workbowl; process tomatoes and juice until finely chopped, six to eight 1-second pulses. Heat butter in heavy-bottomed Dutch oven over medium heat until foaming; add carrot, celery, and onion and cook, stirring occasionally, until softened but not browned, about 4 minutes. Add ground meats and cook, breaking meat into 1-inch pieces with wooden spoon, about 1 minute. Add milk and stir, breaking meat into 1/2-inch bits; bring to simmer and cook, stirring to break meat into small pieces, until almost all liquid has evaporated, 20 to 30 minutes. Using potato masher or wooden spoon, break up any remaining clumps of meat (no large pieces should remain). Add wine and bring to simmer; cook, stirring occasionally, until liquid has evaporated, 20 to 30 minutes. Stir in tomato paste until combined, about 1 minute; add chopped tomatoes, salt, and pepper. Bring to simmer, then reduce heat to medium-low and cook until sauce is slightly thickened, about 15 minutes. (You should have about 6 cups meat sauce.) Transfer meat sauce to bowl and cool until just warm to touch, about 30 minutes.", + "For the béchamel: While meat sauce simmers, melt butter in medium saucepan over medium heat until foaming; add flour and cook, whisking constantly, until thoroughly combined, about 1 1/2 minutes; mixture should not brown. Gradually whisk in milk; increase heat to medium-high and bring to full boil, whisking frequently. Add salt, reduce heat to medium-low, and simmer 10 minutes, stirring occasionally with heatproof rubber spatula or wooden spoon, making sure to scrape bottom and corners of saucepan. (You should have about 3 1/3 cups.) Transfer béchamel to bowl and cool until just warm to touch, about 30 minutes.", + "To assemble and bake: Adjust oven rack to middle position; heat oven to 425 degrees. Place noodles in 13- by 9-inch baking dish and cover with very hot tap water; soak 5 minutes, agitating noodles occasionally to prevent sticking. Remove noodles from water, place in single layer on kitchen towel, and pat dry. Wipe out baking dish and spray lightly with nonstick cooking spray. Stir béchamel to recombine; mix 3/4 cup warm béchamel into warm meat sauce until thoroughly combined.", + "Distribute 1 cup béchamel-enriched meat sauce in baking dish. Place three noodles in single layer on top of sauce, arranging them close together, but not touching, at center of pan. Spread 1 1/4 cups béchamel-enriched meat sauce evenly over noodles, spreading sauce to edge of noodles but not to edge of dish (see illustration 1). Drizzle 1/3 cup béchamel evenly over meat sauce (illustration 2). Sprinkle 1/3 cup Parmesan evenly over béchamel. Repeat layering of noodles, béchamel-enriched meat sauce, bechamel, and cheese 3 more times. Place final 3 noodles on top and cover completely with remaining béchamel, spreading béchamel with rubber spatula and allowing it to spill over noodles (illustration 3). Sprinkle evenly with remaining Parmesan.", + "Spray large sheet foil with nonstick cooking spray and cover lasagna; bake until bubbling, about 30 minutes. Remove foil, increase heat to 450 degrees, and continue to bake until surface is spotty brown, about 15 minutes. Cool 15 minutes; cut into pieces and serve." + ], + "category": "Main Courses, Casseroles", + "yields": "8 servings", + "description": "Could we adapt and simplify this northern Italian classic for the American kitchen? When we started thinking about a simple lasagna Bolognese recipe, there was no denying the appeal of no-boil noodles. After several tests, we found that a five-minute soak proved most effective for getting sturdy, al dente noodles that bound together the layers of ragu and béchamel without soaking up all the moisture. Stumbling through multiple rounds of meat sauce testing gave us the idea of combining the ragu and béchamel when both were lukewarm. The resulting sauce was thickened but easy to spread, with enough moisture for cooking the noodles in our simplified lasagna recipe.", + "total_time": 210, + "cuisine": "Europe, Italian", + "ratings": 4.4, + "ratings_count": 98, + "nutrients": { + "calories": "721", + "fatContent": "40 grams", + "saturatedFatContent": "20 grams", + "unsaturatedFatContent": "14 grams", + "transFatContent": "1 grams", + "carbohydrateContent": "39 grams", + "sugarContent": "13 grams", + "proteinContent": "39 grams", + "sodiumContent": "1165 miligrams", + "cholesterolContent": "119 miligrams" + }, + "image": "https://res.cloudinary.com/hksqkdlah/image/upload/ar_1:1,c_fill,dpr_2.0,f_auto,fl_lossy.progressive.strip_profile,g_faces:auto,q_auto:low,w_150/3801_so04-lasagnabolognes-article", + "keywords": [ + "Main Courses", + "Europe", + "Italian", + "Pasta", + "Grains", + "Rice & Beans", + "Eggs & Dairy", + "Meat", + "Cheese", + "Beef", + "Pork", + "Casseroles" + ] +} diff --git a/tests/test_data/americastestkitchen.com/americastestkitchen_2.testhtml b/tests/test_data/americastestkitchen.com/americastestkitchen_2.testhtml new file mode 100644 index 000000000..28aae8941 --- /dev/null +++ b/tests/test_data/americastestkitchen.com/americastestkitchen_2.testhtml @@ -0,0 +1,3832 @@ + +Lasagna Bolognese, Simplified | America's Test Kitchen Recipe
    America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo

    Lasagna Bolognese, Simplified

    Could we adapt and simplify this northern Italian classic for the American kitchen?

    SERVES 8

    TIME 3 hours, plus 30 minutes cooling

    Lasagna Bolognese, Simplified

    Why This Recipe Works

    Gather Your Ingredients

    Meat Sauce (Ragù)
    Béchamel
    Noodles and Cheese

    Key Equipment

    Key Equipment - Food Processors
    Key Equipment - Dutch Ovens
    Key Equipment - All-Purpose Whisks

    Before You Begin

    *

    For assembly, both the meat sauce and the bechamel should be just warm to the touch, not piping hot. Both sauces can be made, cooled, and refrigerated up to 2 days ahead, then gently reheated until warm. In terms of flavor and texture, we find that Barilla no-boil noodles are the closest to fresh, but this recipe will work with all major brands of no-boil noodles.

    +

    Instructions

    1.

    For the meat sauce: Process carrot, celery, and onion in food processor until finely chopped, about ten 1-second pulses, scraping down bowl as necessary; transfer mixture to small bowl. Wipe out food processor workbowl; process tomatoes and juice until finely chopped, six to eight 1-second pulses. Heat butter in heavy-bottomed Dutch oven over medium heat until foaming; add carrot, celery, and onion and cook, stirring occasionally, until softened but not browned, about 4 minutes. Add ground meats and cook, breaking meat into 1-inch pieces with wooden spoon, about 1 minute. Add milk and stir, breaking meat into 1/2-inch bits; bring to simmer and cook, stirring to break meat into small pieces, until almost all liquid has evaporated, 20 to 30 minutes. Using potato masher or wooden spoon, break up any remaining clumps of meat (no large pieces should remain). Add wine and bring to simmer; cook, stirring occasionally, until liquid has evaporated, 20 to 30 minutes. Stir in tomato paste until combined, about 1 minute; add chopped tomatoes, salt, and pepper. Bring to simmer, then reduce heat to medium-low and cook until sauce is slightly thickened, about 15 minutes. (You should have about 6 cups meat sauce.) Transfer meat sauce to bowl and cool until just warm to touch, about 30 minutes.

    +

    2.

    For the béchamel: While meat sauce simmers, melt butter in medium saucepan over medium heat until foaming; add flour and cook, whisking constantly, until thoroughly combined, about 1 1/2 minutes; mixture should not brown. Gradually whisk in milk; increase heat to medium-high and bring to full boil, whisking frequently. Add salt, reduce heat to medium-low, and simmer 10 minutes, stirring occasionally with heatproof rubber spatula or wooden spoon, making sure to scrape bottom and corners of saucepan. (You should have about 3 1/3 cups.) Transfer béchamel to bowl and cool until just warm to touch, about 30 minutes.

    +

    3.

    To assemble and bake: Adjust oven rack to middle position; heat oven to 425 degrees. Place noodles in 13- by 9-inch baking dish and cover with very hot tap water; soak 5 minutes, agitating noodles occasionally to prevent sticking. Remove noodles from water, place in single layer on kitchen towel, and pat dry. Wipe out baking dish and spray lightly with nonstick cooking spray. Stir béchamel to recombine; mix 3/4 cup warm béchamel into warm meat sauce until thoroughly combined.

    +

    4.

    Distribute 1 cup béchamel-enriched meat sauce in baking dish. Place three noodles in single layer on top of sauce, arranging them close together, but not touching, at center of pan. Spread 1 1/4 cups béchamel-enriched meat sauce evenly over noodles, spreading sauce to edge of noodles but not to edge of dish (see illustration 1). Drizzle 1/3 cup béchamel evenly over meat sauce (illustration 2). Sprinkle 1/3 cup Parmesan evenly over béchamel. Repeat layering of noodles, béchamel-enriched meat sauce, bechamel, and cheese 3 more times. Place final 3 noodles on top and cover completely with remaining béchamel, spreading béchamel with rubber spatula and allowing it to spill over noodles (illustration 3). Sprinkle evenly with remaining Parmesan.

    +

    5.

    Spray large sheet foil with nonstick cooking spray and cover lasagna; bake until bubbling, about 30 minutes. Remove foil, increase heat to 450 degrees, and continue to bake until surface is spotty brown, about 15 minutes. Cool 15 minutes; cut into pieces and serve.

    +

    Test Kitchen Techniques

    FROM OUR TV SPONSORS

    We are thankful to the sponsors who make it possible for us to bring you the America's Test Kitchen TV series on public television. Read more about why we have sponsors.

    This is a members' feature.

    America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo \ No newline at end of file diff --git a/tests/test_data/argiro.gr/argiro.json b/tests/test_data/argiro.gr/argiro.json index 3d0881aa9..47a2f6767 100644 --- a/tests/test_data/argiro.gr/argiro.json +++ b/tests/test_data/argiro.gr/argiro.json @@ -54,5 +54,10 @@ "cook_time": 75, "prep_time": 30, "cuisine": "Ελληνική Κουζίνα", + "ratings": 5.0, + "ratings_count": 6418, + "nutrients": { + "calories": "468 Θερμίδες" + }, "image": "https://www.argiro.gr/wp-content/uploads/2023/08/gemista-400x400.jpg?v=1715951925" } diff --git a/tests/test_data/biancazapatka.com/biancazapatka_2.json b/tests/test_data/biancazapatka.com/biancazapatka_2.json index aa6d14ee4..63a1f18da 100644 --- a/tests/test_data/biancazapatka.com/biancazapatka_2.json +++ b/tests/test_data/biancazapatka.com/biancazapatka_2.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "The Best Vegan Blueberry Cake", "ingredients": [ - "1 cup soy milk (or other plant milk, *see notes))", + "1 cup soy milk (or other plant milk, *see notes)", "juice of 1 lemon (approx. ¼ cup lemon juice)", "½ cup vegetable oil (e.g. canola or sunflower or butter-flavored Alba oil)", "1 tsp vanilla extract (or ground bourbon vanilla or the pulp of a vanilla bean)", @@ -30,7 +30,7 @@ "ingredient_groups": [ { "ingredients": [ - "1 cup soy milk (or other plant milk, *see notes))", + "1 cup soy milk (or other plant milk, *see notes)", "juice of 1 lemon (approx. ¼ cup lemon juice)", "½ cup vegetable oil (e.g. canola or sunflower or butter-flavored Alba oil)", "1 tsp vanilla extract (or ground bourbon vanilla or the pulp of a vanilla bean)", diff --git a/tests/test_data/bitsofcarey.com/bitsofcarey_1.json b/tests/test_data/bitsofcarey.com/bitsofcarey_1.json index 1f034bc3f..ebbc0d3ae 100644 --- a/tests/test_data/bitsofcarey.com/bitsofcarey_1.json +++ b/tests/test_data/bitsofcarey.com/bitsofcarey_1.json @@ -6,11 +6,11 @@ "language": "en-ZA", "title": "Asian Style Sweetcorn Fritters", "ingredients": [ - "2 cups (260 g) sweetcorn (canned (drained) or frozen (thawed))", + "2 cups (260 g) sweetcorn (canned (drained) or frozen (thawed)", "2 spring onions (finely chopped)", "½ cup fresh coriander (chopped)", "¼ cup mint leaves (chopped)", - "1 ½ tsp sambal oelek ((Garlic chilli paste))", + "1 ½ tsp sambal oelek (Garlic chilli paste)", "1 lime (zest of)", "salt and pepper (to taste)", "½ cup (65 g) all purpose flour", diff --git a/tests/test_data/bitsofcarey.com/bitsofcarey_2.json b/tests/test_data/bitsofcarey.com/bitsofcarey_2.json index 766900b7d..4fed8d6c7 100644 --- a/tests/test_data/bitsofcarey.com/bitsofcarey_2.json +++ b/tests/test_data/bitsofcarey.com/bitsofcarey_2.json @@ -11,9 +11,9 @@ "½ tsp coarse black pepper (ground)", "1 egg (large)", "45 ml milk", - "¾ c (180 ml) yellow cornmeal ((fine polenta))", + "¾ c (180 ml) yellow cornmeal (fine polenta)", "¾ c (180 ml) parmesan (finely grated)", - "½ c (125 ml) almond meal ((finely ground almonds))", + "½ c (125 ml) almond meal (finely ground almonds)", "½ tsp (2.5 ml) coarse salt (ground)", "½ tsp (2.5 ml) coarse black pepper (ground)", "1 tsp (5 ml) dried rosemary", @@ -34,9 +34,9 @@ }, { "ingredients": [ - "¾ c (180 ml) yellow cornmeal ((fine polenta))", + "¾ c (180 ml) yellow cornmeal (fine polenta)", "¾ c (180 ml) parmesan (finely grated)", - "½ c (125 ml) almond meal ((finely ground almonds))", + "½ c (125 ml) almond meal (finely ground almonds)", "½ tsp (2.5 ml) coarse salt (ground)", "½ tsp (2.5 ml) coarse black pepper (ground)", "1 tsp (5 ml) dried rosemary", diff --git a/tests/test_data/bluejeanchef.com/bluejeanchef_1.json b/tests/test_data/bluejeanchef.com/bluejeanchef_1.json index b45ac062f..fbd4a6e00 100644 --- a/tests/test_data/bluejeanchef.com/bluejeanchef_1.json +++ b/tests/test_data/bluejeanchef.com/bluejeanchef_1.json @@ -7,7 +7,7 @@ "title": "Chicken Tortilla Soup", "ingredients": [ "2 tablespoons olive oil", - "1 onion (finely diced (about 1 cup))", + "1 onion (finely diced (about 1 cup)", "2 cloves garlic (minced)", "1 Jalapeño pepper (minced or sliced into rings)", "1 red bell pepper (chopped)", diff --git a/tests/test_data/bowlofdelicious.com/bowlofdelicious.json b/tests/test_data/bowlofdelicious.com/bowlofdelicious.json index 52924f5b4..a68796ae1 100644 --- a/tests/test_data/bowlofdelicious.com/bowlofdelicious.json +++ b/tests/test_data/bowlofdelicious.com/bowlofdelicious.json @@ -6,15 +6,15 @@ "language": "en-US", "title": "Six-Minute Seared Ahi Tuna Steaks", "ingredients": [ - "2 ahi tuna (yellowfin tuna) steaks ((about 4 oz. each, 1\" thick - see notes for thinner or thicker))", + "2 ahi tuna (yellowfin tuna) steaks (about 4 oz. each, 1\" thick - see notes for thinner or thicker)", "2 tablespoons soy sauce", "1 tablespoon toasted sesame oil (see notes)", "1 tablespoon honey (see notes)", "1/2 teaspoon kosher salt", "1/4 teaspoon black pepper (to taste)", - "1/4 teaspoon cayenne pepper ((optional))", + "1/4 teaspoon cayenne pepper (optional)", "1 tablespoon canola oil (or olive oil)", - "green onions, toasted sesame seeds, and lime wedges (for serving (optional))" + "green onions, toasted sesame seeds, and lime wedges (for serving (optional)" ], "instructions_list": [ "Pat the ahi tuna steaks dry with a paper towel. Place on a plate or inside a plastic bag.", diff --git a/tests/test_data/brokenovenbaking.com/brokenovenbaking_1.json b/tests/test_data/brokenovenbaking.com/brokenovenbaking_1.json index a68de131a..6ff2acc93 100644 --- a/tests/test_data/brokenovenbaking.com/brokenovenbaking_1.json +++ b/tests/test_data/brokenovenbaking.com/brokenovenbaking_1.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Easy Homemade Strawberry Muffins", "ingredients": [ - "2¼ cups all-purpose flour (divided (weighed in grams for best results))", + "2¼ cups all-purpose flour (divided (weighed in grams for best results)", "2 teaspoons baking powder", "½ teaspoon salt", "½ cup vegetable oil (or other neutral oil)", diff --git a/tests/test_data/cafedelites.com/cafedelites_1.json b/tests/test_data/cafedelites.com/cafedelites_1.json index cc0f8c4e4..51725b5c1 100644 --- a/tests/test_data/cafedelites.com/cafedelites_1.json +++ b/tests/test_data/cafedelites.com/cafedelites_1.json @@ -8,13 +8,13 @@ "ingredients": [ "1/2 cup sugar", "1/2 teaspoon ground cinnamon", - "4 oz. butter, ((125g or 1/2 cup))", - "1 cup + 2 tablespoons water ((280ml))", + "4 oz. butter, (125g or 1/2 cup)", + "1 cup + 2 tablespoons water (280ml)", "2 tablespoons white granulated sugar", "1 teaspoon pure vanilla extract", "3/4 teaspoon ground cinnamon", "1/2 teaspoon salt", - "1 1/4 cups all-purpose or plain flour, ((6.3oz | 180g))", + "1 1/4 cups all-purpose or plain flour, (6.3oz | 180g)", "2 large eggs, (at room temperature)" ], "ingredient_groups": [ @@ -27,13 +27,13 @@ }, { "ingredients": [ - "4 oz. butter, ((125g or 1/2 cup))", - "1 cup + 2 tablespoons water ((280ml))", + "4 oz. butter, (125g or 1/2 cup)", + "1 cup + 2 tablespoons water (280ml)", "2 tablespoons white granulated sugar", "1 teaspoon pure vanilla extract", "3/4 teaspoon ground cinnamon", "1/2 teaspoon salt", - "1 1/4 cups all-purpose or plain flour, ((6.3oz | 180g))", + "1 1/4 cups all-purpose or plain flour, (6.3oz | 180g)", "2 large eggs, (at room temperature)" ], "purpose": "CHURROS" diff --git a/tests/test_data/cafedelites.com/cafedelites_2.json b/tests/test_data/cafedelites.com/cafedelites_2.json index 9fd0b57fb..134e5d197 100644 --- a/tests/test_data/cafedelites.com/cafedelites_2.json +++ b/tests/test_data/cafedelites.com/cafedelites_2.json @@ -6,12 +6,12 @@ "language": "en-US", "title": "Easy Creamy Mashed Potatoes", "ingredients": [ - "2 pounds (1kg) potatoes, ((Russet, Yukon Gold, Dutch Creams, Creme Gold, Creme Royale))", + "2 pounds (1kg) potatoes, (Russet, Yukon Gold, Dutch Creams, Creme Gold, Creme Royale)", "1 teaspoon salt", "1/2 cup hot milk, (or more)", - "1/3 cup unsalted butter, (softened (close to room temp is best))", + "1/3 cup unsalted butter, (softened (close to room temp is best)", "6-8 cloves fresh garlic (finely chopped)", - "1/4 cup sour cream ((reduced fat))", + "1/4 cup sour cream (reduced fat)", "1/4 cup fresh shredded parmesan cheese, (optional)", "Salt and Pepper, (to taste)", "1 tablespoon fresh chopped parsley to garnish, (optional to garnish)" diff --git a/tests/test_data/carlsbadcravings.com/carlsbadcravings_2.json b/tests/test_data/carlsbadcravings.com/carlsbadcravings_2.json index 431c2fdf6..0bce8b886 100644 --- a/tests/test_data/carlsbadcravings.com/carlsbadcravings_2.json +++ b/tests/test_data/carlsbadcravings.com/carlsbadcravings_2.json @@ -13,7 +13,7 @@ "2 tablespoons honey", "1/4 tsp EACH ground ginger, ground cinnamon, salt, dried thyme, dried rosemary", "1/8 teaspoon pepper", - "1/2 cup Cranberry Pistachio Coating mixture ((in directions))", + "1/2 cup Cranberry Pistachio Coating mixture (in directions)", "honey" ], "ingredient_groups": [ @@ -31,7 +31,7 @@ "2 tablespoons honey", "1/4 tsp EACH ground ginger, ground cinnamon, salt, dried thyme, dried rosemary", "1/8 teaspoon pepper", - "1/2 cup Cranberry Pistachio Coating mixture ((in directions))" + "1/2 cup Cranberry Pistachio Coating mixture (in directions)" ], "purpose": "Cheese Log" }, diff --git a/tests/test_data/castironketo.net/castironketo.json b/tests/test_data/castironketo.net/castironketo.json index b5a4c28b8..c7cbbe518 100644 --- a/tests/test_data/castironketo.net/castironketo.json +++ b/tests/test_data/castironketo.net/castironketo.json @@ -14,7 +14,7 @@ "8 ounces cream cheese (softened)", "½ cup heavy cream", "¼ cup chicken broth", - "5 jalapeno peppers (halved (ribs removed if you like less spice))", + "5 jalapeno peppers (halved (ribs removed if you like less spice)", "1 cup shredded sharp cheddar cheese", "6 slices bacon (cooked and crumbled)" ], diff --git a/tests/test_data/celebratingsweets.com/celebratingsweets_1.json b/tests/test_data/celebratingsweets.com/celebratingsweets_1.json index 8b9870690..83d1e8159 100644 --- a/tests/test_data/celebratingsweets.com/celebratingsweets_1.json +++ b/tests/test_data/celebratingsweets.com/celebratingsweets_1.json @@ -15,7 +15,7 @@ "6 ounces raspberries", "6 ounces blackberries", "6 ounces blueberries", - "1/2 cup raspberry or strawberry jam (heated just enough to make it pourable (not hot))" + "1/2 cup raspberry or strawberry jam (heated just enough to make it pourable (not hot)" ], "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.", diff --git a/tests/test_data/chefsavvy.com/chefsavvy.json b/tests/test_data/chefsavvy.com/chefsavvy.json index 68c370677..e88b7d5d6 100644 --- a/tests/test_data/chefsavvy.com/chefsavvy.json +++ b/tests/test_data/chefsavvy.com/chefsavvy.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Slow Cooker Broccoli Beef", "ingredients": [ - "2 pounds chuck steak (sliced thin (about 1-inch thick))", + "2 pounds chuck steak (sliced thin (about 1-inch thick)", "1 cup low sodium beef broth", "1/2 cup low sodium soy sauce", "4 garlic cloves (minced)", diff --git a/tests/test_data/cookingwithjanica.com/cookingwithjanica_1.json b/tests/test_data/cookingwithjanica.com/cookingwithjanica_1.json new file mode 100644 index 000000000..a33b886c8 --- /dev/null +++ b/tests/test_data/cookingwithjanica.com/cookingwithjanica_1.json @@ -0,0 +1,34 @@ +{ + "author": "Jessica Pinney", + "canonical_url": "https://cookingwithjanica.com/air-fryer-breakfast-potatoes/", + "site_name": "Cooking With Janica", + "host": "cookingwithjanica.com", + "language": "en-US", + "title": "Air Fryer Breakfast Potatoes", + "ingredients": [ + "2 lbs gold or russet potatoes", + "1 teaspoon paprika", + "1 teaspoon garlic powder", + "1 teaspoon onion powder", + "Salt and black pepper to taste", + "2 tablespoons oil (EVOO, avocado, canola, etc.)" + ], + "instructions_list": [ + "Preheat your air fryer to 385°F.", + "Wash your potatoes thoroughly. Using a sharp knife, dice them into 1-inch cubes.", + "Place the potatoes in a large bowl. Sprinkle paprika, garlic powder, onion powder, salt, pepper, and oil on top. Mix gently until well combined.", + "Place the seasoned potatoes in the air fryer basket in a single layer. Air fry for a cooking time of 15-20 minutes or until they turn golden brown. (I recommend shaking the basket halfway through to ensure they cook evenly.)" + ], + "category": "Breakfast", + "yields": "4 servings", + "description": "Crispy breakfast potatoes made in the air fryer.", + "total_time": 25, + "cook_time": 15, + "prep_time": 10, + "cuisine": "American", + "image": "https://cookingwithjanica.com/wp-content/uploads/2023/04/air_fryer_breakfast_potatoes.jpg", + "keywords": [ + "breakfast in air fryer", + "easy breakfast potatoes" + ] +} diff --git a/tests/test_data/cookingwithjanica.com/cookingwithjanica_1.testhtml b/tests/test_data/cookingwithjanica.com/cookingwithjanica_1.testhtml new file mode 100644 index 000000000..e93b0cbba --- /dev/null +++ b/tests/test_data/cookingwithjanica.com/cookingwithjanica_1.testhtml @@ -0,0 +1,2574 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Air Fryer Breakfast Potatoes - Cooking With Janica + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + + + + + +
    + + + + +
    +
    + +
    + +
    + +
    + About +
    + + + +
    + Contact +
    + + + + + + + + + +
    + + + +

    © All Rights Reserved. Design inspired by MRD. Theme by OC.

    + +
    + +
    + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/cookingwithjanica.com/cookingwithjanica_2.json b/tests/test_data/cookingwithjanica.com/cookingwithjanica_2.json new file mode 100644 index 000000000..7287cfa82 --- /dev/null +++ b/tests/test_data/cookingwithjanica.com/cookingwithjanica_2.json @@ -0,0 +1,113 @@ +{ + "author": "Jessica Pinney", + "canonical_url": "https://cookingwithjanica.com/christmas-dessert-dip-platter-chocolate-wavy-lays/", + "site_name": "Cooking With Janica", + "host": "cookingwithjanica.com", + "language": "en-US", + "title": "Christmas Dessert Dip Platter", + "ingredients": [ + "1 Stick Unsalted Butter", + "8 oz Cream Cheese", + "1/4 Cup Brown Sugar", + "1/3 Cup White Sugar", + "2 Teaspoons Vanilla Extract", + "1/2 Tsp Salt", + "1 1/2 Cups Chocolate Chips", + "Sprinkles (for garnish)", + "1 8- ounce package cream cheese (softened)", + "¼ cup brown sugar", + "¼ cup powdered sugar (sifted)", + "3 Tablespoons molasses", + "1 teaspoon ground ginger", + "1 teaspoon ground cinnamon", + "dash nutmeg", + "Sprinkles (for garnish)", + "8 oz Marshmallow Fluff", + "8 oz Cream Cheese", + "1 tsp Peppermint Extract", + "1/4 Cup Crushed Candy Canes", + "Milk Chocolate Wavy Lays", + "Dark Chocolate Wavy Lays", + "Milk Chocolate Wavy Lays Covered with Almond Bits" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 Stick Unsalted Butter", + "8 oz Cream Cheese", + "1/4 Cup Brown Sugar", + "1/3 Cup White Sugar", + "2 Teaspoons Vanilla Extract", + "1/2 Tsp Salt", + "1 1/2 Cups Chocolate Chips", + "Sprinkles (for garnish)" + ], + "purpose": "Christmas Cookie Dough Dip Ingredients" + }, + { + "ingredients": [ + "1 8- ounce package cream cheese (softened)", + "¼ cup brown sugar", + "¼ cup powdered sugar (sifted)", + "3 Tablespoons molasses", + "1 teaspoon ground ginger", + "1 teaspoon ground cinnamon", + "dash nutmeg", + "Sprinkles (for garnish)" + ], + "purpose": "Cream Cheese Gingerbread Dip Ingredients" + }, + { + "ingredients": [ + "8 oz Marshmallow Fluff", + "8 oz Cream Cheese", + "1 tsp Peppermint Extract", + "1/4 Cup Crushed Candy Canes" + ], + "purpose": "Peppermint Fluff Dip Ingredients" + }, + { + "ingredients": [ + "Milk Chocolate Wavy Lays", + "Dark Chocolate Wavy Lays", + "Milk Chocolate Wavy Lays Covered with Almond Bits" + ], + "purpose": "For Dipping" + } + ], + "instructions_list": [ + "Christmas Cookie Dough Dip Recipe", + "Add the butter, cream cheese, and sugars to a medium bowl. Cream for 2-3 minutes with a hand mixer.", + "Add vanilla and salt. Mix another minute.", + "Add chocolate chips and mix until just combined.", + "Transfer to a serving bowl and garnish with sprinkles.", + "Cream Cheese Gingerbread Dip Recipe", + "Beat the cream cheese 1-2 minutes, until smooth.", + "Add the rest of the ingredients and beat until well combined.", + "Transfer to serving bowl and garnish with sprinkles.", + "Peppermint Fluff Dip Recipe", + "Add cream cheese, marshmallow cream, and peppermint extract to a medium bowl. Beat with a hand mixer until well combined.", + "Add crushed candy canes & red food coloring. Mix until incorporated.", + "Transfer to serving bowl and top with additional crushed candy canes.", + "Platter Assembly", + "Place all serving bowls on a platter. Place Chocolate Wavy Lay's in empty space around serving bowls.", + "Serve immediately. Store leftovers in airtight containers in the fridge." + ], + "category": "Dessert", + "yields": "15 servings", + "description": "Three Christmas dessert dips served with chocolate-covered potato chips.", + "total_time": 15, + "prep_time": 15, + "cuisine": "American", + "ratings": 5.0, + "ratings_count": 2, + "nutrients": { + "servingSize": "1 serving", + "calories": "529 kcal" + }, + "image": "https://cookingwithjanica.com/wp-content/uploads/2016/12/christmas_dessert_dip_trio_recipe_lays_chocolate_chips.jpg", + "keywords": [ + "christmas dessert", + "dessert dips" + ] +} diff --git a/tests/test_data/cookingwithjanica.com/cookingwithjanica_2.testhtml b/tests/test_data/cookingwithjanica.com/cookingwithjanica_2.testhtml new file mode 100644 index 000000000..e99799ed9 --- /dev/null +++ b/tests/test_data/cookingwithjanica.com/cookingwithjanica_2.testhtml @@ -0,0 +1,2600 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Christmas Dessert Dip Platter with Chocolate Potato Chips + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + + + + + +
    + + + + + +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/cookscountry.com/cookscountry.json b/tests/test_data/cookscountry.com/cookscountry.json index 34ed1b6b2..10e857bf0 100644 --- a/tests/test_data/cookscountry.com/cookscountry.json +++ b/tests/test_data/cookscountry.com/cookscountry.json @@ -73,7 +73,7 @@ "total_time": 75, "cuisine": "Latin America & Caribbean, Mexican", "ratings": 4.2, - "ratings_count": 39, + "ratings_count": 56, "nutrients": { "calories": "687", "fatContent": "31 grams", diff --git a/tests/test_data/cookscountry.com/cookscountry.testhtml b/tests/test_data/cookscountry.com/cookscountry.testhtml index be399ece8..d1f084652 100644 --- a/tests/test_data/cookscountry.com/cookscountry.testhtml +++ b/tests/test_data/cookscountry.com/cookscountry.testhtml @@ -15,3203 +15,44 @@ j.async=true;j.src='//www.googletagmanager.com/gtm.js?id='+i+dl ; f.parentNode.insertBefore(j,f); - })(window,document,'script','dataLayer','GTM-MFMR9K');America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo \ No newline at end of file diff --git a/tests/test_data/cooksillustrated.com/cooksillustrated.json b/tests/test_data/cooksillustrated.com/cooksillustrated.json index 582c6db67..aeb86b2c8 100644 --- a/tests/test_data/cooksillustrated.com/cooksillustrated.json +++ b/tests/test_data/cooksillustrated.com/cooksillustrated.json @@ -21,8 +21,8 @@ "description": "Whisk butter into a little simmering water and—poof!—you've got beurre monté: liquid silk that pairs with any seasoning and gilds everything it touches. Beurre monté, emulsified melted butter, is a classic French preparation that can be drizzled over cooked meats, vegetables, pastas, and other dishes to add richness and a glossy appearance or used as a rich, creamy sauce base for pairing with a wide range of savory or sweet seasonings. Vigorously whisking cold butter into a measured amount of simmering water broke up the butterfat into tiny droplets that dispersed throughout the water, establishing a thick, creamy emulsion. Whisking oyster sauce plus orange zest and juice into the beurre monté produced a bold, rich, easy-to-make sauce that paired especially well with lean roasted or pan-seared proteins such as scallops, cod, pork tenderloin, or chicken breast; it was also great over pasta.", "total_time": 10, "cuisine": "French", - "ratings": 4.5, - "ratings_count": 26, + "ratings": 4.2, + "ratings_count": 44, "nutrients": { "calories": "207", "fatContent": "23 grams", diff --git a/tests/test_data/cooksillustrated.com/cooksillustrated.testhtml b/tests/test_data/cooksillustrated.com/cooksillustrated.testhtml index 0f6a57b99..83dd8e5b5 100644 --- a/tests/test_data/cooksillustrated.com/cooksillustrated.testhtml +++ b/tests/test_data/cooksillustrated.com/cooksillustrated.testhtml @@ -15,3203 +15,44 @@ j.async=true;j.src='//www.googletagmanager.com/gtm.js?id='+i+dl ; f.parentNode.insertBefore(j,f); - })(window,document,'script','dataLayer','GTM-MFMR9K');America's Test Kitchen LogoCook's Country LogoCook's Illustrated Logo \ No newline at end of file diff --git a/tests/test_data/cookwell.com/cookwell_1.json b/tests/test_data/cookwell.com/cookwell_1.json index 25396a84e..1ffbfa7a5 100644 --- a/tests/test_data/cookwell.com/cookwell_1.json +++ b/tests/test_data/cookwell.com/cookwell_1.json @@ -28,7 +28,10 @@ "total_time": 75, "cuisine": "American", "nutrients": { - "calories": "970 calories" + "calories": "970", + "fatContent": "60 g", + "carbohydrateContent": "100 g", + "proteinContent": "12 g" }, "image": "https://cdn.sanity.io/images/g1s4qnmz/production/ba9d3d0d5ff9a0f9f17f8e11df7e93b7f3806a48-1000x1000.jpg", "keywords": [ diff --git a/tests/test_data/cookwell.com/cookwell_2.json b/tests/test_data/cookwell.com/cookwell_2.json index c57f3e223..d1420eeb8 100644 --- a/tests/test_data/cookwell.com/cookwell_2.json +++ b/tests/test_data/cookwell.com/cookwell_2.json @@ -33,7 +33,10 @@ "total_time": 30, "cuisine": "Middle Eastern", "nutrients": { - "calories": "2558 calories" + "calories": "2558", + "fatContent": "49 g", + "carbohydrateContent": "402 g", + "proteinContent": "132 g" }, "image": "https://cdn.sanity.io/images/g1s4qnmz/production/3b2a77f0f746cf90c4f7f49a92b39885ada6e9de-3543x3543.jpg", "keywords": [ diff --git a/tests/test_data/culy.nl/culy_1.json b/tests/test_data/culy.nl/culy_1.json new file mode 100644 index 000000000..1ca6cd2df --- /dev/null +++ b/tests/test_data/culy.nl/culy_1.json @@ -0,0 +1,29 @@ +{ + "author": "Ogechi Chibueze", + "canonical_url": "https://www.culy.nl/recepten/pruimenjam/", + "site_name": "Culy", + "host": "culy.nl", + "language": "nl-NL", + "title": "Pruimenjam: een snel en makkelijk basisrecept binnen 15 minuten - Culy", + "ingredients": [ + "1 kilo pruimen, ontpit en in kwarten", + "250 gram geleisuiker", + "2 eetlepels citroensap", + "1 theelepel kruiden, zoals kaneel of kardemom" + ], + "instructions_list": [ + "Spoel depruimengoed schoon, en ontpit ze. Gebruik hiervoor eventueel een kersenontpitter. Snijd de pruimen vervolgens in kwarten.", + "Zet een grote pan op het vuur en voeg de pruimen met schil en al toe samen met desuikeren hetcitroensap. Doe ook dekruidenerbij, indien je die gebruikt.", + "Breng de pruimenjam aan de kook en laat het ongeveer 10 minuten koken op laag vuur. Je kunt de jam met een staafmixer pureren, voor een gladde jam.", + "Doe de jamproef: neem een lepeltje jam en laat het op een bordje vallen. Trek er vervolgens met je vinger een lijn doorheen. Als de lijn zichtbaar blijft, is ‘ie klaar. Kook de jam anders nog even door en herhaal de proef tot de gewenste dikte is bereikt.", + "Schik de jam, kokendheet, in de jampotten. Draai de deksels goed dicht en laat ze omgekeerd staan. Hierdoor zullen ze vacuümtrekken. Bewaar de jam enkele maanden buiten de koelkast." + ], + "yields": "3 servings", + "description": "Zelf jam maken is een klusje dat ons gelijk doet denken aan vroeger. Deze keer maken we een zoete en knalroze pruimenjam, lichtelijk gekruid met een snuf kaneel. Om d...", + "total_time": 15, + "cook_time": 10, + "prep_time": 5, + "ratings": 3.5, + "ratings_count": 2, + "image": "https://www.culy.nl/wp-content/uploads/2024/10/Pruimenjam_maken_1.jpg" +} diff --git a/tests/test_data/culy.nl/culy_1.testhtml b/tests/test_data/culy.nl/culy_1.testhtml new file mode 100644 index 000000000..c823aa157 --- /dev/null +++ b/tests/test_data/culy.nl/culy_1.testhtml @@ -0,0 +1,2052 @@ + + + + + + + + + + + + + + + + + + + + + + Pruimenjam: een snel en makkelijk basisrecept binnen 15 minuten - Culy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + +
    +
    +
    + +
    +
    + Ogechi Chibueze
    +
    + + Ogechi Chibueze + + Recepten + + 30 okt 2024 +
    + Leestijd: 2 minuten
    +
    +
    + + +

    Culy Basics: pruimenjam maken binnen 15 minuten

    + +

    Zelf jam maken is een klusje dat ons gelijk doet denken aan vroeger. Deze keer maken we een zoete en knalroze pruimenjam, lichtelijk gekruid met een snuf kaneel. Om dolgelukkig van te worden!

    +

    Geleisuiker in pruimenjam

    +

    In de ingrediëntenlijst van jamrecepten staat vaak geleisuiker. Dat is suiker gemengd met pectine, een soort verdikkingsmiddel. Hierdoor is je pruimenjam lekker snel klaar, en hoeft de jam niet uren op het vuur te staan pruttelen. Heb je geen geleisuiker in huis? Dan is dat geen probleem. Voeg dan twee keer zoveel suiker toe, en laat alles koken tot de jam goed is ingedikt, dat duurt ongeveer twee keer zo lang.

    +

    Er gaat trouwens een hoop suiker in jam. Dat is omdat de suiker als een conserveringsmiddel werkt voor de jam. En het maakt de pruimenjam ook nog eens superlekker.

    +

    Wat is het verschil tussen jam, marmelade en compote?

    +

    +
    Pruimenjam maken
    Bron: Ogechi Chibueze voor Culy
    +

    Lekkere smaken met pruimenjam

    +

    Het pruimenseizoen begint in juli, en tot en met september kun je de vruchten van Nederlandse bodem plukken. Maar in veel supermarkten en toko’s kun je ook buiten het seizoen pruimen krijgen. Wij vinden pruimen eigenlijk het lekkerst met herfstkruiden als kaneel, kardemom en nootmuskaat. Maar ook met zomerse smaken als citrus, een andere vruchten, zoals aardbeien en kersen.

    +

    Gooi ook eens een lekkere scheut alcohol door de pruimenjam. Denk aan bourbon of whiskey. Met vanille-extract, honing of ahornsiroop kun je de smaak verzachten.

    +
    Pruimenjam maken
    Bron: Ogechi Chibueze voor Culy
    +

    Pruimenjam maken: zo doe je dat

    +
      +
    1. Spoel de pruimen goed schoon, en ontpit ze. Gebruik hiervoor eventueel een kersenontpitter. Snijd de pruimen vervolgens in kwarten.
    2. +
    3. Zet een grote pan op het vuur en voeg de pruimen met schil en al toe samen met de suiker en het citroensap. Doe ook de kruiden erbij, indien je die gebruikt.
    4. +
    5. Breng de pruimenjam aan de kook en laat het ongeveer 10 minuten koken op laag vuur. Je kunt de jam met een staafmixer pureren, voor een gladde jam.
    6. +
    7. Doe de jamproef: neem een lepeltje jam en laat het op een bordje vallen. Trek er vervolgens met je vinger een lijn doorheen. Als de lijn zichtbaar blijft, is ‘ie klaar. Kook de jam anders nog even door en herhaal de proef tot de gewenste dikte is bereikt.
    8. +
    9. Schik de jam, kokendheet, in de jampotten. Draai de deksels goed dicht en laat ze omgekeerd staan. Hierdoor zullen ze vacuümtrekken. Bewaar de jam enkele maanden buiten de koelkast.
    10. +
    +
    Pruimenjam maken
    Bron: Ogechi Chibueze voor Culy
    +

    Nog meer lekkere jamrecepten:

    + +
    +

    + Foutje gezien? Mail ons! Jouw feedback maakt Culy nóg lekkerder. +

    +
    + +
    +
    +

    Dagelijks de lekkerste recepten in je inbox 🥘

    +

    Een mail waar het water je al van in de mond loopt.

    +
    +
    + + + + + + +
    +
    +

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

    Ook interessant

    +
    +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/culy.nl/culy_2.json b/tests/test_data/culy.nl/culy_2.json new file mode 100644 index 000000000..a2a08470c --- /dev/null +++ b/tests/test_data/culy.nl/culy_2.json @@ -0,0 +1,69 @@ +{ + "author": "Ogechi Chibueze", + "canonical_url": "https://www.culy.nl/recepten/zuurvlees-zoervleisj/", + "site_name": "Culy", + "host": "culy.nl", + "language": "nl-NL", + "title": "Zuurvlees (Limburgs zoervleisj) maken: zo doe je dat zelf - Culy", + "ingredients": [ + "1 ruime kilo rundersukade of runderlappen", + "400 ml water", + "400 ml natuurazijn", + "10 laurierblaadjes", + "10 jeneverbessen", + "10 kruidnagels", + "3 uien, in halve ringen", + "1 flinke klont boter, om in te bakken", + "3 eetlepels appelstroop, of perenstroop", + "3 eetlepels bruine basterdsuiker", + "1 eetlepel speculaaskruiden, of koekkruiden", + "5 plakken ontbijtkoek, verkruimeld" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 ruime kilo rundersukade of runderlappen", + "400 ml water", + "400 ml natuurazijn", + "10 laurierblaadjes", + "10 jeneverbessen", + "10 kruidnagels", + "3 uien, in halve ringen" + ], + "purpose": "Voor de marinade:" + }, + { + "ingredients": [ + "1 flinke klont boter, om in te bakken", + "3 eetlepels appelstroop, of perenstroop", + "3 eetlepels bruine basterdsuiker", + "1 eetlepel speculaaskruiden, of koekkruiden", + "5 plakken ontbijtkoek, verkruimeld" + ], + "purpose": "Voor het zuurvlees:" + } + ], + "instructions_list": [ + "Snijd hetvleesin flinke stukken.", + "Marineer de stukken vlees een nachtje in een mengsel vanwater,natuurazijn,specerijenen degesnedenuien. Zorg dat het vlees volledig onderstaat.", + "Haal het vlees de volgende dag samen met de uien uit de marinade. Vis ook de laurierblaadjes eruit, de kruidnagels en jeneverbessen gooi je weg. Bewaar wel het marinadevocht van het zuurvlees.", + "Zet een grote braadpan op het vuur en smelt daar in een flinke klontboter.", + "Dep het vlees goed droog en bestrooi vervolgens metzoutenpeper.", + "Braad het vlees goudbruin aan alle zijdes. Doe dit eventueel in delen, zodat de pan niet te vol raakt en het vlees goed kan bakken.", + "Haal het vlees uit de pan en voeg de uien toe. Bak deze ongeveer 5 minuten.", + "Doe het vlees en de laurierblaadjes er daarna weer bij, samen met één kopje van hetmarinadevocht, deappelstroop,bruinebasterdsuiker,speculaaskruidenen de verkruimeldeontbijtkoek.", + "Laat ruim een 2 tot 4 uur op laag vuur zachtjes stoven (of zet het ongeveer 8 uur op 80 graden met deksel op de pan in de oven).", + "Maak de saus indien nodig dikker met wat extra ontbijtkoek. Proef het zuurvlees, en breng eventueel op smaak met een beetje zout en peper en voeg eventueel nog wat suiker toe naar smaak." + ], + "yields": "4 servings", + "description": "Elke Limburger kent het, en iedereen die het (nog) niet kent, moet absoluut blijven lezen. Limburgs zuurvlees, ofwel zoervleisj, is een op en top winters ger...", + "total_time": 410, + "cook_time": 380, + "prep_time": 30, + "ratings": 4.45, + "ratings_count": 428, + "nutrients": { + "calories": "645" + }, + "image": "https://www.culy.nl/wp-content/uploads/2016/01/Zuurvlees_Zoervleisj_maken_1.jpg" +} diff --git a/tests/test_data/culy.nl/culy_2.testhtml b/tests/test_data/culy.nl/culy_2.testhtml new file mode 100644 index 000000000..32e081407 --- /dev/null +++ b/tests/test_data/culy.nl/culy_2.testhtml @@ -0,0 +1,2088 @@ + + + + + + + + + + + + + + + + + + + + + Zuurvlees (Limburgs zoervleisj) maken: zo doe je dat zelf - Culy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + +
    +
    +
    + +
    +
    + Ogechi Chibueze
    +
    + + Ogechi Chibueze + + Recepten + + Gisteren +
    + Leestijd: 3 minuten
    +
    +
    + + +

    Zo maak je thuis Limburgs zuurvlees (zoervleisj)

    + +

    Elke Limburger kent het, en iedereen die het (nog) niet kent, moet absoluut blijven lezen. Limburgs zuurvlees, ofwel zoervleisj, is een op en top winters gerecht vol smaak. Met dit zuurvleesrecept kun je er ook thuis van genieten.

    +

    We kregen dit recept voor Limburgs zuurvlees (of zoervleisj dus), dat heel goed thuis te maken is, van een vaste Culy-lezer. Je moet er even wat tijd voor uittrekken en tijdig beginnen door de tijd die nodig is voor het marineren van het vlees. Verder is het gerecht low & slow en hoef je niet veel te doen, een supermakkelijk recept dus!

    + +

    Dit is waarom wild een betere optie is (en probeer ook eens deze stukken)

    +

    +
    Limburgs Zuurvlees Zoervleisj maken recept
    Bron: Ogechi Chibueze voor Culy
    +

    Serveertip voor zuurvlees

    +

    Dit Limburgs zuurvleesrecept kun je op verschillende manieren serveren. Op de Culy-redactie zijn we dol op friet erbij en dan vooral shoestring fries, Deze superdunne frietjes zijn niet helemaal traditoneel, maar wel onwijs lekker. Je maakt het net als gewone friet, alleen snijd je de frieten nog dunner. Een mandoline kan hiervoor handig zijn. Je kunt het natuurlijk ook met gewone – of dikke – frieten serveren.

    +

    Naast friet zijn aardappelpuree of aardappelkroketten ook lekker op je bordje zuurvlees. Doe daar dan spruitjes met spekjes of rodekool bij. En natuurlijk wat lekkers te drinken: een glas stevige rode wijn, een goed abdijbier of een glas port.

    +

    Wat serveer je bij stoofvlees? (hint: bloemkoolrijst, friet en meer)

    +

    +
    Limburgs Zuurvlees Zoervleisj maken recept
    Bron: Ogechi Chibueze voor Culy
    +

    Limburgs zuurvlees maken: het recept

    +

    Een dag van tevoren

    +
      +
    1. Snijd het vlees in flinke stukken.
    2. +
    3. Marineer de stukken vlees een nachtje in een mengsel van water, natuurazijn, specerijen en de gesneden uien. Zorg dat het vlees volledig onderstaat.
    4. +
    +

    De volgende dag

    +
      +
    1. Haal het vlees de volgende dag samen met de uien uit de marinade. Vis ook de laurierblaadjes eruit, de kruidnagels en jeneverbessen gooi je weg. Bewaar wel het marinadevocht van het zuurvlees.
    2. +
    3. Zet een grote braadpan op het vuur en smelt daar in een flinke klont boter.
    4. +
    5. Dep het vlees goed droog en bestrooi vervolgens met zout en peper.
    6. +
    7. Braad het vlees goudbruin aan alle zijdes. Doe dit eventueel in delen, zodat de pan niet te vol raakt en het vlees goed kan bakken.
    8. +
    9. Haal het vlees uit de pan en voeg de uien toe. Bak deze ongeveer 5 minuten.
    10. +
    11. Doe het vlees en de laurierblaadjes er daarna weer bij, samen met één kopje van het marinadevocht, de appelstroop, bruine basterdsuiker, speculaaskruiden en de verkruimelde ontbijtkoek.
    12. +
    13. Laat ruim een 2 tot 4 uur op laag vuur zachtjes stoven (of zet het ongeveer 8 uur op 80 graden met deksel op de pan in de oven).
    14. +
    15. Maak de saus indien nodig dikker met wat extra ontbijtkoek. Proef het zuurvlees, en breng eventueel op smaak met een beetje zout en peper en voeg eventueel nog wat suiker toe naar smaak.
    16. +
    +
    Limburgs Zuurvlees Zoervleisj maken recept
    Bron: Ogechi Chibueze voor Culy
    +

    Meer recepten voor stoofvlees:

    + +
    +

    + Foutje gezien? Mail ons! Jouw feedback maakt Culy nóg lekkerder. +

    +
    + +
    +
    +

    Dagelijks de lekkerste recepten in je inbox 🥘

    +

    Een mail waar het water je al van in de mond loopt.

    +
    +
    + + + + + + +
    +
    +

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

    Ook interessant

    +
    +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/dagelijksekost.vrt.be/dagelijksekost.json b/tests/test_data/dagelijksekost.vrt.be/dagelijksekost.json new file mode 100644 index 000000000..f78eb1a53 --- /dev/null +++ b/tests/test_data/dagelijksekost.vrt.be/dagelijksekost.json @@ -0,0 +1,82 @@ +{ + "author": "Dagelijkse kost", + "canonical_url": "https://dagelijksekost.vrt.be/gerechten/vol-au-vent", + "site_name": "Dagelijkse kost", + "host": "dagelijksekost.vrt.be", + "language": "nl", + "title": "Vol-au-vent", + "ingredients": [ + "4 stengel selder", + "2 Wortels", + "2 Preistengels", + "3 uien", + "5 teentjes Look", + "4 takjes tijm", + "4 blaadje laurier", + "2 takjes rozemarijn", + "1 bosje peterseliestelen", + "zout", + "1 snuifje zout", + "15 bolletje zwarte peper", + "2 kruidnagels", + "1 boerderij kip", + "2 vel bladerdeeg", + "1 eigeel", + "Water", + "1 dopje Water", + "300 g gehakt", + "1 el broodkruim", + "peper", + "250 g Parijse champignons", + "1 klontje boter", + "310 g boter", + "80 g bloem", + "1 liter Kippenbouillon", + "1 scheutje madeirawijn", + "1 dl Room", + "1 citroen", + "nootmuskaat", + "3 eierdooiers", + "2 dopje witte wijn", + "1 snuifje cayennepeper" + ], + "instructions_list": [ + "Bereid een ketel met een (variant op de) klassieke groentebouillon. Je kan ook zelf groentebouillon maken.", + "Breng een ruime hoeveelheid water aan de kook. Spoel alle groenten, snij ze grof en doe ze in de grote pot met water.", + "Voeg de verse kruiden, wat zout en de specerijen toe.", + "Laat de bouillon kort sudderen en leg er vervolgens de kip in.", + "Laat de kippenbouillon een uurtje koken. Gebruik een schuimspaan om tussendoor het vet en onzuiverheden weg te scheppen.", + "Schep de gare kip uit de pot en laat ze afkoelen.", + "Zeef de bouillon. Een deel ervan heb je straks nodig voor het garen van de gehaktballetjes en de bereiding van de saus.", + "Maak zelf de bladerdeegkoekjes om de vulling in te scheppen.", + "Klop een dooier los met een klein beetje water.", + "Verwarm de oven voor tot 180°C.", + "Steek per gebakje een zestal ringen uit het vel bladerdeeg. Gebruik hiervoor een grote dresseerring. Steek uit vier van elke zes lapjes een rondje met behulp van een kleinere dresseerring. Bouw elk kuipje op: onderaan een ronde lap, daarboven vier ‘ringen’ van bladerdeeg, en bovenaan opnieuw een ronde lap. Lijm alle onderdelen aan mekaar met een laagje losgeklopte dooier. Strijk ook eigeel over de bovenkant van het gebakje, zodat het glanzend uit de oven komt. Gebruik een borsteltje om handig te werken.", + "Bak de kuipjes in de oven tot ze luchtig en goudbruin zijn. Reken een baktijd van ongeveer 20 minuten op 180°C.", + "Meng het gehakt, samen met een ei en het broodkruim. Kruid met wat peper van de molen en zout. Rol het vleesmengsel tot identieke kleine balletjes van ongeveer een centimeter diameter.", + "Breng een deel van de (gezeefde) kippenbouillon aan de kook. Laat de balletjes daarin enkele minuten garen op een matig vuur.", + "Snij de paddenstoelen in kwartjes.", + "Smelt een klont boter in een pan en bak de stukjes paddenstoel. Voeg pas tijdens het bakken een geplet teentje knoflook toe zodat de look niet kan verbranden. Voeg een beetje peper en zout toe. Laat de champignons kleuren en zet ze opzij.", + "Pluk al het vlees van het karkas van de kip. Beslis hoe je de kip wil serveren: in eerder grote stukken, hapklare brokken of extra fijn. Zet het vlees even opzij.", + "Start de bereiding van de saus met een roux. Smelt de boter in een kookpot en voeg de bloem eraan toe. Laat het bloemmengsel al roerend “opdrogen”, maar let erop dat de roux niet aanbakt.", + "Zodra je een lichte biscuitgeur ruikt, schenk je een deel van de gezeefde kippenbouillon in de pot. Blijf geduldig doorroeren met een garde om klontertjes te vermijden.", + "Schenk er af en toe wat bouillon bij, en wacht tot de saus bubbelt. Ga door tot je een gebonden, maar tegelijk voldoende vloeibare saus krijgt.", + "Voeg tenslotte een scheutje madeira (of sherry) toe en ook de room. Roer de saus zorgvuldig.", + "Voeg de gebakken paddenstoelen, de stukjes kip en de gehaktballetjes toe aan de saus. Druppel wat vers citroensap in het mengsel en kruid de vol au vent naar smaak met wat peper, zout en versgeraspte nootmuskaat. Roer, proef en voeg naar smaak een extra beetje madeirawijn.", + "Snij de boter in kleine blokjes.", + "Scheid de eieren en doe de dooiers in een pan. (Gebruik bij voorkeur een pan met een bolle onderzijde.) Hou één eierdopje bij om de vloeistof voor deze saus af te meten. Voeg voor elke dooier één dopje vloeistof toe. Ik gebruik 2/3 witte wijn, en 1/3 water. (Het eiwit wordt niet gebruikt.)", + "Klop het mengsel alvast schuimig, alvorens je het op het fornuis zet.", + "Zet de pan op een zacht vuur en blijf zonder ophouden kloppen met de garde. Klop tegen een flinke snelheid in een 8-vorm, of draai je pan voortdurend een kwartslag naar links en naar rechts. Neem de pan af en toe weg van het vuur. Blijf doorgaan tot je een licht gebonden schuimige saus krijgt, waarin de garde sporen nalaat. Laat ze in geen geval aanbranden of te heet worden.", + "Neem de pan van het vuur. Voeg de boterblokjes in delen toe aan de warme schuimige saus. Blijf intussen stevig kloppen met de garde.", + "Knijp het citroensap erbij. Voeg ook een voorzichtig snuifje cayennepeper en wat zout toe.", + "Roer en proef of de smaken in balans zijn.", + "Snij het dekseltje uit elk bladerdeeggebak, en schep een flinke portie van de velouté met kip, balletjes en paddentoelen in en rond het koekje.", + "Lepel wat luchtige hollandaise over elk koninginnenhapje en zet het dekseltje van bladerdeeg erbovenop.", + "Werk elk bord af met een toef pittige tuinkers en geniet." + ], + "category": "Hoofdgerecht", + "yields": "4 servings", + "description": "Videe, vol-au-vent of koninginnenhapje: iedereen weet hoe deze klassieker op het bord verschijnt. Laat je echter niet verrassen, want de bereiding ervan vraagt wat tijd en moeite.Een versgebakken kuipje van bladerdeeg, verse kip, gehaktballetjes en paddenstoelen in een romige saus en de luchtige hollandaise. Wie dit bedacht verdient een standbeeld.", + "total_time": 165, + "image": "https://cdn.dagelijksekost.tv/recipes/LLwEgQWLcNsth6YQ6LrK/landscape/1727274513420_1500x1125?GoogleAccessId=firebase-adminsdk-2hybg%40dagelijkse-kost-prod.iam.gserviceaccount.com&Expires=16725225600&Signature=VpFtAU1gaUvyvNjNl24bS9P1dI4K18Gh%2FLxm7OflJIAF7v9B6lpvrov9B0pjO6zQ4Wa7Az1%2B70aokcbOLa02b9ZLcZ5rgRdX3lLsLEU%2FNoxkblytsN7jMHV8E4KtCpF2BN8KYyRzcjg29s2BjdRxcq%2Bg2UKl6U%2FIGqvXFdPg5zbtRMROaAjYJwQNr4IfWeAOsWAbeVyUGxwwq7LK9Gew%2Fl%2BIq9oUqUkWpX09ChoHBCksGs8Bu2fBuA3v9bYI4h1KpzkqSx%2BZTkBF63YmEZ9jDFotr6AVX6WjovUx0S9ZFrD8VVMC2tuBVyz2sZ8WngWF7nzVhSeUFwtJ5HPCx0eJ5Q%3D%3D" +} diff --git a/tests/test_data/dagelijksekost.vrt.be/dagelijksekost.testhtml b/tests/test_data/dagelijksekost.vrt.be/dagelijksekost.testhtml new file mode 100644 index 000000000..0b8c1bed3 --- /dev/null +++ b/tests/test_data/dagelijksekost.vrt.be/dagelijksekost.testhtml @@ -0,0 +1,2 @@ + +Vol-au-vent | Dagelijkse kost
    dako logo
    Populaire thema's
    Zoeken op
    Vol-au-vent (thumbnail)Vol-au-vent

    Vol-au-vent

    2u 45m
    30
    99%
    81.4K
    Recepten

    Vol-au-vent

    Videe, vol-au-vent of koninginnenhapje: iedereen weet hoe deze klassieker op het bord verschijnt. Laat je echter niet verrassen, want de bereiding ervan vraagt wat tijd en moeite.Een versgebakken kuipje van bladerdeeg, verse kip, gehaktballetjes en paddenstoelen in een romige saus en de luchtige hollandaise. Wie dit bedacht verdient een standbeeld.
    Vol-au-vent (thumbnail)Vol-au-vent

    Vol-au-vent

    2u 45m
    30
    99%
    81.4K
    Recepten

    Vol-au-vent

    Videe, vol-au-vent of koninginnenhapje: iedereen weet hoe deze klassieker op het bord verschijnt. Laat je echter niet verrassen, want de bereiding ervan vraagt wat tijd en moeite.Een versgebakken kuipje van bladerdeeg, verse kip, gehaktballetjes en paddenstoelen in een romige saus en de luchtige hollandaise. Wie dit bedacht verdient een standbeeld.
    Type gerechtHoofdgerecht
    Totale tijd2u 45m
    Ingrediënten30
    Beoordeling99%
    Aantal likes81.4K

    Ingrediënten

    4 personen
    Selder
    4 stengel
    Wortels
    2
    Preistengels
    2
    Uien
    3
    Look
    5 teentjes
    Tijm
    4 takjes
    Laurier
    4 blaadje
    Rozemarijn
    2 takjes
    Peterseliestelen
    1 bosje
    Zout
    Zout
    1 snuifje
    Zwarte peper
    15 bolletje
    Kruidnagels
    2
    Boerderij kip
    1
    Bladerdeeg
    2 vel
    Eigeel
    1
    Water
    Water
    1 dopje
    Gehakt
    300 g
    Broodkruim
    1 el
    Peper
    Parijse champignons
    250 g
    Boter
    1 klontje
    Boter
    310 g
    Bloem
    80 g
    Kippenbouillon
    1 liter
    Madeirawijn
    1 scheutje
    Room
    1 dl
    Citroen
    1
    Nootmuskaat
    Eierdooiers
    3
    Witte wijn
    2 dopje
    Cayennepeper
    1 snuifje

    Benodigdheden

    Een vijzel, een grote zeef, 1 grote dresseerring diameter 80 mm, 1 kleinere dresseerring diameter 60 mm, een borsteltje

    Zie je een fout in dit recept?Een probleem melden

    Instructies

    De bouillon

    1
    Bereid een ketel met een (variant op de) klassieke groentebouillon. Je kan ook zelf groentebouillon maken.
    4 stengel selder, 2 Wortels, 2 Preistengels, 3 uien, 4 teentjes Look
    2
    Breng een ruime hoeveelheid water aan de kook. Spoel alle groenten, snij ze grof en doe ze in de grote pot met water.
    4 takjes tijm, 4 blaadje laurier, 2 takjes rozemarijn, 1 bosje peterseliestelen, zout, 15 bolletje zwarte peper, 2 kruidnagels
    3
    Voeg de verse kruiden, wat zout en de specerijen toe.
    TIP De bolletjes peper kneus je bij voorkeur in de vijzel.
    1 boerderij kip
    4
    Laat de bouillon kort sudderen en leg er vervolgens de kip in.
    TIPHet is belangrijk dat de kip in warme bouillon wordt ondergedompeld.
    5
    Laat de kippenbouillon een uurtje koken. Gebruik een schuimspaan om tussendoor het vet en onzuiverheden weg te scheppen.
    6
    Schep de gare kip uit de pot en laat ze afkoelen.
    7
    Zeef de bouillon. Een deel ervan heb je straks nodig voor het garen van de gehaktballetjes en de bereiding van de saus.
    TIPDe rest van de bouillon kan je invriezen voor diverse soepen.

    Bladerdeegkoekjes

    2 vel bladerdeeg
    8
    Maak zelf de bladerdeegkoekjes om de vulling in te scheppen.
    TIPJe kan de bladerdeegkoekjes natuurlijk ook aankopen bij de warme bakker.
    1 eigeel, Water
    9
    Klop een dooier los met een klein beetje water.
    10
    Verwarm de oven voor tot 180°C.
    11
    Steek per gebakje een zestal ringen uit het vel bladerdeeg. Gebruik hiervoor een grote dresseerring. Steek uit vier van elke zes lapjes een rondje met behulp van een kleinere dresseerring. Bouw elk kuipje op: onderaan een ronde lap, daarboven vier ‘ringen’ van bladerdeeg, en bovenaan opnieuw een ronde lap. Lijm alle onderdelen aan mekaar met een laagje losgeklopte dooier. Strijk ook eigeel over de bovenkant van het gebakje, zodat het glanzend uit de oven komt. Gebruik een borsteltje om handig te werken.
    12
    Bak de kuipjes in de oven tot ze luchtig en goudbruin zijn. Reken een baktijd van ongeveer 20 minuten op 180°C.

    De videevulling (velouté)

    300 g gehakt, 1 el broodkruim, peper, zout
    13
    Meng het gehakt, samen met een ei en het broodkruim. Kruid met wat peper van de molen en zout. Rol het vleesmengsel tot identieke kleine balletjes van ongeveer een centimeter diameter.
    14
    Breng een deel van de (gezeefde) kippenbouillon aan de kook. Laat de balletjes daarin enkele minuten garen op een matig vuur.
    250 g Parijse champignons
    15
    Snij de paddenstoelen in kwartjes.
    1 klontje boter, 1 teentje Look
    16
    Smelt een klont boter in een pan en bak de stukjes paddenstoel. Voeg pas tijdens het bakken een geplet teentje knoflook toe zodat de look niet kan verbranden. Voeg een beetje peper en zout toe. Laat de champignons kleuren en zet ze opzij.
    17
    Pluk al het vlees van het karkas van de kip. Beslis hoe je de kip wil serveren: in eerder grote stukken, hapklare brokken of extra fijn. Zet het vlees even opzij.
    60 g boter, 80 g bloem
    18
    Start de bereiding van de saus met een roux. Smelt de boter in een kookpot en voeg de bloem eraan toe. Laat het bloemmengsel al roerend “opdrogen”, maar let erop dat de roux niet aanbakt.
    1 liter Kippenbouillon
    19
    Zodra je een lichte biscuitgeur ruikt, schenk je een deel van de gezeefde kippenbouillon in de pot. Blijf geduldig doorroeren met een garde om klontertjes te vermijden.
    20
    Schenk er af en toe wat bouillon bij, en wacht tot de saus bubbelt. Ga door tot je een gebonden, maar tegelijk voldoende vloeibare saus krijgt.
    1 scheutje madeirawijn, 1 dl Room
    21
    Voeg tenslotte een scheutje madeira (of sherry) toe en ook de room. Roer de saus zorgvuldig.
    0,5 citroenen, nootmuskaat
    22
    Voeg de gebakken paddenstoelen, de stukjes kip en de gehaktballetjes toe aan de saus. Druppel wat vers citroensap in het mengsel en kruid de vol au vent naar smaak met wat peper, zout en versgeraspte nootmuskaat. Roer, proef en voeg naar smaak een extra beetje madeirawijn.

    De hollandaisesaus

    250 g boter
    23
    Snij de boter in kleine blokjes.
    3 eierdooiers, 2 dopje witte wijn, 1 dopje Water
    24
    Scheid de eieren en doe de dooiers in een pan. (Gebruik bij voorkeur een pan met een bolle onderzijde.) Hou één eierdopje bij om de vloeistof voor deze saus af te meten. Voeg voor elke dooier één dopje vloeistof toe. Ik gebruik 2/3 witte wijn, en 1/3 water. (Het eiwit wordt niet gebruikt.)
    25
    Klop het mengsel alvast schuimig, alvorens je het op het fornuis zet.
    26
    Zet de pan op een zacht vuur en blijf zonder ophouden kloppen met de garde. Klop tegen een flinke snelheid in een 8-vorm, of draai je pan voortdurend een kwartslag naar links en naar rechts. Neem de pan af en toe weg van het vuur. Blijf doorgaan tot je een licht gebonden schuimige saus krijgt, waarin de garde sporen nalaat. Laat ze in geen geval aanbranden of te heet worden.
    27
    Neem de pan van het vuur. Voeg de boterblokjes in delen toe aan de warme schuimige saus. Blijf intussen stevig kloppen met de garde.
    0,5 citroenen, 1 snuifje cayennepeper, 1 snuifje zout
    28
    Knijp het citroensap erbij. Voeg ook een voorzichtig snuifje cayennepeper en wat zout toe.
    29
    Roer en proef of de smaken in balans zijn.

    Afwerken en serveren

    30
    Snij het dekseltje uit elk bladerdeeggebak, en schep een flinke portie van de velouté met kip, balletjes en paddentoelen in en rond het koekje.
    31
    Lepel wat luchtige hollandaise over elk koninginnenhapje en zet het dekseltje van bladerdeeg erbovenop.
    32
    Werk elk bord af met een toef pittige tuinkers en geniet.
    1
    Bereid een ketel met een (variant op de) klassieke groentebouillon. Je kan ook zelf groentebouillon maken.
    2
    Breng een ruime hoeveelheid water aan de kook. Spoel alle groenten, snij ze grof en doe ze in de grote pot met water.
    Wat vond je van dit recept?
    Geef je mening en help anderen om de perfecte keuze te maken!

    Instructies

    De bouillon

    1
    Bereid een ketel met een (variant op de) klassieke groentebouillon. Je kan ook zelf groentebouillon maken.
    4 stengel selder, 2 Wortels, 2 Preistengels, 3 uien, 4 teentjes Look
    2
    Breng een ruime hoeveelheid water aan de kook. Spoel alle groenten, snij ze grof en doe ze in de grote pot met water.
    4 takjes tijm, 4 blaadje laurier, 2 takjes rozemarijn, 1 bosje peterseliestelen, zout, 15 bolletje zwarte peper, 2 kruidnagels
    3
    Voeg de verse kruiden, wat zout en de specerijen toe.
    TIP De bolletjes peper kneus je bij voorkeur in de vijzel.
    1 boerderij kip
    4
    Laat de bouillon kort sudderen en leg er vervolgens de kip in.
    TIPHet is belangrijk dat de kip in warme bouillon wordt ondergedompeld.
    5
    Laat de kippenbouillon een uurtje koken. Gebruik een schuimspaan om tussendoor het vet en onzuiverheden weg te scheppen.
    6
    Schep de gare kip uit de pot en laat ze afkoelen.
    7
    Zeef de bouillon. Een deel ervan heb je straks nodig voor het garen van de gehaktballetjes en de bereiding van de saus.
    TIPDe rest van de bouillon kan je invriezen voor diverse soepen.

    Bladerdeegkoekjes

    2 vel bladerdeeg
    8
    Maak zelf de bladerdeegkoekjes om de vulling in te scheppen.
    TIPJe kan de bladerdeegkoekjes natuurlijk ook aankopen bij de warme bakker.
    1 eigeel, Water
    9
    Klop een dooier los met een klein beetje water.
    10
    Verwarm de oven voor tot 180°C.
    11
    Steek per gebakje een zestal ringen uit het vel bladerdeeg. Gebruik hiervoor een grote dresseerring. Steek uit vier van elke zes lapjes een rondje met behulp van een kleinere dresseerring. Bouw elk kuipje op: onderaan een ronde lap, daarboven vier ‘ringen’ van bladerdeeg, en bovenaan opnieuw een ronde lap. Lijm alle onderdelen aan mekaar met een laagje losgeklopte dooier. Strijk ook eigeel over de bovenkant van het gebakje, zodat het glanzend uit de oven komt. Gebruik een borsteltje om handig te werken.
    12
    Bak de kuipjes in de oven tot ze luchtig en goudbruin zijn. Reken een baktijd van ongeveer 20 minuten op 180°C.

    De videevulling (velouté)

    300 g gehakt, 1 el broodkruim, peper, zout
    13
    Meng het gehakt, samen met een ei en het broodkruim. Kruid met wat peper van de molen en zout. Rol het vleesmengsel tot identieke kleine balletjes van ongeveer een centimeter diameter.
    14
    Breng een deel van de (gezeefde) kippenbouillon aan de kook. Laat de balletjes daarin enkele minuten garen op een matig vuur.
    250 g Parijse champignons
    15
    Snij de paddenstoelen in kwartjes.
    1 klontje boter, 1 teentje Look
    16
    Smelt een klont boter in een pan en bak de stukjes paddenstoel. Voeg pas tijdens het bakken een geplet teentje knoflook toe zodat de look niet kan verbranden. Voeg een beetje peper en zout toe. Laat de champignons kleuren en zet ze opzij.
    17
    Pluk al het vlees van het karkas van de kip. Beslis hoe je de kip wil serveren: in eerder grote stukken, hapklare brokken of extra fijn. Zet het vlees even opzij.
    60 g boter, 80 g bloem
    18
    Start de bereiding van de saus met een roux. Smelt de boter in een kookpot en voeg de bloem eraan toe. Laat het bloemmengsel al roerend “opdrogen”, maar let erop dat de roux niet aanbakt.
    1 liter Kippenbouillon
    19
    Zodra je een lichte biscuitgeur ruikt, schenk je een deel van de gezeefde kippenbouillon in de pot. Blijf geduldig doorroeren met een garde om klontertjes te vermijden.
    20
    Schenk er af en toe wat bouillon bij, en wacht tot de saus bubbelt. Ga door tot je een gebonden, maar tegelijk voldoende vloeibare saus krijgt.
    1 scheutje madeirawijn, 1 dl Room
    21
    Voeg tenslotte een scheutje madeira (of sherry) toe en ook de room. Roer de saus zorgvuldig.
    0,5 citroenen, nootmuskaat
    22
    Voeg de gebakken paddenstoelen, de stukjes kip en de gehaktballetjes toe aan de saus. Druppel wat vers citroensap in het mengsel en kruid de vol au vent naar smaak met wat peper, zout en versgeraspte nootmuskaat. Roer, proef en voeg naar smaak een extra beetje madeirawijn.

    De hollandaisesaus

    250 g boter
    23
    Snij de boter in kleine blokjes.
    3 eierdooiers, 2 dopje witte wijn, 1 dopje Water
    24
    Scheid de eieren en doe de dooiers in een pan. (Gebruik bij voorkeur een pan met een bolle onderzijde.) Hou één eierdopje bij om de vloeistof voor deze saus af te meten. Voeg voor elke dooier één dopje vloeistof toe. Ik gebruik 2/3 witte wijn, en 1/3 water. (Het eiwit wordt niet gebruikt.)
    25
    Klop het mengsel alvast schuimig, alvorens je het op het fornuis zet.
    26
    Zet de pan op een zacht vuur en blijf zonder ophouden kloppen met de garde. Klop tegen een flinke snelheid in een 8-vorm, of draai je pan voortdurend een kwartslag naar links en naar rechts. Neem de pan af en toe weg van het vuur. Blijf doorgaan tot je een licht gebonden schuimige saus krijgt, waarin de garde sporen nalaat. Laat ze in geen geval aanbranden of te heet worden.
    27
    Neem de pan van het vuur. Voeg de boterblokjes in delen toe aan de warme schuimige saus. Blijf intussen stevig kloppen met de garde.
    0,5 citroenen, 1 snuifje cayennepeper, 1 snuifje zout
    28
    Knijp het citroensap erbij. Voeg ook een voorzichtig snuifje cayennepeper en wat zout toe.
    29
    Roer en proef of de smaken in balans zijn.

    Afwerken en serveren

    30
    Snij het dekseltje uit elk bladerdeeggebak, en schep een flinke portie van de velouté met kip, balletjes en paddentoelen in en rond het koekje.
    31
    Lepel wat luchtige hollandaise over elk koninginnenhapje en zet het dekseltje van bladerdeeg erbovenop.
    32
    Werk elk bord af met een toef pittige tuinkers en geniet.
    1
    Bereid een ketel met een (variant op de) klassieke groentebouillon. Je kan ook zelf groentebouillon maken.
    2
    Breng een ruime hoeveelheid water aan de kook. Spoel alle groenten, snij ze grof en doe ze in de grote pot met water.

    Wat vond je van dit recept?
    Geef je mening en help anderen om de perfecte keuze te maken!

    Zie je een fout in dit recept?Een probleem melden
    dako logo
    Vol-au-vent (thumbnail)Vol-au-vent
    4 personen
    2u 45m
    Ingrediënten
    Selder
    4 stengel
    Wortels
    2
    Preistengels
    2
    Uien
    3
    Look
    5 teentjes
    Tijm
    4 takjes
    Laurier
    4 blaadje
    Rozemarijn
    2 takjes
    Peterseliestelen
    1 bosje
    Zout
    Zout
    1 snuifje
    Zwarte peper
    15 bolletje
    Kruidnagels
    2
    Boerderij kip
    1
    Bladerdeeg
    2 vel
    Eigeel
    1
    Water
    Water
    1 dopje
    Gehakt
    300 g
    Broodkruim
    1 el
    Peper
    Parijse champignons
    250 g
    Boter
    1 klontje
    Boter
    310 g
    Bloem
    80 g
    Kippenbouillon
    1 liter
    Madeirawijn
    1 scheutje
    Room
    1 dl
    Citroen
    1
    Nootmuskaat
    Eierdooiers
    3
    Witte wijn
    2 dopje
    Cayennepeper
    1 snuifje

    Vol-au-vent

    Videe, vol-au-vent of koninginnenhapje: iedereen weet hoe deze klassieker op het bord verschijnt. Laat je echter niet verrassen, want de bereiding ervan vraagt wat tijd en moeite.Een versgebakken kuipje van bladerdeeg, verse kip, gehaktballetjes en paddenstoelen in een romige saus en de luchtige hollandaise. Wie dit bedacht verdient een standbeeld.
    Instructies

    De bouillon

    1
    Bereid een ketel met een (variant op de) klassieke groentebouillon. Je kan ook zelf groentebouillon maken.
    4 stengel selder, 2 Wortels, 2 Preistengels, 3 uien, 4 teentjes Look
    2
    Breng een ruime hoeveelheid water aan de kook. Spoel alle groenten, snij ze grof en doe ze in de grote pot met water.
    4 takjes tijm, 4 blaadje laurier, 2 takjes rozemarijn, 1 bosje peterseliestelen, zout, 15 bolletje zwarte peper, 2 kruidnagels
    3
    Voeg de verse kruiden, wat zout en de specerijen toe.
    TIP De bolletjes peper kneus je bij voorkeur in de vijzel.
    1 boerderij kip
    4
    Laat de bouillon kort sudderen en leg er vervolgens de kip in.
    TIPHet is belangrijk dat de kip in warme bouillon wordt ondergedompeld.
    5
    Laat de kippenbouillon een uurtje koken. Gebruik een schuimspaan om tussendoor het vet en onzuiverheden weg te scheppen.
    6
    Schep de gare kip uit de pot en laat ze afkoelen.
    7
    Zeef de bouillon. Een deel ervan heb je straks nodig voor het garen van de gehaktballetjes en de bereiding van de saus.
    TIPDe rest van de bouillon kan je invriezen voor diverse soepen.

    Bladerdeegkoekjes

    2 vel bladerdeeg
    8
    Maak zelf de bladerdeegkoekjes om de vulling in te scheppen.
    TIPJe kan de bladerdeegkoekjes natuurlijk ook aankopen bij de warme bakker.
    1 eigeel, Water
    9
    Klop een dooier los met een klein beetje water.
    10
    Verwarm de oven voor tot 180°C.
    11
    Steek per gebakje een zestal ringen uit het vel bladerdeeg. Gebruik hiervoor een grote dresseerring. Steek uit vier van elke zes lapjes een rondje met behulp van een kleinere dresseerring. Bouw elk kuipje op: onderaan een ronde lap, daarboven vier ‘ringen’ van bladerdeeg, en bovenaan opnieuw een ronde lap. Lijm alle onderdelen aan mekaar met een laagje losgeklopte dooier. Strijk ook eigeel over de bovenkant van het gebakje, zodat het glanzend uit de oven komt. Gebruik een borsteltje om handig te werken.
    12
    Bak de kuipjes in de oven tot ze luchtig en goudbruin zijn. Reken een baktijd van ongeveer 20 minuten op 180°C.

    De videevulling (velouté)

    300 g gehakt, 1 el broodkruim, peper, zout
    13
    Meng het gehakt, samen met een ei en het broodkruim. Kruid met wat peper van de molen en zout. Rol het vleesmengsel tot identieke kleine balletjes van ongeveer een centimeter diameter.
    14
    Breng een deel van de (gezeefde) kippenbouillon aan de kook. Laat de balletjes daarin enkele minuten garen op een matig vuur.
    250 g Parijse champignons
    15
    Snij de paddenstoelen in kwartjes.
    1 klontje boter, 1 teentje Look
    16
    Smelt een klont boter in een pan en bak de stukjes paddenstoel. Voeg pas tijdens het bakken een geplet teentje knoflook toe zodat de look niet kan verbranden. Voeg een beetje peper en zout toe. Laat de champignons kleuren en zet ze opzij.
    17
    Pluk al het vlees van het karkas van de kip. Beslis hoe je de kip wil serveren: in eerder grote stukken, hapklare brokken of extra fijn. Zet het vlees even opzij.
    60 g boter, 80 g bloem
    18
    Start de bereiding van de saus met een roux. Smelt de boter in een kookpot en voeg de bloem eraan toe. Laat het bloemmengsel al roerend “opdrogen”, maar let erop dat de roux niet aanbakt.
    1 liter Kippenbouillon
    19
    Zodra je een lichte biscuitgeur ruikt, schenk je een deel van de gezeefde kippenbouillon in de pot. Blijf geduldig doorroeren met een garde om klontertjes te vermijden.
    20
    Schenk er af en toe wat bouillon bij, en wacht tot de saus bubbelt. Ga door tot je een gebonden, maar tegelijk voldoende vloeibare saus krijgt.
    1 scheutje madeirawijn, 1 dl Room
    21
    Voeg tenslotte een scheutje madeira (of sherry) toe en ook de room. Roer de saus zorgvuldig.
    0,5 citroenen, nootmuskaat
    22
    Voeg de gebakken paddenstoelen, de stukjes kip en de gehaktballetjes toe aan de saus. Druppel wat vers citroensap in het mengsel en kruid de vol au vent naar smaak met wat peper, zout en versgeraspte nootmuskaat. Roer, proef en voeg naar smaak een extra beetje madeirawijn.

    De hollandaisesaus

    250 g boter
    23
    Snij de boter in kleine blokjes.
    3 eierdooiers, 2 dopje witte wijn, 1 dopje Water
    24
    Scheid de eieren en doe de dooiers in een pan. (Gebruik bij voorkeur een pan met een bolle onderzijde.) Hou één eierdopje bij om de vloeistof voor deze saus af te meten. Voeg voor elke dooier één dopje vloeistof toe. Ik gebruik 2/3 witte wijn, en 1/3 water. (Het eiwit wordt niet gebruikt.)
    25
    Klop het mengsel alvast schuimig, alvorens je het op het fornuis zet.
    26
    Zet de pan op een zacht vuur en blijf zonder ophouden kloppen met de garde. Klop tegen een flinke snelheid in een 8-vorm, of draai je pan voortdurend een kwartslag naar links en naar rechts. Neem de pan af en toe weg van het vuur. Blijf doorgaan tot je een licht gebonden schuimige saus krijgt, waarin de garde sporen nalaat. Laat ze in geen geval aanbranden of te heet worden.
    27
    Neem de pan van het vuur. Voeg de boterblokjes in delen toe aan de warme schuimige saus. Blijf intussen stevig kloppen met de garde.
    0,5 citroenen, 1 snuifje cayennepeper, 1 snuifje zout
    28
    Knijp het citroensap erbij. Voeg ook een voorzichtig snuifje cayennepeper en wat zout toe.
    29
    Roer en proef of de smaken in balans zijn.

    Afwerken en serveren

    30
    Snij het dekseltje uit elk bladerdeeggebak, en schep een flinke portie van de velouté met kip, balletjes en paddentoelen in en rond het koekje.
    31
    Lepel wat luchtige hollandaise over elk koninginnenhapje en zet het dekseltje van bladerdeeg erbovenop.
    32
    Werk elk bord af met een toef pittige tuinkers en geniet.
    \ No newline at end of file diff --git a/tests/test_data/dinnerthendessert.com/dinnerthendessert_2.json b/tests/test_data/dinnerthendessert.com/dinnerthendessert_2.json index da7704df3..ba4357595 100644 --- a/tests/test_data/dinnerthendessert.com/dinnerthendessert_2.json +++ b/tests/test_data/dinnerthendessert.com/dinnerthendessert_2.json @@ -10,7 +10,7 @@ "1 yellow onion (, chopped)", "4 cups chicken broth", "3 cups sweet corn (, frozen or fresh)", - "2 russet potatoes (, peeled and diced (Yukon okay too))", + "2 russet potatoes (, peeled and diced (Yukon okay too)", "1 cup heavy cream", "1 teaspoon hot sauce", "1/2 teaspoon chili powder", @@ -30,7 +30,7 @@ "1 yellow onion (, chopped)", "4 cups chicken broth", "3 cups sweet corn (, frozen or fresh)", - "2 russet potatoes (, peeled and diced (Yukon okay too))", + "2 russet potatoes (, peeled and diced (Yukon okay too)", "1 cup heavy cream", "1 teaspoon hot sauce", "1/2 teaspoon chili powder", diff --git a/tests/test_data/domesticate-me.com/domesticateme_1.json b/tests/test_data/domesticate-me.com/domesticateme_1.json index b58fdd7bd..a321bbc2d 100644 --- a/tests/test_data/domesticate-me.com/domesticateme_1.json +++ b/tests/test_data/domesticate-me.com/domesticateme_1.json @@ -18,10 +18,10 @@ "¾ cup grated sharp cheddar cheese", "¾ cup grated provolone cheese (Gouda is also great!)", "¼ cup whole-wheat panko breadcrumbs", - "3 scallions (thinly sliced (optional))", + "3 scallions (thinly sliced (optional)", "For the Yogurt Ranch:", "1½ cups nonfat plain Greek yogurt", - "1 teaspoon dried parsley (crushed (Just use your fingers to crush the flakes.))", + "1 teaspoon dried parsley (crushed (Just use your fingers to crush the flakes.)", "½ teaspoon dried dill weed", "½ teaspoon kosher salt", "¼ teaspoon garlic powder", diff --git a/tests/test_data/eggs.ca/eggsca_1.json b/tests/test_data/eggs.ca/eggsca_1.json new file mode 100644 index 000000000..61fd01dac --- /dev/null +++ b/tests/test_data/eggs.ca/eggsca_1.json @@ -0,0 +1,39 @@ +{ + "author": "Eggs.ca", + "canonical_url": "https://eggs.ca/recipes/creme-brulee/", + "site_name": "Eggs.ca", + "host": "eggs.ca", + "language": "en", + "title": "Classic Crème Brûlée", + "ingredients": [ + "1 ½ cups (375 mL) whipping cream (35%)", + "4 egg yolks", + "¼ cup (60 mL) granulated sugar", + "1 tsp vanilla extract", + "4-6 tsp granulated sugar, for caramelizing" + ], + "instructions_list": [ + "Preheat oven to 325°F (160°C). Place four 1/2 cup (125 mL) ramekins or custard cups in a baking dish. Set aside. Heat cream in saucepan over medium-high heat until small bubbles form around edge of pan. Meanwhile, whisk egg yolks and a 1/4 cup of sugar until thick and lemon-coloured – about 1 to 2 minutes.", + "When cream is hot, gradually whisk into egg yolk mixture. Stir in vanilla. Pour mixture through sieve into ramekins, dividing evenly. Pour very hot water into baking dish to reach halfway up ramekins. Carefully place baking dish in oven. Bake until mostly set but with a slight jiggle in the centre, about 30 to 35 minutes for taller ramekins (about 2 inches (5 cm) high), and 25 to 30 minutes for shallow ramekins (about 1 inch (2.5 cm) high). Carefully remove ramekins from water. Cool on wire rack. When cool, cover with plastic wrap and refrigerate for least 2 hours and up to 2 days.", + "Just before serving (or up to 2 hours before serving), sprinkle sugar evenly over surface of desserts (1 tsp for taller ramekins and 1-1/2 tsp for shallow ramekins). Using a mini torch or by placing the ramekins directly under the broiler, heat until sugar melts and caramelizes. Serve immediately, or for a firmer texture, chill until serving time." + ], + "category": "Desserts & Sweets", + "yields": "4 servings", + "description": "Breaking through crème brûlée’s crispy caramelized top into a thick creamy custard base is pure bliss. Heavy cream gives this classic recipe its silky, rich quality that's like no other dessert.", + "total_time": 50, + "cook_time": 15, + "prep_time": 15, + "nutrients": { + "calories": "441", + "fatContent": "38 g", + "saturatedFatContent": "22 g", + "transFatContent": "1 g", + "carbohydrateContent": "22 g", + "sugarContent": "19 g", + "proteinContent": "5 g", + "sodiumContent": "43 mg", + "fiberContent": "0 g", + "cholesterolContent": "0 mg" + }, + "image": "https://eggs.ca/wp-content/uploads/2024/06/Creme-Brulee-1664x832-1.jpg" +} diff --git a/tests/test_data/eggs.ca/eggsca_1.testhtml b/tests/test_data/eggs.ca/eggsca_1.testhtml new file mode 100644 index 000000000..5335f8449 --- /dev/null +++ b/tests/test_data/eggs.ca/eggsca_1.testhtml @@ -0,0 +1,341 @@ + + + + + Classic Crème Brûlée | Eggs.ca + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    Recipes
    +

    Classic Crème Brûlée

    +
    + +
    Breaking through crème brûlée’s crispy caramelized top into a thick creamy custard base is pure bliss. Heavy cream gives this classic recipe its silky, rich quality that's like no other dessert.
    +
    +
    Serves +4 +
    Prep Time +15 min +
    Cook Time +35 min +
    +
    +
    + + +
    +
    +

    Ingredients

    +
    • 1 ½ cups (375 mL) whipping cream (35%)
    • 4 egg yolks
    • ¼ cup (60 mL) granulated sugar
    • 1 tsp vanilla extract
    • 4-6 tsp granulated sugar, for caramelizing
    +
    +

    Instructions

    +
    • Step 1

      Preheat oven to 325°F (160°C). Place four 1/2 cup (125 mL) ramekins or custard cups in a baking dish. Set aside.

      +

      Heat cream in saucepan over medium-high heat until small bubbles form around edge of pan. Meanwhile, whisk egg yolks and a 1/4 cup of sugar until thick and lemon-coloured – about 1 to 2 minutes.

      +
    • Step 2

      When cream is hot, gradually whisk into egg yolk mixture. Stir in vanilla. Pour mixture through sieve into ramekins, dividing evenly. Pour very hot water into baking dish to reach halfway up ramekins. Carefully place baking dish in oven. Bake until mostly set but with a slight jiggle in the centre, about 30 to 35 minutes for taller ramekins (about 2 inches (5 cm) high), and 25 to 30 minutes for shallow ramekins (about 1 inch (2.5 cm) high).

      +

      Carefully remove ramekins from water. Cool on wire rack. When cool, cover with plastic wrap and refrigerate for least 2 hours and up to 2 days.

      +
    • Step 3

      Just before serving (or up to 2 hours before serving), sprinkle sugar evenly over surface of desserts (1 tsp for taller ramekins and 1-1/2 tsp for shallow ramekins). Using a mini torch or by placing the ramekins directly under the broiler, heat until sugar melts and caramelizes. Serve immediately, or for a firmer texture, chill until serving time.

      +
    +
    +

    Nutrition Facts

    +
    + + + +
    Per serving
    Calories441
    Fat38 g
    Saturated Fat22 g
    Trans Fat1 g
    Carbohydrate441 g
    Fibre0 g
    Sugars19 g
    Protein5 g
    Sodium43 mg
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/tests/test_data/eggs.ca/eggsca_2.json b/tests/test_data/eggs.ca/eggsca_2.json new file mode 100644 index 000000000..d76e5b89d --- /dev/null +++ b/tests/test_data/eggs.ca/eggsca_2.json @@ -0,0 +1,78 @@ +{ + "author": "Eggs.ca", + "canonical_url": "https://eggs.ca/recipes/fudgey-brownies/", + "site_name": "Eggs.ca", + "host": "eggs.ca", + "language": "en", + "title": "Fudgy Brownies", + "ingredients": [ + "1 ¼ cup (315 mL) all-purpose flour", + "1 tsp baking powder", + "½ tsp (2.5 mL) salt", + "¾ cup (175 mL) butter or margarine", + "¾ cup (175 mL) unsweetened cocoa powder", + "1 cup packed brown sugar", + "1 cup granulated sugar", + "4 eggs", + "2 tsp vanilla extract", + "1 cup chopped walnuts", + "2 tbsp butter or margarine", + "¼ cup (60 mL) unsweetened cocoa powder", + "½ tsp (2.5 mL) vanilla extract", + "2 cups sifted icing sugar", + "¼ cup (60 mL) milk (1%)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 ¼ cup (315 mL) all-purpose flour", + "1 tsp baking powder", + "½ tsp (2.5 mL) salt", + "¾ cup (175 mL) butter or margarine", + "¾ cup (175 mL) unsweetened cocoa powder", + "1 cup packed brown sugar", + "1 cup granulated sugar", + "4 eggs", + "2 tsp vanilla extract", + "1 cup chopped walnuts" + ], + "purpose": "Brownies" + }, + { + "ingredients": [ + "2 tbsp butter or margarine", + "¼ cup (60 mL) unsweetened cocoa powder", + "½ tsp (2.5 mL) vanilla extract", + "2 cups sifted icing sugar", + "¼ cup (60 mL) milk (1%)" + ], + "purpose": "Fudgey Icing" + } + ], + "instructions_list": [ + "Brownies", + "Preheat oven to 350°F (180°C).", + "Combine flour, baking powder and salt in medium bowl; set aside. Melt butter in large saucepan over low heat; remove from heat. Stir in cocoa. Beat in brown sugar, sugar, eggs and vanilla. Stir in dry ingredients and walnuts. Spray or butter a 9-inch (23 cm) square pan. Spread batter in pan. Bake in preheated 350°F (180°C) oven for 40 minutes. Do not overbake. Cool completely.", + "Fudgey Icing", + "Melt butter over low heat in medium saucepan. Remove from heat. Stir in cocoa and vanilla. Stir in icing sugar and milk until smooth and of spreading consistency. Spread icing over cooled brownies." + ], + "category": "Desserts & Sweets", + "yields": "20 servings", + "description": "Fudgey brownies are every kid's favourite. These brownies make a decadent dessert and are a great recipe for any bake sale, potluck or birthday celebration.", + "total_time": 55, + "cook_time": 15, + "prep_time": 15, + "nutrients": { + "calories": "294", + "fatContent": "14 g", + "saturatedFatContent": "6 g", + "transFatContent": "0 g", + "carbohydrateContent": "42 g", + "sugarContent": "33 g", + "proteinContent": "5 g", + "sodiumContent": "167 mg", + "fiberContent": "2 g", + "cholesterolContent": "2 mg" + }, + "image": "https://eggs.ca/wp-content/uploads/2024/06/Fudgey-Brownies-UPDATED-CMS.jpg" +} diff --git a/tests/test_data/eggs.ca/eggsca_2.testhtml b/tests/test_data/eggs.ca/eggsca_2.testhtml new file mode 100644 index 000000000..4fce17787 --- /dev/null +++ b/tests/test_data/eggs.ca/eggsca_2.testhtml @@ -0,0 +1,330 @@ + + + + + + Fudgy Brownies | Eggs.ca + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    Recipes
    +

    Fudgy Brownies

    +
    + +
    Fudgey brownies are every kid's favourite. These brownies make a decadent dessert and are a great recipe for any bake sale, potluck or birthday celebration.
    +
    +
    Serves +20 +
    Prep Time +15 min +
    Cook Time +40 min +
    +
    +
    + + +
    +
    +

    Ingredients

    +
    • Brownies

      • 1 ¼ cup (315 mL) all-purpose flour
      • 1 tsp baking powder
      • ½ tsp (2.5 mL) salt
      • ¾ cup (175 mL) butter or margarine
      • ¾ cup (175 mL) unsweetened cocoa powder
      • 1 cup packed brown sugar
      • 1 cup granulated sugar
      • 4 eggs
      • 2 tsp vanilla extract
      • 1 cup chopped walnuts
    • Fudgey Icing

      • 2 tbsp butter or margarine
      • ¼ cup (60 mL) unsweetened cocoa powder
      • ½ tsp (2.5 mL) vanilla extract
      • 2 cups sifted icing sugar
      • ¼ cup (60 mL) milk (1%)
    +
    +

    Instructions

    +
    • Brownies

      • Step 1

        Preheat oven to 350°F (180°C).

        +
      • Step 2

        Combine flour, baking powder and salt in medium bowl; set aside. Melt butter in large saucepan over low heat; remove from heat. Stir in cocoa. Beat in brown sugar, sugar, eggs and vanilla. Stir in dry ingredients and walnuts. Spray or butter a 9-inch (23 cm) square pan. Spread batter in pan. Bake in preheated 350°F (180°C) oven for 40 minutes. Do not overbake. Cool completely.

        +
    • Fudgey Icing

      • Step 1

        Melt butter over low heat in medium saucepan. Remove from heat. Stir in cocoa and vanilla. Stir in icing sugar and milk until smooth and of spreading consistency. Spread icing over cooled brownies.

        +
    +
    +

    Nutrition Facts

    +
    + + + +
    Per serving
    Calories294
    Fat14 g
    Saturated Fat6 g
    Trans Fat0 g
    Carbohydrate294 g
    Fibre2 g
    Sugars33 g
    Protein5 g
    Sodium167 mg
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/tests/test_data/elavegan.com/elavegan_1.json b/tests/test_data/elavegan.com/elavegan_1.json index aaf00b359..ceb8de8e2 100644 --- a/tests/test_data/elavegan.com/elavegan_1.json +++ b/tests/test_data/elavegan.com/elavegan_1.json @@ -7,21 +7,21 @@ "title": "Red Lentil Dahl", "ingredients": [ "1 1/2 cups dry red lentils", - "1 large carrot (finely diced (see notes))", + "1 large carrot (finely diced (see notes)", "1 small bell pepper", "1 large onion (chopped)", "4 cloves of garlic (minced)", "1 heaped tbsp fresh ginger (minced)", "1/2 tbsp vegetable oil", "3 cups vegetable broth (or water)", - "1 cup canned coconut milk ((see notes))", + "1 cup canned coconut milk (see notes)", "1 1/2 tsp ground cumin", "1 tbsp curry powder", "1/2 tbsp sweetener of choice", "1 tsp ground turmeric", "1 tsp paprika", "Sea salt and black pepper (to taste)", - "1/3 tsp red pepper flakes ((optional))" + "1/3 tsp red pepper flakes (optional)" ], "instructions_list": [ "You can watch the short video for visual instructions.Rinse lentils under running water. Chop the onion, garlic, ginger, bell pepper, and carrot.", diff --git a/tests/test_data/elavegan.com/elavegan_2.json b/tests/test_data/elavegan.com/elavegan_2.json index 5a3a3270b..65932e357 100644 --- a/tests/test_data/elavegan.com/elavegan_2.json +++ b/tests/test_data/elavegan.com/elavegan_2.json @@ -6,8 +6,8 @@ "language": "en-US", "title": "Vegan Coffee Cake", "ingredients": [ - "1 cup oat flour ((gluten-free if needed))", - "1/2 cup rice flour ((see notes))", + "1 cup oat flour (gluten-free if needed)", + "1/2 cup rice flour (see notes)", "2 Tbsp cornstarch (or potato starch)", "1/3 cup Erythritol (or sugar)", "1 1/2 tsp baking powder", @@ -15,7 +15,7 @@ "1/2 tsp sea salt", "3/4 cup almond milk (or any other dairy-free milk)", "2/3 cup applesauce (unsweetened)", - "2 Tbsp oil ((see notes))", + "2 Tbsp oil (see notes)", "1 Tbsp apple cider vinegar", "1 tsp vanilla extract", "1/2 cup rice flour (or regular flour, if you're not gluten-free)", @@ -29,8 +29,8 @@ "ingredient_groups": [ { "ingredients": [ - "1 cup oat flour ((gluten-free if needed))", - "1/2 cup rice flour ((see notes))", + "1 cup oat flour (gluten-free if needed)", + "1/2 cup rice flour (see notes)", "2 Tbsp cornstarch (or potato starch)", "1/3 cup Erythritol (or sugar)", "1 1/2 tsp baking powder", @@ -43,7 +43,7 @@ "ingredients": [ "3/4 cup almond milk (or any other dairy-free milk)", "2/3 cup applesauce (unsweetened)", - "2 Tbsp oil ((see notes))", + "2 Tbsp oil (see notes)", "1 Tbsp apple cider vinegar", "1 tsp vanilla extract" ], diff --git a/tests/test_data/fifteenspatulas.com/fifteenspatulas.json b/tests/test_data/fifteenspatulas.com/fifteenspatulas.json index 851afc54c..ebceb89af 100644 --- a/tests/test_data/fifteenspatulas.com/fifteenspatulas.json +++ b/tests/test_data/fifteenspatulas.com/fifteenspatulas.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Creme Brulee", "ingredients": [ - "zest of 4 oranges* ((about 2 tsp))", + "zest of 4 oranges* (about 2 tsp)", "3 cups heavy cream", "5 large egg yolks", "1/2 cup sugar +1 tsp for each crème brûlée", diff --git a/tests/test_data/foodrepublic.com/foodrepublic.json b/tests/test_data/foodrepublic.com/foodrepublic.json index 424abf7c7..42ab880ea 100644 --- a/tests/test_data/foodrepublic.com/foodrepublic.json +++ b/tests/test_data/foodrepublic.com/foodrepublic.json @@ -1,4 +1,5 @@ { + "author": "Michael's Restaurant", "canonical_url": "https://www.foodrepublic.com/recipes/dutch-white-asparagus-recipe/", "site_name": "Food Republic", "host": "foodrepublic.com", @@ -27,7 +28,10 @@ "Goat Cheese And Asparagus Macaroni Salad Recipe", "Roasted Asparagus & Scrambled Eggs Recipe" ], - "yields": "0 servings", + "yields": "4 servings", "total_time": 60, + "cook_time": 40, + "prep_time": 20, + "cuisine": "Dutch", "image": "https://www.foodrepublic.com/img/gallery/dutch-white-asparagus-recipe/intro-import.jpg" } diff --git a/tests/test_data/foodrepublic.com/foodrepublic.testhtml b/tests/test_data/foodrepublic.com/foodrepublic.testhtml index 33a44a70e..15543f4dd 100644 --- a/tests/test_data/foodrepublic.com/foodrepublic.testhtml +++ b/tests/test_data/foodrepublic.com/foodrepublic.testhtml @@ -1,32 +1,56 @@ - - - - - + + + + + + + + + + + + + - Dutch White Asparagus Recipe - Food Republic - - - - + Dutch White Asparagus Recipe + + + + - - + + + + - - - + + @@ -34,14 +58,13 @@ + + + + + - - - - - - - - +
    @@ -91,29 +114,38 @@
  • Recipes
  • News
  • Cook
  • -
  • Food
  • +
  • Facts
  • Drink
  • Restaurants
  • Grocery
  • +
  • Exclusives
  • Features
  • - - +

  • + + + + + + + - + +
    - +
    @@ -124,7 +156,7 @@ Food Republic
    - + - - + + + - + + + + + + +
    - +
    -
    -
    -
    -
    -
    - - - -
    -

    Dutch White Asparagus Recipe

    -
    - - - - - -
    -

    +

    +
    +
    + + +
    + + + +
    +

    Dutch White Asparagus Recipe

    +
    + +
    + + +
    +

    One of the great things about spring menus is all the tender, fresh green vegetable dishes. Longstanding Midtown dining spot Michael's New York, owned by restaurateur Michael McCarty, boasts a Dutch recipe we had to try: citrus-steamed Dutch white asparagus (they actually do a mix of white and green) with a wine-spiked butter sauce, a runny poached egg and a little Parmesan cheese. A little prosciutto never hurt anyone, either.

    - -

    - -
    -
    - -
    - -
    -
    -
    - Dutch White Asparagus Recipe
    - -
    -
    -
    Prep Time
    -
    20
    -
    minutes
    -
    -
    -
    Cook Time
    -
    40
    -
    minutes
    -
    -
    -
    Servings
    -
    0
    -
    servings
    -
    -
    - -
    -
    -
    -
    - -
    - Ingredients -
    -
      -
    • 12 spears Dutch white asparagus
    • -
    • 1/2 each Meyer lemon
    • -
    • 2 cups water
    • -
    • 1 cup grated Parmesan cheese
    • -
    • 1/2 cup Chardonnay
    • -
    • 1/2 cup white wine vinegar
    • -
    • 2 sprigs fresh thyme
    • -
    • 1/2 cup shallots
    • -
    • small chunk of Parmesan rind
    • -
    • 4 tablespoons unsalted butter
    • -
    • 4 fresh eggs
    • -
    • 4 slices prosciutto
    • -
    -
    - Directions -
    -
      -
    1. After peeling and trimming the asparagus, steam it in citrus water — water with Meyer lemon, orange and grapefruit slices — until fork tender.
    2. -
    3. In a pot add the Chardonnay, white wine vinegar, thyme, shallots and chunk of Parmesan rind; reduce about a quarter.
    4. -
    5. Remove from heat and slowly whisk in cubes of butter until sauce is thick and glossy.
    6. -
    7. Pour 2 tablespoons of beurre blanc on a plate, top it with a poached egg, steamed white asparagus, prosciutto and grated Parmesan.
    8. -
    9. Spring Asparagus Soup Recipe
    10. -
    11. Goat Cheese And Asparagus Macaroni Salad Recipe
    12. -
    13. Roasted Asparagus & Scrambled Eggs Recipe
    14. -
    -
    - Rate this recipe -
    -
    -
    -
    -
    -
    -
    - - -
    - - -
    - - -
    -
    -
    - - - -
    +
    +
    +
    + +
    +
    +
    Dutch White Asparagus Recipe
    + +
    +
    +
    Prep Time
    +
    20
    +
    minutes
    +
    +
    +
    Cook Time
    +
    40
    +
    minutes
    +
    +
    +
    Servings
    +
    4
    +
    +
    +
    + Dutch White Asparagus Recipe +
    +
    Total time: 1 hour
    +
    +
    +
    +
    +
    +
    Ingredients
    +
      +
    • 12 spears Dutch white asparagus
    • +
    • 1/2 each Meyer lemon
    • +
    • 2 cups water
    • +
    • 1 cup grated Parmesan cheese
    • +
    • 1/2 cup Chardonnay
    • +
    • 1/2 cup white wine vinegar
    • +
    • 2 sprigs fresh thyme
    • +
    • 1/2 cup shallots
    • +
    • small chunk of Parmesan rind
    • +
    • 4 tablespoons unsalted butter
    • +
    • 4 fresh eggs
    • +
    • 4 slices prosciutto
    • +
    + +
    Directions
    +
      +
    1. After peeling and trimming the asparagus, steam it in citrus water — water with Meyer lemon, orange and grapefruit slices — until fork tender.
    2. +
    3. In a pot add the Chardonnay, white wine vinegar, thyme, shallots and chunk of Parmesan rind; reduce about a quarter.
    4. +
    5. Remove from heat and slowly whisk in cubes of butter until sauce is thick and glossy.
    6. +
    7. Pour 2 tablespoons of beurre blanc on a plate, top it with a poached egg, steamed white asparagus, prosciutto and grated Parmesan.
    8. +
    9. Spring Asparagus Soup Recipe
    10. +
    11. Goat Cheese And Asparagus Macaroni Salad Recipe
    12. +
    13. Roasted Asparagus & Scrambled Eggs Recipe
    14. +
    + +
    + +
    +
    +
    + +
    +
    + - -
    -
    - -
    - -
    -
    - + +
    + +
    + + + + + + +
    +
    + - - - + - - - + + - + \ No newline at end of file diff --git a/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json b/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json index 216f988c9..f0fa60bf4 100644 --- a/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json +++ b/tests/test_data/glutenfreeonashoestring.com/glutenfreeonashoestring_1.json @@ -12,9 +12,8 @@ "1/2 teaspoon kosher salt", "5 1/4 ounces warm water", "1 tablespoon extra virgin olive oil (plus more for handling and brushing)", - "Your favorite pizza toppings ((sauce, shredded or sliced mozzarella cheese))" + "Your favorite pizza toppings (sauce, shredded or sliced mozzarella cheese)" ], - "instructions": "To make the pizza dough.\nIn the bowl of your stand mixer fitted with the paddle attachment, place the flour, yeast, and sugar. Whisk to combine with a separate, handheld whisk. Add the salt, and whisk again to combine well.\nAdd the water and olive oil, and mix very slowly until the flour is absorbed into the liquid. The mixture will be lumpy\nRaise the mixer to medium-high speed in your stand mixer until the dough becomes sticky and smooth (about 3 minutes).\nOil a medium-size bowl, and scrape the pizza dough into the bowl.\nUsing very well-oiled hands, loosely shape the dough into a round.\nCover the bowl tightly with plastic and place in a draft-free location until nearly doubled in size. That will take longer in cool, dry environments and less time in warm, moist places.\nTo bake the pizza.\nWhen you’re ready to make the pizza, place a pizza stone or overturned rimmed baking sheet in the oven and preheat it to 450°F.\nPlace a 14-inch round nonstick pizza baking pan or a large piece of parchment paper in front of you on a flat surface\nThe dough will be super soft, and should only be handled once you’ve coated your hands in olive oil. Turn the dough out onto the center of the pan or paper.\nWorking from the center of the dough out to the edges, begin to press it into a round about 14-inches in diameter.\nCreate a smooth, slightly raised edge around the perimeter of the dough by pressing the edges with one hand toward the palm of your other.\nBrush the shaped dough with more oil, concentrating it on the edges.\nTransfer the shaped and topped dough, still on the pizza baking sheet or parchment paper, to a pizza peel or other flat surface like a cutting board, and transfer it to the hot oven.\nBake for 5 to 6 minutes, or until the crust seems set all the way to the center and the edges have expanded in size.\nRemove the pan from the oven, top the dough with sauce, cheese, and any other toppings you like best, and return the pizza on the pan or paper to the oven.\nBake until the has begun to crisp on the underside, is lightly brown on the edges, and the cheese is brown and bubbling (about 5 minutes).\nRemove from the oven, allow to set for just a few minutes, then slice and serve hot.", "instructions_list": [ "To make the pizza dough.", "In the bowl of your stand mixer fitted with the paddle attachment, place the flour, yeast, and sugar. Whisk to combine with a separate, handheld whisk. Add the salt, and whisk again to combine well.", diff --git a/tests/test_data/goodfooddiscoveries.com/goodfooddiscoveries.json b/tests/test_data/goodfooddiscoveries.com/goodfooddiscoveries.json index d18987620..ac4cafbd3 100644 --- a/tests/test_data/goodfooddiscoveries.com/goodfooddiscoveries.json +++ b/tests/test_data/goodfooddiscoveries.com/goodfooddiscoveries.json @@ -36,6 +36,8 @@ "cook_time": 25, "prep_time": 5, "cuisine": "Italian", + "ratings": 5.0, + "ratings_count": 1, "image": "https://goodfooddiscoveries.com/wp-content/uploads/2023/03/lemon-parmesan-risotto.jpeg", "keywords": [ "lemon", diff --git a/tests/test_data/halfbakedharvest.com/halfbakedharvest.json b/tests/test_data/halfbakedharvest.com/halfbakedharvest.json index 0f6bf6dc5..898495bc3 100644 --- a/tests/test_data/halfbakedharvest.com/halfbakedharvest.json +++ b/tests/test_data/halfbakedharvest.com/halfbakedharvest.json @@ -26,7 +26,6 @@ "instructions_list": [ "1. Bring a large pot of salted water to a boil. Boil the pasta to al dente, according to package directions. Drain and add the pasta right back to the pot. 2. Meanwhile, cook the prosciutto in a large skillet set over medium heat until crispy, about 2 minutes per side. Remove the prosciutto from the skillet. 3. To the skillet, add the butter. Allow the butter to brown until it smells toasted and is a deep golden color, about 3-4 minutes. Stir in the olive oil, shallot, jalapeño, and thyme. Cook 1-2 minutes, then remove from the heat. Pour the browned butter over the hot orzo. Toss to combine. 4. To the orzo, add the basil, chives, lemon juice, vinegar, and honey. Season with salt and pepper and toss. Stir in the corn, tomatoes, and feta. Top the pasta with crispy prosciutto and avocado. Serve warm or at room temp." ], - "category": null, "yields": "6 servings", "description": "When you’re in need of a quick and simple summer meal that's also bright and colorful, make this orzo!", "total_time": 25, diff --git a/tests/test_data/halfbakedharvest.com/halfbakedharvest_groups.json b/tests/test_data/halfbakedharvest.com/halfbakedharvest_groups.json index 18e60bc6f..cd22054cb 100644 --- a/tests/test_data/halfbakedharvest.com/halfbakedharvest_groups.json +++ b/tests/test_data/halfbakedharvest.com/halfbakedharvest_groups.json @@ -15,7 +15,7 @@ "3/4 cup crumbled cotija or feta cheese", "1 pound short cut pasta", "1 head romaine lettuce, shredded", - "2 cups grilled or roasted corn ((3-4 raw))", + "2 cups grilled or roasted corn (3-4 raw)", "1/2 cup fresh basil leaves, torn", "1/2 cup fresh cilantro, chopped", "1/2 cup spicy cheddar cheese, cubed", @@ -44,7 +44,7 @@ "ingredients": [ "1 pound short cut pasta", "1 head romaine lettuce, shredded", - "2 cups grilled or roasted corn ((3-4 raw))", + "2 cups grilled or roasted corn (3-4 raw)", "1/2 cup fresh basil leaves, torn", "1/2 cup fresh cilantro, chopped", "1/2 cup spicy cheddar cheese, cubed", diff --git a/tests/test_data/hungryhappens.net/hungryhappens_2.json b/tests/test_data/hungryhappens.net/hungryhappens_2.json index e9a036560..abc399c0a 100644 --- a/tests/test_data/hungryhappens.net/hungryhappens_2.json +++ b/tests/test_data/hungryhappens.net/hungryhappens_2.json @@ -9,14 +9,14 @@ "1/2 head green cabbage, (fine shredded)", "1/2 large cucumber", "3 tbs dill, (chopped)", - "1/4 cup champagne vinegar ((or white wine vinegar))", + "1/4 cup champagne vinegar (or white wine vinegar)", "salt and pepper (to taste)", "3 avocadoes", "2 tsp Sriracha sauce", "1 lime, (juiced)", "salt and pepper (to taste)", "2 lbs salmon, (skin removed)", - "2 tsp chipotle powder ((or chili powder))", + "2 tsp chipotle powder (or chili powder)", "1 tsp onion powder", "1 tsp dried oregano", "1 lime, (zested + juiced)", @@ -28,7 +28,7 @@ "1/2 head green cabbage, (fine shredded)", "1/2 large cucumber", "3 tbs dill, (chopped)", - "1/4 cup champagne vinegar ((or white wine vinegar))", + "1/4 cup champagne vinegar (or white wine vinegar)", "salt and pepper (to taste)" ], "purpose": "Slaw:" @@ -45,7 +45,7 @@ { "ingredients": [ "2 lbs salmon, (skin removed)", - "2 tsp chipotle powder ((or chili powder))", + "2 tsp chipotle powder (or chili powder)", "1 tsp onion powder", "1 tsp dried oregano", "1 lime, (zested + juiced)", diff --git a/tests/test_data/indianhealthyrecipes.com/indianhealthyrecipes.json b/tests/test_data/indianhealthyrecipes.com/indianhealthyrecipes.json index 28abb7437..6dc36fb02 100644 --- a/tests/test_data/indianhealthyrecipes.com/indianhealthyrecipes.json +++ b/tests/test_data/indianhealthyrecipes.com/indianhealthyrecipes.json @@ -6,11 +6,11 @@ "language": "en-US", "title": "Banana Cake Recipe", "ingredients": [ - "2 cups (240 grams) all-purpose flour (or wheat flour (refer notes))", + "2 cups (240 grams) all-purpose flour (or wheat flour (refer notes)", "2 ½ teaspoons (12.5 g) baking powder", - "½ teaspoon salt ((or ⅓ teaspoon table salt))", - "1 cup (200 grams) fine sugar ((prefer organic))", - "100 grams (3.53 oz) unsalted butter ((soft & cold) )", + "½ teaspoon salt (or ⅓ teaspoon table salt)", + "1 cup (200 grams) fine sugar (prefer organic)", + "100 grams (3.53 oz) unsalted butter (soft & cold) )", "2 eggs", "2 teaspoons (10 ml) vanilla extract", "160 ml milk", diff --git a/tests/test_data/inspiredtaste.net/inspiredtaste_1.json b/tests/test_data/inspiredtaste.net/inspiredtaste_1.json new file mode 100644 index 000000000..f611dedd7 --- /dev/null +++ b/tests/test_data/inspiredtaste.net/inspiredtaste_1.json @@ -0,0 +1,50 @@ +{ + "author": "Joanne Gallagher", + "canonical_url": "https://www.inspiredtaste.net/51500/pressure-cooker-applesauce/", + "site_name": "Inspired Taste - Easy Recipes for Home Cooks", + "host": "inspiredtaste.net", + "language": "en-US", + "title": "Ridiculously Easy Instant Pot Applesauce", + "ingredients": [ + "4 pounds crisp, sweet apples (8 large), rinsed", + "One 3-inch cinnamon stick or 1/2 teaspoon ground cinnamon", + "1 to 2 whole star anise, optional", + "2 tablespoons fresh lemon juice, fresh orange juice, or apple cider vinegar", + "1 ½ teaspoons vanilla extract", + "Brown sugar, honey, maple syrup, or other sweetener to taste, optional" + ], + "instructions_list": [ + "Peel apples, remove the apple cores, and cut apples into 1-inch chunks or wedges.", + "Place the apples, cinnamon stick, lemon juice, vanilla extract, and star anise into the bottom of a 6-quart electric pressure cooker (Instant Pot).", + "Add 1/3 cup of water, then stir the apples around the pot a few times.", + "Close the lid, select the “Pressure Cook” or “Manual” function, and cook on high pressure for 5 minutes. Note that the timer will not start until there is enough pressure inside the pot, so it may not start for a few minutes.", + "When the cooking time is up, do not immediately open the lid and instead let the pressure naturally release for 20 minutes. After 20 minutes, release the remaining pressure using the quick-release button (be careful to keep your hands and face away from the venting steam).", + "Stir or mash the apples into your preferred consistency. An immersion blender also works, but the apples should be so soft that a spoon is enough to mash them into a sauce.", + "Taste the applesauce. If you would like to add a sweetener, add it to taste. Start with a teaspoon and then add more as needed.", + "The applesauce will thicken a little as it cools, but if it seems too watery, return it to the pressure cooker, turn the sauté function on, and simmer until reduced a little." + ], + "category": "Dessert, Sauce", + "yields": "4 cups", + "description": "Instant Pot applesauce is super simple to make, makes the kitchen smell incredible, and tastes much better than anything you can buy at the store. Use apples that you enjoy eating. We particularly love using crisp, sweet apples when making applesauce and generally do not add any sweetener. If you feel the applesauce needs some extra sweetness, add a sweetener to taste at the end of cooking. We recommend brown sugar, maple syrup, or honey. Peeled apples make this recipe easy, but you can use skin-on apples. If you do, use a food mill fitted with a medium disk to blend the sauce and remove most of the cooked skins for the best texture. You can puree the skins into the sauce if you do not have a food mill. Or pass the sauce through a mesh strainer to remove the skins. **The cooking time for this applesauce is 5 minutes, but keep in mind that the pressure cooker takes additional time to reach pressure before the cooking time begins and releases the pressure after the cooking time ends.", + "total_time": 35, + "cook_time": 25, + "prep_time": 10, + "cuisine": "American", + "nutrients": { + "servingSize": "1/4 cup", + "calories": "60", + "fatContent": "0.2g", + "saturatedFatContent": "0g", + "carbohydrateContent": "15.5g", + "sugarContent": "11.6g", + "proteinContent": "0.3g", + "sodiumContent": "1.3mg", + "fiberContent": "2.7g", + "cholesterolContent": "0mg" + }, + "image": "https://www.inspiredtaste.net/wp-content/uploads/2021/10/Instant-Pot-Applesauce-Recipe-4-1200.jpg", + "keywords": [ + "instant pot applesauce", + "pressure cooker applesauce" + ] +} diff --git a/tests/test_data/inspiredtaste.net/inspiredtaste_1.testhtml b/tests/test_data/inspiredtaste.net/inspiredtaste_1.testhtml new file mode 100644 index 000000000..b3fbb3f67 --- /dev/null +++ b/tests/test_data/inspiredtaste.net/inspiredtaste_1.testhtml @@ -0,0 +1,1303 @@ + + + + + + +Ridiculously Easy Instant Pot Applesauce Recipe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +

    Ridiculously Easy Instant Pot Applesauce

    + +
    + +
    + Pin +
    +
    + Save +
    +
    +
    + +

    My family loves this Instant Pot applesauce so much. It’s quick, easy, and tastes incredible! Skip the store-bought jars and packets and make your own. It tastes so much better!

    + + + +
    Easy Instant Pot Applesauce
    + + + +

    I’m still getting over how easy it is to make applesauce in the Instant Pot. Toss in your apples, water, and spices, then close the lid and cook. Release the pressure, and you’ve got applesauce!

    + + + +

    Our family loves homemade applesauce. It tastes way better than the jars or packets at the store and makes your kitchen smell incredible! If you’ve got some leftover apples, try our apple butter recipe. It’s like applesauce but thicker and spreadable.

    + + + +

    Key Ingredients

    + + + +
      +
    • Apples: I love sweet, crisp apples like Honeycrisp, Fuji, Cox, Gala, and Pink Lady. They taste great after cooking, and since they are already on the sweeter side, I usually don’t need to add any sweetener.
    • + + + +
    • Spices: You can experiment with different spices for this recipe, but I love cinnamon sticks and whole star anise. I also add a splash of vanilla extract, which makes the applesauce taste incredible.
    • + + + +
    • Lemon: I love adding a little acid to the apples. Fresh lemon juice is perfect, but fresh orange juice or apple cider vinegar are great substitutes.
    • + + + +
    • Sweetener (optional): I usually skip the sweetener, but you can stir in brown sugar, maple syrup, or honey. If you plan to add some, add the sweetener after the applesauce has finished cooking. This way, you can add to taste.
    • +
    + + + +
    Peeled and chopped apples in an Instant Pot
    + + + +

    How to Make Instant Pot Applesauce

    + + + +

    Making applesauce in a pressure cooker is simple and fuss-free. Toss peeled apples, spices (I like cinnamon and star anise), lemon juice, and water into the pressure cooker. Then, close the lid and cook on high pressure for 5 minutes.

    + + + +
    Making applesauce -- Apples after cooking them in an Instant Pot
    + + + +

    Allow the pressure cooker to release naturally for 20 minutes (this is important for the best texture), and finally, open the lid and mash or stir the apples into a sauce. So easy! If you find the applesauce too tart, stir in a bit of sweetener, like sugar or honey, at the end.

    + + + +
    A bowl of homemade Instant Pot Applesauce
    + + +

    Ridiculously Easy Instant Pot Applesauce

    +
    + Pin +
    +
    + Save +
    +
    + Email +
    +
    +
    +
      +
    • + PREP + +
    • +
    • + COOK + +
    • +
    • + TOTAL + +
    • + +
    +
    +

    Instant Pot applesauce is super simple to make, makes the kitchen smell incredible, and tastes much better than anything you can buy at the store. Use apples that you enjoy eating. We particularly love using crisp, sweet apples when making applesauce and generally do not add any sweetener. If you feel the applesauce needs some extra sweetness, add a sweetener to taste at the end of cooking. We recommend brown sugar, maple syrup, or honey.

    +

    Peeled apples make this recipe easy, but you can use skin-on apples. If you do, use a food mill fitted with a medium disk to blend the sauce and remove most of the cooked skins for the best texture. You can puree the skins into the sauce if you do not have a food mill. Or pass the sauce through a mesh strainer to remove the skins.

    +

    **The cooking time for this applesauce is 5 minutes, but keep in mind that the pressure cooker takes additional time to reach pressure before the cooking time begins and releases the pressure after the cooking time ends.

    +
    +
    Makes 4 Cups
    +
    +

    You Will Need

    4 pounds crisp, sweet apples (8 large), rinsed

    +

    One 3-inch cinnamon stick or 1/2 teaspoon ground cinnamon

    +

    1 to 2 whole star anise, optional

    +

    2 tablespoons fresh lemon juice, fresh orange juice, or apple cider vinegar

    +

    1 ½ teaspoons vanilla extract

    +

    Brown sugar, honey, maple syrup, or other sweetener to taste, optional

    +
    +
    +
    +

    Directions

    +

      1Peel apples, remove the apple cores, and cut apples into 1-inch chunks or wedges.

      +

      2Place the apples, cinnamon stick, lemon juice, vanilla extract, and star anise into the bottom of a 6-quart electric pressure cooker (Instant Pot).

      +

      3Add 1/3 cup of water, then stir the apples around the pot a few times.

      +

      4Close the lid, select the “Pressure Cook” or “Manual” function, and cook on high pressure for 5 minutes. Note that the timer will not start until there is enough pressure inside the pot, so it may not start for a few minutes.

      +

      5When the cooking time is up, do not immediately open the lid and instead let the pressure naturally release for 20 minutes. After 20 minutes, release the remaining pressure using the quick-release button (be careful to keep your hands and face away from the venting steam).

      +

      6Stir or mash the apples into your preferred consistency. An immersion blender also works, but the apples should be so soft that a spoon is enough to mash them into a sauce.

      +

      7Taste the applesauce. If you would like to add a sweetener, add it to taste. Start with a teaspoon and then add more as needed.

      +

      8The applesauce will thicken a little as it cools, but if it seems too watery, return it to the pressure cooker, turn the sauté function on, and simmer until reduced a little.

      +

      +
      + +
    +
    +
    +

    Adam and Joanne's Tips

    +
      +
    • Add more cinnamon: One cinnamon stick adds a little warmth to the applesauce, but it is not overpowering. If you love a lot of cinnamon in your applesauce, add an extra 1/2 teaspoon to the pot.
    • +
    • The nutrition facts provided below are estimates. We did not include sugar in the calculations.
    • +
    +
    +
    + +
    + Nutrition Per Serving + Serving Size + 1/4 cup + / + Calories + 60 + / + Total Fat + 0.2g + / + Saturated Fat + 0g + / + Cholesterol + 0mg + / + Sodium + 1.3mg + / + Carbohydrate + 15.5g + / + Dietary Fiber + 2.7g + / + Total Sugars + 11.6g + / + Protein + 0.3g + + +
    + + AUTHOR: + + Joanne Gallagher +
    + +
    +
    + Inspired Taste Newsletter Signup +
    +
    +
    1 comment… Leave a Review
    +
      +
    • + Conni + October 7, 2021, 12:24 pm +
      +

      Our neighbours gave us a big bucket of ugly duckling looking apples from their tree. Wormy, rotty spots… all kinds. I quartered them, cut out the core & yucky bits and followed your instructions. I normally use a crock pot, but it takes SO much longer. After they cooled a bit I dumped them in the blender (skins on). I’ve NEVER had applesauce THIS fast, THIS easy & THIS good! I froze a bunch in ziplock bags, flat. Perfection! Thank you!

      +
      + Reply +
    • +
    +
    +
    +

    Leave a Reply

    +

    Leave a Review

    Your email address will not be published. Required fields are marked *

    + +

    +
    +

    Rate this recipe!

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

    + +

    +

    All comments are moderated before appearing on the site. Thank you so much for waiting. First time commenting? Please review our comment guidelines. You must be at least 16 years old to post a comment. All comments are governed by our Privacy Policy & Terms.

    +
    + Previous Post: + Next Post: +
    +
    + +
    + +
    + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/inspiredtaste.net/inspiredtaste_2.json b/tests/test_data/inspiredtaste.net/inspiredtaste_2.json new file mode 100644 index 000000000..ddd6c44ad --- /dev/null +++ b/tests/test_data/inspiredtaste.net/inspiredtaste_2.json @@ -0,0 +1,92 @@ +{ + "author": "Joanne Gallagher", + "canonical_url": "https://www.inspiredtaste.net/76710/strawberry-shortcake-recipe/", + "site_name": "Inspired Taste - Easy Recipes for Home Cooks", + "host": "inspiredtaste.net", + "language": "en-US", + "title": "Perfect Strawberry Shortcake", + "ingredients": [ + "2 ¼ cups (292g) all-purpose flour", + "1 tablespoon (12g) aluminum-free baking powder", + "1/4 cup (50g) sugar", + "1/2 teaspoon (2g) fine sea salt", + "3 tablespoons (42g) cold butter", + "1 cup (236ml) whole milk", + "1 large egg, lightly beaten", + "2 pounds (907g) fresh strawberries, hulled and quartered", + "1 ¼ cups (250g) sugar", + "1 ½ cups (355ml) cold heavy whipping cream", + "3 tablespoons (38g) sugar", + "1 teaspoon vanilla extract" + ], + "ingredient_groups": [ + { + "ingredients": [ + "2 ¼ cups (292g) all-purpose flour", + "1 tablespoon (12g) aluminum-free baking powder", + "1/4 cup (50g) sugar", + "1/2 teaspoon (2g) fine sea salt", + "3 tablespoons (42g) cold butter", + "1 cup (236ml) whole milk", + "1 large egg, lightly beaten" + ], + "purpose": "Shortcakes" + }, + { + "ingredients": [ + "2 pounds (907g) fresh strawberries, hulled and quartered", + "1 ¼ cups (250g) sugar" + ], + "purpose": "Strawberry Filling" + }, + { + "ingredients": [ + "1 ½ cups (355ml) cold heavy whipping cream", + "3 tablespoons (38g) sugar", + "1 teaspoon vanilla extract" + ], + "purpose": "Whipped Cream" + } + ], + "instructions_list": [ + "Make Shortcakes", + "Preheat your oven to 375°F (190°C). Line a baking sheet with parchment paper. If you have them, arrange six 4-inch English muffin rings on the sheet.", + "Whisk the flour, baking powder, sugar, and salt in a mixing bowl.", + "Cut the cold butter into small pieces and work it into the flour mixture with a pastry blender, your fingers, or two knives until it resembles coarse crumbs.", + "Stir in the milk and egg until the batter just comes together.", + "Divide the batter evenly among the rings (about 4 tablespoons each). They will spread out, no need to spread them before baking. If you do not have the rings, spoon the batter in tall mounds directly onto the parchment paper and gently smooth the top.", + "Bake for 15 to 17 minutes, turning the baking sheet halfway through. Let the shortcakes cool completely before building and serving.", + "Prepare the Strawberries and Cream", + "While the shortcakes bake, prepare the strawberries. Place a medium bowl into the freezer to chill.", + "Place a third of the strawberries in a saucepan with the sugar. Cook over medium heat, stirring occasionally, just until the sugar dissolves.", + "Pour the mixture into the chilled bowl, add the remaining strawberries, and refrigerate until chilled.", + "Use a stand mixer or electric hand mixer to beat the heavy cream, sugar, and vanilla extract until medium peaks form. Refrigerate until ready to assemble.", + "Assemble the Shortcakes", + "Slice each shortcake in half horizontally (like an English muffin). Place the bottom half on a serving plate, drizzle with a spoonful of strawberry syrup, then add a generous spoonful of whipped cream. Use a slotted spoon to add some of the strawberries on top of the cream, and then place the other half of the shortcake on top. Repeat with more whipped cream and strawberries." + ], + "category": "Dessert ", + "yields": "6 items", + "description": "This strawberry shortcake recipe is honestly so delicious! The secret to making it best is making the super simple strawberry syrup and drizzling some of it over the bottom of your shortcake before adding the whipped cream and strawberries. It softens the shortcake a bit and adds a lovely strawberry flavor. For perfect rounds, I love using 4-inch English muffin rounds. If you do not have these in your kitchen, you can still bake the shortcakes freeform on the baking sheet. They spread a bit more than if you use the rounds, but they still work well! See our photo in the article showing me baking the shortcake batter in rounds vs. freeform on the baking sheet.", + "total_time": 35, + "cook_time": 15, + "prep_time": 20, + "cuisine": "American", + "ratings": 5.0, + "ratings_count": 4, + "nutrients": { + "servingSize": "1 shortcake", + "calories": "620", + "fatContent": "18.3g", + "saturatedFatContent": "10.9g", + "carbohydrateContent": "107.8g", + "sugarContent": "66.8g", + "proteinContent": "9.2g", + "sodiumContent": "236.8mg", + "fiberContent": "4.3g", + "cholesterolContent": "81mg" + }, + "image": "https://www.inspiredtaste.net/wp-content/uploads/2024/06/Strawberry-Shortcake-Recipe-1.jpg", + "keywords": [ + "strawberry shortcake recipe" + ] +} diff --git a/tests/test_data/inspiredtaste.net/inspiredtaste_2.testhtml b/tests/test_data/inspiredtaste.net/inspiredtaste_2.testhtml new file mode 100644 index 000000000..b069d826c --- /dev/null +++ b/tests/test_data/inspiredtaste.net/inspiredtaste_2.testhtml @@ -0,0 +1,1465 @@ + + + + + + +Perfect Strawberry Shortcake Recipe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +

    Perfect Strawberry Shortcake

    + +
    + +
    + Pin +
    +
    + Save +
    +
    +
    + +

    This is the most delicious strawberry shortcake recipe we’ve ever made! We layer our buttery homemade shortcake with strawberries, whipped cream, and an irresistible strawberry syrup to make it extra delicious.

    + + + +
    Best Homemade Strawberry Shortcake
    + + + +

    These strawberry shortcakes are closer to an authentic shortcake than most recipes I’ve seen. The shortcakes have a buttery biscuit flavor with the most wonderful, tender, almost cake-like consistency (thanks to an egg in the batter). They are truly delicious and surprisingly simple to make!

    + + + +

    We worked on this incredible strawberry dessert with Richard Hattaway, and we’ve all fallen head over heels for it. What I love most is the simple strawberry syrup, which we drizzle over the base of our shortcakes before adding whipped cream and fresh strawberries.

    + + + +
    Easy Strawberry Shortcake
    + + + +

    Key Ingredients

    + + + +
      +
    • Strawberries: I use 2 pounds of fresh strawberries. A third of them are cooked with sugar to make a simple strawberry syrup. I drizzle this over the base of our shortcake before adding the whipped cream and strawberries.
    • + + + +
    • Flour: I use all-purpose flour, but soft white wheat flour (like White Lilly, Martha White, and Bob’s Red Mill Fine Pastry Flour) is also excellent.
    • + + + +
    • Baking Powder: I use 1 tablespoon of baking powder to make the shortcakes fluffy and tender. It’s also my secret for the best fluffy biscuits!
    • + + + +
    • Sugar: I use sugar in three ways: in the shortcake batter, for the strawberry syrup, and to sweeten the whipped cream. Granulated sugar, cane sugar, or coconut sugar are fine.
    • + + + +
    • Milk, Butter, and Egg: These are combined with flour to make the shortcakes tender and delicious.
    • + + + +
    • Cream: I use cold heavy cream or heavy whipping cream to make the whipped cream topping.
    • +
    + + + +

    How to Make Strawberry Shortcake

    + + + +

    Homemade strawberry shortcakes have three parts: the shortcake, strawberries in syrup, and whipped cream. But don’t worry, they’re all super easy to make (I promise!).

    + + + +

    The shortcakes are surprisingly simple, more like biscuits than cake. You’ll “cut in” cold butter to the flour mixture until it forms small butter crumbs. I like to use a pastry blender, but two knives or your fingers work just as well. These butter crumbs are key to creating tender, delicious shortcakes because they melt and puff in the oven. The same is true when making homemade biscuits.

    + + + +

    For baking, you can drop spoonfuls of the batter directly onto a baking sheet or use English muffin rings for perfectly round shortcakes (see photo below). I even have a tip in the recipe for making one large, family-style shortcake that you can slice and serve like a cake.

    + + + +
    Baking Shortcakes
    + + + +

    While the shortcakes bake, you’ll make the strawberry syrup. Simply cook some of your strawberries with sugar until the sugar melts. Take it off the heat and gently toss with the remaining strawberries until they’re coated in the syrup, before popping them in the fridge to chill.

    + + + +
    Strawberries in syrup and baked shortcake ready to assemble
    + + + +

    Homemade whipped cream is easy and tastes much better than the canned stuff! Use a stand or hand mixer to beat heavy cream with sugar and vanilla until it’s thick and softly whipped. It only takes a few minutes.

    + + + +

    Now for the fun part: assembling your shortcakes! Split the shortcakes in half, drizzle a spoonful of that delicious strawberry syrup over the bottom, and top with whipped cream, strawberries, the other half of the shortcake, more whipped cream, and even more strawberries. So good!

    + + + +

    I can’t wait for you to try this strawberry shortcake recipe! For more strawberry recipes, take a look at our fresh strawberry cake or this incredible strawberry pie!

    + + +

    Perfect Strawberry Shortcake

    +
    + Pin +
    +
    + Save +
    +
    + Email +
    +
    +
    +
      +
    • + PREP + +
    • +
    • + COOK + +
    • +
    • + TOTAL + +
    • + +
    +
    +

    This strawberry shortcake recipe is honestly so delicious! The secret to making it best is making the super simple strawberry syrup and drizzling some of it over the bottom of your shortcake before adding the whipped cream and strawberries. It softens the shortcake a bit and adds a lovely strawberry flavor.

    +

    For perfect rounds, I love using 4-inch English muffin rounds. If you do not have these in your kitchen, you can still bake the shortcakes freeform on the baking sheet. They spread a bit more than if you use the rounds, but they still work well! See our photo in the article showing me baking the shortcake batter in rounds vs. freeform on the baking sheet.

    +
    +
    Makes 6
    +
    +

    You Will Need

    + Shortcakes

    2 ¼ cups (292g) all-purpose flour

    +

    1 tablespoon (12g) aluminum-free baking powder

    +

    1/4 cup (50g) sugar

    +

    1/2 teaspoon (2g) fine sea salt

    +

    3 tablespoons (42g) cold butter

    +

    1 cup (236ml) whole milk

    +

    1 large egg, lightly beaten

    +
    + Strawberry Filling

    2 pounds (907g) fresh strawberries, hulled and quartered

    +

    1 ¼ cups (250g) sugar

    +
    + Whipped Cream

    1 ½ cups (355ml) cold heavy whipping cream

    +

    3 tablespoons (38g) sugar

    +

    1 teaspoon vanilla extract

    +
    +
    +
    +

    Directions

    +
      +
    • Make Shortcakes
    • 1Preheat your oven to 375°F (190°C). Line a baking sheet with parchment paper. If you have them, arrange six 4-inch English muffin rings on the sheet.

      +

      2Whisk the flour, baking powder, sugar, and salt in a mixing bowl.

      +

      3Cut the cold butter into small pieces and work it into the flour mixture with a pastry blender, your fingers, or two knives until it resembles coarse crumbs.

      +

      4Stir in the milk and egg until the batter just comes together.

      +

      5Divide the batter evenly among the rings (about 4 tablespoons each). They will spread out, no need to spread them before baking. If you do not have the rings, spoon the batter in tall mounds directly onto the parchment paper and gently smooth the top.

      +

      6Bake for 15 to 17 minutes, turning the baking sheet halfway through. Let the shortcakes cool completely before building and serving.

      +

      +
      + +
    +
      +
    • Prepare the Strawberries and Cream
    • 1While the shortcakes bake, prepare the strawberries. Place a medium bowl into the freezer to chill.

      +

      2Place a third of the strawberries in a saucepan with the sugar. Cook over medium heat, stirring occasionally, just until the sugar dissolves.

      +

      3Pour the mixture into the chilled bowl, add the remaining strawberries, and refrigerate until chilled.

      +

      4Use a stand mixer or electric hand mixer to beat the heavy cream, sugar, and vanilla extract until medium peaks form. Refrigerate until ready to assemble.

      +

      +
      + +
    +
      +
    • Assemble the Shortcakes
    • 1Slice each shortcake in half horizontally (like an English muffin). Place the bottom half on a serving plate, drizzle with a spoonful of strawberry syrup, then add a generous spoonful of whipped cream. Use a slotted spoon to add some of the strawberries on top of the cream, and then place the other half of the shortcake on top. Repeat with more whipped cream and strawberries.

      +

      +
      + +
    +
    +
    +

    Adam and Joanne's Tips

    +
      +
    • Make one family-style shortcake: You can bake this batter in a parchment paper-lined 9-inch cake pan or cast iron pan. Add the batter and gently smooth the top, you do not need to spread it out all the way to the sides. The baking time should be similar, possibly requiring a few more minutes than the individual shortcakes. Allow to cook, cut in half horizontally, and build the shortcake as directed above, but build a family-style shortcake instead. Then, cut into the shortcake like a cake or pie for serving. It’s a little more messy, but it looks amazing on the table and is still just as delicious!
    • +
    • Measuring flour: Fluff the flour in its container, then gently scoop it into your measuring cup until slightly mounded. Level off the top with a knife for accurate measuring. For even more accuracy, use a scale and measure the flour by weight (in grams).
    • +
    • Removing shortcake from rings: Run a thin knife around the rings to loosen the shortcake.
    • +
    • The nutrition facts provided below are estimates. These are likely too high since you will have leftover syrup and this recipe is generous with the cream.
    • +
    +
    +
    + +
    + Nutrition Per Serving + Serving Size + 1 shortcake + / + Calories + 620 + / + Total Fat + 18.3g + / + Saturated Fat + 10.9g + / + Cholesterol + 81mg + / + Sodium + 236.8mg + / + Carbohydrate + 107.8g + / + Dietary Fiber + 4.3g + / + Total Sugars + 66.8g + / + Protein + 9.2g + + +
    + + AUTHOR: + + Joanne Gallagher +
    + +
    +
    + Inspired Taste Newsletter Signup +
    +
    +
    13 comments… Leave a Review
    +
      +
    • + Monica + July 1, 2024, 7:12 pm +
      +

      The strawberry shortcake… the absolute best!

      +
      + Reply +
        +
      • + Adam + July 1, 2024, 7:18 pm +
        +

        Yay! 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Excellent!!! + June 30, 2024, 9:41 am +
      +

      This recipe reminds me of my grandmothers, it’s delicious!

      +

      +
      +

      +
      + Reply +
        +
      • + Adam + July 1, 2024, 7:18 pm +
        +

        That is one of the best compliments a recipe can ever get. We are thrilled you love it 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Anita prosser + June 29, 2024, 11:13 pm +
      +

      This strawberry shortcake is amazing! I really appreciate this web sight. You guys use real food and the clarity of the instructions in your recipes make it easy to create the best food Ive ever eaten. It’s like the love you infuse in the recipes comes out in the taste! Thank you for this website and your labor of love in creating it. Anita

      +

      +
      +

      +
      + Reply +
        +
      • + Adam + July 1, 2024, 7:19 pm +
        +

        You made our day with this review and comment 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Isadora + June 29, 2024, 4:25 am +
      +

      Hi from South Africa! just joined and started receiving your recipes. the website is super-user friendly and recipes thus far are fool-proof. Isidora

      +
      + Reply +
        +
      • + Adam + June 29, 2024, 10:13 pm +
        +

        Hi Isadora, We are so happy that you found us and thank you so much! 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Rosalinda Salcedo + June 28, 2024, 8:24 pm +
      +

      This is absolutely amazing!! Love your recipe!! Strawberry shortcake is my absolute favorite dessert!! This is not too sweet and very light!!

      +

      +
      +

      +
      + Reply +
        +
      • + Adam + June 28, 2024, 8:48 pm +
        +

        Yay! We are thrilled that you loved it 🙂

        +
        + Reply +
      • +
      +
    • +
    • + Donna + June 28, 2024, 7:43 pm +
      +

      This looks wonderful. Hope to make it soon! If you’re in a hurry you can get the giant flakey canned biscuits, dip them in melted butter and the coat in sugar. Bake as directed, slice in half and fill with the strawberries.

      +
      + Reply +
    • +
    • + Mila + June 28, 2024, 6:28 pm +
      +

      The Perfect Strawberry Shortcake looks very yummy and easy to follow. We will certainly try it this strawberry season. Thank you for sharing your recipe.

      +

      +
      +

      +
      + Reply +
        +
      • + Adam + June 28, 2024, 7:24 pm +
        +

        Thank you so much Mila. You are going to those this recipe 🙂

        +
        + Reply +
      • +
      +
    • +
    +
    +
    +

    Leave a Reply

    +

    Leave a Review

    Your email address will not be published. Required fields are marked *

    + +

    +
    +

    Rate this recipe!

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

    + +

    +

    All comments are moderated before appearing on the site. Thank you so much for waiting. First time commenting? Please review our comment guidelines. You must be at least 16 years old to post a comment. All comments are governed by our Privacy Policy & Terms.

    +
    + Previous Post: + Next Post: +
    +
    + +
    + +
    + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/izzycooking.com/izzycooking.json b/tests/test_data/izzycooking.com/izzycooking.json index ff2da46cb..d10dd0e6c 100644 --- a/tests/test_data/izzycooking.com/izzycooking.json +++ b/tests/test_data/izzycooking.com/izzycooking.json @@ -6,12 +6,12 @@ "language": "en-CA", "title": "Oreo Cheesecake Bites Recipe (+Video)", "ingredients": [ - "22 Oreo cookies ((Chop 6 of them into small pieces))", + "22 Oreo cookies (Chop 6 of them into small pieces)", "16 ounces cream cheese (softened)", "1/2 cup granulated sugar", "1/2 tsp vanilla extract", "2 eggs", - "1/2 cup sour cream ((or plain Greek yogurt))" + "1/2 cup sour cream (or plain Greek yogurt)" ], "instructions_list": [ "Preheat oven to 325°F. (Make sure your oven temperature is accurate, as a higher temp can cause the cheesecake to crack.)", diff --git a/tests/test_data/jamieoliver.com/jamieoliver.testhtml b/tests/test_data/jamieoliver.com/jamieoliver.testhtml deleted file mode 100644 index 3c1cb875f..000000000 --- a/tests/test_data/jamieoliver.com/jamieoliver.testhtml +++ /dev/null @@ -1,1223 +0,0 @@ - - - - - - - - - - - - - - - Easy chocolate brownie recipe | Best brownie guide | Jamie Oliver - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - -
    - -
    -
    - - -
    -
    - - - - - - - - - - -
    - - - - -
    - - - - - - -
    -
    - - - - -
    - -
    -
    - - -
    -
    - -
    - -
    - - -
    -
    - - - -
    - -
    - -
    -
    - -
    -

    Bloomin' brilliant brownies

    -

    Rich dark chocolate, nuts & sour cherries

    -
    - -
    -
    - -
    -
    - -
    -
    - - - - -
    -
    -
    -
    - -
    - Bloomin' brilliant brownies
    - -
    - -
    - - - -
    - -
    - -
    -

    Bloomin' brilliant brownies

    - - - - - -
    - - -
    -
    -
    -
    - Serves - Serves 20
    - -
    - Time - Cooks In40 minutes plus chilling time
    - -
    - DifficultySuper easy
    -
    -
    -
    - -
    - - - - -
    - -
    - Nutrition per serving Plus - -
    - -
    -
      -
    • - -
      - - Calories - - 291 - - 15% -
      - -
    • -
    • - -
      - - Fat - - 18.4g - - 26% -
      - -
    • -
    • - -
      - - Saturates - - 10.1g - - 51% -
      - -
    • -
    • - -
      - - Sugars - - 24.6g - - 27% -
      - -
    • -
    • - -
      - - Salt - - 0.2g - - 3% -
      - -
    • -
    • - -
      - - Protein - - 3.9g - - 8% -
      - -
    • -
    • - -
      - - Carbs - - 28.3g - - 11% -
      - -
    • -
    • - -
      - - Fibre - - 1.6g - - - -
      - -
    • -
    - -
    - Of an adult's reference intake
    - -
    - -
    - - -
    - -
    - -
    -
    - - Cook with Jamie -
    - -
    - -
    -
    recipe adapted from
    -

    Cook with Jamie

    - - - By Jamie Oliver - - - - -
    -
    - -
    -
    -
    - - - - - - -
    - -
    - -
    -
    - -
    -
    - -
    - -
    - -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Tap For Method
    -
    -
    - - - - - - -
    -

    Ingredients

    -
    - - - - - -
    -
    - -
      -
    • - 200 g quality dark chocolate (70%)
    • -
    • - 250 g unsalted butter
    • -
    • - 75 g dried sour cherries , optional
    • -
    • - 50 g chopped nuts , optional
    • -
    • - 80 g quality cocoa powder
    • -
    • - 65 g plain flour
    • -
    • - 1 teaspoon baking powder
    • -
    • - 360 g caster sugar
    • -
    • - 4 large free-range eggs
    • -
    -
    -
    -
    - -
    -
    - Tap For Method - - -
    -
    - -
    -

    The cost per serving below is generated by Whisk.com and is based on costs in individual supermarkets.  For more information about how we calculate costs per serving read our FAQS

    - -
    - -
    - -
    - -
    - -
    -
    - - Cook with Jamie -
    - -
    - -
    -
    recipe adapted from
    -

    Cook with Jamie

    - - - By Jamie Oliver - - - - -
    -
    - -
    - -
    - -
    -
    - -
    - -
    - - -
    - - -
    - -
    -
    -
    -
    - -
    -
    - Tap For Ingredients
    -
    -
    - -
    -
    -
    -

    Method

    -
    -
    1. Preheat the oven to 180°C/350°F/gas 4. Line a 24cm square baking tin with greaseproof paper.
    2. Snap the chocolate into a large bowl, add the butter and place over a pan of simmering water, until melted, stirring regularly. Stir through the cherries and nuts (if using).
    3. Sift the cocoa powder and flour into a separate bowl, add the baking powder and sugar, then mix together.
    4. Add the dry ingredients to the chocolate, cherry and nut mixture and stir together well. Beat the eggs, then mix in until you have a silky consistency.
    5. Pour the brownie mix into the baking tin, and place in the oven for around 25 minutes. You don’t want to overcook them so, unlike cakes, you don’t want a skewer to come out clean – the brownies should be slightly springy on the outside but still gooey in the middle.
    6. Allow to cool in the tray, then carefully transfer to a large chopping board and cut into chunky squares. Delicious served with a dollop of crème fraîche or yoghurt mixed with some orange zest.
    - - - - -
    - -
    -
    - -
    - -
    - -
    - - - - -
    - -
    -
    -
    -
    - - - - - - - - -
    - - - - -
    - -
    - -
    - -
    -
    - - Cook with Jamie -
    - -
    - -
    -
    recipe adapted from
    -

    Cook with Jamie

    - - - By Jamie Oliver - - - - -
    -
    - -
    - -
    -
    - - -
    -
    - -
    - -
    - - - -
    -
    - -
    -
    -
    - -
    - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - -
    - -
    - - - - - - - - - diff --git a/tests/test_data/jamieoliver.com/jamieoliver.json b/tests/test_data/jamieoliver.com/jamieoliver_1.json similarity index 56% rename from tests/test_data/jamieoliver.com/jamieoliver.json rename to tests/test_data/jamieoliver.com/jamieoliver_1.json index de0d00c42..9730e1fd6 100644 --- a/tests/test_data/jamieoliver.com/jamieoliver.json +++ b/tests/test_data/jamieoliver.com/jamieoliver_1.json @@ -1,19 +1,19 @@ { "author": "Jamie Oliver", - "canonical_url": "https://www.jamieoliver.com/recipes/chocolate-recipes/bloomin-brilliant-brownies/", + "canonical_url": "https://www.jamieoliver.com/recipes/chocolate/bloomin-brilliant-brownies/", "site_name": "Jamie Oliver", "host": "jamieoliver.com", - "language": "en", + "language": "en-GB", "title": "Bloomin' brilliant brownies", "ingredients": [ - "200 g quality dark chocolate (70%)", - "250 g unsalted butter", - "75 g dried sour cherries optional", - "50 g chopped nuts optional", - "80 g quality cocoa powder", - "65 g plain flour", + "200g quality dark chocolate (70%)", + "250g unsalted butter", + "optional: 75g dried sour cherries", + "optional: 50g chopped nuts", + "80g quality cocoa powder", + "65g plain flour", "1 teaspoon baking powder", - "360 g caster sugar", + "360g caster sugar", "4 large free-range eggs" ], "instructions_list": [ @@ -24,36 +24,26 @@ "Pour the brownie mix into the baking tin, and place in the oven for around 25 minutes. You don’t want to overcook them so, unlike cakes, you don’t want a skewer to come out clean – the brownies should be slightly springy on the outside but still gooey in the middle.", "Allow to cool in the tray, then carefully transfer to a large chopping board and cut into chunky squares. Delicious served with a dollop of crème fraîche or yoghurt mixed with some orange zest." ], - "category": "Desserts", + "category": "Baking", "yields": "20 servings", - "description": "This is a great little recipe for easy, fail-safe, gloriously gooey chocolate brownies", + "description": "This easy brownie recipe from Jamie Oliver never disappoints. It's totally foolproof, and packed with dark chocolate, chopped nuts, cocoa powder and sour cherries. Perfect for weekend baking.", "total_time": 40, - "cuisine": "https://schema.org/VegetarianDiet", + "cook_time": 40, "nutrients": { "calories": "291 calories", - "fatContent": "18.4 g fat", - "saturatedFatContent": "10.1 g saturated fat", - "carbohydrateContent": "28.3 g carbohydrate", - "sugarContent": "24.6 g sugar", - "proteinContent": "3.9 g protein", - "sodiumContent": "0.2 g salt", - "fiberContent": "1.6 g fibre" + "fat": "18.4 g", + "portionWeight": "45.9 g", + "protein": "3.9 g", + "salt": "0.2 g", + "saturatedFat": "10.1 g", + "carbs": "28.3 g", + "classification": "140", + "fibre": "1.6 g", + "sugars": "24.6 g" }, - "image": "https://img.jamieoliver.com/jamieoliver/recipe-database/oldImages/large/88_1_1441269331.jpg?tr=w-800,h-800", + "image": "https://asset.jamieoliver.com/images/cq7w2e71/production/f1e42faa99fb1756e2e1463a8b6af3429a4c323a-1447x2171.jpg/brillbrownies.jpg?rect=0,432,1447,1447&w=600&h=600&fm=webp&q=75&fit=crop&auto=format", "keywords": [ - "chocolate", - "brownies", - "brownie", - "vegetarian", - "sweets and desserts", - "baking", - "cooking", - "chocolate brownies", - "party food", - "baking and desserts", - "Christmas", - "Dinner Party", - "non-promotable", - "Popular" + "Party Food", + "Chocolate Main Ingredient" ] } diff --git a/tests/test_data/jamieoliver.com/jamieoliver_1.testhtml b/tests/test_data/jamieoliver.com/jamieoliver_1.testhtml new file mode 100644 index 000000000..dd8b9593e --- /dev/null +++ b/tests/test_data/jamieoliver.com/jamieoliver_1.testhtml @@ -0,0 +1,197 @@ + +Easy chocolate brownie recipe + + + + + + + + + + +
    Jamie drizzling honey on top of a fig tart

    Share your review and contribute to our community!

    Save and access your favourite recipes and products.

    +Enter the email address associated with your account, and we’ll email you a link to reset your + password. +

    Password Strength

    Must contain at least

    +*Enter your email to receive news and exclusive offers from Jamie Oliver Limited about Jamie's + businesses, including books, TV shows, restaurants, products, commercial partners and + campaigning activities. By signing up, you agree to our Terms of Use . Learn how we collect, use and share your data in our Privacy Policy . +

    Cart item

    Just Added

    Easy chocolate brownies stacked on top of each other
    Save recipe

    Bloomin' brilliant brownies

    Rich dark chocolate, nuts & sour cherries

    Easy chocolate brownies stacked on top of each other
    Save recipe

    40 mins plus chilling time
    Super easy

    serves 20

    About the recipe

    This is a great little recipe for easy, fail-safe, gloriously gooey chocolate brownies


    nutrition per serving

    Calories

    g

    Fat

    g

    Saturates

    g

    Sugars

    g

    Salt

    g

    Protein

    g

    Carbs

    g

    Fibre

    of an adult’s reference intake


    Recipe From

    Cook with Jamie

    Cook with Jamie

    +By Jamie Oliver

    +Ingredients +

    200g quality dark chocolate (70%)

    250g unsalted butter

    optional: 75g dried sour cherries

    optional: 50g chopped nuts

    80g quality cocoa powder

    65g plain flour

    1 teaspoon baking powder

    360g caster sugar

    4 large free-range eggs

    Method

    1. Preheat the oven to 180°C/350°F/gas 4. Line a 24cm square baking tin with greaseproof paper.
    2. Snap the chocolate into a large bowl, add the butter and place over a pan of simmering water, until melted, stirring regularly. Stir through the cherries and nuts (if using).
    3. Sift the cocoa powder and flour into a separate bowl, add the baking powder and sugar, then mix together.
    4. Add the dry ingredients to the chocolate, cherry and nut mixture and stir together well. Beat the eggs, then mix in until you have a silky consistency.
    5. Pour the brownie mix into the baking tin, and place in the oven for around 25 minutes. You don’t want to overcook them so, unlike cakes, you don’t want a skewer to come out clean – the brownies should be slightly springy on the outside but still gooey in the middle.
    6. Allow to cool in the tray, then carefully transfer to a large chopping board and cut into chunky squares. Delicious served with a dollop of crème fraîche or yoghurt mixed with some orange zest.

    Tags

    Perfect Christmas gifts

    Recipes you may like

    related features

    \ No newline at end of file diff --git a/tests/test_data/jamieoliver.com/jamieoliver_2.json b/tests/test_data/jamieoliver.com/jamieoliver_2.json new file mode 100644 index 000000000..e6b5ac29b --- /dev/null +++ b/tests/test_data/jamieoliver.com/jamieoliver_2.json @@ -0,0 +1,110 @@ +{ + "author": "Romy Gill", + "canonical_url": "https://www.jamieoliver.com/recipes/chicken/murg-makhani", + "site_name": "Jamie Oliver", + "host": "jamieoliver.com", + "language": "en-GB", + "title": "Butter chicken", + "ingredients": [ + "750g (1 lb 10 oz) skinless, boneless chicken (thighs and breast), cut into bite-size pieces", + "10g (½ oz) ginger root, peeled and grated (shredded)", + "3 large garlic cloves, peeled and grated (shredded)", + "2 tsp tandoori masala", + "1 tsp ground cumin", + "1 tsp ground coriander", + "1 tsp ground black pepper", + "1 tsp salt", + "2 tbsp yoghurt", + "juice of ½ lemon", + "30ml (1 fl oz/2 tbsp) sunflower oil", + "500g (1 lb 2 oz) tomatoes", + "50g (2 oz) butter", + "20g (3/4 oz) ginger root, peeled and grated (shredded)", + "6 large garlic cloves, peeled and grated (shredded)", + "1 tsp tomato purée (paste)", + "1 tsp tandoori masala", + "1 tsp ground cumin", + "1 tsp ground coriander", + "1 tsp chilli powder", + "1 tsp salt", + "1 tsp sugar", + "30g (1½ oz) ground cashew nuts", + "30ml (1 fl oz/2 tbsp) double (heavy) cream", + "6–8 green cardamom seeds, crushed", + "2 tsp dried fenugreek leaves (kasoori methi)", + "your choice of Indian flatbreads or rice" + ], + "ingredient_groups": [ + { + "ingredients": [ + "750g (1 lb 10 oz) skinless, boneless chicken (thighs and breast), cut into bite-size pieces" + ], + "purpose": null + }, + { + "ingredients": [ + "10g (½ oz) ginger root, peeled and grated (shredded)", + "3 large garlic cloves, peeled and grated (shredded)", + "2 tsp tandoori masala", + "1 tsp ground cumin", + "1 tsp ground coriander", + "1 tsp ground black pepper", + "1 tsp salt", + "2 tbsp yoghurt", + "juice of ½ lemon", + "30ml (1 fl oz/2 tbsp) sunflower oil" + ], + "purpose": "FOR THE MARINADE" + }, + { + "ingredients": [ + "500g (1 lb 2 oz) tomatoes", + "50g (2 oz) butter", + "20g (3/4 oz) ginger root, peeled and grated (shredded)", + "6 large garlic cloves, peeled and grated (shredded)", + "1 tsp tomato purée (paste)", + "1 tsp tandoori masala", + "1 tsp ground cumin", + "1 tsp ground coriander", + "1 tsp chilli powder", + "1 tsp salt", + "1 tsp sugar", + "30g (1½ oz) ground cashew nuts", + "30ml (1 fl oz/2 tbsp) double (heavy) cream", + "6–8 green cardamom seeds, crushed", + "2 tsp dried fenugreek leaves (kasoori methi)" + ], + "purpose": "FOR THE SAUCE" + }, + { + "ingredients": [ + "your choice of Indian flatbreads or rice" + ], + "purpose": "TO SERVE" + } + ], + "instructions_list": [ + "To make the marinade, mix all of the marinade ingredients together in a large bowl. Prick the chicken pieces with a fork to allow the marinade to penetrate the meat. Add the chicken to the bowl and stir well to coat thoroughly. Cover the bowl and set aside in the fridge to marinate for at least a couple of hours.", + "When ready to cook, preheat the oven to 180ºC fan/400ºF/gas 6. Spread the marinated chicken out on a baking tray and cook in the hot oven for 15 minutes.", + "While the chicken is cooking, make the sauce. If the chicken finishes cooking before you have finished making the sauce, switch the oven off after the 15 minutes and leave the meat to rest in the oven.", + "Blanch the tomatoes in a bowl of boiling water for a few minutes, then remove their skins. Cut into quarters and remove the seeds, then roughly chop and place in a food processor. Blitz to a smooth purée.", + "Heat the butter in a saucepan over a medium heat. Once the butter has melted, add the ginger and garlic and cook for 1 minute. Add the puréed fresh tomatoes as well as the tomato purée and cook for 8–10 minutes until the tomatoes are cooked through, stirring regularly to avoid them sticking and burning. Add all the spices, chilli powder, salt and sugar, mix well and cook for a further 2 minutes until emulsified. Lower the heat, then add the ground cashew nuts and cream, and stir well. Add 500–600 ml (20–24 fl oz/ 2½ cups–scant 3 cups) water – the quantity you choose to add depends on how runny you want the sauce to be. Bring the mixture to a boil, and when it starts bubbling, add the chicken, lower the heat and cook for a further 8–10 minutes.", + "Sprinkle over the cardamom seeds and dried fenugreek leaves. Stir and leave to rest for at least 10 minutes before serving with rice or any Indian flatbreads." + ], + "category": "Cookbook Club", + "yields": "5 servings", + "description": "There's so many different ways to cook butter chicken – discover Romy Gill's take on this iconic dish.", + "cuisine": "Indian", + "nutrients": { + "forKids": "false" + }, + "image": "https://asset.jamieoliver.com/images/cq7w2e71/production/b76ba59841d87b3d49ad8d16b5a2380a505e579a-958x1280.jpg/160329475?rect=0,161,958,958&w=600&h=600&fm=webp&q=75&fit=crop&auto=format", + "keywords": [ + "Cookbook Club", + "Curry", + "Chicken", + "Indian-style", + "Dinner Party", + "Dinner" + ] +} diff --git a/tests/test_data/jamieoliver.com/jamieoliver_2.testhtml b/tests/test_data/jamieoliver.com/jamieoliver_2.testhtml new file mode 100644 index 000000000..c70821728 --- /dev/null +++ b/tests/test_data/jamieoliver.com/jamieoliver_2.testhtml @@ -0,0 +1,155 @@ + +Butter Chicken | Jamie Oliver Cookbook Club + + + + + + + + + + +
    Jamie drizzling honey on top of a fig tart

    Share your review and contribute to our community!

    Save and access your favourite recipes and products.

    +Enter the email address associated with your account, and we’ll email you a link to reset your + password. +

    Password Strength

    Must contain at least

    +*Enter your email to receive news and exclusive offers from Jamie Oliver Limited about Jamie's + businesses, including books, TV shows, restaurants, products, commercial partners and + campaigning activities. By signing up, you agree to our Terms of Use . Learn how we collect, use and share your data in our Privacy Policy . +

    Cart item

    Just Added

    Murg makhani
    Save recipe

    Butter chicken

    Murg makhani

    Murg makhani
    Save recipe
    Not Too Tricky

    serves 4-5

    About the recipe

    There are so many different recipes for butter chicken. This is my take, because there is a lot of spark and dispute going on in India about butter chicken. We served so much butter chicken in our restaurant, so I went in search of the very best butter chicken recipe and researched how it all started. I found this gave me a better understanding of this best-loved dish. With its silky smooth, gently spiced tomato, cashew and cream gravy, it’s a comforting, warming dish that feels decadent. It was in 2013 when I started to take a closer look at butter chicken and its history. My mentor, chef Manjit Gill, took me to the first ever Moti Mahal restaurant in Daryagang in Delhi. A restaurant co-founded by Kundan Lal Jaggi, Kundal Lal Gujral and Maggu (also known as Thakur Das) and it was where they created both butter chicken and dal makhani.



    Recipe From

    Romy Gill's India

    Romy Gill's India

    +By Romy Gill

    +Ingredients +

    750g (1 lb 10 oz) skinless, boneless chicken (thighs and breast), cut into bite-size pieces

    FOR THE MARINADE

    10g (½ oz) ginger root, peeled and grated (shredded)

    3 large garlic cloves, peeled and grated (shredded)

    2 tsp tandoori masala

    1 tsp ground cumin

    1 tsp ground coriander

    1 tsp ground black pepper

    1 tsp salt

    2 tbsp yoghurt

    juice of ½ lemon

    30ml (1 fl oz/2 tbsp) sunflower oil

    FOR THE SAUCE

    500g (1 lb 2 oz) tomatoes

    50g (2 oz) butter

    20g (3/4 oz) ginger root, peeled and grated (shredded)

    6 large garlic cloves, peeled and grated (shredded)

    1 tsp tomato purée (paste)

    1 tsp tandoori masala

    1 tsp ground cumin

    1 tsp ground coriander

    1 tsp chilli powder

    1 tsp salt

    1 tsp sugar

    30g (1½ oz) ground cashew nuts

    30ml (1 fl oz/2 tbsp) double (heavy) cream

    6–8 green cardamom seeds, crushed

    2 tsp dried fenugreek leaves (kasoori methi)

    TO SERVE

    your choice of Indian flatbreads or rice

    Method

    1. To make the marinade, mix all of the marinade ingredients together in a large bowl. Prick the chicken pieces with a fork to allow the marinade to penetrate the meat. Add the chicken to the bowl and stir well to coat thoroughly. Cover the bowl and set aside in the fridge to marinate for at least a couple of hours.
    2. When ready to cook, preheat the oven to 180ºC fan/400ºF/gas 6. Spread the marinated chicken out on a baking tray and cook in the hot oven for 15 minutes.
    3. While the chicken is cooking, make the sauce. If the chicken finishes cooking before you have finished making the sauce, switch the oven off after the 15 minutes and leave the meat to rest in the oven.
    4. Blanch the tomatoes in a bowl of boiling water for a few minutes, then remove their skins. Cut into quarters and remove the seeds, then roughly chop and place in a food processor. Blitz to a smooth purée.
    5. Heat the butter in a saucepan over a medium heat. Once the butter has melted, add the ginger and garlic and cook for 1 minute. Add the puréed fresh tomatoes as well as the tomato purée and cook for 8–10 minutes until the tomatoes are cooked through, stirring regularly to avoid them sticking and burning. Add all the spices, chilli powder, salt and sugar, mix well and cook for a further 2 minutes until emulsified. Lower the heat, then add the ground cashew nuts and cream, and stir well. Add 500–600 ml (20–24 fl oz/ 2½ cups–scant 3 cups) water – the quantity you choose to add depends on how runny you want the sauce to be. Bring the mixture to a boil, and when it starts bubbling, add the chicken, lower the heat and cook for a further 8–10 minutes.
    6. Sprinkle over the cardamom seeds and dried fenugreek leaves. Stir and leave to rest for at least 10 minutes before serving with rice or any Indian flatbreads.

    Tags

    More Romy Gill recipes

    More Indian-style recipes

    related features

    \ No newline at end of file diff --git a/tests/test_data/jimcooksfoodgood.com/jimcooksfoodgood.json b/tests/test_data/jimcooksfoodgood.com/jimcooksfoodgood.json index cf79f3df5..100a43739 100644 --- a/tests/test_data/jimcooksfoodgood.com/jimcooksfoodgood.json +++ b/tests/test_data/jimcooksfoodgood.com/jimcooksfoodgood.json @@ -6,12 +6,12 @@ "language": "en-US", "title": "German Potato Salad", "ingredients": [ - "3 Pounds Yukon Gold Potatoes ((Or a small white potato))", + "3 Pounds Yukon Gold Potatoes (Or a small white potato)", "2/3 Cup Sherry or Apple Cider Vinegar", "1/2 Cup dijon mustard", "1/2 Cup Bread and Butter Pickles", "1/4 Cup olive oil", - "4 Tablespoons capers ((Plus a splash of brine))", + "4 Tablespoons capers (Plus a splash of brine)", "2 Teaspoons salt", "1/2 Cup Fresh Parsley", "1/4 Cup scallions", diff --git a/tests/test_data/juliegoodwin.com.au/juliegoodwin_1.json b/tests/test_data/juliegoodwin.com.au/juliegoodwin_1.json index 657075071..7e60c4063 100644 --- a/tests/test_data/juliegoodwin.com.au/juliegoodwin_1.json +++ b/tests/test_data/juliegoodwin.com.au/juliegoodwin_1.json @@ -22,5 +22,7 @@ ], "yields": "Makes 1 Slice = 12 Pieces", "total_time": 45, + "cook_time": 35, + "prep_time": 10, "image": "https://juliegoodwin.com.au/wordpress/wp-content/uploads/2016/03/slice.jpg" } diff --git a/tests/test_data/juliegoodwin.com.au/juliegoodwin_2.json b/tests/test_data/juliegoodwin.com.au/juliegoodwin_2.json index cfcdbf7ad..9233d2792 100644 --- a/tests/test_data/juliegoodwin.com.au/juliegoodwin_2.json +++ b/tests/test_data/juliegoodwin.com.au/juliegoodwin_2.json @@ -31,5 +31,7 @@ ], "yields": "Serves 6", "total_time": 35, + "cook_time": 20, + "prep_time": 15, "image": "https://juliegoodwin.com.au/wordpress/wp-content/uploads/2015/09/800-butter-chicken-2.jpg" } diff --git a/tests/test_data/jumbo.com/jumbo.json b/tests/test_data/jumbo.com/jumbo.json new file mode 100644 index 000000000..71056a172 --- /dev/null +++ b/tests/test_data/jumbo.com/jumbo.json @@ -0,0 +1,26 @@ +{ + "author": "Jumbo", + "canonical_url": "/recepten/gewokte-spruiten-in-rodewijnsaus-1000603", + "site_name": "Jumbo Supermarkten", + "host": "jumbo.com", + "language": "nl-NL", + "title": "Gewokte spruiten in rodewijnsaus", + "ingredients": [ + "500 g spruiten", + "250 g gerookte spekreepjes", + "1 el Zonnebloemolie", + "50 hazelnoten", + "200 g rodewijnsaus" + ], + "instructions_list": [ + "Maak de spruitjes schoon en snijd ze in dunne plakjes van 3 mm.", + "Rooster de hazelnoten ca. 4 min. in een droge koekenpan. Hak ze grof.", + "Verhit de olie in een wok en bak de spekreepjes 4 min. Voeg dan de spruiten en hazelnoten toe (houd wat hazelnoten achter om te garneren) en bak nogmaals 4 min. tot de spruiten de gewenste gaarheid hebben. Kruid eventueel naar smaak.", + "Verwarm de rode wijnsaus. Doe de spruiten over in een schaal en bestrooi met de achtergehouden hazelnoten. Serveer de saus erbij in een apart kommetje." + ], + "category": "bijgerecht", + "description": "Knapperig gewokte spruitjes met hartige spekreepjes en geroosterde hazelnoten, geserveerd met een rijke rodewijnsaus. Een bijgerecht vol warmte en smaak.", + "total_time": 10, + "cook_time": 10, + "image": "https://recipe-service.prod.cloud.jumbo.com/recipes/1000603/Gewokte-spruiten-in-rodewijnsaus_1000603-0_560x560" +} diff --git a/tests/test_data/jumbo.com/jumbo.testhtml b/tests/test_data/jumbo.com/jumbo.testhtml new file mode 100644 index 000000000..0c7713201 --- /dev/null +++ b/tests/test_data/jumbo.com/jumbo.testhtml @@ -0,0 +1,183 @@ + + +Gewokte spruiten in rodewijnsaus | Jumbo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Afbeelding van Gewokte spruiten in rodewijnsaus

    Gewokte spruiten in rodewijnsaus

    Jumbo imageJumbo

    Knapperig gewokte spruitjes met hartige spekreepjes en geroosterde hazelnoten, geserveerd met een rijke rodewijnsaus. Een bijgerecht vol warmte en smaak.

    10 min bereiden

    bijgerecht

    4 personen

    0 kcal/pp

    (0)

    Bereidingswijze

    Zet in 4 stappen deze heerlijke Gewokte spruiten in rodewijnsaus op tafel.

    1. Maak de spruitjes schoon en snijd ze in dunne plakjes van 3 mm.
    2. Rooster de hazelnoten ca. 4 min. in een droge koekenpan. Hak ze grof.
    3. Verhit de olie in een wok en bak de spekreepjes 4 min. Voeg dan de spruiten en hazelnoten toe (houd wat hazelnoten achter om te garneren) en bak nogmaals 4 min. tot de spruiten de gewenste gaarheid hebben. Kruid eventueel naar smaak.
    4. Verwarm de rode wijnsaus. Doe de spruiten over in een schaal en bestrooi met de achtergehouden hazelnoten. Serveer de saus erbij in een apart kommetje.

    Tip! Lekker met aardappelpuree.

    eet smakelijk

    Meer zoals dit

    Spruitjes Spruitjes met spekjes Sauzen Groente

    + + \ No newline at end of file diff --git a/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_1.json b/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_1.json new file mode 100644 index 000000000..e229a1f6f --- /dev/null +++ b/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_1.json @@ -0,0 +1,28 @@ +{ + "canonical_url": "https://kellyscleankitchen.com/2024/11/29/protein-pumpkin-pie/", + "site_name": "Kelly's Clean Kitchen", + "host": "kellyscleankitchen.com", + "language": "en-US", + "title": "Protein Pumpkin Pie", + "ingredients": [ + "3 large eggs", + "1.5 cups heavy cream", + "2 scoops Isopure Unflavored Protein Powder", + "1/2 tsp salt", + "3 tsp pumpkin pie spice", + "1/3 cup granulated sugar", + "1 pie crust, can be frozen or homemade, I used a frozen one here for ease" + ], + "instructions_list": [ + "Preheat the oven to 450°F.", + "Whisk together the eggs, heavy cream, protein powder, pumpkin pie spice and sugar until smooth.", + "Pour the pumpkin filling into a crust and bake at 450°F for 10 minutes. Reduce the temperature to 350°F and finish baking for 40-45 minutes. The pie is done when there is a gentle wiggle in the middle, but the edges are set.", + "Remove and cool to room temperature. Then transfer to the fridge and set for 2-3 hours.", + "Slice and serve, enjoy!" + ], + "yields": "8 servings", + "total_time": 60, + "cook_time": 40, + "prep_time": 20, + "image": "https://kellyscleankitchen.com/wp-content/uploads/2024/11/Isopure-Pumpkin-Pie-11.jpg" +} diff --git a/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_1.testhtml b/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_1.testhtml new file mode 100644 index 000000000..bb342ac89 --- /dev/null +++ b/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_1.testhtml @@ -0,0 +1,1002 @@ + + + + + + + + + + + + + Protein Pumpkin Pie - Kelly's Clean Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    + + + + + + +
    + + + + +
    + +
    +
    +
    +
    +
    + +
    +
    + + + + +
    +
    + +
    + +
    +

    Protein Pumpkin Pie

    + +
    +

    I am all about adding protein in where I can, and I find that adding it into desserts is the easiest. This thanksgiving I made a protein packed pumpkin pie and I swear you couldn’t even tell there was protein in there.

    + +

    I use Isopure’s Unflavored Protein Powder which has the best texture and zero flavor. I also love their vanilla and chocolate flavors when I am looking to add it to certain sweets like creme brulees or chocolate budino. Use code “KELLY15” for 15% off Isopure!

    + +
    +
    @kellyscleankitchen

    How to make a pumpkin pie for the holidays🎃 Pumpkin pie is my absolute favorite pie for the holidays. But since I am eating so much rich food I like to add protein and nutrients by sneaking in @Isopure Zero Carb Unflavored Protein Powder. You can’t even tell. Ingredients: 1. 2 cups canned pumpkin puree 2. 3 large eggs 3. 1.5 cups heavy cream 4. Protein Boosted Pumpkin Spice Blend 1. 2 scoops Isopure Unflavored Protein Powder 2. ½ tsp salt 3. 3 tsp pumpkin pie spice 4. 1/3 cup granulated sugar, or sweetener of choice 2nd component: 5. 1 pie crust, can be frozen or homemade, I used a frozen one here for ease Instructions: 1. Preheat the oven to 450°F. 2. Whisk in the heavy cream combined with the Protein Boosted Pumpkin Spice Blend (sugar, salt, pumpkin pie spice, and Isopure Unflavored Protein powder) until smooth. 3. Pour the pumpkin filling into a crust and bake at 450°F for 10 minutes. Reduce the temperature to 350°F and finish baking for 40-45 minutes. The pie is done when there is a gentle wiggle in the middle, but the edges are set. 4. Remove and cool to room temperature. Then transfer to the fridge and set for 2-3 hours. 5. Slice and serve, enjoy! Check out @IsopureCompany for more recipes! Macros: Makes 8 servings Serving Size: 1 slice Calories: 360 Fat: 24g Carbs: 26g Protein: 12g #ad #IsopurePartner #pumpkinpie #dessert #IsopureProteinHacks

    ♬ original sound – Chef Kelly Scott
    +
    • +
      SERVINGS:  8
    • + +
    • PREP TIME: 20 Mins
    • + +
    • COOK TIME: 40 Mins
    • + +
    • TOTAL TIME: 1 Hr
    + +

    + +

    Ingredients:

    + +
    • 3 large eggs
    • + +
    • 1.5 cups heavy cream
    • + +
    • 2 scoops Isopure
      Unflavored Protein Powder
    • + +
    • 1/2 tsp salt
    • + +
    • 3 tsp pumpkin pie spice
    • + +
    • 1/3 cup granulated sugar
    • + +
    • 1 pie crust, can be frozen or homemade, I used a frozen one here for ease
    + +

    Preparation:

    + +
    STEP 1.
    + +


    Preheat the oven to 450°F.

    + +
    STEP 2.
    + +


    Whisk together the eggs, heavy cream, protein powder, pumpkin pie spice and sugar until smooth.

    + +
    STEP 3.
    + +


    Pour the pumpkin filling into a crust and bake at 450°F for 10 minutes. Reduce the temperature to 350°F and finish baking for 40-45 minutes. The pie is done when there is a gentle wiggle in the middle, but the edges are set.

    + +
    STEP 4.
    + +


    Remove and cool to room temperature. Then transfer to the fridge and set for 2-3 hours.

    + +
    STEP 5.
    + +


    Slice and serve, enjoy!

    + +

    + +
    2024-11-29T10:18:44-08:00November 29th, 2024|Mains|0 Comments
    + + + + + + +
    +

    Leave A Comment

    + +
    +
    +
    +
    +
    +

    + +

    +
    +
    + + +
    +
    + + + + + + + +
    +
    + + + + +
    + + Go to Top + +
    + + + \ No newline at end of file diff --git a/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_2.json b/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_2.json new file mode 100644 index 000000000..7a803034c --- /dev/null +++ b/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_2.json @@ -0,0 +1,29 @@ +{ + "canonical_url": "https://kellyscleankitchen.com/2022/09/02/fondant-sweet-potatoes/", + "site_name": "Kelly's Clean Kitchen", + "host": "kellyscleankitchen.com", + "language": "en-US", + "title": "Fondant Sweet Potatoes", + "ingredients": [ + "4 sweet potatoes, cut into 1 inch rounds", + "10 garlic cloves, smashed", + "avocado oil", + "4 tbsp butter", + "2 sprigs rosemary", + "4 sprigs thyme", + "salt and pepper", + "1/2 cup chicken stock" + ], + "instructions_list": [ + "Prep your potatoes, save the scraps for another dish. Smash your garlic and set aside.", + "Arrange oven rack in the middle of the oven at 400*F.", + "Heat oil in a pan over medium high heat. Add potatoes, cut side down and brown for 2-3 minutes. Flip and reduce the heat to low. Add butter, garlic, thyme, and rosemary. Cook until the butter is foaming and starts to brown, 2-3 minutes. Add chicken stock so potatoes are half submerged. Bring to a simmer.", + "Transfer to the oven and bake until the potatoes are fork tender and lightly browned on all sides, 15-20 minutes. Remove from the oven and serve.", + "Step up your potato game with this recipe! 🥔 #potato #potatorecipe #potatotiktok #sweetpotato #fondantpotatoes #gordonramsay #cooking #cooktok" + ], + "yields": "4 servings", + "total_time": 40, + "cook_time": 30, + "prep_time": 10, + "image": "https://kellyscleankitchen.com/wp-content/uploads/2022/09/Fondant-Sweet-Potatoes-4.jpg" +} diff --git a/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_2.testhtml b/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_2.testhtml new file mode 100644 index 000000000..bbe36b1e3 --- /dev/null +++ b/tests/test_data/kellyscleankitchen.com/kellyscleankitchen_2.testhtml @@ -0,0 +1,910 @@ + + + + + + + + + + + + + Fondant Sweet Potatoes - Kelly's Clean Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    + + + + + + +
    + + + + +
    + +
    +
    +
    +
    +
    + +
    +
    + + + + +
    +
    + +
    + +
    +

    Fondant Sweet Potatoes

    + +
    +

    Fondant potatoes are a traditional French side dish where you cut russet potatoes into rounds or squares and then cook in butter, garlic, aromatics and chicken stock. This is the sweet potato version! It is a dish you won’t find too often these days, but is impressive and delicious to all guests you may be cooking for.

    + +

    + +
    • +
      SERVINGS:  4
    • + +
    • PREP TIME: 10 Mins
    • + +
    • COOK TIME: 30 Mins
    • + +
    • TOTAL TIME: 40 Min
    + +

    These are great with a fancier dish and are often used in fine dining, but so fun to make at home!

    + +

    Ingredients:

    + +
    • 4 sweet potatoes, cut into 1 inch rounds
    • 10 garlic cloves, smashed
    • avocado oil
    • 4 tbsp butter
    • 2 sprigs rosemary
    • 4 sprigs thyme
    • salt and pepper
    • 1/2 cup chicken stock
    + +

    Preparation:

    + +
    STEP 1.
    + +

    Prep your potatoes, save the scraps for another dish. Smash your garlic and set aside.

    + +
    STEP 2.
    + +

    Arrange oven rack in the middle of the oven at 400*F.

    + +
    STEP 3.
    + +

    Heat oil in a pan over medium high heat. Add potatoes, cut side down and brown for 2-3 minutes. Flip and reduce the heat to low. Add butter, garlic, thyme, and rosemary. Cook until the butter is foaming and starts to brown, 2-3 minutes. Add chicken stock so potatoes are half submerged. Bring to a simmer.

    + +
    STEP 4.
    + +

    Transfer to the oven and bake until the potatoes are fork tender and lightly browned on all sides, 15-20 minutes. Remove from the oven and serve.

    + +
    + +

    + +
    2022-09-02T13:35:51-08:00September 2nd, 2022|Sides|0 Comments
    + + + + + + +
    +

    Leave A Comment

    + +
    +
    +
    +
    +
    +

    + +

    +
    +
    + +
    +
    + + + + + + + +
    +
    + + + + +
    + + Go to Top + +
    + + diff --git a/tests/test_data/kitchendreaming.com/kitchendreaming_1.json b/tests/test_data/kitchendreaming.com/kitchendreaming_1.json index c98e47b7b..e9c80f17f 100644 --- a/tests/test_data/kitchendreaming.com/kitchendreaming_1.json +++ b/tests/test_data/kitchendreaming.com/kitchendreaming_1.json @@ -15,7 +15,7 @@ "1 teaspoon garlic powder", "4 green onions (, sliced thin)", "3/4 cup hot sauce ([See Note 3])", - "1/2 stick ((4 tbsp) butter)", + "1/2 stick (4 tbsp) butter)", "20 celery sticks ([See Note 4])", "20 carrot sticks ([See Note 4])", "1/2 cup chunky blue cheese dressing ( [See Note 5] - plus more for serving)", diff --git a/tests/test_data/kitchendreaming.com/kitchendreaming_2.json b/tests/test_data/kitchendreaming.com/kitchendreaming_2.json index 16eade148..0d115c581 100644 --- a/tests/test_data/kitchendreaming.com/kitchendreaming_2.json +++ b/tests/test_data/kitchendreaming.com/kitchendreaming_2.json @@ -9,7 +9,7 @@ "2 lbs Boneless and skinless chicken, 1-inch cubes (breast or thighs are both fine here)", "1/2 cup plain Greek yogurt", "2 tablespoons minced garlic", - "1 tablespoon minced ginger ((or finely grated))", + "1 tablespoon minced ginger (or finely grated)", "1 teaspoon Indian Kashmiri powder (red chili powder, more or less to taste)", "2 teaspoons garam masala", "1 teaspoon turmeric", @@ -36,7 +36,7 @@ "2 lbs Boneless and skinless chicken, 1-inch cubes (breast or thighs are both fine here)", "1/2 cup plain Greek yogurt", "2 tablespoons minced garlic", - "1 tablespoon minced ginger ((or finely grated))", + "1 tablespoon minced ginger (or finely grated)", "1 teaspoon Indian Kashmiri powder (red chili powder, more or less to taste)", "2 teaspoons garam masala", "1 teaspoon turmeric", diff --git a/tests/test_data/kitchensanctuary.com/kitchensanctuary.json b/tests/test_data/kitchensanctuary.com/kitchensanctuary.json index 31306784b..6f027f88c 100644 --- a/tests/test_data/kitchensanctuary.com/kitchensanctuary.json +++ b/tests/test_data/kitchensanctuary.com/kitchensanctuary.json @@ -20,7 +20,7 @@ "1 tsp paprika", "1 tsp baking powder", "1 tsp chilli flakes", - "vegetable oil for deep frying ((at least 1 litre/four cups))", + "vegetable oil for deep frying (at least 1 litre/four cups)", "2 tbsp gochujang paste", "2 tbsp honey", "4 tbsp brown sugar", @@ -31,7 +31,7 @@ "1 tbsp sesame oil", "3 spring onions (sliced into thin strips)", "1 tsp sesame seeds", - "½ tsp chilli flakes ((red pepper flakes))" + "½ tsp chilli flakes (red pepper flakes)" ], "ingredient_groups": [ { @@ -55,7 +55,7 @@ "1 tsp paprika", "1 tsp baking powder", "1 tsp chilli flakes", - "vegetable oil for deep frying ((at least 1 litre/four cups))" + "vegetable oil for deep frying (at least 1 litre/four cups)" ], "purpose": "Crispy Coating:" }, @@ -71,7 +71,7 @@ "1 tbsp sesame oil", "3 spring onions (sliced into thin strips)", "1 tsp sesame seeds", - "½ tsp chilli flakes ((red pepper flakes))" + "½ tsp chilli flakes (red pepper flakes)" ], "purpose": "Sauce:" } diff --git a/tests/test_data/kookjij.nl/kookjij_1.json b/tests/test_data/kookjij.nl/kookjij_1.json new file mode 100644 index 000000000..6ad0960e7 --- /dev/null +++ b/tests/test_data/kookjij.nl/kookjij_1.json @@ -0,0 +1,41 @@ +{ + "author": "Wilmie Willemse", + "canonical_url": "kookjij.nl", + "host": "kookjij.nl", + "language": "nl", + "title": "Koolrabi ovenschotel", + "ingredients": [ + "2 koolrabi", + "6 aardappelen", + "200 ml (kook)room", + "250 ml runderbouillon", + "500 gram gehakt (gemengd)", + "2 teentjes knoflook", + "1 ui", + "olijfolie", + "peper en zout (naar smaak)", + "200 gr fetakaas" + ], + "instructions_list": [ + "Verwarm de oven voor op 180°C.", + "Doe de kookroom en de bouillon in een pannetje en laat dit tot ongeveer de helft inkoken.", + "Schil de aardappels en de koolrabi en snijd in zo dun mogelijke plakjes.", + "Fruit de fijngesnipperde knoflook en de fijngesnipperde ui in een beetje olijfolie.", + "Eenmaal glazig kan je het gehakt erbij voegen en stevig aanbraden.", + "Breng indien nodig op smaak met peper en zout.", + "Doe in een ovenschotel eerst de helft van het gehakt, dan een laag koolrabi, dan een laag aardappel dan de andere helft van het gehakt, en eindig met een laatste laag koolrabi.", + "Overgiet het geheel met de ingekookte room-bouillon, verkruimel de feta erover en zet 45 tot 60 minuten in de oven.", + "Zet op het laatst even de grill aan voor een mooi bruin korstje." + ], + "category": "Hoofdgerechten, Ovenschotels", + "yields": "6 servings", + "description": "Koolrabi vind ik erg lekker, de smaak zit een beetje tussen witte kool en radijsjes in. Dus als ik een recept tegen kom met een anders dan andere bereidingswijze dan wil ik dat graag uitproberen. Ik kwam dit recept op internet tegen en het bleek ook al in aangepaste vorm gemaakt te zijn. Daar heb ik nog eens een keer mijn eigen inspiratie aan toegevoegd en zo is deze verbastering weer ontstaan. Overigens wel een hele lekkere en gezonde verbastering. Aandachtspuntje is wel dat de schotel lang genoeg in de oven staat omdat de koolrabi en aardappel er rauw ingaan. In het originele recept werd 40 minuten genoemd maar ik vind 45 tot 60 minuten toch beter. Natuurlijk is ook elke oven weer anders dus de oventijden zijn altijd richttijden.", + "total_time": 90, + "cook_time": 90, + "cuisine": "Europese", + "image": "https://www.kookjij.nl/media/j45b5lhkjb45lhkjb45blj5/thumbnails/259x180x6731dbfb9d67c_259_180.jpg.pagespeed.ic.D1IMFjt4QU.webp", + "keywords": [ + "Koolrabi", + "ovenschotel" + ] +} diff --git a/tests/test_data/kookjij.nl/kookjij_1.testhtml b/tests/test_data/kookjij.nl/kookjij_1.testhtml new file mode 100644 index 000000000..59e400c37 --- /dev/null +++ b/tests/test_data/kookjij.nl/kookjij_1.testhtml @@ -0,0 +1,1027 @@ + + + + + + + + + + Koolrabi ovenschotel - Online Recepten - KookJij + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    +
    +
    +
    + + + KookJij + + +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + + + + + + + + + + + +
    +
    +
    + +
    +
    + +
    + +
    + + +
    + +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    +

    Recept

    + « Terug naar recepten +
    +
    + + + + + +

    + Koolrabi ovenschotel +

    +
    Koolrabi vind ik erg lekker, de smaak zit een beetje tussen witte kool en +radijsjes in. +Dus als ik een recept tegen kom met een anders dan andere +bereidingswijze dan wil ik dat graag uitproberen. Ik kwam dit recept op +internet tegen en het bleek ook al in aangepaste vorm gemaakt te zijn. Daar +heb ik nog eens een keer mijn eigen inspiratie aan toegevoegd en zo is +deze verbastering weer ontstaan. Overigens wel een hele lekkere en +gezonde verbastering. +Aandachtspuntje is wel dat de schotel lang genoeg in de oven staat omdat +de koolrabi en aardappel er rauw ingaan. In het originele recept werd 40 +minuten genoemd maar ik vind 45 tot 60 minuten toch beter. Natuurlijk is +ook elke oven weer anders dus de oventijden zijn altijd richttijden.
    + + + +
    +
    +
    +
    + Recept van: + +
    +
    + Bereidingstijd: + 90 min +
    +
    + Personen: + 6 personen +
    +
    + Categorieën: + +
      +
    1. > Hoofdgerechten - Ovenschotels
    2. +
    +
    +
    +
    + Bevat per éénpersoons portie: + +
    +
    + Waardering: + + + +
    +
    + Herkomst: + Nederland +
    +
    + Keuken: + Europese +
    +
    + Bron: + sos recepten/Koken op hakken/Aangepast en in eigen keuken gemaakt en gefotografeerd +
    + +
    + Geplaatst op: + + + +
    +
    +
    +
    + + +
    +
    + + +
    +
    + +
    + + +
    + +
    +

    Bereiding

    +
    +

    Hoe Koolrabi ovenschotel te bereiden

    +
    1. Verwarm de oven voor op 180°C.
    2. +
    3. Doe de kookroom en de bouillon in een pannetje en laat dit tot ongeveer de helft inkoken.
    4. +
    5. Schil de aardappels en de koolrabi en snijd in zo dun mogelijke plakjes.
    6. +
    7. Fruit de fijngesnipperde knoflook en de fijngesnipperde ui in een beetje olijfolie.
    8. +
    9. Eenmaal glazig kan je het gehakt erbij voegen en stevig aanbraden.
    10. +
    11. Breng indien nodig op smaak met peper en zout.
    12. +
    13. Doe in een ovenschotel eerst de helft van het gehakt, dan een laag koolrabi, dan een laag aardappel dan de andere helft van het gehakt, en eindig met een laatste laag koolrabi.
    14. +
    15. Overgiet het geheel met de ingekookte room-bouillon, verkruimel de feta erover en zet 45 tot 60 minuten in de oven.
    16. +
    17. Zet op het laatst even de grill aan voor een mooi bruin korstje.
    18. +
    + +
    +
    + + +
    + + + + +
    + +
    +

    Reageer op dit recept

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

    Maak favoriet
    + + + +
    Print dit recept
    + +
    +
    + Waardeer dit recept +
    +
    + + +
    +
    + +
    +
    +
    + + +
    +
    + + +
    +
    + + + Uw bericht mag nog karakters bevatten +
    +
    + + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    + + + + + +
    + +
    +

    Reacties op dit recept

    +
    + +

    Er zijn nog geen reacties geplaatst

    + +
    +
    + +
    +
    +
    + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/kookjij.nl/kookjij_2.json b/tests/test_data/kookjij.nl/kookjij_2.json new file mode 100644 index 000000000..034942e86 --- /dev/null +++ b/tests/test_data/kookjij.nl/kookjij_2.json @@ -0,0 +1,46 @@ +{ + "author": "Petra Wiggers", + "canonical_url": "kookjij.nl", + "host": "kookjij.nl", + "language": "nl", + "title": "Aardappelschotel met bloemkool, prei en tomaten", + "ingredients": [ + "600 gram aardappelen Opperdoezer Ronde", + "zout, peper, nootmuskaat", + "1 middelgrote bloemkool 2", + "50 gram kerstomaten", + "2 eetlepels zonnebloemolie", + "1 middelgrote ui, ontveld en gesnipperd", + "1 flinke prei, schoongemaakt en in smalle ringen", + "10 gram roomboter", + "100 gram geraspte belegen kaas" + ], + "instructions_list": [ + "Aardappelen wassen en in kleine stukken snijden. In kokend water met zout in plm. 10 tot 15 minuten garen. Goed laten uitdampen. Eventueel schil verwijderen.", + "Bloemkool in kleine roosjes snijden en in water met zout plm. 5 minuten garen. De bloemkool moet nog stevig zijn. In een vergiet goed uitlekken.", + "Kerstomaatjes eventueel ontvellen (heb ik gedaan) en halveren.", + "Olie verhitten in een koekenpan en hierin de gesnipperde ui glazig bakken.Preiringetjes en tomaatjes even meebakken. Laat de roomboter hierin smeltenMeng de aardappelen, bloemkool, prei, tomaatjes en de helft van de kaas door elkaar in een ovenschaal. Maak op smaak met peper, zout en nootmuskaat.", + "Verdeel de rest van de geraspte kaas erover en zet de schaal plm. 20 tot 25 minuten in het midden van de op 200 graden voorverwarmde oven tot de kaas een goudbruine kleur heeft gekregen." + ], + "category": "Vergeten Groenten, Opperdoezer Ronde", + "yields": "4 servings", + "description": "De aardappelen voor deze ovenschotel heb ik niet geschild, maar wel in stukken gesneden. De aardappelen, voorgekookte bloemkool, prei en tomaten worden met een deel van de kaas door elkaar gemengd en gaan zo in de ovenschaal.", + "total_time": 20, + "cook_time": 20, + "cuisine": "Europese", + "equipment": [ + "ovenschaal", + "mes", + "snijplank", + "vergiet", + "koekenpan", + "pannen" + ], + "image": "https://www.kookjij.nl/media/j45b5lhkjb45lhkjb45blj5/thumbnails/64ef540a8e7d8_259_180.jpg", + "keywords": [ + "Aardappelschotel", + "bloemkool", + "prei", + "tomaten" + ] +} diff --git a/tests/test_data/kookjij.nl/kookjij_2.testhtml b/tests/test_data/kookjij.nl/kookjij_2.testhtml new file mode 100644 index 000000000..b8e83580d --- /dev/null +++ b/tests/test_data/kookjij.nl/kookjij_2.testhtml @@ -0,0 +1,1012 @@ + + + + + + + + + + Aardappelschotel met bloemkool, prei en tomaten - Online Recepten - KookJij + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    +
    +
    +
    + + + KookJij + + +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + + + + + + + + + + + +
    +
    +
    + +
    +
    + +
    + +
    + + +
    + +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    +

    Recept

    + « Terug naar recepten +
    +
    + + + + + +

    + Aardappelschotel met bloemkool, prei en tomaten +

    +
    De aardappelen voor deze ovenschotel heb ik niet geschild, maar wel in stukken gesneden. De aardappelen, voorgekookte bloemkool, prei en tomaten worden met een deel van de kaas door elkaar gemengd en gaan zo in de ovenschaal.
    + + + +
    +
    +
    +
    + Recept van: + +
    +
    + Bereidingstijd: + 20 min +
    +
    + Personen: + 4 personen +
    +
    + Categorieën: + +
      +
    1. > Vergeten Groenten - Opperdoezer Ronde
    2. +
    +
    +
    +
    + Bevat per éénpersoons portie: + +
    +
    + Waardering: + + + +
    +
    + Herkomst: + Nederland +
    +
    + Keuken: + Europese +
    +
    + Bron: + Eigen recept +
    + +
    + Geplaatst op: + + + +
    +
    +
    +
    + + +
    +
    + + +
    +
    + +
    + + +
    + +
    +

    Bereiding

    +
    +

    Hoe Aardappelschotel met bloemkool, prei en tomaten te bereiden

    +
    1. Aardappelen wassen en in kleine stukken snijden. In kokend water met zout in plm. 10 tot 15 minuten garen. Goed laten uitdampen. Eventueel schil verwijderen.
    2. +
    3. Bloemkool in kleine roosjes snijden en in water met zout plm. 5 minuten garen. De bloemkool moet nog stevig zijn. In een vergiet goed uitlekken.
    4. +
    5. Kerstomaatjes eventueel ontvellen (heb ik gedaan) en halveren.
    6. +
    7. Olie verhitten in een koekenpan en hierin de gesnipperde ui glazig bakken.Preiringetjes en tomaatjes even meebakken. Laat de roomboter hierin smeltenMeng de aardappelen, bloemkool, prei, tomaatjes en de helft van de kaas door elkaar in een ovenschaal. Maak op smaak met peper, zout en nootmuskaat.
    8. +
    9. Verdeel de rest van de geraspte kaas erover en zet de schaal plm. 20 tot 25 minuten in het midden van de op 200 graden voorverwarmde oven tot de kaas een goudbruine kleur heeft gekregen.
    10. +
    + +

    Mijn kookverhaal (Petra Wiggers)

    +
    Dit is een vegetarische ovenschotel. Je kunt hier een stukje vlees bij eten, maar ook wat stukjes spek smaken goed door de ovenschotel.
    +
    +
    + + +
    + + + + +
    + +
    +

    Reageer op dit recept

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

    Maak favoriet
    + + + +
    Print dit recept
    + +
    +
    + Waardeer dit recept +
    +
    + + +
    +
    + +
    +
    +
    + + +
    +
    + + +
    +
    + + + Uw bericht mag nog karakters bevatten +
    +
    + + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    + + + + + +
    + +
    +

    Reacties op dit recept

    +
    + +

    Er zijn nog geen reacties geplaatst

    + +
    +
    + +
    +
    +
    + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.json b/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.json new file mode 100644 index 000000000..ebf2f7b5d --- /dev/null +++ b/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.json @@ -0,0 +1,28 @@ +{ + "author": "La Cucina Italiana", + "canonical_url": "https://www.lacucinaitaliana.com/recipe/pasta/caserecce-with-broccoli-and-tuna", + "site_name": "La Cucina Italiana", + "host": "lacucinaitaliana.it", + "language": "en-US", + "title": "Casarecce Pasta With Broccoli and Tuna", + "ingredients": [ + "12OZ. casarecce or other short pasta", + "12OZ. broccoli crowns", + "5OZ. oil-packed tuna", + "2OZ. shallot, chopped", + "wild fennel", + "red chili pepper", + "2SPRIG thyme", + "extra-virgin olive oil", + "salt" + ], + "instructions_list": [ + "Boil the broccoli in a large pot of unsalted water until just crisp-tender, around 3 minutes. Drain with a slotted spoon. Add salt to the water and add pasta to cook until al dente.", + "In the meantime, chop thyme and wild fennel. Sauté broccoli and chopped shallot in oil. Add tuna, chili pepper, chopped thyme and fennel, salt and 2 ladles (around 1 cup) pasta cooking water. Cook for 10 minutes.", + "Drain the pasta when al dente and return to the warm pot. Stir in the sauce and sauté to coat. Serve immediately." + ], + "yields": "4 servings", + "description": "This simple pasta with tuna and broccoli is the perfect weeknight meal.", + "total_time": 30, + "image": "https://rms.condenast.it/rms/public/5d3/f03/de5/thumb_982_1200_670_0_0_auto.jpg" +} diff --git a/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.testhtml b/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.testhtml new file mode 100644 index 000000000..66d62d211 --- /dev/null +++ b/tests/test_data/lacucinaitaliana.com/lacucinaitaliana.testhtml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Casarecce Pasta With Broccoli and Tuna Recipe - La Cucina Italiana + + + +
    + +
    La Cucina Italiana

    Casarecce Pasta With Broccoli and Tuna

    + Tested by La cucina Italiana
    Editorial staff by Editorial staff
    • 4.2 / 5

    new!

    + + diff --git a/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.json b/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.json new file mode 100644 index 000000000..90cfe2813 --- /dev/null +++ b/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.json @@ -0,0 +1,34 @@ +{ + "author": "La Cucina Italiana", + "canonical_url": "https://www.lacucinaitaliana.it/ricetta/dolcetti-fillo-frutta-secca-miele/", + "site_name": "La Cucina Italiana", + "host": "lacucinaitaliana.it", + "language": "it-IT", + "title": "Dolcetti di pasta fillo, frutta secca e miele", + "ingredients": [ + "250 g frutta secca mista (fichi secchi, datteri, uvetta ammorbiditain acqua, noci, mandorle,albicocche disidratate)", + "6 fogli di pasta fillo", + "miele", + "acqua di rose" + ], + "instructions_list": [ + "Sminuzzate la frutta secca e mescolatela ottenendo un granulato. Profumatelo con acqua di rose.", + "Disponete i fogli di fillo sovrapposti a due a due.", + "Spennellateli con il miele, quindi distribuitevi sopra il granulato.", + "Tagliate ogni doppio foglio in 4 strisce. Arricciate la pasta e arrotolatela a spirale, senza mai staccarvi dal piano di lavoro. Una volta ottenuta una chiocciolina per ogni striscia, adagiatela nell’incavo di uno stampo multiplo da muffin. Riempitelo tutto.", + "Infornate lo stampo a 200 °C per circa 15 minuti.", + "Sfornate e togliete i dolcetti dallo stampo, quindi serviteli con altro miele." + ], + "yields": "12 servings", + "description": "Scoprite come preparare i Dolcetti di pasta fillo, frutta secca e miele, una ricetta dal sapore orientale", + "total_time": 35, + "image": "https://media-assets.lacucinaitaliana.it/photos/67766a9c882f5b2b196e4cfc/16:9/w_1600,h_900,c_limit/Dolcetti%20di%20fillo,%20frutta%20secca%20e%20miele%20copia.jpg", + "keywords": [ + "dolcetti", + "miele api", + "frutta secca", + "vegetariana", + "facile", + "magazine" + ] +} diff --git a/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.testhtml b/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.testhtml new file mode 100644 index 000000000..c21c675e1 --- /dev/null +++ b/tests/test_data/lacucinaitaliana.it/lacucinaitaliana.testhtml @@ -0,0 +1,1314 @@ +Ricetta Dolcetti di pasta fillo, frutta secca e miele | La Cucina Italiana
    Skip to main content

    Dolcetti di fillo, frutta secca e miele

    Dolcetti che ci trasportano nelle atmosfere orientali dei viaggi di Marco Polo raccontati ne Il milione e anche al banchetto di nozze del mercante veneziano…
    frutta secca
    Chiara Cadeddu

    Questi Dolcetti di fillo, frutta secca e miele ci piace immaginarli al banchetto delle nozze tra Marco Polo e Donata Badoer. Appena tornato a Venezia, liberato dalla provvida prigionia dei genovesi che gli ha permesso di dettare Il Milione, il mercante si sposa con una celebrazione in pompa magna in cui noi abbiamo sognato preparazioni che mescolano ingredienti esotici e nostrani, in omaggio alla vita avventurosa dello sposo.

    Nel Milione il miele, anzi, il mèle, è spesso citato. Negli harem dei sultani dalle cento bellissime spose, le favorite che tessono le loro trame di potere e di passione sono ghiotte di pasticcini realizzati con fichi, datteri e frutta secca, dolcissimi e un tantino sensuali...

    Scoprite anche queste ricette: Crostata al miele con noci e nocciole, Baklava Facile, Torrone, Torta di pasta fillo con fichi, miele e pistacchi, Biscotti al miele con marmellata di pere, Dolce di banane nocciole e miele, Brioche mignon all’anice e miele, Frittelle di mele cotogne e miele

    • Tempo

      35 minuti

    • Prodotto

      12 pezzi

    Ingredienti

    250

    g frutta secca mista (fichi secchi, datteri, uvetta ammorbiditain acqua, noci, mandorle,albicocche disidratate)

    6

    fogli di pasta fillo

    miele

    acqua di rose

    Procedimento

    1. Step 1

      Sminuzzate la frutta secca e mescolatela ottenendo un granulato. Profumatelo con acqua di rose.

      Step 2

      Disponete i fogli di fillo sovrapposti a due a due.

      Step 3

      Spennellateli con il miele, quindi distribuitevi sopra il granulato.

      Step 4

      Tagliate ogni doppio foglio in 4 strisce. Arricciate la pasta e arrotolatela a spirale, senza mai staccarvi dal piano di lavoro. Una volta ottenuta una chiocciolina per ogni striscia, adagiatela nell’incavo di uno stampo multiplo
      da muffin. Riempitelo tutto.

      Step 5

      Infornate lo stampo a 200 °C per circa 15 minuti.

      Step 6

      Sfornate e togliete i dolcetti dallo stampo, quindi serviteli con altro miele.

      Ricetta: Walter Pedrazzi, Foto: Chiara Cadeddu, Styling: Beatrice Prada

      +
      Chiara Cadeddu

    Vota la ricetta Dolcetti di fillo, frutta secca e miele

    \ No newline at end of file diff --git a/tests/test_data/lanascooking.com/lanascooking_1.json b/tests/test_data/lanascooking.com/lanascooking_1.json new file mode 100644 index 000000000..1584b13e5 --- /dev/null +++ b/tests/test_data/lanascooking.com/lanascooking_1.json @@ -0,0 +1,57 @@ +{ + "author": "Lana Stuart", + "canonical_url": "https://www.lanascooking.com/southern-tomato-cracker-salad/", + "site_name": "Lana's Cooking", + "host": "lanascooking.com", + "language": "en-US", + "title": "Southern Tomato Cracker Salad", + "ingredients": [ + "3 very ripe medium tomatoes", + "1 cup mayonnaise", + "1/2 shallot (finely minced)", + "40 saltine crackers (1 sleeve)", + "2 tablespoons chives (finely chopped)", + "Kosher salt and ground black pepper to taste" + ], + "instructions_list": [ + "Start by removing the core, or stem end) of the tomatoes and then cut each in half through the middle or \"waist.\"", + "Working over a medium bowl or into the sink, press each tomato half gently to get rid of most of the seeds and juice.", + "Dice the tomatoes. Place the diced tomatoes in a large mixing bowl and sprinkle lightly with salt. Remove a few tablespoons of diced tomatoes for garnish and set them aside.", + "Into the bowl with the diced tomatoes, add the minced shallot, half of the chives, black pepper, and mayonnaise. Fold together gently to combine.", + "Crumble the crackers creating mostly large pieces for the best texture.", + "Add the broken saltine crackers to the bowl with the tomato mixture and fold gently to combine.", + "Taste for seasoning and adjust if necessary.", + "Garnish with the reserved tomatoes and remaining chives.", + "Serve immediately." + ], + "category": "Salads,Side Dishes,Vegetables", + "yields": "4 servings", + "description": "If you like a southern tomato sandwich, then you'll fall head over heels for this 15-minute Southern Tomato Cracker Salad recipe!", + "total_time": 15, + "prep_time": 15, + "cuisine": "Southern, Vintage", + "ratings": 5.0, + "ratings_count": 3, + "nutrients": { + "servingSize": "1 serving", + "calories": "278 kcal", + "fatContent": "15 g", + "saturatedFatContent": "2 g", + "unsaturatedFatContent": "12 g", + "transFatContent": "0.2 g", + "carbohydrateContent": "32 g", + "sugarContent": "5 g", + "proteinContent": "4 g", + "sodiumContent": "750 mg", + "fiberContent": "2 g", + "cholesterolContent": "9 mg" + }, + "image": "https://www.lanascooking.com/wp-content/uploads/2022/06/southern-tomato-cracker-salad-feature-1200.jpg", + "keywords": [ + "cracker salad", + "southern salads", + "southern tomato cracker salad", + "tomato salad", + "vintage salad recipe" + ] +} diff --git a/tests/test_data/lanascooking.com/lanascooking_1.testhtml b/tests/test_data/lanascooking.com/lanascooking_1.testhtml new file mode 100644 index 000000000..b15bf1d5e --- /dev/null +++ b/tests/test_data/lanascooking.com/lanascooking_1.testhtml @@ -0,0 +1,1610 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Southern Tomato Cracker Salad Recipe - Lana's Cooking + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    + +
    + + + + + +
    + + +

    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    Home » Recipes » Salad Recipes » Southern Tomato Cracker Salad

    Southern Tomato Cracker Salad

    +
    + +
    +
    + + + + + +
    5 from 3 votes
    + + +
    +

    If you enjoy the flavors of the classic southern tomato sandwich, then you’ll fall head over heels for this Southern Tomato Cracker Salad recipe! It takes 15 minutes from start to finish and there’s no cooking at all. Perfect for hot summer days when you don’t want to heat up the kitchen.

    + + + +

    There’s not much better in the middle of summer than a classic tomato sandwich. Two pieces of white bread slathered with mayonnaise and topped with salted and peppered tomato slices. Yum!

    A serving of tomato cracker salad on a white plate.
    + + + +

    Well, if you’re a fan of tomato sandwiches, then you’ll love their next of kin, the Southern Tomato Cracker Salad! It takes the same flavor profile and transforms it into a crunchy, creamy salad that’s great for family dinners or entertaining.

    + + + +

    This combination of ripe tomatoes, creamy mayonnaise, and saltine crackers is a great side dish to serve with burgers, grilled chicken, or steaks. It’s a southern summer classic recipe that has been around for decades.

    + + + +
    A serving of tomato cracker salad on a white plate.
    + + + + + +
    +

    ❤️ Why I Love This Recipe

    + + + +
    + + + +
      +
    • It’s a great way to use fresh summer tomatoes!
    • + + + +
    • Tastes like a tomato sandwich in a bowl.
    • + + + +
    • It’s one of those great old southern heritage recipes that people still enjoy.
    • +
    +
    + + + +
    +

    🍅 Ingredient Notes

    + + + +
    + + + +
    Ingredients needed to make cracker salad.
    + + + +

    This post contains affiliate links.

    + + + +
      +
    • Ripe Fresh Tomatoes – Look for medium sized tomatoes that are completely ripe. They should be very bright in color but with no bruising or soft spots. I often use Romas for this recipe because they’re less “juicy” than other varieties. Heirloom tomato varieties make a really beautiful salad but they’re more expensive unless you grow them yourself.
    • + + + +
    • MayonnaiseHomemade mayonnaise is always best but, of course, most of us purchase it. I recommend Duke’s brand in the south and Hellman’s if you don’t have access to Duke’s.
    • + + + +
    • Shallot – I love the flavor of shallots in this recipe. They’re like a mild, sweet onion with a hint of garlic. However, they can be a bit pricey so feel free to substitute with red onion if you like.
    • + + + +
    • Saltine Crackers – You’ll need one “sleeve” (that’s about 40) of plain old Nabisco saltines. No need to try to be fancy with this recipe.
    • + + + +
    • Chives – Cut the chives very finely. You can also substitute very finely chopped green onions.
    • + + + +
    • Kosher Salt and Black Pepper – You won’t need much salt because of the crackers. I like quite a bit of ground black pepper for this.
    • +
    + + +
    + +
    +
    +
    +
    + + + +

    The complete ingredient list with detailed measurements is included in the printable recipe card at the bottom of this post.

    +
    + +
    + + + +
    +

    🔪 How to Make Southern Tomato Cracker Salad

    + + + +
    + + + +

    Prepare the Tomatoes

    + + + +
    Tomatoes being prepared for the salad on a wooden board.
    STEP 1-2.
    + + + +
      +
    1. Start by removing the core (or stem end) of the tomatoes and then cut each in half through the middle or “waist.” 
    2. + + + +
    3. Working over a medium bowl or into the sink, press each tomato half gently to get rid of most of the seeds and juice.
    4. +
    + + + +

    👉 PRO TIP:  You don’t have to remove everything, but try to extract most of the juice to keep the salad from being soggy. It also helps to leave the tomato halves to drain with the cut side down on a paper towel for a few minutes.

    +
    + + + +
    + + + + +
      +
    1. Dice the tomatoes. Place the diced tomatoes in a large mixing bowl and sprinkle lightly with salt. Remove a few tablespoons of diced tomatoes for garnish and set them aside.
    2. + + + +
    3. Into the bowl with the diced tomatoes, add the minced shallot, half of the chives, black pepper, and mayonnaise. Fold together gently to combine.
    4. +
    +
    + + +
    Pyrex Smart Essentials 3-Piece Mixing Bowl Set
    • Set includes 1-qt, 1.5-qt, and 2.5-qt round glass bowls.
    • High-quality tempered glass resists stains and odors. Freezer, microwave, and dishwasher safe. 
    • Loved for generations - experienced cooks and beginners alike have reached for Pyrex brand glassware products because they’re affordable, durable, and great for all their cooking, serving, and storing needs.
    This post contains affiliate links. Lana's Cooking is reader-supported and earns a tiny commission at no extra cost to you when you shop from our links.
    + + + +
    +

    Crumble the Crackers and Mix the Salad

    + + + + + + + +
      +
    1. Crumble the crackers creating mostly large pieces for the best texture.
    2. +
    + + + +

    👉 PRO TIP: Notice the size of the cracker pieces in the photo? You want them to be fairly large pieces. If you crumble them too small the whole salad will turn out mushy. That’s not what you want :-) 

    + + + +
      +
    1. Add the broken saltine crackers to the bowl with the tomato mixture and fold gently to combine.
    2. + + + +
    3. Taste for seasoning and adjust if necessary.
    4. +
    +
    + + + +
    +

    Garnish and Serve

    + + + +
    Garnish added to top of cracker salad.
    STEP 8.
    + + + +
      +
    1. Garnish with the reserved tomatoes and remaining chives.
    2. + + + +
    3. Serve immediately.
    4. +
    + + + +

    For best taste and texture, this salad should be mixed and served immediately. 

    +
    + + + +
    A serving of tomato cracker salad on a white plate.
    + + + +
    +

    🔀 Suggestions and Variations

    + + + +
    + + + +
      +
    • Some cooks include a few chopped, hard boiled eggs in the recipe.
    • + + + +
    • You can easily substitute the shallot and chives with finely diced green onions if you like.
    • + + + +
    • Use halved cherry tomatoes.
    • +
    +
    + + + +
    +

    ❓ Questions and Tips About Southern Tomato Cracker Salad

    + + + +
    + + + +
    Can I make cracker salad ahead of time?

    Because this salad wilts and becomes soggy pretty quickly, it’s best when eaten within minutes of being made. You can, however, prepare all the ingredients ahead of time and combine them when you’re ready to serve.

    How do I store leftover tomato cracker salad?

    It’s best to make the quantity of salad that you think you’ll need for one meal. Leftovers simply don’t keep well.

    +
    + + +
    + +
    + +
    +
    Lana Stuart.
    +
    + + + +
    +

    Questions? I’m happy to help!

    + + + +

    If you have more questions about the recipe, or if you’ve made it and would like to leave a comment, scroll down to leave your thoughts, questions, and/or rating!

    + + + +

    Thanks so much for stopping by!

    +
    + +
    + +
    + + +
    +

    📖 Recipe

    + + +
    +
    +

    Want to save this recipe?

    + + + +

    Enter your email below and get it sent straight to your inbox.

    + + +
    + Save Recipe
    +
    +
    + +
    + +
    +

    My Southern Table cookbook
    by Lana Taylor Stuart

    + + + +
    + + + + + + + +
      +
    • 346 pages; 246 recipes with full-color photos
    • + + + +
    • Durable softcover binding
    • + + + +
    • Personalized and signed by Lana
    • + + + +
    • Retail $39.99; Holiday Price $29.99 with FREE shipping
    • + + + +
    • In stock and ready to ship
    • +
    + + + + + + + + +
    + +
    + + + +
    + +
    A serving of tomato cracker salad on a white plate.
    +
    +
    +

    Southern Tomato Cracker Salad

    +
    +
    If you like a southern tomato sandwich, then you'll fall head over heels for this 15-minute Southern Tomato Cracker Salad recipe!
    +
    +
    5 from 3 votes
    +
    + Print It + + Rate It + + + + + Add to Collection +
    +
    Course: Salads, Side Dishes, Vegetables
    Cuisine: Southern, Vintage
    +
    Prep Time: 15 minutes
    Total Time: 15 minutes
    + +
    Servings: 4 servings
    + + +
    Calories: 278kcal
    +
    Author: Lana Stuart
    + + + +
    + +

    Ingredients

    • 3 very ripe medium tomatoes
    • 1 cup mayonnaise
    • 1/2 shallot finely minced
    • 40 saltine crackers (1 sleeve)
    • 2 tablespoons chives finely chopped
    • Kosher salt and ground black pepper to taste
    + +

    Instructions

    • Start by removing the core, or stem end) of the tomatoes and then cut each in half through the middle or “waist.”
    • Working over a medium bowl or into the sink, press each tomato half gently to get rid of most of the seeds and juice.
    • Dice the tomatoes. Place the diced tomatoes in a large mixing bowl and sprinkle lightly with salt. Remove a few tablespoons of diced tomatoes for garnish and set them aside.
    • Into the bowl with the diced tomatoes, add the minced shallot, half of the chives, black pepper, and mayonnaise. Fold together gently to combine.
    • Crumble the crackers creating mostly large pieces for the best texture.
    • Add the broken saltine crackers to the bowl with the tomato mixture and fold gently to combine.
    • Taste for seasoning and adjust if necessary.
    • Garnish with the reserved tomatoes and remaining chives.
    • Serve immediately.
    + +

    Notes

    This salad is best mixed and served immediately. Leftovers do not store well.
    +When preparing the tomatoes, try to extract most of the juice to keep the salad from being soggy. It also helps to leave the tomato halves to drain with the cut side down on a paper towel for a few minutes.
    +Make sure that the pieces of crumbled crackers are fairly large to keep the best texture in the salad. Crumbling them too small will result in a mushy salad.
    +Look for medium sized tomatoes that are completely ripe. They should be very bright in color but with no bruising or soft spots. I often use Romas for this recipe because they’re less “juicy” than other varieties. Heirloom tomato varieties make a beautiful salad but are more expensive.
    + + +

    Nutrition Information

    Serving 1serving | Calories 278kcal | Carbohydrates 32g | Protein 4g | Fat 15g | Saturated Fat 2g | Polyunsaturated Fat 9g | Monounsaturated Fat 3g | Trans Fat 0.2g | Cholesterol 9mg | Sodium 750mg | Potassium 296mg | Fiber 2g | Sugar 5g | Vitamin A 873IU | Vitamin C 14mg | Calcium 21mg | Iron 2mg
    +
    +

    Nutrition information is calculated by software based on the ingredients in each recipe. It is an estimate only and is provided for informational purposes. You should consult your healthcare provider or a registered dietitian if precise nutrition calculations are needed for health reasons.

    +
    +
    + +
    Share on Facebook + + Pin Recipe +
    +
    +
    Tried this recipe? Pin it for Later!Follow @LanasCookingBlog or tag #LanasCooking!
    +
    + + + +
    +

    🧾 More Recipes You’ll Like

    + + + +
    + + + + +
    +
    +
    +
    +
    +
    + + + + + +
    +
    +
    +
    + 5 from 3 votes (2 ratings without comment) +
    +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +
    +

    + +

    +

    One Comment

      +
    1. +
      +
      +
      + Dasso says:
      + + + +
      + +
      +

      5 stars
      +So good! So quick! So Southern!! So yummy.

      +
      + +
      +
    2. +
    +
    +
    +
    + + +
    +
    +
    + +
    + +
    + +
    + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/lanascooking.com/lanascooking_2.json b/tests/test_data/lanascooking.com/lanascooking_2.json new file mode 100644 index 000000000..5207c641e --- /dev/null +++ b/tests/test_data/lanascooking.com/lanascooking_2.json @@ -0,0 +1,78 @@ +{ + "author": "Lana Stuart", + "canonical_url": "https://www.lanascooking.com/oven-roasted-turkey/", + "site_name": "Lana's Cooking", + "host": "lanascooking.com", + "language": "en-US", + "title": "Oven Roasted Turkey with Gravy", + "ingredients": [ + "1 cup butter (softened)", + "2 tablespoons seasoned salt (recommended: Jane's Crazy Mixed-Up Salt)", + "10 pounds turkey (fresh or frozen)", + "½ cup pan drippings from turkey", + "½ cup all-purpose flour", + "3 ¾ cups turkey or chicken broth or stock" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 cup butter (softened)", + "2 tablespoons seasoned salt (recommended: Jane's Crazy Mixed-Up Salt)", + "10 pounds turkey (fresh or frozen)" + ], + "purpose": "For the Turkey:" + }, + { + "ingredients": [ + "½ cup pan drippings from turkey", + "½ cup all-purpose flour", + "3 ¾ cups turkey or chicken broth or stock" + ], + "purpose": "For the Gravy:" + } + ], + "instructions_list": [ + "To Roast the Turkey:", + "If using a frozen turkey, thaw in the refrigerator allowing at least 24 hours for every 4 pounds of turkey.", + "Approximately 1 1/2 hours before cooking, remove the turkey from the refrigerator and let it sit at room temperature.", + "Preheat the oven to 325 degrees. Drain any juices from the turkey and pat it dry with paper towels.", + "Place the turkey breast side up on a rack in a roasting pan.", + "Tuck the wings under the turkey and secure the legs with kitchen twine if needed.", + "Rub the turkey generously with the butter. Sprinkle evenly with seasoned salt.", + "Place the turkey in the preheated oven.", + "About 2/3 through cooking time, check to make sure the breast and tops of the legs aren't browning too quickly. If needed, cover the turkey loosely with a tent of aluminum foil to prevent overcooking.", + "Turkey is done when the temperature in the thigh registers 180 degrees on a meat thermometer.", + "Remove from the oven and let stand for at least 20 minutes before carving.", + "To Make the Gravy:", + "Remove drippings from the turkey roasting pan and place in a medium saucepan.", + "Using a whisk, blend the flour into the pandrippings.", + "Whisk in the stock or broth a little at a time", + "Place the saucepan over medium high heat and bring to a boil. Reduce the heat to low and simmer for about 5 minutes." + ], + "category": "Main Course,Main Dishes", + "yields": "6 servings", + "description": "A simple method for cooking a beautifully moist Oven Roasted Turkey with golden, crispy skin and instructions for making the best pan gravy.", + "total_time": 215, + "cook_time": 180, + "prep_time": 15, + "cuisine": "American", + "ratings": 5.0, + "ratings_count": 6, + "nutrients": { + "servingSize": "1", + "calories": "1198 kcal", + "fatContent": "72 g", + "saturatedFatContent": "35 g", + "carbohydrateContent": "13 g", + "sugarContent": "3 g", + "proteinContent": "121 g", + "sodiumContent": "3408 mg", + "fiberContent": "1 g", + "cholesterolContent": "472 mg" + }, + "image": "https://www.lanascooking.com/wp-content/uploads/2020/11/oven-roasted-turkey-feature-1200x1200-1.jpg", + "keywords": [ + "oven roasted turkey", + "turkey gravy" + ] +} diff --git a/tests/test_data/lanascooking.com/lanascooking_2.testhtml b/tests/test_data/lanascooking.com/lanascooking_2.testhtml new file mode 100644 index 000000000..548b25746 --- /dev/null +++ b/tests/test_data/lanascooking.com/lanascooking_2.testhtml @@ -0,0 +1,1676 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Oven Roasted Turkey with Gravy Recipe - Lana’s Cooking + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    + +
    + + + + + +
    + + +

    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    Home » Recipes » Main Dish Recipes » Oven Roasted Turkey with Gravy

    Oven Roasted Turkey with Gravy

    +
    + +
    +
    + + + + + +
    5 from 6 votes
    + + +
    +

    Our Thanksgiving dinner just wouldn’t be complete without the turkey! Here’s my simple method for cooking a beautifully moist Oven Roasted Turkey with golden, crispy skin and instructions for making the best pan gravy!

    + + + +

    Turkey is the star of the show at most of our Thanksgiving tables, isn’t it? I know for our family, the holiday just wouldn’t be the same without it.

    Oven Roasted Turkey with Gravy on a white serving platter.
    + + + +

    Don’t be intimidated by the thought of cooking something as large as a turkey. If you can roast a chicken, you can cook a turkey!

    + + + +

    This simple method works just as well whether your turkey is fresh or frozen. It does take a little effort to get the timing right, so I find that making a plan the week before is really helpful.

    + + + +

    I always plan out any necessary thawing time, plus time to bring the turkey to room temperature before cooking, plus time to prep and time to cook and rest. Let’s go over those times together, shall we?

    + + + +
    Carved Oven Roasted Turkey with Gravy presented on a white serving platter.
    + + + + + +
    +

    How to Plan Your Thanksgiving Cooking Timetable

    + + + +
      +
    • When making a plan for cooking Thanksgiving dinner, I start by deciding what time I’ll serve dinner and work backward from there. Begin with the timing for the turkey, which is explained below.
    • + + + +
    • Plan all the side dishes and desserts and determine which can be made in advance. Allow yourself plenty of time so that you don’t feel rushed and overwhelmed. Many steps of individual recipes can be made in advance, with the final dish assembled quickly on Thanksgiving day.
    • + + + +
    • Most desserts can (and should!) be made in advance, with only garnishing reserved for the last moment.
    • + + + +
    • Check to make sure you have all the flatware, china, crystal, and table linens you need well in advance. Don’t forget serving pieces! You’ll need bowls, platters, trays, and serving spoons and forks.
    • + + + +
    • Plan ahead to have beverages ready and ice on hand if needed.
    • +
    +
    + + + +
    +

    👉 PRO TIP: Use a large insulated cooler with ice as an extra refrigerator if you need more space.

    +
    + + + +
    +

    Timing Cooking of the Turkey

    + + + +

    If you’re starting with a frozen turkey, you’ll need to thaw it in its original packaging in the refrigerator (or in a large cooler with a couple of bags of ice), allowing at least 24 hours for every 4 pounds. After it’s thawed, keep it in the fridge (or on ice in a cooler) until you’re ready to cook.

    + + + +

    About 1 1/2 hours before you start cooking, take the turkey out of the fridge to bring it to room temperature. Having it at room temp will help it cook more evenly and faster.

    + + + +

    Prep time is pretty quick. I allow about 15 minutes to slather on the butter and sprinkle on the seasonings.

    + + + +

    Cooking time, of course, varies according to the total weight of the turkey. I’ve included a roasting timetable for you further down in the post. You’ll also need to allow time for the turkey to rest before carving.

    + + + +

    So, let’s get started with the recipe!

    +
    + + + +

    👉 Or just purchase my Thanksgiving Planner and Cookbook with all the timetables, recipes, and menus you need to make your planning easy!

    + + + +
    +

    Ingredient Notes

    + + + +
    The simple ingredients you'll need to make an oven roasted turkey.
    Butter, seasoned salt, turkey. (For the gravy: pan drippings from the turkey, flour, chicken or turkey broth).
    + + + +

    This post contains affiliate links. Lana’s Cooking is reader-supported and earns a tiny commission at no extra cost to you when you shop from our links.

    + + + +
      +
    • Fresh or Frozen Turkey — When choosing your Thanksgiving turkey, you should plan on 1 to 1 1/2 pounds per person; if you’d like to have leftovers, bump it up to 2 pounds per person.
    • + + + +
    • Butter — Like most southern cooks, I use salted butter for everything.
    • + + + +
    • Seasoning Salt — Use any seasoning mixture you like. I prefer Jane’s Crazy Mixed-Up Salt. Other people swear by Bell’s Seasoning or Lawry’s Seasoned Salt. Of course, just plain salt and black pepper work well, too.
    • +
    + + +
    + +
    +
    +
    +
    + + + +

    The complete ingredient list with detailed measurements is included in the printable recipe card at the bottom of this post.

    +
    + +
    + + + +
    +

    What Size Turkey Should I Buy?

    + + + +

    I always plan on 1 to 1 1/2 pounds of turkey per person (this allows for discarding skin, bones, etc.). Go for 2 pounds if you want to have lots of leftovers!

    +
    + + + +
    +

    How to Cook an Oven Roasted Turkey with Gravy

    + + + +

    Preheat the oven to 325 degrees.

    + + + +

    This process for how to cook a turkey in the oven is really simple and basic. All you’ll need are a turkey (thawed if frozen), some butter, and seasoning salt. As far as equipment goes, you will need a roasting pan and a rack of some kind.

    +
    + + + +
    +

    Prepare the Turkey

    + + + +

    Remove the turkey from its packaging and, using disposable paper towels, pat it dry very thoroughly.

    + + + +

    Make sure to remove the packet of giblets and neck from inside the cavity before proceeding with the recipe.

    + + + +
    +

    👉 PRO TIP: Like many cooks, I often use the giblets and neck to make stock for the gravy. Place the giblets in a saucepan and cover them with water and about half a teaspoon of salt. Bring to a boil and reduce to a simmer. Cook for about 30 minutes. Strain the broth and use it to make gravy.

    +
    + + + +

    If using a whole turkey, tuck the wing tips underneath the body. With some brands, the legs will be tucked under a flap of skin. If yours aren’t, simply tie them together with twine.

    + + + +

    Place the turkey on a rack in the roasting pan.

    +
    + + + +
    +
    Turkey in a roasting pan being rubbed with butter.
    + + + +

    Rub the skin all over with a generous amount of softened, room temperature butter.

    + + + +
    +

    👉 PRO TIP: I typically use between one and two sticks of butter for a medium sized turkey. You want it very well coated.

    +
    +
    + + + +
    +
    Turkey in roasting pan coated with butter and seasoned salt.
    + + + +

    Sprinkle well with salt and pepper, a seasoned salt mixture, or your favorite combination of spices. My favorite seasoning to use is Jane’s Crazy Mixed-Up Salt. However, I know many people use Bell’s Seasoning. You use whatever you like.

    +
    + + + +
    +

    Bake Until Golden Brown

    + + + +

    Place the pan in the preheated oven and set a timer for about 2/3 through the cooking time. When the turkey is about 2/3 done, check for browning.

    + + + +
    +

    👉 PRO TIP: Check the turkey periodically throughout the cooking time, and if you feel that the breast and the top of the drumsticks are getting too brown, make a tent of lightweight foil to drape over the top of the turkey to keep it from over-browning.

    +
    +
    + + + +
    +

    Cook according to the following timetable:

    + + + +

    Turkey Roasting Time Table Per Pound

    + + + +
    6-7 pounds2 – 2 1/2 hours
    7-10 pounds2 1/2 – 3 hours
    10 – 18 pounds3 – 3 1/2 hours
    18 – 22 pounds3 1/2 – 4 hours
    22 – 24 pounds4 – 4 1/2 hours
    24 – 30 pounds4 1/2 – 5 hours
    + + + +

    Test for doneness with a meat thermometer. A thermometer placed deep within the thigh should read 180 degrees when done.

    +
    + + + +
    Finished turkey resting in roasting pan.
    + + + +
    +

    Allow Adequate Resting Time

    + + + +

    Remove the turkey from the oven and let it stand for 20 to 30 minutes before carving.

    + + + +

    Resting time is very important as it allows the juices to redistribute through the meat, ensuring the turkey is moist throughout. Carving too quickly can cause a drier end product.

    +
    + + + +
    Gravy poured from a gravy boat onto a plate containing sliced oven roasted turkey and side dishes.
    + + + +
    +

    How to Make Turkey Gravy

    + + + +

    Remove about 1/2 cup of the drippings from the roasting pan and place them in a medium saucepan over medium-high heat. Using a whisk, blend the flour into the pan drippings. Whisk in the stock or broth a little at a time.

    + + + +

    Bring to a boil. Reduce the heat to low and simmer for about 5 minutes. Some cooks dice the giblets and add them to the gravy. It’s optional but tasty! My grandmother always added a chopped, hard-boiled egg. Again, an optional addition.

    + + + +

    Serve sliced roast turkey on a large platter with the gravy drizzled over or on the side.

    +
    + + + +
    +

    Recipe Options

    + + + +

    This is a very basic but quite delicious recipe. I often enhance the flavors by placing halved shallots, garlic, onion, lemons, and oranges inside the cavity, along with fresh herbs such as rosemary, sage, and thyme. Remove and discard these after cooking.

    +
    + + + + + + + +
    +

    Questions About Oven Roasted Turkey

    + + + +
    What if I don’t have a roasting rack?

    If you don’t have a roasting rack, you can form a coil of scrunched up aluminum foil to place in the bottom of your pan or use a bed of vegetables such as carrots and celery to keep the turkey raised off the bottom of the pan.

    How often should I baste the turkey?

    I skip it completely. Basting a turkey means frequently opening the oven door, which results in temperature fluctuations that can cause a dry turkey (particularly the breast meat). The butter rubbed all over will keep the turkey moist without the need for basting

    I’m a little nervous about trying to handle that big bird. Advice?

    I get it. Moving that big, hot turkey around can be intimidating. So, you could always consider roasting two small ones instead! They’ll cook faster, too, since you’ll base your cooking time on the smaller weights.

    Do you cover the turkey when roasting?

    No. Don’t cover the turkey while roasting. If you notice later in the cooking that the breast or legs are getting too brown, you can lightly place some foil over the top, but don’t completely cover the turkey.

    +
    + + +
    + +
    + +
    +
    Lana Stuart.
    +
    + + + +
    +

    Questions? I’m happy to help!

    + + + +

    If you have more questions about the recipe, or if you’ve made it and would like to leave a comment, scroll down to leave your thoughts, questions, and/or rating!

    + + + +

    Thanks so much for stopping by!

    +
    + +
    + +
    + + +
    +

    Recipe

    + + +
    +
    +

    Want to save this recipe?

    + + + +

    Enter your email below and get it sent straight to your inbox.

    + + +
    + Save Recipe
    +
    +
    + +
    + +
    +

    My Southern Table cookbook
    by Lana Taylor Stuart

    + + + +
    + + + + + + + +
      +
    • 346 pages; 246 recipes with full-color photos
    • + + + +
    • Durable softcover binding
    • + + + +
    • Personalized and signed by Lana
    • + + + +
    • Retail $39.99; Holiday Price $29.99 with FREE shipping
    • + + + +
    • In stock and ready to ship
    • +
    + + + + + + + + +
    + +
    + + + +
    + +
    Oven Roasted Turkey with Gravy on a white serving platter.
    +
    +
    +

    Oven Roasted Turkey with Gravy

    +
    +
    A simple method for cooking a beautifully moist Oven Roasted Turkey with golden, crispy skin and instructions for making the best pan gravy.
    +
    +
    5 from 6 votes
    +
    + Print It + + Rate It + + + + + Add to Collection +
    +
    Course: Main Course, Main Dishes
    Cuisine: American
    +
    Prep Time: 15 minutes
    Cook Time: 3 hours
    Resting Time: 20 minutes
    Total Time: 3 hours 35 minutes
    + +
    Servings: 6 servings
    + + +
    Calories: 1198kcal
    +
    Author: Lana Stuart
    + + + +
    + +

    Ingredients

    For the Turkey:

    • 1 cup butter softened
    • 2 tablespoons seasoned salt recommended: Jane's Crazy Mixed-Up Salt
    • 10 pounds turkey fresh or frozen

    For the Gravy:

    • ½ cup pan drippings from turkey
    • ½ cup all-purpose flour
    • 3 ¾ cups turkey or chicken broth or stock
    + +

    Instructions

    To Roast the Turkey:

    • If using a frozen turkey, thaw in the refrigerator allowing at least 24 hours for every 4 pounds of turkey.
    • Approximately 1 1/2 hours before cooking, remove the turkey from the refrigerator and let it sit at room temperature.
    • Preheat the oven to 325 degrees. Drain any juices from the turkey and pat it dry with paper towels.
    • Place the turkey breast side up on a rack in a roasting pan.
    • Tuck the wings under the turkey and secure the legs with kitchen twine if needed.
    • Rub the turkey generously with the butter. Sprinkle evenly with seasoned salt.
    • Place the turkey in the preheated oven.
    • About 2/3 through cooking time, check to make sure the breast and tops of the legs aren't browning too quickly. If needed, cover the turkey loosely with a tent of aluminum foil to prevent overcooking.
    • Turkey is done when the temperature in the thigh registers 180 degrees on a meat thermometer.
    • Remove from the oven and let stand for at least 20 minutes before carving.

    To Make the Gravy:

    • Remove drippings from the turkey roasting pan and place in a medium saucepan.
    • Using a whisk, blend the flour into the pandrippings.
    • Whisk in the stock or broth a little at a time
    • Place the saucepan over medium high heat and bring to a boil. Reduce the heat to low and simmer for about 5 minutes.
    + +

    Notes

    The times, servings, and nutrition information are calculated based on a 10-pound fresh, unfrozen turkey.
    +When purchasing your turkey, allow 1 to 1 1/2 pounds per person. More if you’d like lots of leftovers.
    +Turkey Roasting Time Table:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    6 – 7 pounds2 – 2 1/2 hours
    7 – 10 pounds2 1/2 – 3 hours
    10 – 18 pounds3 – 3 1/2 hours
    18 – 22 pounds3 1/2 – 4 hours
    22 -24 pounds4 – 4 1/2 hours
    24 – 30 pounds4 1/2 – 5 hours
    +Times stated are approximate. Use a meat thermometer to determine when your turkey is done correctly.
    +Tips:
    +
      +
    • If you don’t have a roasting rack, form a coil of aluminum foil to place in the bottom of your pan or use a bed of vegetables such as carrots and celery to keep the turkey raised off the bottom of the pan.
    • +
    • Skip the basting – basting a turkey means frequently opening the oven door which results in temperature fluctuations that can result in a dry finished bird. The butter rubbed all over will keep the turkey moist without the need for basting.
    • +
    + + +

    Nutrition Information

    Serving 1 | Calories 1198kcal | Carbohydrates 13g | Protein 121g | Fat 72g | Saturated Fat 35g | Cholesterol 472mg | Sodium 3408mg | Potassium 1378mg | Fiber 1g | Sugar 3g | Vitamin A 1246IU | Vitamin C 1mg | Calcium 73mg | Iron 5mg
    +
    +

    Nutrition information is calculated by software based on the ingredients in each recipe. It is an estimate only and is provided for informational purposes. You should consult your healthcare provider or a registered dietitian if precise nutrition calculations are needed for health reasons.

    +
    +
    + +
    Share on Facebook + + Pin Recipe +
    +
    +
    Tried this recipe? Pin it for Later!Follow @LanasCookingBlog or tag #LanasCooking!
    +
    + + + +

    — This post was originally published on November 11, 2020. It has been updated with additional information.

    +
    +
    +
    +
    +
    + + + + + +
    +
    +
    +
    + 5 from 6 votes (5 ratings without comment) +
    +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +
    +

    + +

    +

    2 Comments

      +
    1. +
      +
      +
      + Miss P says:
      + + + +
      + +
      +

      5 stars
      +Oh. My. Goodness. Absolutely superb. Nothing compares.
      +And the photography is outstanding!

      +
      + +
      +
        +
      1. +
        + + +
        +

        Thanks! I do enjoy a really good roast turkey.

        +
        + +
        +
      2. +
      +
    2. +
    +
    +
    +
    + + +
    +
    +
    + +
    + +
    + +
    + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/leitesculinaria.com/leitesculinaria_1.json b/tests/test_data/leitesculinaria.com/leitesculinaria_1.json index 9b44d31f0..f11561805 100644 --- a/tests/test_data/leitesculinaria.com/leitesculinaria_1.json +++ b/tests/test_data/leitesculinaria.com/leitesculinaria_1.json @@ -8,7 +8,7 @@ "ingredients": [ "1 3/4 pounds red jalapeño peppers (stems removed and halved lengthwise)", "3 garlic cloves", - "2 tablespoons garlic powder ((optional))", + "2 tablespoons garlic powder (optional)", "2 tablespoons granulated sugar (plus more as needed)", "1 tablespoon light brown sugar", "1 tablespoon kosher salt (plus more as needed)", diff --git a/tests/test_data/leitesculinaria.com/leitesculinaria_2.json b/tests/test_data/leitesculinaria.com/leitesculinaria_2.json index 13ffbd8aa..36fa55193 100644 --- a/tests/test_data/leitesculinaria.com/leitesculinaria_2.json +++ b/tests/test_data/leitesculinaria.com/leitesculinaria_2.json @@ -14,14 +14,14 @@ "2 bay leaf", "1/2 teaspoon allspice berries", "4 whole cloves", - "Kosher salt (to taste (optional))", + "Kosher salt (to taste (optional)", "3 tablespoons (1 1/2 oz) unsalted butter or lard", "2 cups hearty red table wine", "2 tablespoons store-bought or homemade tomato paste", "1/2 teaspoon ground cinnamon", - "Boiled white potatoes ((optional))", - "Roasted red peppers ((optional))", - "Cooked greens ((optional))" + "Boiled white potatoes (optional)", + "Roasted red peppers (optional)", + "Cooked greens (optional)" ], "ingredient_groups": [ { @@ -34,7 +34,7 @@ "2 bay leaf", "1/2 teaspoon allspice berries", "4 whole cloves", - "Kosher salt (to taste (optional))", + "Kosher salt (to taste (optional)", "3 tablespoons (1 1/2 oz) unsalted butter or lard", "2 cups hearty red table wine", "2 tablespoons store-bought or homemade tomato paste", @@ -44,9 +44,9 @@ }, { "ingredients": [ - "Boiled white potatoes ((optional))", - "Roasted red peppers ((optional))", - "Cooked greens ((optional))" + "Boiled white potatoes (optional)", + "Roasted red peppers (optional)", + "Cooked greens (optional)" ], "purpose": "For serving" } diff --git a/tests/test_data/lovingitvegan.com/lovingitvegan.json b/tests/test_data/lovingitvegan.com/lovingitvegan.json index 476a70b8e..eac85b913 100644 --- a/tests/test_data/lovingitvegan.com/lovingitvegan.json +++ b/tests/test_data/lovingitvegan.com/lovingitvegan.json @@ -6,10 +6,10 @@ "language": "en-US", "title": "Kale Smoothie", "ingredients": [ - "1 1/4 cups Soy Milk ((300ml) or Almond Milk)", - "2 Frozen Bananas ((200g) previously peeled, broken into quarters and frozen for at least 12 hours)", - "1/2 cup Raw Cashews ((75g))", - "2 cups Kale ((56g) Torn up, packed)", + "1 1/4 cups Soy Milk (300ml) or Almond Milk)", + "2 Frozen Bananas (200g) previously peeled, broken into quarters and frozen for at least 12 hours)", + "1/2 cup Raw Cashews (75g)", + "2 cups Kale (56g) Torn up, packed)", "4 Medjool Dates (Pitted)", "1 tsp Minced Ginger", "1/8 tsp Cinnamon", diff --git a/tests/test_data/madamecuisine.de/madamecuisine_1.json b/tests/test_data/madamecuisine.de/madamecuisine_1.json index 4646f6507..fb89fc05c 100644 --- a/tests/test_data/madamecuisine.de/madamecuisine_1.json +++ b/tests/test_data/madamecuisine.de/madamecuisine_1.json @@ -46,6 +46,18 @@ "yields": "4 servings", "description": "Dieser leckere Eintopf wird mit viel Gemüse, Bohnen, Gewürzen und Kräutern zubereitet. Die Gemüse-Sorten lassen sich - je nach Geschmack und Saison - beliebig variieren. Ein einfaches Essen, das sich wunderbar vorbereiten lässt und durchaus auch Gäste tauglich ist. ", "total_time": 60, + "cook_time": 40, + "prep_time": 20, "cuisine": "Amerikanisch, Deutsch", - "image": "https://www.madamecuisine.de/wp-content/uploads/2024/10/gemueseeintopf-mit-wintergemuese04.jpg" + "ratings": 5.0, + "ratings_count": 4, + "nutrients": { + "servingSize": "1 Portion", + "calories": "540 kcal" + }, + "image": "https://www.madamecuisine.de/wp-content/uploads/2024/10/gemueseeintopf-mit-wintergemuese04.jpg", + "keywords": [ + "Eintopf", + "Gemüseeintopf" + ] } diff --git a/tests/test_data/madamecuisine.de/madamecuisine_2.json b/tests/test_data/madamecuisine.de/madamecuisine_2.json index 97af5c1b7..b16afb6e2 100644 --- a/tests/test_data/madamecuisine.de/madamecuisine_2.json +++ b/tests/test_data/madamecuisine.de/madamecuisine_2.json @@ -35,6 +35,21 @@ "yields": "2 servings", "description": "Shakshuka, das sind versunkene Eier in einer Tomatensoße mit Paprika und Zwiebeln. Die Soße in einer Pfanne langsam einköcheln, dann die Eier im Ofen stocken lassen.", "total_time": 60, + "cook_time": 45, + "prep_time": 15, "cuisine": "Israelisch / Arabisch", - "image": "https://www.madamecuisine.de/wp-content/uploads/2019/11/shakshuka02-720x480.jpg" + "ratings": 4.64, + "ratings_count": 495, + "nutrients": { + "servingSize": "1 Portion", + "calories": "440 kcal" + }, + "image": "https://www.madamecuisine.de/wp-content/uploads/2019/11/shakshuka02-720x480.jpg", + "keywords": [ + "Paprika", + "Schakschuka", + "Shakshuka", + "Tomaten", + "Versunkene Eier" + ] } diff --git a/tests/test_data/madsvin.com/madsvin.json b/tests/test_data/madsvin.com/madsvin.json index 4862b3663..6be92492a 100644 --- a/tests/test_data/madsvin.com/madsvin.json +++ b/tests/test_data/madsvin.com/madsvin.json @@ -7,11 +7,11 @@ "title": "Pandekager", "ingredients": [ "125 gram hvedemel", - "3 æg ((mellemstore))", + "3 æg (mellemstore)", "3 dl mælk (jeg brugte sødmælk - anden mælk kan også fint bruges)", "2 spsk sukker (både rørsukker og hvid sukker kan bruges)", "½ stang vanilje (eller 1 spsk vaniljesukker)", - "25 gram smør ((smeltet))", + "25 gram smør (smeltet)", "½ tsk salt", "smør (til stegning - neutral olie kan også bruges)" ], diff --git a/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.json b/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.json new file mode 100644 index 000000000..9ee7dc34c --- /dev/null +++ b/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.json @@ -0,0 +1,65 @@ +{ + "author": "Andrew Bernard", + "canonical_url": "https://makeitdairyfree.com/the-best-vegan-mac-and-cheese/", + "site_name": "Make It Dairy Free", + "host": "makeitdairyfree.com", + "language": "en-US", + "title": "The Best Baked Vegan Mac and Cheese", + "ingredients": [ + "1 pound macaroni noodles, (uncooked (16oz or 454g) (Use gluten free if needed)", + "15 oz can butter beans, (drained and rinsed (439g)", + "2 cups dairy free milk (480g)", + "1/2 cup vegetable stock (120g)", + "1/2 cup vegan butter (113g)", + "1/3 cup nutritional yeast (27g)", + "2 tablespoon lemon juice", + "1 teaspoon salt", + "1 teaspoon cracked black pepper", + "1/4 teaspoon paprika", + "2 cups vegan shredded cheddar cheese, (divided (240g)", + "1 cup vegan parmesan cheese (115g)", + "1/3 cup seasoned panko breadcrumbs (20g)", + "2 teaspoon olive oil, (optional)" + ], + "instructions_list": [ + "Bring a salted pot of water to a boil. Preheat oven to 350˚F/180˚C degrees. Cook 1lb macaroni noodles according to the package. Drain noodles once done and set aside.", + "While noodles cook, to a high powdered blender, add 15oz can butter beans, 2 cups dairy free milk, 1/2 cup stock, 1/2 cup vegan butter, 1/3 cupnutritional yeast, 2 tablespoons lemon juice, 1 teaspoon each salt and pepper, 1/4 teaspoon paprika, 1 cup each non-dairy cheddar shreds and parmesan cheese. Blend this until smooth. Set aside.", + "In a lightly greased 9x13 casserole dish, add the drained, cooked noodles. Pour the sauce mixture over the noodles and carefully stir together.", + "Top with remaining 1 cup of the cheese shreds. If using the oil, in a small bowl combine the oil with the breadcrumbs and stir to well coated. Sprinkle evenly across the top.", + "Bake for 25-30 minutes or until breadcrumbs have started turning golden brown on top. Remove from oven and let set for 15 minutes before cutting into." + ], + "category": "Main Course,Side Dish", + "yields": "16 servings", + "description": "This is the best vegan mac and cheese recipe ever! Directions for stovetop version and the most delicious baked vegan mac and cheese ever! Not cashew based, so allergy friendly!", + "total_time": 50, + "cook_time": 30, + "prep_time": 15, + "cuisine": "American", + "ratings": 4.91, + "ratings_count": 125, + "equipment": [ + "9×13 casserole dish" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "127 kcal", + "fatContent": "5 g", + "saturatedFatContent": "1 g", + "carbohydrateContent": "16 g", + "sugarContent": "2 g", + "proteinContent": "3 g", + "sodiumContent": "384 mg", + "fiberContent": "1 g" + }, + "image": "https://makeitdairyfree.com/wp-content/uploads/2019/10/the-best-vegan-mac-and-cheese-6.jpg", + "keywords": [ + "dairy free holidays", + "dairy free main course", + "dairy free recipes", + "dairy free side dish", + "vegan holidays", + "vegan main course", + "vegan recipes", + "vegan side dish" + ] +} diff --git a/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.testhtml b/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.testhtml new file mode 100644 index 000000000..010132622 --- /dev/null +++ b/tests/test_data/makeitdairyfree.com/makeitdairyfree_1.testhtml @@ -0,0 +1,2424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Baked Vegan Mac and Cheese - Make It Dairy Free + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
      + + +
    • +
    • +
    +
    + +
    + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.json b/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.json new file mode 100644 index 000000000..3bc68e408 --- /dev/null +++ b/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.json @@ -0,0 +1,109 @@ +{ + "author": "Larisha Bernard", + "canonical_url": "https://makeitdairyfree.com/veggie-packed-crispy-rice-salad-with-peanut-dressing/", + "site_name": "Make It Dairy Free", + "host": "makeitdairyfree.com", + "language": "en-US", + "title": "The Best Crispy Rice Salad with Veggies and Peanut Dressing", + "ingredients": [ + "2 cups pre-cooked rice, (cooled)", + "1 tablespoon chili garlic sauce", + "1 tablespoon chili crunch oil", + "1 tablespoon sesame oil", + "1 tablespoon soy sauce", + "1 lime (juice from 1/2 and zest from whole)", + "5 mini cucumbers, (thinly sliced)", + "2 avocados, (cubed)", + "1 red bell pepper, (chopped)", + "3-5 green onions, (chopped)", + "2 cups red cabbage, (finely sliced)", + "1 cup unsalted peanuts, (chopped (150g)", + "1 cup edamame, (shelled and cooked (160g)", + "1 cup fresh basil, (chopped (16g)", + "½ cup cilantro, (chopped (8g)", + "1/4 cup peanut butter (65g)", + "3 tablespoons Olive Oil", + "3 Tablespoons rice vinegar", + "3 Cloves garlic, (minced)", + "1/2 lime, ( juiced)", + "2 Tablespoons Toasted Sesame Oil", + "2 Tablespoons soy sauce", + "1 1/2 Tablespoons maple syrup", + "1 inch fresh ginger, (grated (2.5cm)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "2 cups pre-cooked rice, (cooled)", + "1 tablespoon chili garlic sauce", + "1 tablespoon chili crunch oil", + "1 tablespoon sesame oil", + "1 tablespoon soy sauce", + "1 lime (juice from 1/2 and zest from whole)" + ], + "purpose": "For the Crispy Rice:" + }, + { + "ingredients": [ + "5 mini cucumbers, (thinly sliced)", + "2 avocados, (cubed)", + "1 red bell pepper, (chopped)", + "3-5 green onions, (chopped)", + "2 cups red cabbage, (finely sliced)", + "1 cup unsalted peanuts, (chopped (150g)", + "1 cup edamame, (shelled and cooked (160g)", + "1 cup fresh basil, (chopped (16g)", + "½ cup cilantro, (chopped (8g)" + ], + "purpose": "For the Salad:" + }, + { + "ingredients": [ + "1/4 cup peanut butter (65g)", + "3 tablespoons Olive Oil", + "3 Tablespoons rice vinegar", + "3 Cloves garlic, (minced)", + "1/2 lime, ( juiced)", + "2 Tablespoons Toasted Sesame Oil", + "2 Tablespoons soy sauce", + "1 1/2 Tablespoons maple syrup", + "1 inch fresh ginger, (grated (2.5cm)" + ], + "purpose": "For the Creamy Peanut Ginger Dressing:" + } + ], + "instructions_list": [ + "Make Crispy Rice: Preheat oven to 400˚F (200˚C). Add 2 cups cooked and cooled rice to a bowl, along with 1 tbsp each chili garlic sauce, chili crunch oil, sesame oil and soy sauce, and the zest from 1 lime and juice from 1/2 of it. Stir to combine everything evenly. Place on baking sheet and bake for 25-35 minutes or just until crispy.", + "While that's baking, to a large bowl, add the 5 mini sliced cucumbers, 2 cubed avocados, 1 chopped red bell pepper, 3-5 chopped green onions, 2 cups shredded cabbage, 1 cup each chopped peanuts, edamame, fresh chopped basil, and 1/2 cup chopped cilantro. Stir together very well.", + "In a small blender, add 1/4 cup peanut butter, 3 tbsp each olive oil and rice vinegar, 3 cloves garlic, 1/2 lime juiced, 2 tbsp each toasted sesame oil and soy sauce, 1 1/2 cups maple syrup, and 1 inch grated ginger. Blend until combined.*Note: If you don't have a small blender, you can do this by whisking by hand, just finely mince the garlic first.", + "When rice is finished, let cool and then add to the bowl with the peanut butter sauce and combine so the sauce is evenly all over." + ], + "category": "Main Course,Salad", + "yields": "4 servings", + "description": "If you've never made crispy rice salad then you are in for a treat! This meal prep, no leafy green salad option is perfect for those looking for amazing flavor, with little effort.", + "total_time": 45, + "cook_time": 30, + "prep_time": 15, + "cuisine": "Asian", + "nutrients": { + "servingSize": "0.25 g", + "calories": "1172 kcal", + "fatContent": "68 g", + "saturatedFatContent": "10 g", + "unsaturatedFatContent": "52 g", + "transFatContent": "0.003 g", + "carbohydrateContent": "122 g", + "sugarContent": "20 g", + "proteinContent": "31 g", + "sodiumContent": "1282 mg", + "fiberContent": "22 g" + }, + "dietary_restrictions": [ + "Vegan Diet", + "Vegetarian Diet" + ], + "image": "https://makeitdairyfree.com/wp-content/uploads/2024/12/crispy-rice-salad-6.jpg", + "keywords": [ + "vegan main course" + ] +} diff --git a/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.testhtml b/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.testhtml new file mode 100644 index 000000000..889607e85 --- /dev/null +++ b/tests/test_data/makeitdairyfree.com/makeitdairyfree_2.testhtml @@ -0,0 +1,1873 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Veggie Packed Crispy Rice Salad with Peanut Dressing - Make It Dairy Free + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
      + + +
    • +
    • +
    +
    + +
    + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/mealprepmanual.com/mealprepmanual_1.json b/tests/test_data/mealprepmanual.com/mealprepmanual_1.json new file mode 100644 index 000000000..e6a0f9bc1 --- /dev/null +++ b/tests/test_data/mealprepmanual.com/mealprepmanual_1.json @@ -0,0 +1,73 @@ +{ + "author": "Josh Cortis", + "canonical_url": "https://mealprepmanual.com/slow-cooker-big-boy-beef-stroganoff/", + "site_name": "The Meal Prep Manual", + "host": "mealprepmanual.com", + "language": "en-US", + "title": "Slow Cooker Big Boy Beef Stroganoff", + "ingredients": [ + "2½ lbs top round roast", + "½ cup cream cheese", + "2 cups beef broth", + "1 tbsp Worcestershire sauce", + "2 tsp garlic powder", + "2 tsp paprika", + "1 tsp salt", + "1 tsp pepper", + "1 medium onion", + "1 lb carrots", + "½ lb mushrooms", + "1½ lbs pasta (I used fusilli)", + "3 tbsp starch (tapioca or cornstarch)", + "¼ cup water", + "½ cup plain greek yogurt", + "1 tbsp dijon mustard", + "¼ cup chopped parsley for garnish (optional)" + ], + "instructions_list": [ + "For the Slow Cooker", + "Wash and cut all of your vegetables. Cut your onion into a small dice, the carrots into a large dice (about 1 inch pieces), and your mushrooms into a large dice as well.", + "Into the vessel of your slow cooker add the beef broth, Worcestershire sauce, onions, salt, pepper, garlic powder, and paprika. Stir to mix in the seasonings.", + "For the beef I used top round (London Broil). This is a cheap, lean piece of meat. Top sirloin is a more tender piece of beef of similar leanness but it is more expensive. Feel free to use either.", + "Lay the beef into the vessel and place it into the slow cooker. Cook on high for 4 hours or low for 6 hours.", + "When there are 30 minutes left of cook time, add in the mushrooms and carrots and stir to cover with the liquid.", + "For the Pasta", + "After you add in the vegetables you can start on your pasta. Bring a large pot of water to a boil and add the pasta of your choosing. I used fusilli.", + "Strain and set aside when finished cooking.", + "For the Sauce", + "After the slow cooker timer is finished, remove the lid and pull out the beef. Set it aside to break down.", + "Mix together 3 tbsp of tapioca starch (or cornstarch) with ¼ cup of cold water to make a slurry.", + "Drizzle the slurry into the slow cooker and stir constantly to thicken the sauce.", + "Next add in the cream cheese, Greek yogurt, and dijon mustard. Stir to melt the cheese and combine.", + "Break the beef down into bite sized pieces or shred it up. Add it to the sauce and mix.", + "Dump in your pasta and mix until all of the sauce is evenly distributed. Taste test and adjust with salt and pepper to meet your needs.", + "Plating", + "This recipe makes 5 servings. Divide the contents of the slow cooker evenly between your containers. Top with chopped parsley for garnish if you please." + ], + "category": "Main Dish", + "yields": "5 servings", + "description": "This Big Boy Beef Stroganoff is perfect for bulking season containing over 1000 calories and 80g of protein. It is made using a slow cooker to save you time and effort.", + "total_time": 260, + "cook_time": 240, + "prep_time": 20, + "cuisine": "meal prep", + "ratings": 5.0, + "ratings_count": 1, + "equipment": [ + "Slow cooker" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "1013 kcal", + "fatContent": "22 g", + "carbohydrateContent": "125 g", + "proteinContent": "80 g", + "fiberContent": "8.8 g" + }, + "image": "https://mealprepmanual.com/wp-content/uploads/2024/12/Big-Boy-Beef-Stroganoff-.jpg", + "keywords": [ + "beef", + "free", + "gluten free" + ] +} diff --git a/tests/test_data/mealprepmanual.com/mealprepmanual_1.testhtml b/tests/test_data/mealprepmanual.com/mealprepmanual_1.testhtml new file mode 100644 index 000000000..e43c874fb --- /dev/null +++ b/tests/test_data/mealprepmanual.com/mealprepmanual_1.testhtml @@ -0,0 +1,1413 @@ + + + + + + + + + + + + + + Slow Cooker Big Boy Beef Stroganoff - THE MEAL PREP MANUAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + + + + + + + +
    + + + +
    + + +
    + + +
    + + +
    +
    +
    +
    +
    +
    +
    +

    Slow Cooker Big Boy Beef Stroganoff

    +
    +
    +
    +
    +
    +
    +
    + Big Boy Beef Stroganoff
    +
    +
    +
    +
    +
    +
    +
    +

    Slow Cooker Big Boy Beef Stroganoff

    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + This Big Boy Beef Stroganoff is perfect for bulking season containing over 1000 calories and 80g of protein. It is made using a slow cooker to save you time and effort.
    +
    +
    +
    +
    +
    +
    +
    + PREP TIME
    +
    +
    +
    + 20 Minutes
    +
    +
    +
    +
    +
    +
    +
    + COOK TIME
    +
    +
    +
    + 4 Hours
    +
    +
    +
    +
    +
    +
    +
    +

    Per Serving – Makes

    +
    +
    +
    + 1013 Calories
    +
    +
    +
    +

    125g C | 80g P | 22g F

    +
    +
    +
    +
    +
    +
    +
    +

    How to Meal Prep Slow Cooker Big Boy Beef Stroganoff

    +
    +
    +
    +

    A link to register for the MPM Club, a subscription service for a library of meal prep recipes

    +
    +
    +
    +

    A link to register for the MPM Club, a subscription service for a library of meal prep recipes

    +
    +
    +
    +
    +
    Big Boy Beef Stroganoff
    +
    +
    +

    Slow Cooker Big Boy Beef Stroganoff

    +
    +
    5 from 1 vote
    + + +
    +
    +
    Course: Main Dish
    Cuisine: meal prep
    Keyword: beef, free, gluten free
    +
    Prep Time: 20 minutes
    Cook Time: 4 hours
    Total Time: 4 hours 20 minutes
    +
    Servings: 5 servings
    + +
    Calories: 1013kcal
    + + +
    +
    This Big Boy Beef Stroganoff is perfect for bulking season containing over 1000 calories and 80g of protein. It is made using a slow cooker to save you time and effort.
    +
    + + +Print Recipe + Pin Recipe + Share on Facebook + + + + +
    + +
    +
    +

    Equipment

    + + +

    Ingredients

    • lbs (1135 g) top round roast
    • ½ cup (150 g) cream cheese
    • 2 cups (600 g) beef broth
    • 1 tbsp (15 g) Worcestershire sauce
    • 2 tsp (6 g) garlic powder
    • 2 tsp (6 g) paprika
    • 1 tsp (6 g) salt
    • 1 tsp (3 g) pepper
    • 1 medium (200 g) onion
    • 1 lb (454 g) carrots
    • ½ lb (227 g) mushrooms
    • lbs (681 g) pasta I used fusilli
    • 3 tbsp (24 g) starch tapioca or cornstarch
    • ¼ cup (60 g) water
    • ½ cup (150 g) plain greek yogurt
    • 1 tbsp (15 g) dijon mustard
    • ¼ cup chopped parsley for garnish optional
    +
    +
    +

    Instructions

    For the Slow Cooker

    • Wash and cut all of your vegetables. Cut your onion into a small dice, the carrots into a large dice (about 1 inch pieces), and your mushrooms into a large dice as well.
    • Into the vessel of your slow cooker add the beef broth, Worcestershire sauce, onions, salt, pepper, garlic powder, and paprika. Stir to mix in the seasonings.
    • For the beef I used top round (London Broil). This is a cheap, lean piece of meat. Top sirloin is a more tender piece of beef of similar leanness but it is more expensive. Feel free to use either.
    • Lay the beef into the vessel and place it into the slow cooker. Cook on high for 4 hours or low for 6 hours.
    • When there are 30 minutes left of cook time, add in the mushrooms and carrots and stir to cover with the liquid.

    For the Pasta

    • After you add in the vegetables you can start on your pasta. Bring a large pot of water to a boil and add the pasta of your choosing. I used fusilli.
    • Strain and set aside when finished cooking.

    For the Sauce

    • After the slow cooker timer is finished, remove the lid and pull out the beef. Set it aside to break down.
    • Mix together 3 tbsp of tapioca starch (or cornstarch) with ¼ cup of cold water to make a slurry.
    • Drizzle the slurry into the slow cooker and stir constantly to thicken the sauce.
    • Next add in the cream cheese, Greek yogurt, and dijon mustard. Stir to melt the cheese and combine.
    • Break the beef down into bite sized pieces or shred it up. Add it to the sauce and mix.
    • Dump in your pasta and mix until all of the sauce is evenly distributed. Taste test and adjust with salt and pepper to meet your needs.

    Plating

    • This recipe makes 5 servings. Divide the contents of the slow cooker evenly between your containers. Top with chopped parsley for garnish if you please.
    +
    +
    + + +
    + +

    Nutrition

    Calories: 1013kcal | Carbohydrates: 125g | Protein: 80g | Fat: 22g | Fiber: 8.8g
    + + +
    + + + +

    + + + +

    NUTRITIONAL INFO FOR THE Slow Cooker Big Boy Beef Stroganoff

    + + + +

    The information in this table represents the estimate for the total nutrition of the recipe as it is written. If you wanted to split the recipe into more or less servings than what is originally listed you can use this table to determine the nutritional estimates.  If you update the number of servings in the “Servings” field of the recipe above, the information in these tables are no longer accurate as you have updated the ingredients.

    + + +
    +
    +
    Servings
    +
    + +
    +
    +
    +
    Carbs
    +
    625.8g
    +
    +
    +
    Protein
    +
    398.4g
    +
    +
    +
    Fat
    +
    107.8g
    +
    +
    +
    Calories
    +
    5067 cals
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +

    Other recipes you might like

    +
    + +
    +
    + +
    + + + +

    + This Post Has One Comment +

    + +
      + +
    1. + +
      + + +
      +
      + Chris + + +
      + +
      + +
      + +
      +

      5 stars
      +Nice

      +
      +
      +
      + +
      + +
    2. +
    + + + + +
    +
    +
    + 5 from 1 vote
    +
    +
    +

    Leave a Reply

    + +
    + Recipe Rating +




    +
    +
    +
    + +
    + +

    + +

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

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    Membership:

    +
    +
    +
    +
    +
    +

    Status: Not logged in 

    +
    +
    +
    +
    +
    +

    Renewal:

    +
    +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/mealprepmanual.com/mealprepmanual_2.json b/tests/test_data/mealprepmanual.com/mealprepmanual_2.json new file mode 100644 index 000000000..acad18d21 --- /dev/null +++ b/tests/test_data/mealprepmanual.com/mealprepmanual_2.json @@ -0,0 +1,101 @@ +{ + "author": "Josh Cortis", + "canonical_url": "https://mealprepmanual.com/sriracha-lime-chicken-bowls/", + "site_name": "The Meal Prep Manual", + "host": "mealprepmanual.com", + "language": "en-US", + "title": "Sriracha Lime Chicken Bowls", + "ingredients": [ + "2 lbs boneless skinless chicken thighs", + "1 lb broccoli (I use frozen)", + "1 large japanese sweet potato (any kind is fine)", + "5 stalks green onions", + "2 cups cooked rice", + "2 tbsp oil", + "3 tbsp sriracha", + "3 tbsp lime juice", + "2½ tbsp honey", + "2 tsp onion powder", + "2 tsp garlic powder", + "1 tsp salt", + "1 tsp pepper" + ], + "ingredient_groups": [ + { + "ingredients": [ + "2 lbs boneless skinless chicken thighs", + "1 lb broccoli (I use frozen)", + "1 large japanese sweet potato (any kind is fine)", + "5 stalks green onions", + "2 cups cooked rice", + "2 tbsp oil" + ], + "purpose": "For the Bowls" + }, + { + "ingredients": [ + "3 tbsp sriracha", + "3 tbsp lime juice", + "2½ tbsp honey", + "2 tsp onion powder", + "2 tsp garlic powder", + "1 tsp salt", + "1 tsp pepper" + ], + "purpose": "For the Sauce" + } + ], + "instructions_list": [ + "For the Rice", + "Cook enough rice to yield 2 cups (300g) of cooked rice. 1 cup of dry rice will make between 2-3 cups of rice depending on what kind you use.", + "For the Sauce", + "Mix the lime juice, sriracha, honey, onion powder, garlic powder, salt, and pepper together. Whisk to combine.", + "For the Chicken", + "Preheat your oven to 400 °F (204 °C).", + "Place the chicken thighs into a large bowl. Cut off any excess fat or skin from the thighs.", + "Pour roughly ½ of the sauce over the top of the chicken and mix it with the chicken until it is completely coated. Allowing it to marinate for 30 minutes to a couple of hours is best but if you want to just cook it immediately, that will do.", + "Line a sheet pan with foil and lay the chicken thighs smooth side down on the sheet pan, ensuring enough space between each thigh to promote proper browning.", + "Cook the chicken for 20-25 minutes then remove from oven and flip. Return to the oven for an additional 5-10 minutes.", + "Once finished, remove from the oven and allow it to rest before cutting.", + "For the Vegetables", + "While the chicken is cooking, wash and cut all of your vegetables.", + "Cut the green onion whites and greens into thin slices, separating them for their use later.", + "Cut the sweet potato into a medium to large dice, about ½ inch in size.", + "Add the potatoes to a large bowl and drizzle in 1 tbsp of oil and salt and pepper to your liking. Toss to coat.", + "Spread the potatoes out on an oiled sheet tray and place into the oven for 20-25 minutes, flipping around the 15 minute mark. I would recommend you place this tray above your chicken so the chicken isn't subjected to the steam from the potatoes.", + "While the potatoes are cooking, thaw out the broccoli in the microwave. Don't cook it or heat it, just thaw it to take out the chill and drain away any water that is released.", + "Place the thawed broccoli into a large bowl and add the scallion whites with 1 tbsp of oil and a bit of salt and pepper. Toss to coat.", + "Heat a large skillet over medium high heat and add in the broccoli and scallions. Cook for 3-5 minutes to develop some color on the broccoli but be careful to not overcook it as it will lose its texture and become mushy.", + "Construction", + "After the chicken has rested for a bit, cut it into a medium to large dice to match the size of the potatoes.", + "Add the chicken and potatoes to the skillet with the broccoli along with the remaining sauce. Stir to combine.", + "Add in 2 cups of cooked rice and mix again. Taste test and adjust with salt and pepper as needed.", + "Plating", + "This recipe makes 5 servings. Divide the contents of the skillet 5 ways. Garnish with green onion tops and a lime wedge if you wish." + ], + "category": "Main Dish", + "yields": "5 servings", + "description": "These Sriracha Lime Chicken Bowls have less than 500 calories and 41g of protein making them great for if you want to maintain a calorie deficit. They are made up of chicken, sweet potatoes, rice, and broccoli.", + "total_time": 60, + "cook_time": 40, + "prep_time": 20, + "cuisine": "Asian,meal prep", + "ratings": 5.0, + "ratings_count": 3, + "nutrients": { + "servingSize": "1 serving", + "calories": "498 kcal", + "fatContent": "14 g", + "carbohydrateContent": "52 g", + "proteinContent": "41 g", + "fiberContent": "5.7 g" + }, + "image": "https://mealprepmanual.com/wp-content/uploads/2024/09/Sriracha-Lime-Chicken-Bowls.jpg", + "keywords": [ + "chicken", + "free", + "gluten free", + "meal prep", + "under 500 calories" + ] +} diff --git a/tests/test_data/mealprepmanual.com/mealprepmanual_2.testhtml b/tests/test_data/mealprepmanual.com/mealprepmanual_2.testhtml new file mode 100644 index 000000000..92f1934e3 --- /dev/null +++ b/tests/test_data/mealprepmanual.com/mealprepmanual_2.testhtml @@ -0,0 +1,1481 @@ + + + + + + + + + + + + + + Sriracha Lime Chicken Bowls - THE MEAL PREP MANUAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    + + + + + + + +
    + + + +
    + + +
    + + +
    + + +
    +
    +
    +
    +
    +
    +
    +

    Sriracha Lime Chicken Bowls

    +
    +
    +
    +
    +
    +
    +
    + Sriracha Lime Chicken Bowls in a black meal prep container.
    +
    +
    +
    +
    +
    +
    +
    +

    Sriracha Lime Chicken Bowls

    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + These Sriracha Lime Chicken Bowls have less than 500 calories and 41g of protein making them great for if you want to maintain a calorie deficit. They are made up of chicken, sweet potatoes, rice, and broccoli.
    +
    +
    +
    +
    +
    +
    +
    + PREP TIME
    +
    +
    +
    + 20 Minutes
    +
    +
    +
    +
    +
    +
    +
    + COOK TIME
    +
    +
    +
    + 40 Minutes
    +
    +
    +
    +
    +
    +
    +
    +

    Per Serving – Makes 5

    +
    +
    +
    + 498 Calories
    +
    +
    +
    +

    52g C | 41g P | 14g F

    +
    +
    +
    +
    +
    +
    +
    +

    How to Meal Prep Sriracha Lime Chicken Bowls

    +
    +
    +
    +

    A link to register for the MPM Club, a subscription service for a library of meal prep recipes

    +
    +
    +
    +

    A link to register for the MPM Club, a subscription service for a library of meal prep recipes

    +
    +
    +
    +
    +
    Sriracha Lime Chicken Bowls in a black meal prep container.
    +
    +
    +

    Sriracha Lime Chicken Bowls

    +
    +
    5 from 3 votes
    + + +
    +
    +
    Course: Main Dish
    Cuisine: Asian, meal prep
    Keyword: chicken, free, gluten free, meal prep, under 500 calories
    +
    Prep Time: 20 minutes
    Cook Time: 40 minutes
    Total Time: 1 hour
    +
    Servings: 5 servings
    + +
    Calories: 498kcal
    + + +
    +
    These Sriracha Lime Chicken Bowls have less than 500 calories and 41g of protein making them great for if you want to maintain a calorie deficit. They are made up of chicken, sweet potatoes, rice, and broccoli.
    +
    + + +Print Recipe + Pin Recipe + Share on Facebook + + + + +
    + +
    +
    + + + +

    Ingredients

    For the Bowls

    For the Sauce

    +
    +
    +

    Instructions

    For the Rice

    • Cook enough rice to yield 2 cups (300g) of cooked rice. 1 cup of dry rice will make between 2-3 cups of rice depending on what kind you use.

    For the Sauce

    • Mix the lime juice, sriracha, honey, onion powder, garlic powder, salt, and pepper together. Whisk to combine.

    For the Chicken

    • Preheat your oven to 400 °F (204 °C).
    • Place the chicken thighs into a large bowl. Cut off any excess fat or skin from the thighs.
    • Pour roughly ½ of the sauce over the top of the chicken and mix it with the chicken until it is completely coated. Allowing it to marinate for 30 minutes to a couple of hours is best but if you want to just cook it immediately, that will do.
    • Line a sheet pan with foil and lay the chicken thighs smooth side down on the sheet pan, ensuring enough space between each thigh to promote proper browning.
    • Cook the chicken for 20-25 minutes then remove from oven and flip. Return to the oven for an additional 5-10 minutes.
    • Once finished, remove from the oven and allow it to rest before cutting.

    For the Vegetables

    • While the chicken is cooking, wash and cut all of your vegetables.
    • Cut the green onion whites and greens into thin slices, separating them for their use later.
    • Cut the sweet potato into a medium to large dice, about ½ inch in size.
    • Add the potatoes to a large bowl and drizzle in 1 tbsp of oil and salt and pepper to your liking. Toss to coat.
    • Spread the potatoes out on an oiled sheet tray and place into the oven for 20-25 minutes, flipping around the 15 minute mark. I would recommend you place this tray above your chicken so the chicken isn't subjected to the steam from the potatoes.
    • While the potatoes are cooking, thaw out the broccoli in the microwave. Don't cook it or heat it, just thaw it to take out the chill and drain away any water that is released.
    • Place the thawed broccoli into a large bowl and add the scallion whites with 1 tbsp of oil and a bit of salt and pepper. Toss to coat.
    • Heat a large skillet over medium high heat and add in the broccoli and scallions. Cook for 3-5 minutes to develop some color on the broccoli but be careful to not overcook it as it will lose its texture and become mushy.

    Construction

    • After the chicken has rested for a bit, cut it into a medium to large dice to match the size of the potatoes.
    • Add the chicken and potatoes to the skillet with the broccoli along with the remaining sauce. Stir to combine.
    • Add in 2 cups of cooked rice and mix again. Taste test and adjust with salt and pepper as needed.

    Plating

    • This recipe makes 5 servings. Divide the contents of the skillet 5 ways. Garnish with green onion tops and a lime wedge if you wish.
    +
    +
    + + +
    + +

    Nutrition

    Calories: 498kcal | Carbohydrates: 52g | Protein: 41g | Fat: 14g | Fiber: 5.7g
    + + +
    + + + +

    + + + +

    NUTRITIONAL INFO FOR THE Sriracha Lime Chicken Bowls

    + + + +

    The information in this table represents the estimate for the total nutrition of the recipe as it is written. If you wanted to split the recipe into more or less servings than what is originally listed you can use this table to determine the nutritional estimates.  If you update the number of servings in the “Servings” field of the recipe above, the information in these tables are no longer accurate as you have updated the ingredients.

    + + +
    +
    +
    Servings
    +
    + +
    +
    +
    +
    Carbs
    +
    259.1g
    +
    +
    +
    Protein
    +
    204.9g
    +
    +
    +
    Fat
    +
    70.3g
    +
    +
    +
    Calories
    +
    2488.7 cals
    +
    +
    + + + +

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

    Other recipes you might like

    +
    + +
    +
    + +
    + + + +

    + This Post Has 3 Comments +

    + +
      + +
    1. + +
      + + +
      +
      + Bob + + +
      + +
      + +
      + +
      +

      5 stars
      +Very good, this guy is amazing. Even my mom loves him…. 👍

      +
      +
      +
      + +
      + +
    2. + +
    3. + +
      + + +
      +
      + Maria Lerma + + +
      + +
      + +
      + +
      +

      5 stars
      +dang Josh you really cooked w this one!! this recipe slaps

      +
      +
      +
      + +
      + +
    4. + +
    5. + +
      + + +
      +
      + Adam + + +
      + +
      + +
      + +
      +

      5 stars
      +This was a solid recipe. Can see myself making this one again for future mealprep.

      +
      +
      +
      + +
      + +
    6. +
    + + + + +
    +
    +
    + 5 from 3 votes
    +
    +
    +

    Leave a Reply

    + +
    + Recipe Rating +




    +
    +
    +
    + +
    + +

    + +

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

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    Membership:

    +
    +
    +
    +
    +
    +

    Status: Not logged in 

    +
    +
    +
    +
    +
    +

    Renewal:

    +
    +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_data/meganvskitchen.com/meganvskitchen_1.json b/tests/test_data/meganvskitchen.com/meganvskitchen_1.json new file mode 100644 index 000000000..529f9a43b --- /dev/null +++ b/tests/test_data/meganvskitchen.com/meganvskitchen_1.json @@ -0,0 +1,48 @@ +{ + "author": "Megan", + "canonical_url": "https://meganvskitchen.com/crispy-ground-beef-tacos/", + "site_name": "Megan vs Kitchen", + "host": "meganvskitchen.com", + "language": "en-US", + "title": "Crispy Beef Tacos", + "ingredients": [ + "1 pound ground beef (lean, 90%)", + "1 packet of taco seasoning", + "¾ cup enchilada sauce", + "2.5 cups Oaxaca cheese (or Mexican cheese or Monterey Jack )", + "10 corn tortillas", + "1 tbs olive oil", + "Toppings: (hot sauce, guacamole, salsa, pickled onions, sour cream, lime wedge)" + ], + "instructions_list": [ + "Preheat oven to 450F.", + "Brown beef in a skillet over medium-high high heat. Mix in taco seasoning and enchilada sauce. Bring to a simmer, then remove pan from the heat.", + "Wrap corn tortillas in a damp paper towel and microwave for 30-60 seconds or until they are pliable.", + "Brush one side of a tortilla with olive oil. Flip it so the oiled side is on the pan. Add 2 tablespoons of shredded cheese to half of the tortilla, top with 1/4 cup of ground beef, and 2 more tablespoons of shredded cheese. Fold the tortilla over the filling*.", + "Repeat with the remaining tortillas and range the tacos in a single layer on your baking sheet.", + "Bake for 16 minutes, or until the tortillas are crispy and the cheese has melted. Let them cool for 3 minutes before serving." + ], + "category": "Main Course", + "yields": "10 servings", + "description": "These Crispy Ground Beef Tacos are an easy weeknight win. They only take 35 minutes to make, and everyone will love dipping them in salsa, queso, and guacamole!", + "total_time": 35, + "cook_time": 35, + "cuisine": "Mexican", + "ratings": 4.67, + "ratings_count": 9, + "nutrients": { + "servingSize": "2 taco", + "calories": "524 kcal", + "fatContent": "30 g", + "saturatedFatContent": "16 g", + "transFatContent": "0.6 g", + "carbohydrateContent": "28 g", + "sugarContent": "4 g", + "proteinContent": "36 g", + "fiberContent": "4 g" + }, + "image": "https://meganvskitchen.com/wp-content/uploads/2023/07/Crispy-Beef-Tacos-Sheet-Pan.jpg", + "keywords": [ + "Crispy Beef Tacos" + ] +} diff --git a/tests/test_data/meganvskitchen.com/meganvskitchen_1.testhtml b/tests/test_data/meganvskitchen.com/meganvskitchen_1.testhtml new file mode 100644 index 000000000..247d5dc9a --- /dev/null +++ b/tests/test_data/meganvskitchen.com/meganvskitchen_1.testhtml @@ -0,0 +1,973 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Crispy Ground Beef Tacos (Baked) - Megan vs Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/meganvskitchen.com/meganvskitchen_2.json b/tests/test_data/meganvskitchen.com/meganvskitchen_2.json new file mode 100644 index 000000000..612a467aa --- /dev/null +++ b/tests/test_data/meganvskitchen.com/meganvskitchen_2.json @@ -0,0 +1,77 @@ +{ + "author": "Megan", + "canonical_url": "https://meganvskitchen.com/cheesy-bean-and-rice-burrito/", + "site_name": "Megan vs Kitchen", + "host": "meganvskitchen.com", + "language": "en-US", + "title": "Cheesy Bean and Rice Burrito", + "ingredients": [ + "¼ cup sour cream", + "¼ cup mayonnaise", + "2 tablespoons pickled jalapenos diced (optional)", + "2 tablespoons pickled jalapeno juice (optional)", + "1 teaspoon paprika", + "1 teaspoon cumin", + "½ teaspoon garlic powder", + "½ teaspoon onion powder", + "½ teaspoon chipotle chili powder or regular chili powder", + "8 9-inch flour tortillas", + "1 16-oz can of refried beans", + "2 2/3 cups Spanish rice (I used a box of New East’s Spanish rice which makes about 3 cups)", + "2 cups Mexican cheese blend" + ], + "ingredient_groups": [ + { + "ingredients": [ + "¼ cup sour cream", + "¼ cup mayonnaise", + "2 tablespoons pickled jalapenos diced (optional)", + "2 tablespoons pickled jalapeno juice (optional)", + "1 teaspoon paprika", + "1 teaspoon cumin", + "½ teaspoon garlic powder", + "½ teaspoon onion powder", + "½ teaspoon chipotle chili powder or regular chili powder" + ], + "purpose": "Creamy Jalapeno Sauce" + }, + { + "ingredients": [ + "8 9-inch flour tortillas", + "1 16-oz can of refried beans", + "2 2/3 cups Spanish rice (I used a box of New East’s Spanish rice which makes about 3 cups)", + "2 cups Mexican cheese blend" + ], + "purpose": "Cheesy Bean and Rice Burrito" + } + ], + "instructions_list": [ + "In a small bowl, mix together the creamy jalapeno sauce ingredients.", + "Lay a tortilla flat, spread 1/4 cup of refried beans, 1/3 cup of Spanish rice, 1/4 cup of Mexican cheese, and 1/2 tablespoon* of jalapeno sauce down the middle. Roll into a burrito.", + "Fold the burrito.", + "Place a skillet over medium heat. Add burrito seam side down. Toast on both sides till brown." + ], + "category": "Dinner", + "yields": "8 servings", + "description": "Inspired by Taco Bell, this copycat Cheesy Bean and Rice Burrito is easy to make, cheap, and so much better than the original.", + "total_time": 35, + "cook_time": 15, + "prep_time": 20, + "cuisine": "American", + "ratings": 4.79, + "ratings_count": 37, + "nutrients": { + "servingSize": "1 Burrito", + "calories": "385 kcal", + "fatContent": "15.1 g", + "saturatedFatContent": "6.9 g", + "carbohydrateContent": "51 g", + "sugarContent": "2.1 g", + "proteinContent": "13.4 g", + "fiberContent": "3.2 g" + }, + "image": "https://meganvskitchen.com/wp-content/uploads/2022/11/IMG_5024-scaled.jpg", + "keywords": [ + "cheesy bean and rice burrito" + ] +} diff --git a/tests/test_data/meganvskitchen.com/meganvskitchen_2.testhtml b/tests/test_data/meganvskitchen.com/meganvskitchen_2.testhtml new file mode 100644 index 000000000..73a7aa718 --- /dev/null +++ b/tests/test_data/meganvskitchen.com/meganvskitchen_2.testhtml @@ -0,0 +1,957 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cheesy Bean and Rice Burrito - Megan vs Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/minimalistbaker.com/minimalistbaker.json b/tests/test_data/minimalistbaker.com/minimalistbaker.json index aaab65d1c..6f166aea7 100644 --- a/tests/test_data/minimalistbaker.com/minimalistbaker.json +++ b/tests/test_data/minimalistbaker.com/minimalistbaker.json @@ -10,7 +10,7 @@ "1 Tbsp lemon juice", "1 Tbsp nutritional yeast, plus more to taste", "1/2 tsp garlic powder", - "1/4-1/2 tsp sea salt ((plus more to taste))", + "1/4-1/2 tsp sea salt (plus more to taste)", "4-6 Tbsp water", "1/4 cup fresh chopped parsley or cilantro" ], diff --git a/tests/test_data/modernhoney.com/modernhoney_1.json b/tests/test_data/modernhoney.com/modernhoney_1.json index 0b51e7978..57e155211 100644 --- a/tests/test_data/modernhoney.com/modernhoney_1.json +++ b/tests/test_data/modernhoney.com/modernhoney_1.json @@ -6,14 +6,14 @@ "language": "en-US", "title": "Honey Garlic Chicken", "ingredients": [ - "1 to 1 1/4 1b. Chicken Breast ((about 4 thinly sliced chicken breasts or 2 large sliced in half))", - "Salt and Pepper ((sprinkle on both sides of chicken)11/)", + "1 to 1 1/4 1b. Chicken Breast (about 4 thinly sliced chicken breasts or 2 large sliced in half)", + "Salt and Pepper (sprinkle on both sides of chicken)11/)", "1/4 cup Flour*", "4 Tablespoons Salted Butter", - "3 Garlic Cloves ((minced))", + "3 Garlic Cloves (minced)", "1 Tablespoon Apple Cider Vinegar", "1 Tablespoon Soy Sauce", - "1/3 cup Honey ((plus more for drizzling, if desired))" + "1/3 cup Honey (plus more for drizzling, if desired)" ], "instructions_list": [ "Generously sprinkle thinly sliced chicken breast with salt and pepper on both sides. Heat a large skillet over medium-high heat. Add 2 Tablespoons of butter to the skillet and let melt.", diff --git a/tests/test_data/natashaskitchen.com/natashaskitchen_1.json b/tests/test_data/natashaskitchen.com/natashaskitchen_1.json new file mode 100644 index 000000000..4db5e712e --- /dev/null +++ b/tests/test_data/natashaskitchen.com/natashaskitchen_1.json @@ -0,0 +1,50 @@ +{ + "author": "Natalya Drozhzhin", + "canonical_url": "https://natashaskitchen.com/sugar-cookies-recipe/", + "site_name": "NatashasKitchen.com", + "host": "natashaskitchen.com", + "language": "en-US", + "title": "Christmas Sugar Cookies Recipe", + "ingredients": [ + "1 cup unsalted butter (softened at room temperature)", + "1 cup granulated sugar", + "1 egg (large)", + "1 tsp vanilla extract", + "3 cups all-purpose flour (measured correctly)", + "1 Tbsp baking powder", + "1/4 tsp salt" + ], + "instructions_list": [ + "Preheat oven to 350 °F with a rack in the center. Whisk together flour with baking powder and salt in a small bowl and set aside.", + "Using a stand-up or handheld mixer, beat the butter together with sugar. To the mixture add vanilla extract and egg and beat to combine.", + "To the butter mixture, add flour in 3 parts until fully incorporated.", + "Divide the dough into two equal parts. On a lightly floured surface, roll into ¼-inch thickness. Use a cookie cutter to cut out your favorite shapes.", + "Bake cookies on a parchment or silicone-lined baking sheet at 350˚F for 10 minutes, or until the edges are just beginning to turn golden.", + "Let the cookies cool for about 5 minutes on the baking sheet before moving them to a wire rack to cool completely and decorating with cookie icing." + ], + "category": "Cookies,Dessert", + "yields": "40 servings", + "description": "Everyone needs an Easy Sugar Cookies Recipe! These are literally melt-in-your-mouth delicious. I am positive these Christmas cookies will win you over.", + "total_time": 30, + "cook_time": 10, + "prep_time": 20, + "cuisine": "American", + "ratings": 4.99, + "ratings_count": 575, + "nutrients": { + "servingSize": "1 serving", + "calories": "96 kcal", + "fatContent": "5 g", + "saturatedFatContent": "3 g", + "carbohydrateContent": "12 g", + "sugarContent": "5 g", + "proteinContent": "1 g", + "sodiumContent": "17 mg", + "fiberContent": "1 g", + "cholesterolContent": "16 mg" + }, + "image": "https://natashaskitchen.com/wp-content/uploads/2019/12/Sugar-Cookies-8.jpg", + "keywords": [ + "sugar cookies" + ] +} diff --git a/tests/test_data/natashaskitchen.com/natashaskitchen_1.testhtml b/tests/test_data/natashaskitchen.com/natashaskitchen_1.testhtml new file mode 100644 index 000000000..5645587dd --- /dev/null +++ b/tests/test_data/natashaskitchen.com/natashaskitchen_1.testhtml @@ -0,0 +1,1563 @@ + + + + + + + + + + + + + + + + + + + + + Christmas Sugar Cookies - NatashasKitchen.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + +
    +
    Home > Dessert > Cookies > Christmas Sugar Cookies
    +
    +
    +

    Christmas Sugar Cookies

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

    Everyone needs an Easy Sugar Cookie Recipe! These are buttery and literally melt-in-your-mouth delicious and my go-to sugar cookie dough. You can bake them soft or crisp. These Christmas Sugar cookies have been part of my holiday cookie-decorating tradition for years!

    + + + +
    Sugar cookies recipe decorated on a platter for Christmas

    This post may contain affiliate links. Read my disclosure policy.

    + + + +

    I love festive holiday treats like melt-in-your-mouth Snowball Cookies, soft Chocolate Chip Cookies, and of course Baklava. These beautifully decorated sugar cookies are a beautiful addition to the Christmas cookie platter.

    + + + + + + + +

    I love simple dishes that use minimal ingredients. During the holidays, I love baking, but I don’t love the cleanup afterwards. This recipe for Christmas sugar cookies gives me the best of both worlds — perfect cookies and an easy clean-up. You also don’t have to chill the dough so you can cut and bake the cookies right away, saving you time. I’m so excited to share this recipe with you! 

    + + + +

    One of my favorite Christmas traditions is cookie decorating, and my family has been doing this since the kids were tiny. The kids love the creative freedom to do what they want with their cookies, and of course, they are even more excited to eat them!

    + + + +
    + + + +

    Whether you are planning a cookie-making party for your Christmas party or for the holiday cookie platter, you need a sugar cookie recipe that you can rely on. These cookies taste amazing, keep their shape, and are perfect for eating plain or decorating them with sugar cookie icing and sprinkles. Let’s get started! 

    + + + +
    Christmas Sugar cookies decorated with frosting and festive holiday sprinkles
    + + + +

    Tips For The Best Christmas Sugar Cookies

    + + + +

    Sugar cookies may seem simple, but there are a lot of bad recipes out there! After much trial and error, I feel confident that I have mastered the art of the sugar cookie. Here are all the best tips and tricks I have gathered throughout the years to get the best flavor and texture: 

    + + + +

    Tip #1: Soften your butter

    + + + +

    Butter should be softened at room temperature. If the butter is too soft or partially melted, you will end up with a sticky dough that is difficult to roll out.

    + + + +

    Tip #2: Rolling Out Sugar Cookies Dough

    + + + +

    Roll your dough out directly on a silicone baking mat or piece of parchment paper so you do not have to transfer your delicate shapes onto a baking sheet later. You can cut your shapes out right atop the mat and make your life a bit easier.

    + + + +

    Tip #3: How Thick Should Sugar Cookies be Rolled Out?

    + + + +

    Roll your dough out to about ¼-inch thick. This is the sweet spot. You’ll have cookies thick enough to keep their shape, while also thin enough to promote even baking. 

    + + + +
    Sugar cookies rolled to 1/4-inch thickness
    + + + +

    Tip #4: Avoid Crumbly Dough

    + + + +

    Crumbly dough makes for misshapen cookies that are prone to uneven baking. To prevent this, don’t overmix your dough. You want the dough to be as smooth as possible. However, if you do get a crumbly texture, add ½ tbsp of water, or milk to the batter and incorporate it until it remoistens the dough.

    + + + +

    Tip #5: Avoid Overbaking

    + + + +

    10 minutes might seem like a very short baking time for cookies. But, trust me, do not overbake them! At around 10 minutes, the edges of the cookies should just start to turn golden brown. This is the time to pull them! If you continue baking, you risk compromising that signature tenderness of a perfect sugar cookie. 

    + + + +
    How to make perfectly baked Sugar Cookies without over-baking
    + + + +

    How to Make Cut-Out Sugar Cookies

    + + + +
      +
    • Combine your flour, baking powder and salt together in a small bowl and set the dry mixture aside. 
    • + + + +
    • Using a stand mixer or handheld mixer, cream together your butter, sugar and vanilla extract until smooth and creamy.
    • + + + +
    • Add the flour to the butter mixture in thirds, mixing until incorporated between additions.
    • + + + +
    • Divide the dough into two equal parts and dust your work surface with flour to keep the dough from sticking. You can also dust the top of the dough lightly. Use a rolling pin to roll out each piece to an even ¼-inch thickness. Lift the dough gently to ensure it’s not sticking to your counter before cutting out shapes.
    • + + + +
    • Use a cookie cutter to cut out your favorite shapes or freeze your dough for later use. Note that larger cookies will take slightly longer to bake. Transfer the cookies to a cookie sheet, keeping them 1 inch apart (they do expand a bit in the oven).
    • + + + +
    • Bake the cookies at 350˚F for 10 minutes or until the edges are just starting to turn golden. That’s your cue to pull them out. Let the cookies cool on the baking pan for 5 minutes so they are easier to move without cracking then transfer to wire racks and let the cookies cool completely before decorating.
    • +
    + + + +
    Step by step photos how to make sugar cookies by creaming together butter and sugar, adding flour, dividing dough and cutting shapes
    + + + +

    Storing Sugar Cookies

    + + + +

    The great part about this recipe is that it can be made a couple of days in advance and the cookies will still retain their freshness. Below, I will share how you should store them and also how you can freeze your dough or baked cookies for later munching! 

    + + + +
      +
    • Storing Cookies at Room Temperature: Store baked sugar cookies on the counter in an airtight container. They will keep for up to a week. Remember, if you have decorated your Christmas Sugar Cookies, let the frosting firm up, and then store them between layers of parchment paper to prevent sticking and/or destroying your designs. 
    • + + + +
    • To freeze baked sugar cookies: allow cookies to cool completely, then stack the cookies in an airtight container between layers of parchment paper. Freeze cookies for up to 2 months. When you are ready to eat them, thaw at room temperature. 
    • + + + +
    • To freeze your sugar cookie dough: roll it into a ball or a log. Wrap it tightly in plastic wrap and store it in an airtight container or freezer bag. The dough will keep for up to 2 months before you need to use it. When you are ready to bake, allow the dough to thaw in the refrigerator overnight. Then, bring it to room temperature for 1 hour before you shape your cookies and bake them. 
    • +
    + + + +
    Baked sugar cookies ready for baking
    + + + +

    How to Decorate Christmas Cookies

    + + + +

    To decorate sugar cookies, I love to use our 3-ingredient cookie icing from our Gingerbread Cookie Recipe, or you can make a royal icing, and add food coloring. To pipe the frosting, transfer to a squeeze bottle or little zip bags (handy and inexpensive for cookie decorating parties).

    + + + +

    If you prefer, you can purchase an icing decorating kit with pre-made frostings in a variety of colors, which makes it easy. Don’t forget the Christmas sprinkles and crushed candy canes.

    + + + +
    Decorated Christmas cookies with sprinkles and frosting
    + + + +

    Decorated Christmas cookies have a way of making the holidays more merry and bright, even if you aren’t the best at decorating. The perfectly imperfect ones are the most endearing anyway.

    + + + +
    + + + +

    Christmas Sugar Cookies make my heart so happy because they unlock sweet memories over the years, like the cookie decorating party in the photo above when my husband and I hosted the family Christmas Eve party.

    + + + +

    I’d love to hear about your special Christmas traditions around cookies in the comments below.

    + + + + + + + +

    These are our best-loved (and reviewed) Christmas cookies to fill up your holiday cookie tray. These are well-loved by all ages and you’re sure to find some new favorites in this list. Looking for more Christmas recipes and inspiration? Check out our Christmas archives here.

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

    Christmas Sugar Cookies Recipe 

    + +
    4.99 from 575 votes
    + +
    Author: Natalya Drozhzhin
    + +
    +
    +
    Sugar cookies recipe decorated on a Christmas cookie platter
    +
    +
    +
    Everyone needs an Easy Sugar Cookies Recipe! These are literally melt-in-your-mouth delicious. I am positive these Christmas cookies will win you over. 
    + + +
    +
    + +
    +
    Prep Time: 20 minutes
    Cook Time: 10 minutes
    Total Time: 30 minutes
    +
    + +

    Ingredients 

    Servings: 40 cookies
    + + + +

    Instructions

    • Preheat oven to 350 °F with a rack in the center. Whisk together flour with baking powder and salt in a small bowl and set aside. 
    • Using a stand-up or handheld mixer, beat the butter together with sugar. To the mixture add vanilla extract and egg and beat to combine.
    • To the butter mixture, add flour in 3 parts until fully incorporated. 
    • Divide the dough into two equal parts. On a lightly floured surface, roll into ¼-inch thickness. Use a cookie cutter to cut out your favorite shapes. 
    • Bake cookies on a parchment or silicone-lined baking sheet at 350˚F for 10 minutes, or until the edges are just beginning to turn golden.
    • Let the cookies cool for about 5 minutes on the baking sheet before moving them to a wire rack to cool completely and decorating with cookie icing
    + + + + + +

    Nutrition Per Serving

    96kcal Calories12g Carbs1g Protein5g Fat3g Saturated Fat16mg Cholesterol17mg Sodium43mg Potassium1g Fiber5g Sugar148IU Vitamin A16mg Calcium1mg Iron
    + +
    + +
    Nutrition Facts
    Christmas Sugar Cookies Recipe 
    Amount per Serving
    Calories
    96
    % Daily Value*
    Fat
     
    5
    g
    8
    %
    Saturated Fat
     
    3
    g
    19
    %
    Cholesterol
     
    16
    mg
    5
    %
    Sodium
     
    17
    mg
    1
    %
    Potassium
     
    43
    mg
    1
    %
    Carbohydrates
     
    12
    g
    4
    %
    Fiber
     
    1
    g
    4
    %
    Sugar
     
    5
    g
    6
    %
    Protein
     
    1
    g
    2
    %
    Vitamin A
     
    148
    IU
    3
    %
    Calcium
     
    16
    mg
    2
    %
    Iron
     
    1
    mg
    6
    %
    * Percent Daily Values are based on a 2000 calorie diet.
    + +
    +
    Course: Cookies, Dessert
    Cuisine: American
    Keyword: sugar cookies
    Skill Level: Easy
    Cost to Make: $
    +
    Calories: 96
    +
    +
    + Natasha's Kitchen Cookbook
    +
    + +
    +
    + +
    +
    +

    Natalya Drozhzhin

    + +
    +
    +
    +

    Natalya is a food blogger who founded Momsdish to make cooking easier. Growing up on a farm in Ukraine, Natalya was inspired by the amazing dishes that were prepared using simple ingredients. Natalya is most notably known for making cooking approachable for any person.

    + +

    Read more posts by Natalya

    + + +
    +
    +
    + + +
    + +
    + + + + + +
    + +
    +
    +
    +
    + 4.99 from 575 votes (497 ratings without comment) +
    +
    +
    +

    Leave a Comment

    + +
    + Recipe Rating +




    +
    +
    +

    +
    + +

    + +

    +
    + + + + +
    +

    Comments

    + +
    + +
      +
    • +
      + +
      +
      Crystal Gingras
      +
      December 15, 2024
      +
      +
      +

      mine were to crumbly when I was trying to roll them out

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      Jacqueline Heim
      +
      December 14, 2024
      +
      +
      +
      + +
      +

      My cookies tasted good but they spread out to much. Didn’t make out the shapes very well. What can I do?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 14, 2024
        +
        +
        +

        Hi Jacqueline! It could be that the cookie dough was too warm. You can chill it in the refrigerator for a bit if needed. Make sure you oven is fully preheated before you start baking them. I would also ensure you’re measuring all of your ingredients correctly. I have a tutorial on How to Measure Ingredientshere.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Ashmita
      +
      December 14, 2024
      +
      +
      +

      Is it fine to use salted butter instead of unsalted butter?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 14, 2024
        +
        +
        +

        Hi Ashmita! If you do, don’t add salt like the recipe states.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Barbara Norton
      +
      December 11, 2024
      +
      +
      +
      + +
      +

      Make this recipe every year for the last 40 years!! My family asks for them all the time

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      sara
      +
      December 8, 2024
      +
      +
      +

      is it really 1 Tbsp of baking powder? Or is it 1Tsp?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 8, 2024
        +
        +
        +

        Hi Sara! That’s correct, 1 tablespoon. I hope you love the recipe!

        +

        Reply

        +
        + +
        +
      • +
      • +
        + +
        +
        Glenda
        +
        December 14, 2024
        +
        +
        +

        What effect does the baking powder have on the end result? I see so many recipes that do not include baking powder.

        +

        Reply

        +
        + +
        +
          +
        • +
          + +
          +
          NatashasKitchen.com
          +
          December 14, 2024
          +
          +
          +

          Hi Glenda! The baking powder gives these a puffy, soft, cake-like texture.

          +

          Reply

          +
          + +
          +
            +
          • +
            + +
            +
            Jacqueline Randall
            +
            December 14, 2024
            +
            +
            +

            This recipe doesn’t require letting the dough sit in the fridge for an hour?

            +

            Reply

            +
            + +
            +
              +
            • +
              + +
              +
              Natashas Kitchen
              +
              December 14, 2024
              +
              +
              +

              Hi Jacqueline, that’s right it is not required, you can of course if that is your preference, but this recipe doesn’t need it. I hope that helps.

              +
              + +
              +
            • +
            +
          • +
          +
        • +
        +
      • +
      +
    • +
    • +
      + +
      +
      Sarah Dowling
      +
      December 7, 2024
      +
      +
      +
      + +
      +

      Made your recipe with vegan butter because of a dairy intolerance and they turned out perfect. I thought maybe they would spread but the edges were nice and crisp and the cookies tasted delicious.

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 7, 2024
        +
        +
        +

        Hi Sarah! Thank you for sharing that with us. Glad they turned out well for you.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Elizabeth
      +
      December 6, 2024
      +
      +
      +

      Can I use 1/4 of salted and 1/4 of unsalted butter and just omit the tsp of salt?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 6, 2024
        +
        +
        +

        Hi Elizabeth! That should be fine.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Ginger
      +
      November 29, 2024
      +
      +
      +

      I haven’t made sugar cookies in years and this year I thought it would be nice to share with my grandkids. This recipe is great! Dough is easy to work, doesn’t stick and is delicious!!

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      Zhenya
      +
      November 26, 2024
      +
      +
      +
      + +
      +

      Theses cookies are amazing. Simple the best and the easiest recipe i ever tried. And i tried so many and was never happy with the results. Thank you!

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      lilly
      +
      November 23, 2024
      +
      +
      +
      + +
      +

      this was such an easy bake and also delish

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        Pat Martin
        +
        December 8, 2024
        +
        +
        +

        Please get rid of the advertising. It takes too long to write the recipe down & it’s very frustrating

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    + + + +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +

    As Featured On

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

    Never Go "Hangry" Again!

    +

    Get weekly updates on new recipes, exclusive giveaways plus behind the scenes photos.

    +
    +

    +

    +
    + +
    +
    +
    +
    + + +
    + + + + diff --git a/tests/test_data/natashaskitchen.com/natashaskitchen_2.json b/tests/test_data/natashaskitchen.com/natashaskitchen_2.json new file mode 100644 index 000000000..f0514e5a5 --- /dev/null +++ b/tests/test_data/natashaskitchen.com/natashaskitchen_2.json @@ -0,0 +1,90 @@ +{ + "author": "Natasha Kravchuk", + "canonical_url": "https://natashaskitchen.com/cranberry-bread/", + "site_name": "NatashasKitchen.com", + "host": "natashaskitchen.com", + "language": "en-US", + "title": "Cranberry Bread with Orange Glaze", + "ingredients": [ + "1 1/2 cups all-purpose flour", + "1 tsp baking powder", + "1/4 tsp salt", + "1/4 cup milk (room temperature)", + "Zest of 1 large orange (divided)", + "1/4 cup orange juice (freshly squeezed)", + "6 Tbsp unsalted butter (softened)", + "3/4 cup granulated sugar", + "2 large eggs (room temperature)", + "1 1/2 cups fresh cranberries (rinsed and patted dry)", + "1/2 Tbsp all-purpose flour", + "1 cup powdered sugar", + "1 1/2 Tbsp freshly squeezed orange juice (or to reach desired consistency)", + "1 tsp orange zest (reserved from the orange above)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "1 1/2 cups all-purpose flour", + "1 tsp baking powder", + "1/4 tsp salt", + "1/4 cup milk (room temperature)", + "Zest of 1 large orange (divided)", + "1/4 cup orange juice (freshly squeezed)", + "6 Tbsp unsalted butter (softened)", + "3/4 cup granulated sugar", + "2 large eggs (room temperature)", + "1 1/2 cups fresh cranberries (rinsed and patted dry)", + "1/2 Tbsp all-purpose flour" + ], + "purpose": "Cranberry Bread Ingredients" + }, + { + "ingredients": [ + "1 cup powdered sugar", + "1 1/2 Tbsp freshly squeezed orange juice (or to reach desired consistency)", + "1 tsp orange zest (reserved from the orange above)" + ], + "purpose": "Orange Glaze Ingredients:" + } + ], + "instructions_list": [ + "How to Make Cranberry Orange Bread:", + "Prep: Preheat oven to 350˚F. Butter a 6 cup (8 1/2 by 4 1/2 bread loaf pan) then dust with flour, tapping out the excess flour.", + "In a medium mixing bowl, whisk together: flour, baking powder, and salt. Set aside.", + "In a measuring cup, combine together milk, zest of 1 orange (Reserve 1 tsp zest for the glaze), and orange juice. Set aside.", + "In a large mixing bowl, cream together butter and granulated sugar on medium/high speed (2-3 minutes on high speed). It won’t be smooth, just combined. Beat in 2 large eggs, mixing until well incorporated.", + "Add flour mixture in 2 parts, alternating with the milk mixture and mixing on medium/low speed just until incorporated with each addition. Scrape the sides of the bowl with a spatula as needed.", + "Toss cranberries with 1/2 Tbsp flour then fold them into the batter just until incorporated. Spread the batter into your prepared pan and bake for 45-50 min at 350˚F until golden on top and a toothpick inserted into the center comes out clean. Let cool in pan 10-15 minutes then run a cake release tool or knife around the edges and transfer the loaf to a wire rack to cool completely before glazing.", + "To Make the Glaze:", + "In a separate bowl, stir together powdered sugar, orange juice and reserved teaspoon of zest. Stir until smooth. It should have a drizzling consistency. Add more orange juice to thin it out or powdered sugar to make it thicker." + ], + "category": "Breakfast,Dessert", + "yields": "8 servings", + "description": "Orange Glazed Cranberry bread is loaded with juicy cranberries with a moist and tender crumb. This stays moist for a few days after it’s made so it’s perfect as a homemade Christmas gift.", + "total_time": 60, + "cook_time": 50, + "prep_time": 10, + "cuisine": "American", + "ratings": 4.99, + "ratings_count": 867, + "nutrients": { + "servingSize": "1 serving", + "calories": "326 kcal", + "fatContent": "10 g", + "saturatedFatContent": "6 g", + "unsaturatedFatContent": "4 g", + "transFatContent": "1 g", + "carbohydrateContent": "56 g", + "sugarContent": "36 g", + "proteinContent": "4 g", + "sodiumContent": "95 mg", + "fiberContent": "2 g", + "cholesterolContent": "64 mg" + }, + "image": "https://natashaskitchen.com/wp-content/uploads/2021/12/Cranberry-Bread-SQ.jpg", + "keywords": [ + "Cranberry Bread", + "Cranberry Orange Bread", + "Orange Cranberry Bread" + ] +} diff --git a/tests/test_data/natashaskitchen.com/natashaskitchen_2.testhtml b/tests/test_data/natashaskitchen.com/natashaskitchen_2.testhtml new file mode 100644 index 000000000..d4a11a782 --- /dev/null +++ b/tests/test_data/natashaskitchen.com/natashaskitchen_2.testhtml @@ -0,0 +1,1979 @@ + + + + + + + + + + + + + + + + + + + + + Cranberry Bread with Orange Glaze (VIDEO) - NatashasKitchen.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + + + +
    +
    + +
    +
    +
    + +

    Orange-glazed Cranberry bread has a moist and tender crumb and is loaded with juicy cranberries. It has the perfect balance of sweet and tangy and just like our famous Banana Bread, this loaf stays moist for a few days (in case you needed a homemade Christmas gift idea).

    + + + +

    This is a copycat version of my favorite bakery’s cranberry loaf and this one turned out even better – more cranberries and the orange glaze makes it truly special. You’ll love every bite. 

    + + + +
    Sliced cranberry bread with fresh cranberries

    This post may contain affiliate links. Read my disclosure policy.

    + + + +

    We love cranberry recipes during the holidays like Sugared Cranberries, Cranberry Bundt Cake, and of course this Cranberry Bread recipe. If you love tangy and juicy cranberries, this recipe is a must-try!

    + + + +

    Cranberry Bread Video Tutorial

    + + + +
    + + + +

    If you enjoyed this video for Cranberry Bread, please subscribe to our Youtube Channel (P.S. Click the BELL icon so you can be the first to know when we post a new video). Thank you for subscribing!

    + + + +

    Ingredients for Cranberry Orange Bread

    + + + +
      +
    • Flour – use all-purpose to give the bread structure
    • + + + +
    • Baking powder – leavening to make the loaf rise
    • + + + +
    • Salt – balances the sweetness
    • + + + +
    • Milk – best at room temperature
    • + + + +
    • Orange zest and juice – be sure to zest the orange before juicing it. Reserve a teaspoon of zest for the glaze.
    • + + + +
    • Butter – Adds moisture to the loaf. Use unsalted butter softened at room temperature.
    • + + + +
    • Sugar – to balance the tanginess of the cranberries
    • + + + +
    • Eggs – give the bread a moist, tender crumb
    • + + + +
    • Cranberries – rinsed and dried then tossed in 1/2 Tbsp of flour to keep them from sinking in the batter (see substitution options in common questions section)
    • +
    + + + +
    Ingredients for homemade cranberry bread with orange glaze
    + + + +

    How to Make Cranberry Bread

    + + + +
      +
    1. Whisk dry ingredients – whisk together flour, baking powder and salt.
    2. + + + +
    3. Combine wet ingredients – in a measuring cup, stir together milk, orange juice and zest.
    4. + + + +
    5. Cream butter and sugar together in a large mixing bowl then beat in eggs until well combined.
    6. + + + +
    7. Combine batter – Add flour mixture in 2 additions, alternating with the milk mixture, mixing just until combined.
    8. + + + +
    9. Flour cranberries – rinse and dry cranberries then toss them with 1/2 Tbsp flour to coat. Fold in cranberries just until incorporated. Spread batter into buttered and floured 8.5×4.5 bread pan.
    10. + + + +
    11. Bake the bread for 45-50 minutes until golden on top and a toothpick inserted in the center comes out clean. Cool in the pan for 10-15 minutes then transfer to a rack to cool completely.
    12. +
    + + + +
    Step by step how to make cranberry bread recipe
    + + + +

    Pro Tip: Tossing cranberries in a little flour coats them lightly and prevents them from sinking to the bottom of the loaf as it bakes. This ensures cranberries are evenly disbursed in the finished loaf.

    + + + +
    Cranberry Orange bread in loaf pan
    + + + +

    The Best Glaze for Cranberry Bread

    + + + +

    Orange and cranberry are complimentarily flavored just like peanut butter and jelly. Topping the cranberry bread with orange juice and the orange zest-infused glaze makes this bread irresistible. I’m not sure if it’s breakfast or dessert but I’ve served it both ways. All you need for this easy 3-ingredient glaze is:

    + + + +
      +
    • Powdered sugar – I spoon it into the cup and level the top for a consistent measure.
    • + + + +
    • Orange juice – Freshly squeezed is best and don’t worry about straining. A little pulp won’t hurt the bread.
    • + + + +
    • Orange zest – do not skip the zest. It adds deep orange floral notes to the glaze.
    • +
    + + + +
    Orange glazed cranberry bread slices
    + + + +

    Common Questions

    + + + +
    Can I use frozen cranberries?

    Yes, you can use frozen cranberries in the same quantity and add them frozen (do not thaw). You may need to bake just a few minutes longer or until a toothpick inserted into the center comes out clean.

    Can I Substitute Dried Cranberries?

    You can substitute with 2/3 cup dried cranberries and reduce the sugar in the recipe to 2/3 cup since dried cranberries aren’t as tart. The dried cranberries will be juicer if you soak them in very warm water for 10 minutes then drain and pat dry before using. 

    Can I add nuts?

    You can make this a cranberry nut bread by folding in 1/2 cup of coarsely chopped walnuts or pecans when adding the cranberries to the batter.

    + + + +
    Close up slices of cranberry orange glazed bread
    + + + +

    This sweet bread is total comfort food. All you need is a mug of tea or coffee to go with a thick, fresh slice of cranberry bread.

    + + + +

    Make-Ahead

    + + + +
      +
    • Room Temperature – wrap cranberry bread loosely in plastic wrap or store in an airtight container for up to 3 days.
    • + + + +
    • Refrigerate – you can cover and store the loaf in the refrigerator for up to a week.
    • + + + +
    • Freezing – cool the loaf completely to room temperature then place in a freezer-safe zip bag, removing any excess air. Freeze up to three months. Thaw in the refrigerator overnight before serving.
    • +
    + + + +
    Slice of cranberry bread broken in half to show tender center
    + + + +

    Pro Tip: Cranberries are only available for a season in grocery stores so buy extra and store them in the freezer so you can keep enjoying this cranberry bread year-round.

    + + + +

    More Cranberry Recipes

    + + + +

    These are our best cranberry recipes using both fresh and dried cranberries.

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

    Cranberry Bread with Orange Glaze

    + +
    4.99 from 867 votes
    + +
    Author: Natasha Kravchuk
    + +
    +
    +
    Cranberry Bread with Orange Glaze
    +
    +
    +
    Orange Glazed Cranberry bread is loaded with juicy cranberries with a moist and tender crumb. This stays moist for a few days after it’s made so it’s perfect as a homemade Christmas gift.
    + + +
    +
    + +
    +
    Prep Time: 10 minutes
    Cook Time: 50 minutes
    Total Time: 1 hour
    +
    + +

    Ingredients 

    Servings: 8 people (makes 1 loaf)

    Cranberry Bread Ingredients

    • 1 1/2 cups all-purpose flour
    • 1 tsp baking powder
    • 1/4 tsp salt
    • 1/4 cup milk, room temperature
    • Zest of 1 large orange, divided
    • 1/4 cup orange juice, freshly squeezed
    • 6 Tbsp unsalted butter, softened
    • 3/4 cup granulated sugar
    • 2 large eggs, room temperature
    • 1 1/2 cups fresh cranberries, rinsed and patted dry
    • 1/2 Tbsp all-purpose flour

    Orange Glaze Ingredients:

    • 1 cup powdered sugar
    • 1 1/2 Tbsp freshly squeezed orange juice, or to reach desired consistency
    • 1 tsp orange zest, reserved from the orange above
    + + + +

    Instructions

    How to Make Cranberry Orange Bread:

    • Prep: Preheat oven to 350˚F. Butter a 6 cup (8 1/2 by 4 1/2 bread loaf pan) then dust with flour, tapping out the excess flour.
    • In a medium mixing bowl, whisk together: flour, baking powder, and salt. Set aside.
    • In a measuring cup, combine together milk, zest of 1 orange (Reserve 1 tsp zest for the glaze), and orange juice. Set aside.
    • In a large mixing bowl, cream together butter and granulated sugar on medium/high speed (2-3 minutes on high speed). It won’t be smooth, just combined. Beat in 2 large eggs, mixing until well incorporated.
    • Add flour mixture in 2 parts, alternating with the milk mixture and mixing on medium/low speed just until incorporated with each addition. Scrape the sides of the bowl with a spatula as needed.
    • Toss cranberries with 1/2 Tbsp flour then fold them into the batter just until incorporated. Spread the batter into your prepared pan and bake for 45-50 min at 350˚F until golden on top and a toothpick inserted into the center comes out clean. Let cool in pan 10-15 minutes then run a cake release tool or knife around the edges and transfer the loaf to a wire rack to cool completely before glazing.

    To Make the Glaze:

    • In a separate bowl, stir together powdered sugar, orange juice and reserved teaspoon of zest. Stir until smooth. It should have a drizzling consistency. Add more orange juice to thin it out or powdered sugar to make it thicker.
    + + + + + +

    Nutrition Per Serving

    326kcal Calories56g Carbs4g Protein10g Fat6g Saturated Fat1g Polyunsaturated Fat3g Monounsaturated Fat1g Trans Fat64mg Cholesterol95mg Sodium144mg Potassium2g Fiber36g Sugar370IU Vitamin A8mg Vitamin C47mg Calcium1mg Iron
    + +
    + +
    Nutrition Facts
    Cranberry Bread with Orange Glaze
    Amount per Serving
    Calories
    326
    % Daily Value*
    Fat
     
    10
    g
    15
    %
    Saturated Fat
     
    6
    g
    38
    %
    Trans Fat
     
    1
    g
    Polyunsaturated Fat
     
    1
    g
    Monounsaturated Fat
     
    3
    g
    Cholesterol
     
    64
    mg
    21
    %
    Sodium
     
    95
    mg
    4
    %
    Potassium
     
    144
    mg
    4
    %
    Carbohydrates
     
    56
    g
    19
    %
    Fiber
     
    2
    g
    8
    %
    Sugar
     
    36
    g
    40
    %
    Protein
     
    4
    g
    8
    %
    Vitamin A
     
    370
    IU
    7
    %
    Vitamin C
     
    8
    mg
    10
    %
    Calcium
     
    47
    mg
    5
    %
    Iron
     
    1
    mg
    6
    %
    * Percent Daily Values are based on a 2000 calorie diet.
    + +
    +
    Course: Breakfast, Dessert
    Cuisine: American
    Keyword: Cranberry Bread, Cranberry Orange Bread, Orange Cranberry Bread
    Skill Level: Easy
    Cost to Make: $
    +
    Calories: 326
    +
    +
    + Natasha's Kitchen Cookbook
    +
    + +
    +
    + +
    +
    +

    Natasha Kravchuk

    + +
    +
    +
    +

    Welcome to my kitchen! I am Natasha, the creator behind Natasha's Kitchen (established in 2009), and I share family-friendly, authentic recipes. I am a New York Times Best-Selling cookbook author and a trusted video personality in the culinary world. My husband, Vadim, and I run this blog together, ensuring every recipe we share is thoroughly tested and approved. Our mission is to provide you with delicious, reliable recipes you can count on. Thanks for stopping by! I am so happy you are here.

    + +

    Read more posts by Natasha

    + + +
    +
    +
    + + +
    + +
    + + + + + +
    + +
    +
    +
    +
    + 4.99 from 867 votes (636 ratings without comment) +
    +
    +
    +

    Leave a Comment

    + +
    + Recipe Rating +




    +
    +
    +

    +
    + +

    + +

    +
    + + + + +
    +

    Comments

    + +
    + +
      +
    • +
      + +
      +
      Darcie Jenkins
      +
      December 16, 2024
      +
      +
      +

      Your comment is awaiting moderation.

      +
      + +
      +

      I made this two ways; using the normal recipe and one using Trader Joe’s gluten free flour mix. Both were amazing! I used zest from 3 oranges because I like a strong orange flavor. I’m going to try making it as muffins next time so they are single serving and easier to freeze. Thanks for the recipe!

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 16, 2024
        +
        +
        +

        Thank you for sharing, Darcie!

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Pauline
      +
      December 16, 2024
      +
      +
      +

      I’m wondering if i can make the cake ahead of time andfeweze it?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 16, 2024
        +
        +
        +

        Hi Pauline! Yes, it freezes well.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Mary
      +
      December 16, 2024
      +
      +
      +
      + +
      +

      What did I do wrong? I floured the cranberries so they wouldn’t sink, but they all rose to the top! The taste is good, but the cranberry taste is only at the top. I would like to make these as gifts. Any suggestions?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 16, 2024
        +
        +
        +

        Hi Mary! A few things to try- make sure to coat them well and pat them completely dry before hand. Don’t over-mix the batter. You may even try to layer them in the batter instead of folding them in. For example, pour 1/3 of the batter into the pan, top it with cranberries, repeat. I hope that’s helpful.

        +

        Reply

        +
        + +
        +
          +
        • +
          + +
          +
          denyse
          +
          December 16, 2024
          +
          +
          +

          Hi Natasha
          +First I love your recipes!!
          +Would your cranberry bread recipe work okay with dried cranberries that I could soak in oj before
          +Thanks

          +

          Reply

          +
          + +
          +
            +
          • +
            + +
            +
            NatashasKitchen.com
            +
            December 16, 2024
            +
            +
            +

            Hi Denyse! Yes- see my note in the common questions section regarding using dried cranberries.

            +

            Reply

            +
            + +
            +
          • +
          +
        • +
        +
      • +
      +
    • +
    • +
      + +
      +
      Veronica
      +
      December 15, 2024
      +
      +
      +
      + +
      +

      Prep and bake time are definitely off. Took closer to 20 minutes to get all ingredients prepped and mixed. Baking took 1 hour in a glass pan. I had to cover the bread because it was starting to brown too much. There was also way too much glaze, like double the amount I needed. This is the 2nd sweet bread recipe I’ve tried from NK and both have been lackluster.

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        NatashasKitchen.com
        +
        December 16, 2024
        +
        +
        +

        Hi Veronica! I’m really sorry to hear that. This recipe generally has great reviews. It’s a very popular one around this time of the year, often used to gift for the holidays. Glass pans affect how it bakes, they require a longer bake time and a lower temperature to prevent browning.
        +You can definitely decrease the glaze, or leave it off entirely.

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Charmaine Speltz
      +
      December 15, 2024
      +
      +
      +

      Can frozen cranberries be substituted for fresh cranberries??

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        Natasha's Kitchen
        +
        December 15, 2024
        +
        +
        +

        Yes frozen will work. Please check this portion of the recipe “Common Questions”

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Joan Young
      +
      December 15, 2024
      +
      +
      +
      + +
      +

      This Cranberry/Orange Bread is a favorite with our family; it is delicious. I always make it without the glaze as I think it keeps better.

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      Val
      +
      December 15, 2024
      +
      +
      +

      Oh I just saw the post about using frozen cranberries. Thank you, I should have looked a little better.

      +

      Reply

      +
      + +
      +
    • +
    • +
      + +
      +
      Val
      +
      December 15, 2024
      +
      +
      +

      I wondered if I could use frozen cranberries?

      +

      Reply

      +
      + +
      +
        +
      • +
        + +
        +
        Natasha's Kitchen
        +
        December 15, 2024
        +
        +
        +

        Yes frozen will work. Please check this portion of the recipe “Common Questions”

        +

        Reply

        +
        + +
        +
      • +
      +
    • +
    • +
      + +
      +
      Alison
      +
      December 15, 2024
      +
      +
      +

      I have used this recipe for the past few years to give to others as Christmas gifts. I bake 2 loaves at a time and add an extra 15 minutes or so to the baking time. It is always well received! Thank you for a great gift-worthy recipe!

      +

      Reply

      +
      + +
      +
    • +
    + + + +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +

    As Featured On

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

    Never Go "Hangry" Again!

    +

    Get weekly updates on new recipes, exclusive giveaways plus behind the scenes photos.

    +
    +

    +

    +
    + +
    +
    +
    +
    + + +
    + + + diff --git a/tests/test_data/nhs.uk/nhshealthierfamilies_1.json b/tests/test_data/nhs.uk/nhshealthierfamilies_1.json index 5213e4e12..99a1944ff 100644 --- a/tests/test_data/nhs.uk/nhshealthierfamilies_1.json +++ b/tests/test_data/nhs.uk/nhshealthierfamilies_1.json @@ -26,9 +26,10 @@ "Meanwhile, cook the rice according to pack instructions.", "Season the chilli with pepper and serve with the boiled rice." ], - "category": null, "yields": "4 servings", - "description": "This classic chilli is packed with flavour. It also freezes well, so is perfect for batch-cooking.", + "description": "This classic chilli is packed with flavour. It also freezes well, so is perfect to batch-cook.", "total_time": 35, - "image": "https://assets.nhs.uk/campaigns-cms-prod/images/Chilli-con-carne_x7m8d91.width-320.jpg" + "cook_time": 25, + "prep_time": 10, + "image": "https://digitalcampaignsstorage.blob.core.windows.net/campaigns-cms-prod/images/Chilli-con-carne_x7m8d91.width-320.jpg" } diff --git a/tests/test_data/nhs.uk/nhshealthierfamilies_1.testhtml b/tests/test_data/nhs.uk/nhshealthierfamilies_1.testhtml index ae6efa5ae..debae96c2 100644 --- a/tests/test_data/nhs.uk/nhshealthierfamilies_1.testhtml +++ b/tests/test_data/nhs.uk/nhshealthierfamilies_1.testhtml @@ -6,7 +6,6 @@ - @@ -22,18 +21,18 @@ Easy Chilli Con Carne - Recipes - Healthier Families - NHS - + + + - - - - - + + + @@ -53,18 +52,18 @@ + + - - - + - + @@ -75,6 +74,8 @@ + + @@ -107,23 +108,23 @@ window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); - + gtag('config', 'G-1K4S0MRD2T'); - + - + Skip to main content - - + + @@ -149,114 +150,114 @@ + - - + + + + - - - - - - + + + - +
    - - - - - - + + + + + +
    - +
    - - + +
    - - - + + + @@ -273,8 +274,8 @@

    Chilli con carne recipe

    This classic chilli is packed with flavour. It also freezes well, so is perfect to batch-cook.

    Prep: 10 mins
    Cook: 25 mins
    Serves 4

    - - + +
    @@ -282,34 +283,34 @@
    - - + +

    Per serving:

    • 2,042kJ / 488kcals
    • 30g protein
    • 5g fat, of which 1.5g saturates
    • 82g carbohydrate, of which 12g sugars
    • 7g fibre
    • 0.9g salt
    - - + +
    - +
    Chilli made with beef, mushrooms, peppers and kidney beans served with rice @@ -320,58 +321,58 @@
    - +

    Ingredients

    • 300g extra-lean minced beef
    • 1 large onion, finely chopped
    • 2 garlic cloves, finely chopped
    • 400g chopped tomatoes
    • 2 tablespoons tomato purée
    • 2 teaspoons chilli powder
    • 1 teaspoon ground cumin
    • 1 red pepper, deseeded and chopped
    • 2 handfuls of cup or button mushrooms, sliced
    • 410g red kidney beans, drained
    • 150ml reduced-salt vegetable or chicken stock
    • 300g easy-cook white or brown rice
    • 1 pinch ground black pepper
    - +

    Method

      - - + +
    1. - +

      Heat a large saucepan and add the minced beef, a handful at a time, cooking it until browned. Add the onion and garlic, then cook for another 2 to 3 minutes.

      - +
      Information:

      Turkey mince also makes an excellent chilli – and it's lower in fat too. If you want to keep things vegetarian, substitute the minced beef with vegetarian mince, or try our tasty veggie chilli recipe.

      - +
    2. - - + +
    3. - +

      Add the chopped tomatoes, tomato purée, spices, red pepper, mushrooms, kidney beans and stock. Stir well, bring to the boil, then lower the heat and simmer gently for 15 to 20 minutes.

      - +
    4. - - + +
    5. - +

      Meanwhile, cook the rice according to pack instructions.

      - +
    6. - - + +
    7. - +

      Season the chilli with pepper and serve with the boiled rice.

      - +
      Information:

      Chilli makes a really versatile topping or filling, and is also great for reheating leftovers. So instead of rice, try serving with baked potatoes, topped with a spoonful of low-fat plain yoghurt and some chopped cucumber and tomatoes – or in a wholewheat wrap.

      - +
    8. - +
    @@ -383,128 +384,128 @@ "@context": "https://schema.org", "@type": "Recipe", "description": "This classic chilli is packed with flavour. It also freezes well, so is perfect to batch-cook.", - "image": "https://assets.nhs.uk/campaigns-cms-prod/images/Chilli-con-carne_x7m8d91.width-320.jpg", + "image": "https://digitalcampaignsstorage.blob.core.windows.net/campaigns-cms-prod/images/Chilli-con-carne_x7m8d91.width-320.jpg", "recipeIngredient": ["300g extra-lean minced beef", "1 large onion, finely chopped", "2 garlic cloves, finely chopped", "400g chopped tomatoes", "2 tablespoons tomato pur\u00e9e", "2 teaspoons chilli powder", "1 teaspoon ground cumin", "1 red pepper, deseeded and chopped", "2 handfuls of cup or button mushrooms, sliced", "410g red kidney beans, drained", "150ml reduced-salt vegetable or chicken stock", "300g easy-cook white or brown rice", "1 pinch ground black pepper"], "name": "Chilli con carne recipe", "recipeInstructions": "Heat a large saucepan and add the minced beef, a handful at a time, cooking it until browned. Add the onion and garlic, then cook for another 2 to 3 minutes.Add the chopped tomatoes, tomato purée, spices, red pepper, mushrooms, kidney beans and stock. Stir well, bring to the boil, then lower the heat and simmer gently for 15 to 20 minutes.Meanwhile, cook the rice according to pack instructions.Season the chilli with pepper and serve with the boiled rice." } - - + +
    - +
    - - + +
    - - + +
    - +
    - - + +
    - - - + + + @@ -518,61 +519,61 @@
    - +

    - + Sign up for Healthy Steps emails - +

    - - + +

    Want the recipe for a healthier family? Join today and over 8 weeks you'll get easy tips from nutrition experts and parents, healthy swaps and tasty recipes on a budget.

    - +
    - - + +
    - +
    - - - + + +
    - + + - - - - + + + diff --git a/tests/test_data/nhs.uk/nhshealthierfamilies_2.json b/tests/test_data/nhs.uk/nhshealthierfamilies_2.json index 74c8b6379..9313f11e6 100644 --- a/tests/test_data/nhs.uk/nhshealthierfamilies_2.json +++ b/tests/test_data/nhs.uk/nhshealthierfamilies_2.json @@ -39,9 +39,10 @@ "Meanwhile, sprinkle the breadcrumbs onto a large plate. Season with a little pepper. Dip each fish fillet in the beaten egg, then coat in the breadcrumbs. Place on the baking sheet, then transfer to the oven when you turn the potatoes, so that it cooks for 15 to 20 minutes. To check that the fish is cooked, it should flake easily when tested with a fork.", "Heat the mushy peas in a saucepan, then serve with the fish and chips." ], - "category": null, "yields": "4 servings", - "description": "Try our recipe for healthier, homemade fish and chips! Click to read the ingredients and a step-by-step guide to making it", + "description": "Make your own healthier version of fish and chips at home!", "total_time": 50, - "image": "https://assets.nhs.uk/campaigns-cms-prod/images/Recipes-square-healthy-fish-and-chips.width-320.jpg" + "cook_time": 40, + "prep_time": 10, + "image": "https://digitalcampaignsstorage.blob.core.windows.net/campaigns-cms-prod/images/Recipes-square-healthy-fish-and-chips.width-320.jpg" } diff --git a/tests/test_data/nhs.uk/nhshealthierfamilies_2.testhtml b/tests/test_data/nhs.uk/nhshealthierfamilies_2.testhtml index 946d1a8c0..448b212f4 100644 --- a/tests/test_data/nhs.uk/nhshealthierfamilies_2.testhtml +++ b/tests/test_data/nhs.uk/nhshealthierfamilies_2.testhtml @@ -6,7 +6,6 @@ - @@ -22,18 +21,18 @@ Healthy homemade fish and chips - Recipes - Healthier Families - NHS - + + + - - - - - + + + @@ -53,18 +52,18 @@ + + - - - + - + @@ -75,6 +74,8 @@ + + @@ -107,23 +108,23 @@ window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); - + gtag('config', 'G-1K4S0MRD2T'); - + - + Skip to main content - - + + @@ -149,114 +150,114 @@ + - - + + + + - - - - - - + + + - +
    - - - - - - + + + + + +
    - +
    - - + +
    - - - + + + @@ -273,8 +274,8 @@

    Good old fish and chips recipe

    Make your own healthier version of fish and chips at home!

    Prep: 10 mins
    Cook: 40 mins
    Serves 4

    - - + +
    @@ -282,34 +283,34 @@
    - - + +

    Per serving:

    • 1,682kJ / 402kcal
    • 34g protein
    • 56g carbohydrate of which 3g sugars
    • 6g fat of which 1g saturates
    • 4g fibre
    • 1g salt
    - - + +
    - +
    Homebaked chips and fillets of fish with breadcrumbs @@ -320,58 +321,58 @@
    - -

    Ingredients

    • 4 potatoes, scrubbed, each cut into 8 wedges
    • 1 tablespoon vegetable oil
    • 75g dried white or wholemeal breadcrumbs
    • 1 egg, beaten with 2 tbsp cold water
    • 4 fillets skinless white fish, like haddock, cod or pollock

    Swappable or optional

    • 300g mushy peas
    • 1 pinch ground black pepper (optional)

    Swap tip

    You can use any frozen, fresh or canned peas if you don't have mushy ones.

    - + +

    Ingredients

    • 4 potatoes, scrubbed, each cut into 8 wedges
    • 1 tablespoon vegetable oil
    • 75g dried white or wholemeal breadcrumbs
    • 1 egg, beaten with 2 tbsp cold water
    • 4 fillets skinless white fish, like haddock, cod or pollock

    Swappable or optional

    • 300g mushy peas
    • 1 pinch ground black pepper (optional)

    Swap tip

    You can use any frozen, fresh or canned peas if you don't have mushy ones.

    +

    Method

      - - + +
    1. - +

      Preheat the oven to 200C (fan 180C, gas mark 6). Lightly grease a baking sheet with a little vegetable oil.

      - +
    2. - - + +
    3. - +

      Put the potato wedges into a roasting tin. Add the remaining vegetable oil and toss to coat. Season with black pepper. Transfer to the oven to bake for 35 to 40 minutes, turning them over after 20 minutes.

      - +
      Information:

      Not peeling the potatoes means you get more fibre in your diet – and they're quicker to prepare.

      - +
    4. - - + +
    5. - +

      Meanwhile, sprinkle the breadcrumbs onto a large plate. Season with a little pepper. Dip each fish fillet in the beaten egg, then coat in the breadcrumbs. Place on the baking sheet, then transfer to the oven when you turn the potatoes, so that it cooks for 15 to 20 minutes. To check that the fish is cooked, it should flake easily when tested with a fork.

      - +
      Information:

      Look out for dried breadcrumbs flavoured with lemon or spices to add extra flavour to the fish, or add some finely grated lemon zest or a pinch of paprika to plain dried breadcrumbs.

      - +
    6. - - + +
    7. - +

      Heat the mushy peas in a saucepan, then serve with the fish and chips.

      - +
    8. - +
    @@ -383,128 +384,128 @@ "@context": "https://schema.org", "@type": "Recipe", "description": "Make your own healthier version of fish and chips at home!", - "image": "https://assets.nhs.uk/campaigns-cms-prod/images/Recipes-square-healthy-fish-and-chips.width-320.jpg", + "image": "https://digitalcampaignsstorage.blob.core.windows.net/campaigns-cms-prod/images/Recipes-square-healthy-fish-and-chips.width-320.jpg", "recipeIngredient": ["4 potatoes, scrubbed, each cut into 8 wedges", "1 tablespoon vegetable oil", "75g dried white or wholemeal breadcrumbs", "1 egg, beaten with 2 tbsp cold water", "4 fillets skinless white fish, like haddock, cod or pollock", "300g mushy peas", "1 pinch\u00a0ground black pepper (optional)"], "name": "Good old fish and chips recipe", "recipeInstructions": "Preheat the oven to 200C (fan 180C, gas mark 6). Lightly grease a baking sheet with a little vegetable oil.Put the potato wedges into a roasting tin. Add the remaining vegetable oil and toss to coat. Season with black pepper. Transfer to the oven to bake for 35 to 40 minutes, turning them over after 20 minutes.Meanwhile, sprinkle the breadcrumbs onto a large plate. Season with a little pepper. Dip each fish fillet in the beaten egg, then coat in the breadcrumbs. Place on the baking sheet, then transfer to the oven when you turn the potatoes, so that it cooks for 15 to 20 minutes. To check that the fish is cooked, it should flake easily when tested with a fork.Heat the mushy peas in a saucepan, then serve with the fish and chips." } - - + +
    - +
    - - + +
    - - + +
    - +
    - - + +
    - - - + + + @@ -518,61 +519,61 @@
    - +

    - + Sign up for Healthy Steps emails - +

    - - + +

    Want the recipe for a healthier family? Join today and over 8 weeks you'll get easy tips from nutrition experts and parents, healthy swaps and tasty recipes on a budget.

    - +
    - - + +
    - +
    - - - + + +
    - + + - - - - + + + diff --git a/tests/test_data/noracooks.com/noracooks.json b/tests/test_data/noracooks.com/noracooks.json new file mode 100644 index 000000000..51a082d7e --- /dev/null +++ b/tests/test_data/noracooks.com/noracooks.json @@ -0,0 +1,66 @@ +{ + "author": "Nora", + "canonical_url": "https://www.noracooks.com/vegan-chocolate-cake/", + "site_name": "Nora Cooks", + "host": "noracooks.com", + "language": "en-US", + "title": "The Best Vegan Chocolate Cake", + "ingredients": [ + "1 cup unsweetened almond milk", + "1 tablespoon apple cider vinegar", + "2 cups all purpose flour", + "1 3/4 cups granulated sugar", + "3/4 cup cocoa powder", + "2 teaspoons baking powder", + "1 1/2 teaspoons baking soda", + "1 teaspoon salt", + "1/2 cup canola oil OR melted coconut oil", + "2/3 cup unsweetened applesauce", + "1 tablespoon pure vanilla extract", + "1 cup boiling water", + "1 cup cocoa powder", + "1 1/2 cups vegan butter, softened (baking sticks preferred)", + "4-5 cups powdered sugar", + "2 teaspoons pure vanilla extract", + "1/4-1/2 cup unsweetened almond milk" + ], + "instructions_list": [ + "For the Chocolate Cake", + "Preheat oven to 350 degrees F and grease two 9-inch cake pans. I also line them with parchment rounds and lightly flour for easy removal of the cakes later.", + "Measure 1 cup unsweetened almond milk and add the tablespoon of vinegar to it. Stir slightly and set aside to curdle.", + "In a large bowl, add the flour, sugar, cocoa powder, baking powder, baking soda and salt. Whisk well to combine.", + "Now add the oil, applesauce, vanilla and almond milk/vinegar mixture. Mix on medium speed with a hand mixer (or stand mixer with the paddle attachment) until well combined.", + "Lower the speed and carefully pour in the boiling water, continuing to mix into the cake batter until combined. The batter will seem very runny at this point; that is how it should be, trust me!", + "Divide the batter evenly between your cake pans. Bake for 30-35 minutes, or until a toothpick inserted in the center comes out clean. After 10 minutes of cooling in the pan, carefully remove the cakes from the pans and let cool completely before frosting.", + "For the Chocolate Buttercream Frosting", + "Add the cocoa powder to a large bowl (I just wipe out the cake bowl and use it for the frosting). Whisk well to remove any clumps.", + "Add the softened vegan butter and mix with a hand mixer until creamed and well combined.", + "Add half of the powdered sugar and half of the almond milk, and mix until combined. Add the rest of the powdered sugar and vanilla extract. Mix starting on low, and turn to high. Mix until fluffy and combined.", + "If the frosting seems too dry, add more milk, a tablespoon or two at a time. If the frosting seems too wet and doesn't hold it's shape, add more powdered sugar until it thickens up.", + "Frost the cake using an icing spatula or just a butter knife." + ], + "category": "Dessert", + "yields": "16 servings", + "description": "The Best Vegan Chocolate Cake- A quick and easy recipe, made in 1 bowl! This really is the best chocolate cake ever, vegan or otherwise. It's super moist, rich and full of chocolate.", + "total_time": 55, + "cook_time": 35, + "prep_time": 20, + "cuisine": "American", + "ratings": 4.96, + "ratings_count": 1806, + "nutrients": { + "servingSize": "1 serving", + "calories": "496 kcal", + "fatContent": "25 g", + "saturatedFatContent": "4 g", + "carbohydrateContent": "71 g", + "sugarContent": "53 g", + "proteinContent": "4 g", + "sodiumContent": "408 mg", + "fiberContent": "4 g" + }, + "image": "https://www.noracooks.com/wp-content/uploads/2018/07/IMG_8885.jpg", + "keywords": [ + "vegan chocolate cake" + ] +} diff --git a/tests/test_data/noracooks.com/noracooks.testhtml b/tests/test_data/noracooks.com/noracooks.testhtml new file mode 100644 index 000000000..cb0cc1972 --- /dev/null +++ b/tests/test_data/noracooks.com/noracooks.testhtml @@ -0,0 +1,827 @@ + + + + + + + + + + + + + + + + + + + + + + + + + The Best Vegan Chocolate Cake - Nora Cooks + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    The Best Vegan Chocolate Cake

    PublishedJul 26, 2018

    Updated Feb 07, 2024

    4.96 stars (1806 ratings)
    Jump to Recipe

    This post may contain affiliate links. Read my full disclosure here.

    +

    The Best Vegan Chocolate Cake- A quick and easy recipe, made in 1 bowl! This really is the best chocolate cake ever, vegan or otherwise. It’s super moist, rich and full of chocolate. 

    +

    slice of vegan chocolate cake on a plate

    +

    My birthday was a few weeks ago, so what did I do? I asked my mom to watch all 3 kids for a few hours so I could create and photograph the BEST EVER Vegan Chocolate Cake. Pretty great birthday if you ask me! 😉

    +

    For some reason, every time I get a vegan piece of cake out (such as at Whole Foods or elsewhere), I am disappointed. The frosting is usually yummy, but the cake part is either 1. strange tasting OR 2. super dry, not moist at all. Seriously disappointing.

    +

    I’ve also made a few of the vegan chocolate cake recipes out there, but even those weren’t quite moist enough or perfect enough for my taste. So I did a little thinking and experimenting and I finally came up with the best, most perfectly moist and delicious vegan chocolate cake recipe!

    +

    vegan chocolate cake with a slice taken out of it

    +

    The frosting is a mouthwatering, ultra rich chocolate buttercream. I recommend using earth balance vegan buttery sticks, I haven’t found another brand that tastes quite as good.

    +

    If you are looking for a lighter alternative, check out this Chocolate Cake with Cashew Vanilla Frosting. There is nothing “light” about this Chocolate Cake! It is a full on indulgent recipe. And I’m okay with that.

    +

     

    +

     

    +

    vegan chocolate frosting in a bowl with a whisk

    +

    What is the secret to a super moist vegan chocolate cake?

    +

    A couple of things make this cake super moist. The applesauce helps (don’t worry, you can’t taste it). But the BIG secret is to add a cup of boiling hot water to the cake batter right before baking. It makes such a difference!

    +

    The batter will appear runny when you add it, but don’t worry, that is completely correct and exactly what it should be like. It results in the most moist, delicious chocolate cake I’ve ever tasted!

    +

    vegan chocolate cake frosted close up

    +

    If you are craving a chocolate fix about now, or are new to being vegan and miss good tasting cake, give this recipe a try! It’s easy to make and hard to mess it up.

    +

    OR if you are wanting to try something other than chocolate, give this Vegan Lemon Cake a go! It’s one of my most popular dessert recipes, and impresses people every time I make it.

    +

    slice of vegan chocolate cake with a fork taking a bite.

    +

    Sign-up to get new recipes by email and receive a FREE 5 Day Family Friendly Vegan Meal Plan! SUBSCRIBE NOW.

    +

    Recipe inspired by Add A Pinch.

    +
    +
    slice of vegan chocolate cake with a fork taking a bite.
    +
    4.96 stars (1806 ratings)
    +

    The Best Vegan Chocolate Cake

    +
    The Best Vegan Chocolate Cake- A quick and easy recipe, made in 1 bowl! This really is the best chocolate cake ever, vegan or otherwise. It's super moist, rich and full of chocolate. 
    +
    Prep: 20 minutes
    Cook: 35 minutes
    Total: 55 minutes
    Servings: 16 servings
    +
    + + +

    Ingredients 
     

    Chocolate Cake

    • 1 cup unsweetened almond milk
    • 1 tablespoon apple cider vinegar
    • 2 cups all purpose flour
    • 1 3/4 cups granulated sugar
    • 3/4 cup cocoa powder
    • 2 teaspoons baking powder
    • 1 1/2 teaspoons baking soda
    • 1 teaspoon salt
    • 1/2 cup canola oil OR melted coconut oil
    • 2/3 cup unsweetened applesauce
    • 1 tablespoon pure vanilla extract
    • 1 cup boiling water

    Chocolate Buttercream Frosting

    • 1 cup cocoa powder
    • 1 1/2 cups vegan butter, softened baking sticks preferred
    • 4-5 cups powdered sugar
    • 2 teaspoons pure vanilla extract
    • 1/4-1/2 cup unsweetened almond milk
    +

    Instructions 

    For the Chocolate Cake

    • Preheat oven to 350 degrees F and grease two 9-inch cake pans. I also line them with parchment rounds and lightly flour for easy removal of the cakes later.
    • Measure 1 cup unsweetened almond milk and add the tablespoon of vinegar to it. Stir slightly and set aside to curdle.
    • In a large bowl, add the flour, sugar, cocoa powder, baking powder, baking soda and salt. Whisk well to combine.
    • Now add the oil, applesauce, vanilla and almond milk/vinegar mixture. Mix on medium speed with a hand mixer (or stand mixer with the paddle attachment) until well combined. 
    • Lower the speed and carefully pour in the boiling water, continuing to mix into the cake batter until combined. The batter will seem very runny at this point; that is how it should be, trust me!
    • Divide the batter evenly between your cake pans. Bake for 30-35 minutes, or until a toothpick inserted in the center comes out clean. After 10 minutes of cooling in the pan, carefully remove the cakes from the pans and let cool completely before frosting.

    For the Chocolate Buttercream Frosting

    • Add the cocoa powder to a large bowl (I just wipe out the cake bowl and use it for the frosting). Whisk well to remove any clumps.
    • Add the softened vegan butter and mix with a hand mixer until creamed and well combined.
    • Add half of the powdered sugar and half of the almond milk, and mix until combined. Add the rest of the powdered sugar and vanilla extract. Mix starting on low, and turn to high. Mix until fluffy and combined.
    • If the frosting seems too dry, add more milk, a tablespoon or two at a time. If the frosting seems too wet and doesn't hold it's shape, add more powdered sugar until it thickens up. 
    • Frost the cake using an icing spatula or just a butter knife.
    +

    Video

    +

    Notes

      +
    1. For cupcakes, fill liners half full and bake for 20-25 minutes. The whole recipe will yield approximately 24 cupcakes.
    2. +
    3. Double the recipe to make a 4 layer cake, or cut in half to make a 1 layer round cake. You can also make a bundt cake, simply bake for 45 minutes. Or a 9 x 13 inch cake, baking for about 35-40 minutes.
    4. +
    5. Don't like a lot of frosting? Cut the frosting ingredients in half. The recipe as written makes enough for thick layers of frosting.
    6. +
    7. Nut allergy? You may substitute soy milk or another milk for the almond milk, any non-dairy milk will work here.
    8. +
    9. No applesauce? Substitute 2 flax eggs (2 tbs ground flax + 5 tbs water), whipped aquafaba or another egg replacer such as Bob's Red Mill (2 eggs worth). 
    10. +
    +

    Nutrition

    Serving: 1serving | Calories: 496kcal | Carbohydrates: 71g | Protein: 4g | Fat: 25g | Saturated Fat: 4g | Sodium: 408mg | Potassium: 222mg | Fiber: 4g | Sugar: 53g | Vitamin C: 1mg | Calcium: 59mg | Iron: 2mg
    +
    Course: Dessert
    Cuisine: American
    Author: Nora Taylor
    +
    Did you make this recipe?Mention @nora_cooks_vegan_ or tag #noracooks!
    +
    PLEASE NOTE THIS PAGE DOES CONTAIN AFFILIATE LINKS. I ONLY LINK TO PRODUCTS I ABSOLUTELY LOVE AND RECOMMEND. THANK YOU FOR YOUR SUPPORT.
    +

    We are a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to amazon.com. Read my full disclosure here.

    +
    +
    +
    +

    About Nora

    + + +
    +
    +
    +

    Posted In: , , , , ,

    +
    + +
    +
    +
    +

    you may also like:

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

    Comments

    +
      +
    1. +
      + + +
      +

      I just baked this to make 3 9” round layer cakes and doubled the recipe and the cakes inside are like mush but tooth pick is coming out dry? I followed the recipe put it in for 35 mins

      +
      + +
      +
        +
      1. +
        + + +
        +

        Did you make any substitutions or changes to the recipe? I’m not sure how long they will need to bake if you doubled and are using 9 inch pans, they may need more time.

        +
        + +
        +
      2. +
      +
    2. +
    3. +
      + + +
      +

      My husband & I are detoxing from mold spores that you couldn’t see or smell. We can’t have any type of sugar while detoxing. Can this cake be made with just stevia? If so how much?

      +
      + +
      +
        +
      1. + +
      2. +
      +
    4. +
    5. +
      + + +
      +

      I’m looking to make this into a 4 layer 6” cake! I’m guessing adjusting the ingredients x1.5 should be enough batter, any idea what the baking time should be? Thank you!

      +
      + +
      +
        +
      1. +
        + + +
        +

        Hi there! I think 1.5 times the batter should be enough for a 4 layer 6 inch cake. I’m guessing a bit less time but I’m not sure, perhaps check often after 20 minutes or so until a toothpick inserted in the middle comes out clean.

        +
        + +
        +
      2. +
      +
    6. +
    7. + +
        +
      1. + +
      2. +
      +
    8. +
    9. +
      + + +
      +
      + +
      +

      I make this cake once a year for my partner’s birthday. This year my non-vegan Mother In Law wanted to make it for Thanksgiving and it was the most popular dish of the day for all! Sorry Nora, everyone calls it my chocolate cake recipe. 😉

      +
      + +
      +
    10. +
    11. +
      + + +
      +
      + +
      +

      Made this for thanksgiving and everyone loved it. Super moist, fluffy frosting and not too sweet. This will be my go to recipe for chocolate cake. And very easy to make too. Thank you.

      +
      + +
      +
        +
      1. +
        + + +
        +

        You are welcome, Maria! I’m thrilled you loved the cake! Thanks for your fabulous review and feedback! Happy cooking!

        +
        + +
        +
      2. +
      +
    12. +
    13. +
      + + +
      +
      + +
      +

      This is a fabulous cake! It is moist, wonderfully chocolatey, easy to make without any “special” ingredients that most vegan recipes seem to require, and my Thanksgiving guests absolutely loved it. They couldn’t believe it was vegan!

      +

      Thank you for this great recipe – it’s a keeper and I know I’ll make it again and again! So yummy!

      +
      + +
      +
        +
      1. +
        + + +
        +

        You are welcome! We love this cake at our place! I’m so glad it was a it with your guests! Thanks for your awesome review and feedback! Happy cooking!

        +
        + +
        +
      2. +
      +
    14. +
    15. +
      + + +
      +
      + +
      +

      INCREDIBLE. I made this for a party and everyone, vegans and non vegans alike, LOVED it.

      +

      Note: I reduced the sugar by about 30g and used sweetened applesauce. I also used a whipped ganache instead of buttercream!

      +
      + +
      +
        +
      1. +
        + + +
        +

        I’m thrilled you loved the cake and that it came out wonderful with your adjustments! Thanks for sharing your great review and baking experience! Happy cooking!

        +
        + +
        +
      2. +
      +
    16. +
    17. +
      + + +
      +
      + +
      +

      This recipe is wonderful! Both the cake and cupcakes turned out great. I was wondering if you had a suggestion for a gluten-free flour to use for this? Thanks.

      +
      + +
      +
        +
      1. +
        + + +
        +

        Hi Cliff. I am glad you are lo king the cake! Thanks for your awesome review! You can simply substitute a quality gluten free flour like Better Batter or King Arthur Measure for Measure. For gluten free, I prefer to make my Gluten Free Vegan Chocolate Cake, which is almost identical, but gluten free. Happy baking!

        +
        + +
        +
          +
        1. +
          + + +
          +

          I use a cup of Yogi’s Turmeric Honey Chai instead of the water. The comments I have received have been nothing short of “the best” comments for any cake I have made. Thanks for this recipe.

          +
          + +
          +
            +
          1. +
            + + +
            +

            You are welcome, Chris! Your addition sounds amazing! Thanks for sharing this idea! Glad the cake was a hit!

            +
            + +
            +
          2. +
          +
        2. +
        +
      2. +
      +
    18. +
    19. +
      + + +
      +
      + +
      +

      This is absolutely the most amazing chocolate cake ever.
      +My granddaughter is learning to be a vegan baker and I keep throwing your recipes at her.
      +This cake is the one that I make and take pieces to my family, who are not vegans, and they rave over it. It is so dense, moist and yet fluffy and keeping it in the fridge just makes it even more delicious. Thanks for all of your amazing recipes.

      +
      + +
      +
    20. +
    +
    +

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    + +
    + Recipe Rating +




    +
    +
    +

    + +

    + +

    +

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_1.json b/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_1.json index 5c171da62..6d0c99e72 100644 --- a/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_1.json +++ b/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_1.json @@ -12,7 +12,7 @@ "1 pinch salt", "1 teaspoon vanilla extract (ideally transparent to keep the mixture white)", "½ teaspoon coconut extract", - "1 1/2 cups pineapple (chopped (see notes))", + "1 1/2 cups pineapple (chopped (see notes)", "2 tablespoons unsweetened coconut flakes" ], "instructions_list": [ diff --git a/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_2.json b/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_2.json index 3e07ec205..79ac9694a 100644 --- a/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_2.json +++ b/tests/test_data/notenoughcinnamon.com/notenoughcinnamon_2.json @@ -9,7 +9,7 @@ "1 lb potato gnocchi (500g fresh shelf-stable, or frozen)", "1 pint cherry or grape tomatoes, cut in half (2 cups)", "1 small red onion (cut into 1-inch chunks)", - "2 bell peppers (cut into 1-inch chunks (I like to use one red and one yellow for color))", + "2 bell peppers (cut into 1-inch chunks (I like to use one red and one yellow for color)", "1 tsp garlic powder", "1 tbsp Italian herbs seasoning", "1/2 teaspoon sea salt", @@ -24,7 +24,7 @@ "1 lb potato gnocchi (500g fresh shelf-stable, or frozen)", "1 pint cherry or grape tomatoes, cut in half (2 cups)", "1 small red onion (cut into 1-inch chunks)", - "2 bell peppers (cut into 1-inch chunks (I like to use one red and one yellow for color))", + "2 bell peppers (cut into 1-inch chunks (I like to use one red and one yellow for color)", "1 tsp garlic powder", "1 tbsp Italian herbs seasoning", "1/2 teaspoon sea salt", diff --git a/tests/test_data/okokorecepten.nl/okokorecepten_1.json b/tests/test_data/okokorecepten.nl/okokorecepten_1.json new file mode 100644 index 000000000..90246ea4b --- /dev/null +++ b/tests/test_data/okokorecepten.nl/okokorecepten_1.json @@ -0,0 +1,48 @@ +{ + "author": "okoko recepten", + "canonical_url": "okokorecepten.nl", + "site_name": "okoko recepten", + "host": "okokorecepten.nl", + "language": "nl", + "title": "Zuurkoolsoep", + "ingredients": [ + "2 eetlepels olie", + "1 grote ui, gesnipperd", + "200 g zuurkool, uitgelekt en fijngesneden", + "½ blikje tomaatstukjes", + "2 theelepels tijm", + "2 kippenbouillontabletten", + "2 plakjes kipfilet (vleeswaar), in dunne reepjes", + "2 takjes basilicum, in fijne reepjes" + ], + "category": "Voorgerecht", + "yields": "4 servings", + "description": "Zuurkoolsoep. Kijk voor de bereidingswijze op okokorecepten.nl.", + "total_time": 30, + "cook_time": 30, + "cuisine": "Hollands", + "ratings": 7.9, + "ratings_count": 18, + "nutrients": { + "calories": "75 kcal", + "fatContent": "5 g vet", + "carbohydrateContent": "4 g koolhydraten", + "proteinContent": "4 g eiwit" + }, + "image": "https://www.okokorecepten.nl/i/recepten/redactie/2009-2/zuurkoolsoep-500.jpg", + "keywords": [ + "recept", + "zuurkoolsoep", + "hollands", + "voorgerecht", + "gevogelte", + "olie", + "ui", + "zuurkool", + "tomaatstukjes", + "tijm", + "kippenbouillontablet", + "kipfilet", + "basilicum" + ] +} diff --git a/tests/test_data/okokorecepten.nl/okokorecepten_1.testhtml b/tests/test_data/okokorecepten.nl/okokorecepten_1.testhtml new file mode 100644 index 000000000..bbae24035 --- /dev/null +++ b/tests/test_data/okokorecepten.nl/okokorecepten_1.testhtml @@ -0,0 +1,594 @@ + + + + + + + + + + + Zuurkoolsoep - recept - okoko recepten + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + + +
    + +
    + + + +
    + + + + +
    + +
    +
    + + + + +
    + +
    + + +
    + +
    +
    + + + +
    + +

    Zuurkoolsoep

    +
      +
    • 4 personen
    • +
    • 30 min
    • +
    • waardering 7,9
    • +
    +
      +
    • Voorgerecht
    • +
    • Hollands
    • +
    • Gevogelte
    • +
    +
    + +
    + + +

    bevat per portie

    +
      +
    • 75 kcal
    • +
    • 4 g eiwit
    • +
    • 5 g vet
    • +
    • 4 g koolhydraten
    • +
    + + +

    Ingrediënten

    +
      +
    • 2 eetlepels olie
    • +
    • 1 grote ui, gesnipperd
    • +
    • 200 g zuurkool, uitgelekt en fijngesneden
    • +
    • ½ blikje tomaatstukjes
    • +
    +
      +
    • 2 theelepels tijm
    • +
    • 2 kippenbouillontabletten
    • +
    • 2 plakjes kipfilet (vleeswaar), in dunne reepjes
    • +
    • 2 takjes basilicum, in fijne reepjes
    • +
    + +
    + + +

    Bereiden

    +

    Verhit de olie in een pan en fruit de ui zachtjes aan. Bak de zuurkool ca. 2 minuten zachtjes mee. Roer de tomaatstukjes erdoor en verwarm alles nog ca. 1 minuut.

    +

    Voeg de tijm, de bouillontabletten en 1 liter water toe en breng alles aan de kook. Laat de soep ca. 20 minuten zachtjes koken.

    +

    Pureer de soep eventueel met een staafmixer. Schep de zuurkoolsoep in kommen en garneer met reepjes kipfilet en basilicum.

    + +

    Extra benodigd

    +

    Staafmixer

    + +
    + +
    + + + +
    +

    Bron

    +

    Het recept 'Zuurkoolsoep' wordt je aangeboden door okoko recepten. Beeld: istetiana | Shutterstock.com

    +
    + +
    +

    Waardeer dit recept (18 stemmen)

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

    Overige soep recept tips

    + +
    + + +
    + +
    +

    Reacties op dit recept

    +
      +
    • +

      RobLekker.

      +

      reageren

      +
    • +
    • +

      tonGa ik zeker proberen, lijkt me lekker!!

      +

      reageren

      +
    • +
    • +

      EllyVerrassend. Beetje zurig maar wel lekker.

      +
        +
      • +

        IngridaDoet u enkele aardappelen en een wortel en geen tomaten, neem zuur weg.

        +
      • +
      +

      reageren

      +
    • +
    • +

      NelieVervang de kippenbouillontabletten door groentebouillontabletten, laat de plakjes kipfilet weg en je hebt een heerlijke vegetarische zuurkoolsoep.

      +

      reageren

      +
    • +
    • +

      IngridaIn Litouwen nooit pureren, ook toevoegen gedroogde paddestoelen.

      +

      reageren

      +
    • +
    + +
    + + + + + +
    + +
    + + + + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/okokorecepten.nl/okokorecepten_2.json b/tests/test_data/okokorecepten.nl/okokorecepten_2.json new file mode 100644 index 000000000..1a373e23c --- /dev/null +++ b/tests/test_data/okokorecepten.nl/okokorecepten_2.json @@ -0,0 +1,79 @@ +{ + "author": "Peter Gordon", + "canonical_url": "okokorecepten.nl", + "site_name": "okoko recepten", + "host": "okokorecepten.nl", + "language": "nl", + "title": "Dichtgeschroeide zalm met norisaus, gomasio en avocado", + "ingredients": [ + "600 g gekoelde zalmloin (zie tips onderaan het recept), in vier porties van 150 g", + "lichte slaolie", + "2 avocado's", + "2 eetlepels limoensap (of citroensap)", + "¼ theelepel fijn geraspte limoenschil (of citroenschil)", + "2 wortels, geschild, boven- en onderkant eraf, daarna in linten geschaafd", + "100 g waterkers, alleen de topjes, gewassen", + "4 eetlepels norisaus (zie onderaan het recept)", + "4 eetlepels knapperig gebakken boekweit of geroosterde noten of pompoenpitten", + "1 eetlepel geroosterde witte sesamzaadjes", + "½ theelepel zoutvlokken" + ], + "ingredient_groups": [ + { + "ingredients": [ + "600 g gekoelde zalmloin (zie tips onderaan het recept), in vier porties van 150 g", + "lichte slaolie", + "2 avocado's", + "2 eetlepels limoensap (of citroensap)", + "¼ theelepel fijn geraspte limoenschil (of citroenschil)", + "2 wortels, geschild, boven- en onderkant eraf, daarna in linten geschaafd", + "100 g waterkers, alleen de topjes, gewassen", + "4 eetlepels norisaus (zie onderaan het recept)", + "4 eetlepels knapperig gebakken boekweit of geroosterde noten of pompoenpitten" + ], + "purpose": null + }, + { + "ingredients": [ + "1 eetlepel geroosterde witte sesamzaadjes", + "½ theelepel zoutvlokken" + ], + "purpose": "voor de gomasio" + } + ], + "instructions_list": [ + "Zet een grote kom ijswater klaar. Haal de zalm uit de koelkast, dep die droog met keukenpapier, bestrijk elk stuk zalm met ½ theelepel olie en besprenkel het met een beetje zout.", + "Verhit een koekenpan met dikke bodem en antiaanbaklaag. Leg er een stuk zalm in als de pan begint te roken en bak de zalm 15 seconden. Draai deze daarna snel maar voorzichtig en schroei de zalm aan alle kanten dicht. Haal de zalm uit de pan en dompel die onder in het ijswater, zodat de zalm niet meer verder gaart. Bak de overige stukken zalm op dezelfde manier.", + "Haal de zalm voorzichtig uit het water als alle stukken er 4 minuten in ondergedompeld zijn geweest en dep ze droog op een theedoek. Zet ze afgedekt zo'n 6 uur in de koelkast voordat je het gerecht samenstelt.", + "Maak de gomasio door de sesamzaadjes grof te stampen met een vijzel en stamper en daarna kort het zout erdoor te stampen zodat het een beetje grof blijft.", + "Verwijder vlak voor het serveren het vlees van de avocado's en snij dat in blokjes. Vermeng ze met de limoenschil en het limoensap. Voeg de wortel toe en hussel alles voorzichtig met een kwart van de gomasio.", + "Verdeel voor het serveren de salade over de borden en bestrooi met de waterkers. Snij de zalm in plakjes van 5 mm en leg die erbovenop. Lepel de norisaus erover en bestrooi het geheel daarna met de rest van de gomasio en de knapperige boekweit (of noten of pompoenpitten). Serveer op kamertemperatuur." + ], + "category": "Hoofdgerecht", + "yields": "4 servings", + "description": "Dichtgeschroeide zalm met norisaus, gomasio en avocado, uit het kookboek 'Sensationele salades' van Peter Gordon. Kijk voor de bereidingswijze op okokorecepten.nl.", + "total_time": 25, + "cook_time": 15, + "prep_time": 10, + "cuisine": "Japans", + "ratings": 8.3, + "ratings_count": 3, + "image": "https://www.okokorecepten.nl/i/recepten/kookboeken/2016/sensationele-salades/dichtgeschroeide-zalm-norisaus-gomasio-avocado-500.jpg", + "keywords": [ + "recept", + "dichtgeschroeide zalm met norisaus gomasio en avocado", + "dichtgeschroeide", + "zalm", + "norisaus", + "gomasio", + "avocado", + "japans", + "hoofdgerecht", + "vis", + "slaolie", + "limoen", + "wortel", + "waterkers", + "sesamzaad" + ] +} diff --git a/tests/test_data/okokorecepten.nl/okokorecepten_2.testhtml b/tests/test_data/okokorecepten.nl/okokorecepten_2.testhtml new file mode 100644 index 000000000..29aa1582c --- /dev/null +++ b/tests/test_data/okokorecepten.nl/okokorecepten_2.testhtml @@ -0,0 +1,610 @@ + + + + + + + + + + + Dichtgeschroeide zalm met norisaus, gomasio en avocado - recept - okoko recepten + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + + +
    + +
    + + + +
    + + + + +
    + +
    +
    + + + + +
    + +
    + + +
    + +
    +
    + + + +
    + +

    Dichtgeschroeide zalm met norisaus, gomasio en avocado

    +
      +
    • 4 personen
    • +
    • 25 min
    • +
    • waardering 8,3
    • +
    +
      +
    • Hoofdgerecht
    • +
    • Japans
    • +
    • Vis
    • +
    +
    + +
    + + + +

    Ingrediënten

    +
      +
    • 600 g gekoelde zalmloin (zie tips onderaan het recept), in vier porties van 150 g
    • +
    • lichte slaolie
    • +
    • 2 avocado's
    • +
    • 2 eetlepels limoensap (of citroensap)
    • +
    • ¼ theelepel fijn geraspte limoenschil (of citroenschil)
    • +
    • 2 wortels, geschild, boven- en onderkant eraf, daarna in linten geschaafd
    • +
    +
      +
    • 100 g waterkers, alleen de topjes, gewassen
    • +
    • 4 eetlepels norisaus (zie onderaan het recept)
    • +
    • 4 eetlepels knapperig gebakken boekweit of geroosterde noten of pompoenpitten
    • +
    • voor de gomasio
    • +
    • 1 eetlepel geroosterde witte sesamzaadjes
    • +
    • ½ theelepel zoutvlokken
    • +
    + +
    + + +

    Voorbereiden

    +

    Zet een grote kom ijswater klaar. Haal de zalm uit de koelkast, dep die droog met keukenpapier, bestrijk elk stuk zalm met ½ theelepel olie en besprenkel het met een beetje zout.

    +

    Verhit een koekenpan met dikke bodem en antiaanbaklaag. Leg er een stuk zalm in als de pan begint te roken en bak de zalm 15 seconden. Draai deze daarna snel maar voorzichtig en schroei de zalm aan alle kanten dicht. Haal de zalm uit de pan en dompel die onder in het ijswater, zodat de zalm niet meer verder gaart. Bak de overige stukken zalm op dezelfde manier.

    +

    Haal de zalm voorzichtig uit het water als alle stukken er 4 minuten in ondergedompeld zijn geweest en dep ze droog op een theedoek. Zet ze afgedekt zo'n 6 uur in de koelkast voordat je het gerecht samenstelt.

    + +

    Bereiden

    +

    Maak de gomasio door de sesamzaadjes grof te stampen met een vijzel en stamper en daarna kort het zout erdoor te stampen zodat het een beetje grof blijft.

    +

    Verwijder vlak voor het serveren het vlees van de avocado's en snij dat in blokjes. Vermeng ze met de limoenschil en het limoensap. Voeg de wortel toe en hussel alles voorzichtig met een kwart van de gomasio.

    +

    Verdeel voor het serveren de salade over de borden en bestrooi met de waterkers. Snij de zalm in plakjes van 5 mm en leg die erbovenop. Lepel de norisaus erover en bestrooi het geheel daarna met de rest van de gomasio en de knapperige boekweit (of noten of pompoenpitten). Serveer op kamertemperatuur.

    + +

    Tips

    +

    'Je kunt alles behalve het dichtschroeien van de zalm al minstens een paar dagen van tevoren doen, dus met een goede planning kun je een gerecht maken dat eruitziet alsof het in een restaurant thuishoort. Om dit gerecht er werkelijk fantastisch uit te laten zien moet je het dikste deel van de zalmfilet gebruiken (zalmloin). Zorg ervoor dat er geen huid, graten of bloedlijn meer in zitten voor je begint. Het gerecht is ook heerlijk met tonijn. Gomasio is een Japans kruidenmengsel dat ik altijd bij de hand heb; goma is het Japanse woord voor sesam en shio is het woord voor zout (of getijde, zoals eb en vloed). Gomasio is dan ook een heerlijk mengsel van gestampte geroosterde sesamzaadjes en zoutvlokken dat veel minder zout bevat – en dat is beter voor de gezondheid.' - Peter Gordon

    + +

    Norisaus

    +

    Dit recept levert meer op dan je nodig hebt, maar de saus is lastig in kleine hoeveelheden te maken en blijft afgedekt in de koelkast 3 weken goed.

    +

    +

    30 g nori (circa 10 vellen van sushiformaat)

    +

    100 ml mirin

    +

    100 ml sake

    +

    75 ml (5 eetlepels) tamari (sojasaus zonder tarwe)

    +

    3 eetlepels rodewijnazijn

    +

    +

    Rooster de helft van de nori voorzichtig boven open vuur, in een koekenpan of onder een grill. Omdat nori net papier is, kan die vlam vatten, dus hou het in de gaten. De nori moet verkleuren van bijna zwart naar groen. Scheur (of knip met een schaar) de geroosterde en de niet-geroosterde norivellen in heel kleine stukjes. Doe alle vloeistoffen in een pan en breng ze aan de kook, verlaag het vuur en laat alles zachtjes doorkoken en roer de nori er geleidelijk door tot er een pasta-achtig mengsel ontstaat. Kook het 1 minuut onder voortdurend roeren. Mix het mengsel met een staafmixer tot een pasta, laat die dan afkoelen en bewaar de norisaus in de koelkast.

    + +
    + +
    + + + +
    +

    Kookboek

    +

    Het recept 'Dichtgeschroeide zalm met norisaus, gomasio en avocado' is afkomstig uit het kookboek...

    + + +

    Sensationele salades

    +

    Peter Gordon

    +
    +

    Chef Peter Gordon's salades met groente, granen, kaas, vlees of vis zijn stuk voor stuk een feest voor de zintuigen. De perfecte combinaties van smaken en... lees verder

    +

    © Unieboek Het Spectrum

    +
    + + +
    +

    Waardeer dit recept (3 stemmen)

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

    Zalm recept tips

    + +
    + + +
    + +
    +

    Reacties op dit recept

    +
      +
    • Er zijn nog geen reacties op dit recept. Wees de eerste!
    • +
    + +
    + + + + + +
    + +
    + + + + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/peelwithzeal.com/peelwithzeal_1.json b/tests/test_data/peelwithzeal.com/peelwithzeal_1.json index 1e5dc1474..195f8033b 100644 --- a/tests/test_data/peelwithzeal.com/peelwithzeal_1.json +++ b/tests/test_data/peelwithzeal.com/peelwithzeal_1.json @@ -12,7 +12,7 @@ "2 14-ounce cans pinto beans (drain 1 can only)", "2 14-ounce cans navy beans (drain 1 can only)", "1 cup beef stock", - "1/2 cup molasses ((not blackstrap))", + "1/2 cup molasses (not blackstrap)", "1/2 cup ketchup", "1/4 cup brown sugar", "2 tablespoons brown mustard", diff --git a/tests/test_data/preppykitchen.com/preppykitchen_1.json b/tests/test_data/preppykitchen.com/preppykitchen_1.json new file mode 100644 index 000000000..b8ddb2497 --- /dev/null +++ b/tests/test_data/preppykitchen.com/preppykitchen_1.json @@ -0,0 +1,61 @@ +{ + "author": "John Kanell", + "canonical_url": "https://preppykitchen.com/rocky-road-cookies/", + "site_name": "Preppy Kitchen", + "host": "preppykitchen.com", + "language": "en-US", + "title": "Rocky Road Cookies Recipe", + "ingredients": [ + "1⅔ cups all-purpose flour (200g)", + "½ cup cocoa powder (50g)", + "1 teaspoon baking soda", + "½ teaspoon salt", + "¾ cup unsalted butter (softened (168g)", + "¾ cup light brown sugar (165g)", + "⅓ cup granulated sugar (66g)", + "1 large egg (room temperature)", + "2 teaspoons vanilla extract", + "1 cup mini marshmallows (divided (56g)", + "¾ cup semi-sweet chocolate chips (135g)", + "½ cup almonds (chopped (75g)" + ], + "instructions_list": [ + "Preheat the oven to 350°F.", + "In a medium mixing bowl, whisk to combine the flour, cocoa powder, baking soda and salt.", + "In the bowl of a stand mixer fitted with the paddle attachment (or in a large bowl, using a handheld electric mixer), cream the butter, light brown sugar, and granulated sugars on medium speed for about 3 minutes until lightened in color and fluffy.", + "Add the egg and vanilla and mix for 30 seconds, just until combined.", + "Add the flour mixture in three parts, mixing on low speed just until combined between each addition. WIth a spatula, fold in ¾ cup of the marshmallows (40g), the chocolate chips and almonds.", + "Scoop 1½ tablespoon-sized cookies (about 32g each) with a triggered cookie scoop or two spoons, onto parchment lined baking sheets, leaving about 2 inches of space between each cookie. Gently press 2 to 3 of the remaining ¼ cup of marshmallows (16g) into the top of each cookie.", + "Bake for 8 to 10 minutes or until the edges are set and the tops appear dry. Let cool on the pan for 5 minutes, then transfer to a cooling rack to cool completely." + ], + "category": "Dessert", + "yields": "28 servings", + "description": "Rocky Road Cookies with gooey marshmallows, melty chocolate chips, and crunchy nuts are about to be your new favorite treat!", + "total_time": 20, + "cook_time": 10, + "prep_time": 10, + "cuisine": "American", + "equipment": [ + "Stand mixer or handheld electric mixer" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "157 kcal", + "fatContent": "9 g", + "saturatedFatContent": "4 g", + "unsaturatedFatContent": "4 g", + "transFatContent": "0.2 g", + "carbohydrateContent": "19 g", + "sugarContent": "11 g", + "proteinContent": "2 g", + "sodiumContent": "88 mg", + "fiberContent": "1 g", + "cholesterolContent": "20 mg" + }, + "image": "https://preppykitchen.com/wp-content/uploads/2024/12/Rocky-Road-Cookies-Recipe-Card.jpg", + "keywords": [ + "how to make rocky road cookies", + "rocky road cookies", + "rocky road cookies recipe" + ] +} diff --git a/tests/test_data/preppykitchen.com/preppykitchen_1.testhtml b/tests/test_data/preppykitchen.com/preppykitchen_1.testhtml new file mode 100644 index 000000000..51180b2f8 --- /dev/null +++ b/tests/test_data/preppykitchen.com/preppykitchen_1.testhtml @@ -0,0 +1,995 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Rocky Road Cookies Recipe - Preppy Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Footer

    +
    + +
    + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/preppykitchen.com/preppykitchen_2.json b/tests/test_data/preppykitchen.com/preppykitchen_2.json new file mode 100644 index 000000000..a9ea09877 --- /dev/null +++ b/tests/test_data/preppykitchen.com/preppykitchen_2.json @@ -0,0 +1,82 @@ +{ + "author": "John Kanell", + "canonical_url": "https://preppykitchen.com/mongolian-beef/", + "site_name": "Preppy Kitchen", + "host": "preppykitchen.com", + "language": "en-US", + "title": "Mongolian Beef Recipe", + "ingredients": [ + "⅓ cup soy sauce (80ml)", + "⅓ cup water (80ml)", + "⅓ cup light brown sugar (73g)", + "1 ½ tablespoons minced ginger", + "6 garlic cloves (minced)", + "1 pound flank steak (thinly sliced against the grain (450g)", + "⅓ cup cornstarch (37g)", + "3 tablespoons vegetable oil", + "10 dried red chilies (or ½ teaspoon crushed red pepper flakes), optional)", + "5 green onions (sliced into 1-inch pieces (2¾oucnes/80g)" + ], + "ingredient_groups": [ + { + "ingredients": [ + "⅓ cup soy sauce (80ml)", + "⅓ cup water (80ml)", + "⅓ cup light brown sugar (73g)", + "1 ½ tablespoons minced ginger", + "6 garlic cloves (minced)" + ], + "purpose": "For the Sauce" + }, + { + "ingredients": [ + "1 pound flank steak (thinly sliced against the grain (450g)", + "⅓ cup cornstarch (37g)", + "3 tablespoons vegetable oil", + "10 dried red chilies (or ½ teaspoon crushed red pepper flakes), optional)", + "5 green onions (sliced into 1-inch pieces (2¾oucnes/80g)" + ], + "purpose": "For the Beef" + } + ], + "instructions_list": [ + "For the Sauce:", + "In a medium bowl, whisk together the soy sauce, water, brown sugar, ginger, and garlic. Set aside.", + "For the Beef:", + "In a large bowl, toss the steak with the cornstarch until well coated.", + "In a large skillet or wok, heat the oil over medium-high heat. Shake the beef strips to remove excess cornstarch, and then add the beef to the skillet. Cook, stirring occasionally, until the beef is browned and mostly cooked through, 3 to 4 minutes. Transfer the beef to a large bowl.", + "With the skillet still over medium-high heat, add the sauce to the skillet and cook, stirring occasionally, scraping any browned bits from the bottom of the skillet with a spoon, until the sauce is thickened, about 3 minutes. Stir in the beef, red chilies (if using), and green onions.", + "Cook, stirring often, until the beef is well coated and the green onions are softened, about 1 minute. Serve immediately over rice." + ], + "category": "Main Course", + "yields": "4 servings", + "description": "Quick and savory Mongolian Beef is a restaurant favorite you can make at home in less 20 minutes! Tender and juicy flank steak is the perfect cut of meat to sear before being coated in a homemade sauce. Serve this family-friendly dish with rice and your favorite vegetable.", + "total_time": 20, + "cook_time": 10, + "prep_time": 10, + "cuisine": "Chinese", + "equipment": [ + "Mixing Bowls", + "Large skillet or wok" + ], + "nutrients": { + "servingSize": "1 serving", + "calories": "385 kcal", + "fatContent": "16 g", + "saturatedFatContent": "4 g", + "unsaturatedFatContent": "11 g", + "transFatContent": "0.1 g", + "carbohydrateContent": "33 g", + "sugarContent": "19 g", + "proteinContent": "27 g", + "sodiumContent": "1152 mg", + "fiberContent": "1 g", + "cholesterolContent": "68 mg" + }, + "image": "https://preppykitchen.com/wp-content/uploads/2024/12/Mongolian-Beef-Recipe-Card.jpg", + "keywords": [ + "how to make Mongolian Beef", + "Mongolian Beef", + "Mongolian Beef recipe" + ] +} diff --git a/tests/test_data/preppykitchen.com/preppykitchen_2.testhtml b/tests/test_data/preppykitchen.com/preppykitchen_2.testhtml new file mode 100644 index 000000000..aa5cbc71c --- /dev/null +++ b/tests/test_data/preppykitchen.com/preppykitchen_2.testhtml @@ -0,0 +1,958 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Easy Mongolian Beef Recipe - Preppy Kitchen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Footer

    +
    + +
    + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/rainbowplantlife.com/rainbowplantlife.json b/tests/test_data/rainbowplantlife.com/rainbowplantlife.json index 46600dc39..40dddab3d 100644 --- a/tests/test_data/rainbowplantlife.com/rainbowplantlife.json +++ b/tests/test_data/rainbowplantlife.com/rainbowplantlife.json @@ -10,9 +10,9 @@ "1/2 cup (75-85g) fresh blueberries", "1/3 cup (45g) brown sugar or coconut sugar", "1 teaspoon ground cinnamon", - "1/4 teaspoon nutmeg ((I recommend freshly grated nutmeg))", + "1/4 teaspoon nutmeg (I recommend freshly grated nutmeg)", "Scant 1/2 teaspoon ground ginger", - "2 pinches of ground cardamom ((optional))", + "2 pinches of ground cardamom (optional)", "10 tablespoons (140g) vegan butter*", "1 1/2 cups (180g) all-purpose flour", "Scant 2/3 cup (60g) (old-fashioned rolled oats)", @@ -21,8 +21,8 @@ "2 teaspoons baking powder", "1 1/3 cups (320 mL) full-fat oat milk***", "1 1/2 teaspoons pure vanilla extract", - "1/4 teaspoon pure almond extract ((optional))", - "For serving: vegan vanilla ice cream ((optional))" + "1/4 teaspoon pure almond extract (optional)", + "For serving: vegan vanilla ice cream (optional)" ], "instructions_list": [ "Arrange a rack in the middle of your oven and preheat it to 375°F/190°C.", diff --git a/tests/test_data/rainbowplantlife.com/rainbowplantlife_groups.json b/tests/test_data/rainbowplantlife.com/rainbowplantlife_groups.json index bd69ab8f8..122df7c1c 100644 --- a/tests/test_data/rainbowplantlife.com/rainbowplantlife_groups.json +++ b/tests/test_data/rainbowplantlife.com/rainbowplantlife_groups.json @@ -6,13 +6,13 @@ "language": "en", "title": "Vegan Pasta Salad", "ingredients": [ - "1 pound fusilli, (rotini, or penne rigate (a ridged pasta))", + "1 pound fusilli, (rotini, or penne rigate (a ridged pasta)", "1 cup (112g) raw walnuts", "5 ounces (140g) sourdough loaf, (baguette, or country-style bread, sliced)", "1 (12-ounce/340g) jar of roasted red bell peppers**, (drained from the liquid in the jar)", "3 garlic cloves, (roughly chopped)", - "1 medium lemon, (zested and juiced (3 tablespoons juice; save the zest for the Topping))", - "½ to 1 teaspoon smoked paprika ((use 1 teaspoon for prominent smokiness))", + "1 medium lemon, (zested and juiced (3 tablespoons juice; save the zest for the Topping)", + "½ to 1 teaspoon smoked paprika (use 1 teaspoon for prominent smokiness)", "½ teaspoon red pepper flakes", "1 teaspoon kosher salt, (plus more to taste)", "Freshly cracked black pepper to taste", @@ -22,14 +22,14 @@ "1 cup (16g) flat-leaf parsley, (finely chopped)", "1 ½ cups (24g) fresh basil, (finely chopped)", "3 tablespoons capers***, (chopped)", - "¼ teaspoon red pepper flakes ((optional) )", + "¼ teaspoon red pepper flakes (optional) )", "½ teaspoon flaky sea salt", "3 cups (60g) baby arugula, (chopped)" ], "ingredient_groups": [ { "ingredients": [ - "1 pound fusilli, (rotini, or penne rigate (a ridged pasta))" + "1 pound fusilli, (rotini, or penne rigate (a ridged pasta)" ], "purpose": null }, @@ -39,8 +39,8 @@ "5 ounces (140g) sourdough loaf, (baguette, or country-style bread, sliced)", "1 (12-ounce/340g) jar of roasted red bell peppers**, (drained from the liquid in the jar)", "3 garlic cloves, (roughly chopped)", - "1 medium lemon, (zested and juiced (3 tablespoons juice; save the zest for the Topping))", - "½ to 1 teaspoon smoked paprika ((use 1 teaspoon for prominent smokiness))", + "1 medium lemon, (zested and juiced (3 tablespoons juice; save the zest for the Topping)", + "½ to 1 teaspoon smoked paprika (use 1 teaspoon for prominent smokiness)", "½ teaspoon red pepper flakes", "1 teaspoon kosher salt, (plus more to taste)", "Freshly cracked black pepper to taste", @@ -55,7 +55,7 @@ "1 cup (16g) flat-leaf parsley, (finely chopped)", "1 ½ cups (24g) fresh basil, (finely chopped)", "3 tablespoons capers***, (chopped)", - "¼ teaspoon red pepper flakes ((optional) )", + "¼ teaspoon red pepper flakes (optional) )", "½ teaspoon flaky sea salt", "3 cups (60g) baby arugula, (chopped)" ], diff --git a/tests/test_data/recette.plus/recetteplus.json b/tests/test_data/recette.plus/recetteplus.json new file mode 100644 index 000000000..d33355883 --- /dev/null +++ b/tests/test_data/recette.plus/recetteplus.json @@ -0,0 +1,47 @@ +{ + "author": "sofie", + "canonical_url": "https://www.recette.plus/recettes/plat-principal/2330-pignons-de-poulet-a-la-creme.html", + "site_name": "Recette Plus : Découvrez toutes les recettes de cuisine française et du monde", + "host": "recette.plus", + "language": "fr", + "title": "Pignons de poulet à la crème", + "ingredients": [ + "1 Oignon jaune", + "2 Tomate", + "10 g Beurre", + "1 cuillère à soupe Huile d'olive", + "4 Pignons", + "20 cl Crème liquide" + ], + "instructions_list": [ + "Faites rôtir les pignons au four dans du beurre pendant 1 h.", + "Émincez l'oignon et faites-le revenir dans une poêle avec un peu d'huile d'olive et mettre de côté.", + "Une fois cuit, mettre les pignons de poulet dans la poêle avec le beurre, et les pignons qui sortent du four.", + "Ensuite ajoutez la crème, les tomates coupées en dés et les oignons cuits auparavant. Laissez mijoter 15 min le temps que les tomates se ramollissent.", + "Servir chaud accompagné par exemple de pommes de terre sautées." + ], + "category": "Plat principal", + "yields": "2 servings", + "total_time": 95, + "cook_time": 75, + "prep_time": 20, + "equipment": [ + "1 Four", + "1 Set 3 poêles", + "1 Dénoyauteur", + "1 Balance de cuisine" + ], + "image": "https://www.recette.plus/uploads/posts/2023-08/urecipes_d00e2528110cb18d8c3b33b0e0cf0b6a.webp", + "keywords": [ + "Pignons de poulet à la crème", + "oignon jaune", + "tomate", + "beurre", + "huile dolive", + "pignons", + "crème liquide", + "poulet en sauce", + "facile", + "bon marché" + ] +} diff --git a/tests/test_data/recette.plus/recetteplus.testhtml b/tests/test_data/recette.plus/recetteplus.testhtml new file mode 100644 index 000000000..2b098b989 --- /dev/null +++ b/tests/test_data/recette.plus/recetteplus.testhtml @@ -0,0 +1,2011 @@ + + + + Pignons de poulet à la crème + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + +
    + + + + + +
    +
    + + + + + + + + +
    + + + + + + + + + + +
    + + + + + + + + +
    + +
    + + + + + + + +
    + + + + +
    +
    + +
    + + +
    + + +
    +

    Ingrédients

    +
    + + +
    +
    + + +
    2 Personnes
    + + + +
    + +
    + + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + + + + + +
    + +
    + +
    +

    Ustensiles

    +
    + + +
      +
    • Four
      1 Four
    • + + +
    • Set 3 poêles
      1 Set 3 poêles
    • + + +
    • Dénoyauteur
      1 Dénoyauteur
    • + + +
    • Balance de cuisine
      1 Balance de cuisine
    • + +
    + + +
    + +
    +
    +

    Préparation

    +
    + + + + + + +
      +
    • +
      + +
      +
      + Temps de Preparation +
      +
      +
      20 min
      + +
      +
      + +
      +
    • +
    • +
      + +
      +
      + Repos +
      +
      +
      -
      + +
      +
      + +
      +
    • + +
    • +
      +
      +
      + Cuisson +
      +
      +
      75 min
      + +
      +
      +
      +
    • +
    + + + + + + + + + + + + +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + + + + + + + + + + +
    +
    +
    + + + + + + + +

    Recettes Suggérées

    +
    + + +
    + Recette +
    +
    +
    Méli-mélo dorzo et de verdure
    + +
    +
    + +
    + Recette +
    +
    +
    Pastèque pizza salée
    + +
    +
    + +
    + Recette +
    +
    +
    Tarte aux pignons et sa frangipane
    + +
    +
    + +
    + Recette +
    +
    +
    Tarte aux pommes, pignons et noisette
    + +
    +
    + +
    + Recette +
    +
    +
    Pennes au poulet, tomates séchées et pignons
    + +
    +
    + +
    + Recette +
    +
    +
    Poulet aigre-doux au four
    + +
    +
    + +
    + Recette +
    +
    +
    Poulet mariné façon Cricri
    + +
    +
    + +
    + Recette +
    +
    +
    Sauté de veau aux raisins et pignons
    + +
    +
    + +
    + Recette +
    +
    +
    spaghetti aux asperges, artichauts et pignons
    + +
    +
    + +
    + Recette +
    +
    +
    Velouté de courgettes aux pignons de pin
    + +
    +
    +
    +
    +
    + + +
    +
    Commentaires (0)
    +
    + +
    + + +
    +
    +
    +
    + + + +
    + + +
    +
    + + +
    +
    + +
    +
    +
    Il n'y a pas encore de commentaires. Vous pouvez être le premier!
    + +
    + +
    +
    + +
    + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/test_data/recipegirl.com/recipegirl_1.json b/tests/test_data/recipegirl.com/recipegirl_1.json index 9c666af3a..238ed7b3c 100644 --- a/tests/test_data/recipegirl.com/recipegirl_1.json +++ b/tests/test_data/recipegirl.com/recipegirl_1.json @@ -10,14 +10,14 @@ "1 tablespoon extra virgin olive oil", "2 tablespoons butter (divided)", "3 medium garlic cloves, (minced)", - "Three 6.5-ounce cans chopped clams, (drained (save the juice))", + "Three 6.5-ounce cans chopped clams, (drained (save the juice)", "¾ cup white wine", "½ medium lemon, (juiced)", "2 tablespoons chopped fresh Italian parsley", "¾ cup whipping cream", "salt and freshly ground black pepper, (to taste)", "grated Parmesan cheese for topping, (if desired)", - "½ medium lemon, (sliced for garnish (optional))" + "½ medium lemon, (sliced for garnish (optional)" ], "instructions_list": [ "Cook the pasta according to package directions. Make the sauce while the pasta is cooking.", diff --git a/tests/test_data/recipeland.com/recipeland_1.json b/tests/test_data/recipeland.com/recipeland_1.json new file mode 100644 index 000000000..5ac107c91 --- /dev/null +++ b/tests/test_data/recipeland.com/recipeland_1.json @@ -0,0 +1,45 @@ +{ + "author": "L-monti @ Recipeland", + "canonical_url": "https://recipeland.com/recipe/v/peanut-butter-pretzel-cookies-52124", + "site_name": "RecipeLand.com", + "host": "recipeland.com", + "language": "en", + "title": "Peanut Butter Pretzel Cookies", + "ingredients": [ + "1 ½ cups all-purpose flour", + "1 teaspoon baking soda", + "1 stick butter room temp.", + "½ stick butter flavored crisco", + "1 1/4 cup sugar", + "1 cup peanut butter", + "2 large eggs room temp.", + "6 cups pretzels crushed" + ], + "instructions_list": [ + "Preheat oven to 350℉ (180℃).", + "In a bowl, whisk together flour and baking soda.", + "In a large bowl, beat the butter, sugar, and peanut butter on medium speed, about five minutes.", + "Add the eggs, one at a time, beating between each addition.", + "Gradually add the flour mixture, beating just until combined.", + "Place crushed pretzels in a bowl.", + "Using a medium-sized cookie scoop, make balls of dough and drop them into the crushed pretzels, and coat.", + "Bake cookie for 10 to 15 minutes or until golden brown but soft to the touch." + ], + "yields": "30 servings", + "description": "Perfect mix of sweet and salty! Pretzels add crunch and bring out the peanutty flavor of the peanut butter.", + "total_time": 60, + "cook_time": 30, + "prep_time": 30, + "cuisine": "Fusion", + "ratings": 3.8, + "ratings_count": 153, + "nutrients": { + "calories": "150 calories" + }, + "image": "https://recipeland.com/images/r/3328/b0ba99dd45cba4e36ffe_1024.jpg", + "keywords": [ + "Cookies", + "Peanut Butter", + "Sweets" + ] +} diff --git a/tests/test_data/recipeland.com/recipeland_1.testhtml b/tests/test_data/recipeland.com/recipeland_1.testhtml new file mode 100644 index 000000000..8defa155d --- /dev/null +++ b/tests/test_data/recipeland.com/recipeland_1.testhtml @@ -0,0 +1,2874 @@ + + + + + + + + + + + + + + + + +Peanut Butter Pretzel Cookies Recipe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    + + +
    +
    +
    + + Search + +
    +
    +
    + + + by Ingredient
    +
    +
    +
    + +
    + + +
    +
    +
    +
    + + +
    +
    + +
    +
    + + + + + + + +
    +
    + +
    + + +
    + + + + +
    +
    + + + +
    + +
    + +
    +
    +

    Peanut Butter Pretzel Cookies

    +
    + + + + + + + + + + + +
    +
    StarStarStarHalf starEmpty star
    +
    +

    Your rating

    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    + +
    + + +
    + Peanut Butter Pretzel Cookies +
    + + + + +
    + + +
    +
    + L-monti - home chef
    +

    Perfect mix of sweet and salty! Pretzels add crunch and bring out the peanutty flavor of the peanut butter.

    +
     
    + +
    + + +
    +
    +
    +

    Yield

    + 30 + servings +
    +
    +

    Prep

    + 30 + min +
    +
    +

    Cook

    + 30 + min +
    +
    +

    Ready

    + 1 + hrs +
    +
    + +
    Trans-fat Free, Low Sodium
    +
    + + +
    +

    Ingredients

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AmountMeasureIngredientFeatures
    1 ½cups +all-purpose flour +
    +
    + + Camera +
    1teaspoon +baking soda +
    +
    + + Camera +
    1stick +butter +
    room temp. +
    + + Camera +
    ½stick +butter +
    flavored crisco +
    + + Camera +
    1 1/4 cup +sugar +
    +
    + + Camera +
    1cup +peanut butter +
    +
    + + Camera +
    2large +eggs +
    room temp. +
    + + Camera +
    6cups +pretzels +
    crushed +
    +* + +
    +
    +
    +

    Ingredients

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AmountMeasureIngredientFeatures
    + 355 + ml + all-purpose flour +
    +
    + + Camera +
    + 5 + ml + baking soda +
    +
    + + Camera +
    + 113 + g + butter +
    room temp. +
    + + Camera +
    + 56.5 + g + butter +
    flavored crisco +
    + + Camera +
    + 296 + ml + sugar +
    +
    + + Camera +
    + 237 + ml + peanut butter +
    +
    + + Camera +
    + 2 + large + eggs +
    room temp. +
    + + Camera +
    + 1.4 + l + pretzels +
    crushed +
    + * +
    +
    +
    + + +
    + + + + +
    +
    +

    Directions

    +

    Preheat oven to 350℉ (180℃).

    + +

    In a bowl, whisk together flour and baking soda.

    + +

    In a large bowl, beat the butter, sugar, and peanut butter on medium speed, about five minutes.

    + +

    Add the eggs, one at a time, beating between each addition.

    + +

    Gradually add the flour mixture, beating just until combined.

    + +

    Place crushed pretzels in a bowl.

    + +

    Using a medium-sized cookie scoop, make balls of dough and drop them into the crushed pretzels, and coat.

    + +

    Bake cookie for 10 to 15 minutes or until golden brown but soft to the touch.

    +
    +
    + + + + +
    + +
    + +
    + +
    + + +
    + + + +
    + * not incl. in nutrient facts + + Arrow up button +
    + +
    +

    Comments

    +
    +
    +
    +
    + recipeUser + + +
    +
    +

    Great recipe, thanks :)

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + recipeUser + + +
    +
    +

    Great recipe, thanks :)

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + anonymous + + +
    +
    +

    Could I use powdered sugar instead of regular sugar? I have a texture problem with regular sugar.

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + railrecipe + + +
    +
    +

    Peanut is always good for health. Your recipe of Peanut Butter Pretzel Cookies is nice. +
    https://www.railrecipe.com

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + Barth deRosa + + +
    +
    +

    Could I use backing powder instead of baking soda for this peanut butter pretzel cookies ? +

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + GF weir + + +
    +
    +

    Looks great . I will be making them.

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + Pinkerstar + + +
    +
    +

    Great recipe, thank you so much

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + anonymous + + +
    +
    +

    I took this recipe one step further, I melted some chocolate and poured over the tops of them.... When cookies have cooled I set them out on a large sheet of parchment paper,.. melted Hershey's Kisses in the Microwave and covered the tops of them, they came out great

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + Box lunches seattle + + +
    +
    +

    Discover the best meal kit from Box-lunches.com - fresh, delicious, and nutritious ingredients delivered right to your door. Enjoy the convenience of home-cooked meals without the hassle of grocery shopping.

    + +

    https://box-lunches.com/box-meals

    +
    + + +
    + Reply + +
    +
    +
    +
    +
    +
    + MenuValley + + +
    +
    +

    recipe is good for startups, and its test must be delicious. Let me know who is the lover of fast food like https://jackintheboxmenuprices.us/

    +
    + + +
    + Reply + +
    +
    +
    +
    + +
    + +

     

    + +
    +
    +

     

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

    Nutrition Facts

    +Serving Size 32g (1.1 oz) +
    +
    Amount per Serving
    +
    +Calories 15056% from fat +
    +
     % Daily Value *
    +
    +Total Fat 9g +14% +
    +
    +Saturated Fat 4g +20% +
    +
    +Trans Fat +0g +
    +
    +Cholesterol 26mg +9% +
    +
    +Sodium 95mg +4% +
    +
    +Total Carbohydrate +5g +5% +
    +
    +Dietary Fiber 1g +3% +
    +
    +Sugars g +
    +
    +Protein +7g +
    +
    +
    +Vitamin A 3% + +Vitamin C 0% +
    +
    +Calcium 1% + +Iron 3% +
    +
    +* based on a 2,000 calorie diet +How is this calculated? +
    +
    +
    + + + +
    + + + + + + +
    + + +
    + +
    + +
    +
     
    + + + + + + +
    +

    Email this recipe

    +
    +

    +
    +
    + +
    +
    + +
    + + + + + +
    +
    + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    +
    + Recipes by Recipeland logo +
    +
    + + +
    +
    + +
    +
    +

    About

    + +
    + +

    Founded in 1996, years before Google and the term blogger existed, RecipeLand.com™ was created to answer an elusive question faced by home cooks everywhere.

    + + Sean and Zhangbo Wenzel, Founders RecipeLand.com +

    What recipes can I make with these ingredients?

    + +

    Tired of buying ingredients for new recipes every time you cook? Imagine if you could type what ingredients you have into a recipe finder, and it would only show you recipes based on what you already have. No more wasted food, save time, save money.

    +

    Now you too can find recipes by ingredients and save your favorites in your own recipe box.

    +

    Fast-forward 28 years and Recipeland™ is a family affair, exclusively run by Sean, Zhangbo, and their daughter Keira.

    + +

    Save time

    + +

    RecipeLand, stands out from other recipe websites, many of which have been acquired by large corporations and turned into clickbait machines. Instead of bombarding you with endless scrolling before you get to recipes, you will find the tools you need to easily search and find the exact recipe you're looking for. Our goal is to make your recipe search process as efficient and enjoyable as possible.

    +

    Family owned and operated we are kept busy testing recipes in the RecipeLand.com kitchen and shooting photographs of the final main dish in the RecipeLand.com studio.

    +
    +
    + + +
    + +
    +
    +

    56,025

    + recipes +
    +
    +

    400+

    + collections  +
    +
    +

    152K

    + members +
    +
    +
    +
    +

    Send feedback

    +

    Tell us what you like, what you would like to see, bug reports and support questions are all welcome!

    +
    +
    + +
    +
    + +
    + +
    +
    + +
    + ©1996-2024 Sean Wenzel & Infinite Networks Inc. + All rights reserved. + Legal Privacy
    +
    +
    + + + + + + + diff --git a/tests/test_data/recipeland.com/recipeland_2.json b/tests/test_data/recipeland.com/recipeland_2.json new file mode 100644 index 000000000..0ddfe2ee3 --- /dev/null +++ b/tests/test_data/recipeland.com/recipeland_2.json @@ -0,0 +1,93 @@ +{ + "author": "RecipeLand", + "canonical_url": "https://recipeland.com/recipe/v/ropa-vieja-43426", + "site_name": "RecipeLand.com", + "host": "recipeland.com", + "language": "en", + "title": "Ropa Vieja", + "ingredients": [ + "2 pounds beef, flank steak (london broil)", + "1 each bay leaves", + "1 small onions", + "1 whole tomatoes ripe", + "1 each celery stalks", + "1 tablespoon salt", + "1 ¼ cups olive oil", + "½ each green bell peppers finely chopped", + "2 each garlic cloves minced", + "1 each bay leaves", + "½ teaspoon oregano", + "¼ teaspoon cumin", + "10 ½ ounces tomato sauce", + "¼ teaspoon sugar", + "1 tablespoon white wine vinegar", + "½ cup stock from cooked meat", + "1 teaspoon salt", + "¼ cup wine burgandy" + ], + "ingredient_groups": [ + { + "ingredients": [ + "2 pounds beef, flank steak (london broil)", + "1 each bay leaves", + "1 small onions", + "1 whole tomatoes ripe", + "1 each celery stalks", + "1 tablespoon salt" + ], + "purpose": null + }, + { + "ingredients": [ + "1 ¼ cups olive oil", + "½ each green bell peppers finely chopped", + "2 each garlic cloves minced", + "1 each bay leaves", + "½ teaspoon oregano", + "¼ teaspoon cumin", + "10 ½ ounces tomato sauce", + "¼ teaspoon sugar", + "1 tablespoon white wine vinegar", + "½ cup stock from cooked meat", + "1 teaspoon salt", + "¼ cup wine burgandy" + ], + "purpose": "Tomato sauce for ropa vieja" + } + ], + "instructions_list": [ + "In a suitable soup kettle, place the meat, bay leaf, whole onion, tomato, celery rib cut in half, and the salt.", + "Cover with cold water and bring to a rapid boil.", + "Skim several times.", + "Lower heat and cook until meat is tender (approximately 1 hour).", + "Allow meat to cool in stock, then remove to platter and shred.", + "Strain stock and reserve to be used in sauce and the rest for a hearty soup.", + "TOMATO SAUCE FOR ROPA VIEJA: Heat oil in large skillet.", + "Add onion and green pepper and sauté until transparent.", + "Add the garlic, bay leaf, oregano, cumin, and cook 5 minutes longer.", + "Combine tomato sauce, sugar, vinegar, stock, salt, and wine.", + "Add to sauté.", + "Stir to mix well and bring to a boil.", + "Lower heat and cook for approximately 30 minutes, stirring at intervals.", + "In a 2½ quart casserole with cover, place the shredded meat.", + "Pour sauce over the meat and mix well.", + "Cover and simmer for another 20 to 30 minutes, stirring occasionally.", + "Serve over white rice accompanied by very ripe fried plantains, when available." + ], + "category": "Main Dish", + "yields": "6 servings", + "total_time": 150, + "cook_time": 130, + "prep_time": 20, + "cuisine": "Fusion", + "ratings": 5.0, + "ratings_count": 2, + "nutrients": { + "calories": "650 calories" + }, + "image": "https://recipeland.com/images/r/9821/d89290e8de19f5bf9da3_1024.jpg", + "keywords": [ + "Rice", + "Meats" + ] +} diff --git a/tests/test_data/recipeland.com/recipeland_2.testhtml b/tests/test_data/recipeland.com/recipeland_2.testhtml new file mode 100644 index 000000000..c9e32fee4 --- /dev/null +++ b/tests/test_data/recipeland.com/recipeland_2.testhtml @@ -0,0 +1,2838 @@ + + + + + + + + + + + + + + + + + +Ropa Vieja Recipe | RecipeLand + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    + + +
    +
    +
    + + Search + +
    +
    +
    + + + by Ingredient
    +
    +
    +
    + +
    + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + + + + + + +
    +
    + +
    + + +
    + + + + +
    +
    + + + +
    + +
    + +
    +
    +

    Ropa Vieja

    +
    + + + + + + + + + + + +
    +
    StarStarStarStarStar
    +
    +

    Your rating

    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    + +
    + + +
    + Ropa Vieja +
    + + + + +
    + + +
    +
    + Ashley1234 - home chef
    +

    +
     
    +
    + + +
    +
    +
    +

    Yield

    + 6 + servings +
    +
    +

    Prep

    + 20 + min +
    +
    +

    Cook

    + 130 + min +
    +
    +

    Ready

    + 150 + min +
    +
    + +
    Trans-fat Free, Low Carb
    +
    + + +
    +

    Ingredients

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AmountMeasureIngredientFeatures
    2pounds +beef, flank steak (london broil) +
    +
    + + Camera +
    1each +bay leaves +
    +
    +* + Camera +
    1small +onions +
    +
    + + Camera +
    1whole +tomatoes +
    ripe +
    +* + Camera +
    1each +celery stalks +
    +
    + + Camera +
    1tablespoon +salt +
    +
    + + Camera +
    + Tomato sauce for ropa vieja +
    1 ¼cups +olive oil +
    +
    + + Camera +
    ½each +green bell peppers +
    finely chopped +
    + + Camera +
    2each +garlic cloves +
    minced +
    + + Camera +
    1each +bay leaves +
    +
    +* + Camera +
    ½teaspoon +oregano +
    +
    + + Camera +
    ¼teaspoon +cumin +
    +
    + + Camera +
    10 ½ounces +tomato sauce +
    +
    + + Camera +
    ¼teaspoon +sugar +
    +
    + + Camera +
    1tablespoon +white wine vinegar +
    +
    + + Camera +
    ½cup +stock +
    from cooked meat +
    + + Camera +
    1teaspoon +salt +
    +
    + + Camera +
    ¼cup +wine +
    burgandy +
    +* + Camera +
    +
    +
    +

    Ingredients

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AmountMeasureIngredientFeatures
    + 907.2 + g + beef, flank steak (london broil) +
    +
    + + Camera +
    + 1 + each + bay leaves +
    +
    + * + Camera +
    + 1 + small + onions +
    +
    + + Camera +
    + 1 + whole + tomatoes +
    ripe +
    + * + Camera +
    + 1 + each + celery stalks +
    +
    + + Camera +
    + 15 + ml + salt +
    +
    + + Camera +
    + Tomato sauce for ropa vieja +
    + 296 + ml + olive oil +
    +
    + + Camera +
    + 0.5 + each + green bell peppers +
    finely chopped +
    + + Camera +
    + 2 + each + garlic cloves +
    minced +
    + + Camera +
    + 1 + each + bay leaves +
    +
    + * + Camera +
    + 2.5 + ml + oregano +
    +
    + + Camera +
    + 1.3 + ml + cumin +
    +
    + + Camera +
    + 303.5 + ml/g + tomato sauce +
    +
    + + Camera +
    + 1.3 + ml + sugar +
    +
    + + Camera +
    + 15 + ml + white wine vinegar +
    +
    + + Camera +
    + 118 + ml + stock +
    from cooked meat +
    + + Camera +
    + 5 + ml + salt +
    +
    + + Camera +
    + 59 + ml + wine +
    burgandy +
    + * + Camera +
    +
    +
    + + +
    + + + + +
    +
    +

    Directions

    +

    In a suitable soup kettle, place the meat, bay leaf, whole onion, tomato, celery rib cut in half, and the salt.

    + +

    Cover with cold water and bring to a rapid boil.

    + +

    Skim several times.

    + +

    Lower heat and cook until meat is tender (approximately 1 hour).

    + +

    Allow meat to cool in stock, then remove to platter and shred.

    + +

    Strain stock and reserve to be used in sauce and the rest for a hearty soup.

    + +

    TOMATO SAUCE FOR ROPA VIEJA: Heat oil in large skillet.

    + +

    Add onion and green pepper and sauté until transparent.

    + +

    Add the garlic, bay leaf, oregano, cumin, and cook 5 minutes longer.

    + +

    Combine tomato sauce, sugar, vinegar, stock, salt, and wine.

    + +

    Add to sauté.

    + +

    Stir to mix well and bring to a boil.

    + +

    Lower heat and cook for approximately 30 minutes, stirring at intervals.

    + +

    In a 2½ quart casserole with cover, place the shredded meat.

    + +

    Pour sauce over the meat and mix well.

    + +

    Cover and simmer for another 20 to 30 minutes, stirring occasionally.

    + +

    Serve over white rice accompanied by very ripe fried plantains, when available.

    +
    +
    + + + + +
    + +
    + +
    + +
    + + +
    + + + +
    + * not incl. in nutrient facts + + Arrow up button +
    + +
    +

    Comments

    +
    +
    + +
    + +

     

    + +
    +
    +

     

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

    Nutrition Facts

    +Serving Size 307g (10.8 oz) +
    +
    Amount per Serving
    +
    +Calories 65074% from fat +
    +
     % Daily Value *
    +
    +Total Fat 54g +83% +
    +
    +Saturated Fat 9g +47% +
    +
    +Trans Fat +0g +
    +
    +Cholesterol 51mg +17% +
    +
    +Sodium 1681mg +70% +
    +
    +Total Carbohydrate +3g +3% +
    +
    +Dietary Fiber 1g +5% +
    +
    +Sugars g +
    +
    +Protein +69g +
    +
    +
    +Vitamin A 5% + +Vitamin C 28% +
    +
    +Calcium 6% + +Iron 18% +
    +
    +* based on a 2,000 calorie diet +How is this calculated? +
    +
    +
    + + + +
    + + + + + + +
    + +
    +
    +
    + +
    + +
    +
     
    + + + + + + +
    +

    Email this recipe

    +
    +

    +
    +
    + +
    +
    + +
    + + + + + +
    +
    + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    +
    + Recipes by Recipeland logo +
    +
    + + +
    +
    + +
    +
    +

    About

    + +
    + +

    Founded in 1996, years before Google and the term blogger existed, RecipeLand.com™ was created to answer an elusive question faced by home cooks everywhere.

    + + Sean and Zhangbo Wenzel, Founders RecipeLand.com +

    What recipes can I make with these ingredients?

    + +

    Tired of buying ingredients for new recipes every time you cook? Imagine if you could type what ingredients you have into a recipe finder, and it would only show you recipes based on what you already have. No more wasted food, save time, save money.

    +

    Now you too can find recipes by ingredients and save your favorites in your own recipe box.

    +

    Fast-forward 28 years and Recipeland™ is a family affair, exclusively run by Sean, Zhangbo, and their daughter Keira.

    + +

    Save time

    + +

    RecipeLand, stands out from other recipe websites, many of which have been acquired by large corporations and turned into clickbait machines. Instead of bombarding you with endless scrolling before you get to recipes, you will find the tools you need to easily search and find the exact recipe you're looking for. Our goal is to make your recipe search process as efficient and enjoyable as possible.

    +

    Family owned and operated we are kept busy testing recipes in the RecipeLand.com kitchen and shooting photographs of the final main dish in the RecipeLand.com studio.

    +
    +
    + + +
    + +
    +
    +

    56,029

    + recipes +
    +
    +

    400+

    + collections  +
    +
    +

    152K

    + members +
    +
    +
    +
    +

    Send feedback

    +

    Tell us what you like, what you would like to see, bug reports and support questions are all welcome!

    +
    +
    + +
    +
    + +
    + +
    +
    + +
    + ©1996-2024 Sean Wenzel & Infinite Networks Inc. + All rights reserved. + Legal Privacy
    +
    +
    + + + + + + + diff --git a/tests/test_data/recipetineats.com/recipetineats_1.json b/tests/test_data/recipetineats.com/recipetineats_1.json index d7db858ee..8b8b86d79 100644 --- a/tests/test_data/recipetineats.com/recipetineats_1.json +++ b/tests/test_data/recipetineats.com/recipetineats_1.json @@ -6,8 +6,8 @@ "language": "en-US", "title": "Crispy potato straws (Pommes Paille)", "ingredients": [ - "1 potato ((Aus: Sebago, US: russet, UK: Maris Piper), or other starchy or all-rounder potato (Note 1))", - "1 1/2 - 2 cups vegetable oil ((canola, sunflower or peanut oil))", + "1 potato (Aus: Sebago, US: russet, UK: Maris Piper), or other starchy or all-rounder potato (Note 1)", + "1 1/2 - 2 cups vegetable oil (canola, sunflower or peanut oil)", "Sea salt flakes (, crushed with fingers into a powder)" ], "instructions_list": [ diff --git a/tests/test_data/recipetineats.com/recipetineats_2.json b/tests/test_data/recipetineats.com/recipetineats_2.json index 60c221d24..b0d85fd08 100644 --- a/tests/test_data/recipetineats.com/recipetineats_2.json +++ b/tests/test_data/recipetineats.com/recipetineats_2.json @@ -8,9 +8,9 @@ "ingredients": [ "1/2 cup / 100g brown sugar, tightly packed", "1 tbsp water", - "1 kg / 2 lb pork shoulder ((butt) or boneless skinless pork belly, cut into 3 cm / 1.2\" pieces (Note 1a))", - "1.5 cups / 375 ml coconut water ((Note 1b))", - "1 eschallot / shallot (, very finely sliced (Note 2))", + "1 kg / 2 lb pork shoulder (butt) or boneless skinless pork belly, cut into 3 cm / 1.2\" pieces (Note 1a)", + "1.5 cups / 375 ml coconut water (Note 1b)", + "1 eschallot / shallot (, very finely sliced (Note 2)", "2 garlic cloves (, minced)", "1 1/2 tbsp fish sauce", "1/4 tsp white pepper", @@ -21,9 +21,9 @@ "ingredients": [ "1/2 cup / 100g brown sugar, tightly packed", "1 tbsp water", - "1 kg / 2 lb pork shoulder ((butt) or boneless skinless pork belly, cut into 3 cm / 1.2\" pieces (Note 1a))", - "1.5 cups / 375 ml coconut water ((Note 1b))", - "1 eschallot / shallot (, very finely sliced (Note 2))", + "1 kg / 2 lb pork shoulder (butt) or boneless skinless pork belly, cut into 3 cm / 1.2\" pieces (Note 1a)", + "1.5 cups / 375 ml coconut water (Note 1b)", + "1 eschallot / shallot (, very finely sliced (Note 2)", "2 garlic cloves (, minced)", "1 1/2 tbsp fish sauce", "1/4 tsp white pepper" diff --git a/tests/test_data/redhousespice.com/redhousespice_2.json b/tests/test_data/redhousespice.com/redhousespice_2.json index 4549cecd7..0b1078403 100644 --- a/tests/test_data/redhousespice.com/redhousespice_2.json +++ b/tests/test_data/redhousespice.com/redhousespice_2.json @@ -6,7 +6,7 @@ "language": "en-US", "title": "Smashed Cucumber Salad (拍黄瓜)", "ingredients": [ - "1 large cucumber (or 2 small ones (about 350g/12oz))", + "1 large cucumber (or 2 small ones (about 350g/12oz)", "¼ tsp salt", "2 cloves garlic (minced)", "1 tbsp light soy sauce", diff --git a/tests/test_data/rewe.de/rewe.json b/tests/test_data/rewe.de/rewe.json index ab5e5d8ba..ab14bce3f 100644 --- a/tests/test_data/rewe.de/rewe.json +++ b/tests/test_data/rewe.de/rewe.json @@ -36,7 +36,18 @@ "yields": "4", "description": "Wir treiben es gerne bunt! Starte auch du mit einer ausgewogenen Familien-Mahlzeit durch. Hol dir das REWE Rezept für Wintergemüse-Gnocchi-Pfanne & Kräuterdip.", "total_time": 45, - "ratings": 4.63, - "ratings_count": 35, - "image": "https://c.rewe-static.de/31535699/6/31535699.png" + "ratings": 4.69, + "ratings_count": 42, + "nutrients": { + "servingSize": "4 Portionen", + "calories": "677 kcal" + }, + "image": "https://c.rewe-static.de/31535699/6/31535699.png", + "keywords": [ + "Vegetarisch", + "Winter", + "Party", + "Dip", + "gesund" + ] } diff --git a/tests/test_data/rewe.de/rewe.testhtml b/tests/test_data/rewe.de/rewe.testhtml index 3ac4ff764..35e6fa48d 100644 --- a/tests/test_data/rewe.de/rewe.testhtml +++ b/tests/test_data/rewe.de/rewe.testhtml @@ -1,4 +1,4 @@ -Wintergemüse-Gnocchi-Pfanne mit Kräuterdip Rezept - REWE.de
    • 800 g +
      REWE Beste Wahl Gnocchi (Kühlregal)
    • 0  +
      Salz
    • 2  +
      rote Zwiebeln
    • 0.5  +
      Spitzkohl
    • 2  +
      Möhren
    • 1 Stange(n) +
      Lauch
    • 1  +
      Rote Bete (frisch)
    • 50 g +
      REWE Beste Wahl aromatische Walnüsse
    • 2 EL +
      Rohrzucker
    • 0.5 Bd. +
      Schnittlauch
    • 0.5 Bd. +
      Petersilie
    • 400 g +
      Quark (Halbfettstufe)
    • 0  +
      Pfeffer
    • 0  +
      Zitronensaft
    • 1 Prise(n) +
      Zucker
    • 3 EL +
      Rapsöl
    • 0  +
      Muskatnuss

    Utensilien

    Sparschäler, Hobel,

    Utensilien

    Sparschäler, Hobel,

    Sammel Euros mit REWE Bonus

    Lös dieses Guthaben jederzeit ein und spar beim Einkaufen

    Leg gleich los und sicher dir deinen 5 € Start-Bonus

    Gib uns dein Feedback

    Hast du Feedback für unsere Redaktion? Hier kannst du uns Feedback zum Rezept geben.

    Gib uns dein Feedback

    Hast du Feedback für unsere Redaktion? Hier kannst du uns Feedback zum Rezept geben.

    Bewertungen mit Kommentar

    Hat's geschmeckt? Sag uns, wie dir unser Rezept gefallen hat.
    Dieses Rezept wurde noch nicht kommentiert, mit deiner Bewertung mit Kommentar hilfst du anderen dabei, schneller zu finden, was sie mögen.
    Du kannst deine Bewertung kommentieren, wenn du dich anmeldest.

    Bewertungen mit Kommentar

    Hat's geschmeckt? Sag uns, wie dir unser Rezept gefallen hat.
    Dieses Rezept wurde noch nicht kommentiert, mit deiner Bewertung mit Kommentar hilfst du anderen dabei, schneller zu finden, was sie mögen.
    Du kannst deine Bewertung kommentieren, wenn du dich anmeldest.
    Frittata mit Feldsalat
    • Glutenfrei
    1h 5min
    Einfach
    Gemüse-Crumble
    3 Zutaten im Angebot
    • Vegetarisch
    45min
    Einfach
    Rhabarber-Galettes mit Ziegenkäse
    1 Zutat im Angebot
    Grün-weißer Spargel-Reissalat mit Zitronen-Vinaigrette
    1 Zutat im Angebot
    • Wenig Zucker
    • Vegetarisch
    • Glutenfrei
    45min
    Einfach

    Frittata mit Feldsalat
    • Glutenfrei
    1h 5min
    Einfach
    Gemüse-Crumble
    • Vegetarisch
    45min
    Einfach
    Grün-weißer Spargel-Reissalat mit Zitronen-Vinaigrette
    • Vegetarisch
    • Glutenfrei
    • Wenig Zucker
    45min
    Einfach

    Thunfisch Mousse
      15min
      Einfach
      Kartoffel-Wirsing-Taler mit Frischkäse-Dip
      • Vegetarisch
      • Kalorienarm
      1h 5min
      Einfach
      Gemüse-Rösti
      • Vegetarisch
      • Glutenfrei
      45min
      Einfach
      Herbstliches Ofengemüse mit Dip
      • Vegetarisch
      • Glutenfrei
      • Kalorienarm
      1h 10min
      Einfach