recipe_scraper 1.0.1 copy "recipe_scraper: ^1.0.1" to clipboard
recipe_scraper: ^1.0.1 copied to clipboard

A Dart package that allows you to scrape recipe data from websites using JSON-LD structured data (schema.org Recipe markup).

Recipe Scraper #

A Dart package that allows you to scrape recipe data from websites using JSON-LD structured data. This package can be used in any Dart or Flutter project. It extracts comprehensive recipe information including ingredients, instructions, nutrition facts, and more from recipe websites that implement schema.org Recipe markup.

Features #

  • πŸ” Automatic Recipe Detection: Scrapes recipes from any website using JSON-LD structured data
  • 🍳 Comprehensive Data Extraction: Extracts all recipe details including:
    • Title, description, and images
    • Ingredients with automatic parsing (quantity, unit, name)
    • Step-by-step instructions
    • Nutrition information (calories, protein, carbs, fat, etc.)
    • Cooking times (prep, cook, total)
    • Servings and ratings
    • Keywords and dietary restrictions
  • πŸ₯— Diet Support: Recognizes restricted diets (vegan, vegetarian, gluten-free, etc.)
  • πŸ“Š Structured Data Models: Type-safe models for Recipe, Ingredient, and RestrictedDiet
  • 🌐 Wide Compatibility: Works with any website implementing schema.org Recipe markup

Installation #

Add the following dependency to your pubspec.yaml file:

dependencies:
  recipe_scraper: ^1.0.1

Then, run dart pub get (for Dart projects) or flutter pub get (for Flutter projects) to install the package.

Usage #

Basic Recipe Scraping #

Import the recipe_scraper package and use the scrapeRecipe() function to extract recipe data from a URL:

import 'package:recipe_scraper/recipe_scraper.dart';

// Scrape a recipe from a URL
final recipe = await scrapeRecipe('https://example.com/recipe-page');

if (recipe != null) {
  print('Title: ${recipe.title}');
  print('Description: ${recipe.description}');
  print('Servings: ${recipe.servings}');
  print('Total Time: ${recipe.totalTime}');
} else {
  print('No recipe found at this URL');
}

Accessing Recipe Details #

final recipe = await scrapeRecipe('https://example.com/recipe-page');

if (recipe != null) {
  // Basic information
  print('Title: ${recipe.title}');
  print('Description: ${recipe.description}');
  print('Rating: ${recipe.rating}');
  print('Keywords: ${recipe.keywords.join(", ")}');

  // Images
  if (recipe.imageUrls.isNotEmpty) {
    print('Main image: ${recipe.imageUrls.first}');
  }

  // Servings and timing
  print('Servings: ${recipe.servings} ${recipe.servingsType ?? ""}');
  print('Prep time: ${recipe.prepTime}');
  print('Cook time: ${recipe.cookTime}');
  print('Total time: ${recipe.totalTime}');
}

Working with Ingredients #

The package automatically parses ingredient strings into structured data:

final recipe = await scrapeRecipe('https://example.com/recipe-page');

if (recipe != null) {
  for (final ingredient in recipe.ingredients) {
    print('${ingredient.quantity} ${ingredient.unit ?? ""} ${ingredient.name}');
    // Example output: "2 cups flour"
  }
}

Accessing Instructions #

final recipe = await scrapeRecipe('https://example.com/recipe-page');

if (recipe != null) {
  print('Instructions:');
  for (var i = 0; i < recipe.instructions.length; i++) {
    print('${i + 1}. ${recipe.instructions[i]}');
  }
}

Nutrition Information #

final recipe = await scrapeRecipe('https://example.com/recipe-page');

