diff --git a/README.md b/README.md index e1ce729..ba79d2f 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,12 @@ recipeScraper("some.recipe.url").then(recipe => { - https://www.nomnompaleo.com/ - https://www.omnivorescookbook.com/ - https://pinchofyum.com/ +- https://recipetineats.com/ - https://www.seriouseats.com/ - https://www.simplyrecipes.com/ - https://smittenkitchen.com/ - https://thepioneerwoman.com/ +- https://tastesbetterfromscratch.com/ - https://therealfoodrds.com/ - https://www.thespruceeats.com/ - https://whatsgabycooking.com/ diff --git a/scrapers/index.js b/scrapers/index.js index afd65f1..c5d3ad8 100644 --- a/scrapers/index.js +++ b/scrapers/index.js @@ -26,6 +26,7 @@ const domains = { nomnompaleo: require("./nomnompaleo"), omnivorescookbook: require("./omnivorescookbook"), pinchofyum: require("./pinchofyum"), + recipetineats: require("./recipetineats"), seriouseats: require("./seriouseats"), simplyrecipes: require("./simplyrecipes"), smittenkitchen: require("./smittenkitchen"), diff --git a/scrapers/recipetineats.js b/scrapers/recipetineats.js new file mode 100644 index 0000000..8c0cbda --- /dev/null +++ b/scrapers/recipetineats.js @@ -0,0 +1,76 @@ +const request = require("request"); +const cheerio = require("cheerio"); + +const RecipeSchema = require("../helpers/recipe-schema"); + +const recipeTinEats = url => { + const Recipe = new RecipeSchema(); + return new Promise((resolve, reject) => { + if (!url.includes("recipetineats.com/")) { + reject(new Error("url provided must include 'recipetineats.com/'")); + } else { + request(url, (error, response, html) => { + if (!error && response.statusCode === 200) { + const $ = cheerio.load(html); + const body = $(".wprm-recipe-container"); + + Recipe.image = $("meta[property='og:image']").attr("content"); + Recipe.name = $("meta[property='og:title']").attr("content"); + + $(".wprm-recipe-ingredient").each((i, el) => { + Recipe.ingredients.push( + $(el) + .text() + .replace(/\s\s+/g, " ") + .replace("▢", "") + .trim() + ); + }); + + $(".wprm-recipe-instruction-group").each((i, el) => { + Recipe.instructions.push( + $(el) + .children(".wprm-recipe-group-name") + .text() + ); + $(el) + .find(".wprm-recipe-instruction-text") + .each((i, elChild) => { + Recipe.instructions.push($(elChild).text()); + }); + }); + + $(".wprm-recipe-time-container").each((i, el) => { + let text = $(el).text(); + if (text.includes("Prep:")) { + Recipe.time.total = text.replace("Prep:", "").trim(); + } else if (text.includes("Cook:")) { + Recipe.time.prep = text.replace("Cook:", "").trim(); + } else if (text.includes("Total:")) { + Recipe.time.cook = text.replace("Total:", "").trim(); + } + }); + + Recipe.servings = $(".wprm-recipe-time") + .first() + .text() + .trim(); + + if ( + !Recipe.name || + !Recipe.ingredients.length || + !Recipe.instructions.length + ) { + reject(new Error("No recipe found on page")); + } else { + resolve(Recipe); + } + } else { + reject(new Error("No recipe found on page")); + } + }); + } + }); +}; + +module.exports = recipeTinEats; diff --git a/test/constants/recipetineatsConstants.js b/test/constants/recipetineatsConstants.js new file mode 100644 index 0000000..7393b61 --- /dev/null +++ b/test/constants/recipetineatsConstants.js @@ -0,0 +1,63 @@ +module.exports = { + testUrl: + "https://www.recipetineats.com/dan-dan-noodles-spicy-sichuan-noodles/", + invalidUrl: "https://www.recipetineats.com/notarealurl", + invalidDomainUrl: "www.invalid.com", + nonRecipeUrl: "https://www.recipetineats.com/nagi-recipetin-eats/", + expectedRecipe: { + name: "Dan Dan Noodles (Spicy Sichuan noodles)", + ingredients: [ + "2 tbsp Chinese sesame sauce (sub tahini, Note 1)", + "1.5 tbsp Chinese chilli paste in oil , adjust spiciness (Note 2)", + "4 tbsp light soy sauce (Note 3)", + "2 garlic cloves , minced", + "3 tsp white sugar", + "1/2 tsp Chinese five spice powder (Note 4)", + "1 tsp Sichuan pepper powder , preferably freshly ground (Note 5)", + "3 tbsp (or more!) chilli oil , preferably Chinese (Note 6)", + "3/4 cup (185ml) chicken broth/stock , hot, low sodium", + "2 tsp Hoisin sauce", + "1 tsp dark soy sauce (Note 7)", + "1 tbsp Chinese cooking wine (sub 2 tbsp extra chicken stock)", + "1/2 tsp Chinese five spice powder (Note 4)", + "1 tbsp vegetable oil", + "250g/ 8oz pork mince (ground pork)", + "1 tsp vegetable oil", + "30g (1/4 cup) Sui Mi Ya Cai (preserved mustard greens) , finely chopped (Note 8)", + "500g/1lb white fresh noodles , medium thickness (Note 9)", + "16 choy sum stems , cut into 15cm pieces", + "2 green onions , finely sliced", + "1 tbsp peanuts , finely chopped (optional)" + ], + instructions: [ + "Dan Dan Sauce:", + "Mix all ingredients except oil and chicken stock. Then gently stir in oil and stock - oil should be sitting on surface. Set aside.", + "Pork:", + 'Mix together hoisin, soy, Chinese wine and five spice ("Sauce").', + "Heat oil in a skillet or wok over high heat. Add pork and cook, breaking it up as you, until it changes from pink to white. Add Sauce and cook for 1 minute, then transfer into a bowl.", + "Sui mi ya cai (preserved mustard greens):", + "Return skillet to stove, reduce to medium heat. Add oil into middle of skillet.", + "Add Sui mi ya cai and stir for 30 seconds, just to warm through. Set aside.", + "Noodles & choi sum:", + "Bring a large pot of water to the boil. Cook noodles per packet directions.", + "Add choi sum for last 1 minute of cooking.", + "Drain.", + "Assemble:", + "Ladle 1/4 of Dan Dan Sauce into a bowl. Pile in noodles, top with pork and Sui mi ya cai. Place choi sum on side.", + "Sprinkle with peanuts and green onions and serve.", + "To eat, mix it all up to coat the noodles well with Sauce, then devour!" + ], + tags: [], + time: { + prep: "15 mins", + cook: "", + active: "", + inactive: "", + ready: "", + total: "15 mins" + }, + servings: "15 mins", + image: + "https://www.recipetineats.com/wp-content/uploads/2020/02/Dan-Dan-Noodles_4-2.jpg" + } +}; diff --git a/test/recipetineats.test.js b/test/recipetineats.test.js new file mode 100644 index 0000000..e69de29