if (recipe != null) {
  print('Nutrition Facts:');
  if (recipe.calories != null) print('Calories: ${recipe.calories}');
  if (recipe.protein != null) print('Protein: ${recipe.protein}g');
  if (recipe.carbohydrates != null) print('Carbs: ${recipe.carbohydrates}g');
  if (recipe.fat != null) print('Fat: ${recipe.fat}g');
  if (recipe.saturatedFat != null) print('Saturated Fat: ${recipe.saturatedFat}g');
  if (recipe.sugar != null) print('Sugar: ${recipe.sugar}g');
  if (recipe.fiber != null) print('Fiber: ${recipe.fiber}g');
  if (recipe.sodium != null) print('Sodium: ${recipe.sodium}mg');
}

Checking Dietary Restrictions #

final recipe = await scrapeRecipe('https://example.com/recipe-page');

if (recipe != null && recipe.restrictedDiets != null) {
  for (final diet in recipe.restrictedDiets!) {
    print('Suitable for: ${diet.name}');
  }

  // Check for specific diet
  if (recipe.restrictedDiets!.contains(RestrictedDiet.veganDiet)) {
    print('This recipe is vegan!');
  }
}

Serialization #

The Recipe model supports JSON serialization:

final recipe = await scrapeRecipe('https://example.com/recipe-page');

if (recipe != null) {
  // Convert to JSON
  final json = recipe.toJson();

  // Convert to Map
  final map = recipe.toMap();

  // Recreate from Map
  final recipeFromMap = Recipe.fromMap(map);
}

How It Works #

The package works by:

  1. Fetching the HTML content from the provided URL
  2. Parsing the HTML to find <script type="application/ld+json"> tags
  3. Extracting JSON-LD structured data that follows the schema.org Recipe format
  4. Parsing the structured data into type-safe Dart models

This approach works with most modern recipe websites that implement proper structured data markup, including popular sites like AllRecipes, Food Network, Bon AppΓ©tit, and many more.

Requirements #

  • Dart SDK: ^3.1.3
  • No Flutter-specific dependencies (works with pure Dart projects too!)

Supported Platforms #

This package works on all Dart/Flutter platforms:

  • βœ… Android: Works out of the box
  • βœ… iOS: Works out of the box
  • βœ… Desktop (Windows, macOS, Linux): Works out of the box
  • ⚠️ Web: Works with limitations (see below)

Web Platform Note #

When using this package on the web platform, you will encounter CORS (Cross-Origin Resource Sharing) errors when trying to fetch recipes from external websites. This is a browser security feature that prevents web pages from making requests to different domains.

Solution: You need to use a proxy server to fetch the recipe data. You can:

  1. Set up your own proxy server that forwards requests
  2. Use a CORS proxy service (for development/testing only)
  3. Fetch the recipe data from your backend server instead of directly from the client

Example with a proxy:

// Instead of directly fetching from the recipe URL:
final recipe = await scrapeRecipe('https://example.com/recipe');

// Use your proxy server:
final recipe = await scrapeRecipe('https://your-proxy.com/fetch?url=https://example.com/recipe');

Limitations #

  • Only works with websites that implement JSON-LD structured data using schema.org Recipe markup
  • Ingredient parsing may not be perfect for all formats
  • Some websites may have incomplete structured data
  • Web Platform: When running on web, you may encounter CORS (Cross-Origin Resource Sharing) errors. To resolve this, you'll need to use a proxy server to fetch the recipe data. This is a browser security limitation and cannot be bypassed directly from the client side.

Contributing #

Contributions are welcome! Please feel free to submit issues or pull requests on GitHub.

License #

This project is licensed under the BSD-3-Clause License - see the LICENSE file for details.

About #

Created to make recipe scraping simple and reliable for Flutter/Dart applications. Perfect for building recipe apps, meal planners, or cooking assistants!

1
likes
140
points
141
downloads

Publisher

unverified uploader

Weekly Downloads

A Dart package that allows you to scrape recipe data from websites using JSON-LD structured data (schema.org Recipe markup).

Repository (GitHub)
View/report issues

Topics

#recipe #scraper #json-ld #schema

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

html, http

More

Packages that depend on recipe_scraper