chez-grater-0.0.2: src/Chez/Grater/Scraper/Site.hs
-- |Description: Ingredient and step scrapers for all the websites we know about.
module Chez.Grater.Scraper.Site
( allScrapers, debugI, debugS
) where
import Chez.Grater.Internal.Prelude
import Chez.Grater.Scraper.Types
( IngredientScraper(..), ScrapeMeta(..), ScrapeName(..), ScrapeVersion(..), ScrapedIngredient(..)
, ScrapedStep(..), Scrapers(..), SiteName(..), StepScraper(..), inception
)
import Data.Function (on)
import Text.HTML.Scalpel ((//), (@:), (@=), Scraper, Selector)
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as Text
import qualified Text.HTML.Scalpel as Scalpel
allScrapers :: Scrapers
allScrapers = Scrapers ingredientScrapers allIngredientScrapers stepScrapers allStepScrapers
ingredientScrapers :: HashMap SiteName IngredientScraper
ingredientScrapers = HashMap.fromList
[ ("allrecipes.com", allrecipesI)
, ("cooking.nytimes.com", nytimesI)
, ("food.com", geniusKitchen2I)
, ("geniuskitchen.com", geniusKitchen1I)
, ("tasteofhome.com", geniusKitchen1I)
, ("rachlmansfield.com", tastyI2)
, ("cookieandkate.com", tastyI1)
, ("simpleveganblog.com", tastyI1)
, ("eatyourselfskinny.com", tastyI1)
, ("lexiscleankitchen.com", tastyI2)
, ("sallysbakingaddiction.com", tastyI2)
, ("gimmesomeoven.com", tastyI2)
, ("pinchofyum.com", tastyI2)
, ("alexandracooks.com", tastyI3)
, ("naturallyella.com", tastyI3)
, ("brownedbutterblondie.com", tastyI3)
, ("foodnetwork.com", foodNetworkI)
, ("cafedelites.com", wprmI)
, ("budgetbytes.com", wprmI)
, ("daringgourmet.com", wprmI)
, ("recipetineats.com", wprmI)
, ("cookingclassy.com", wprmI)
, ("natashaskitchen.com", wprmI)
, ("justonecookbook.com", wprmI)
, ("loveandlemons.com", wprmI)
, ("foodiecrush.com", wprmI)
, ("therecipecritic.com", wprmI)
, ("ambitiouskitchen.com", wprmI)
, ("halfbakedharvest.com", wprmI)
, ("ohsweetbasil.com", wprmI)
, ("myfoodstory.com", wprmI)
, ("easypeasyfoodie.com", wprmI)
, ("veganricha.com", wprmI)
, ("simplydeliciousfood.com", wprmI)
, ("deliciouseveryday.com", wprmI)
, ("iamafoodblog.com", wprmI)
, ("thelastfoodblog.com", wprmI)
, ("thefoodblog.net", wprmI)
, ("onceuponafoodblog.com", wprmI)
, ("anotherfoodblogger.com", wprmI)
, ("minimalistbaker.com", wprmI)
, ("davidlebovitz.com", wprmI)
, ("skinnytaste.com", wprmI)
, ("twopeasandtheirpod.com", wprmI)
, ("sweetandsavorymeals.com", wprmI)
, ("melskitchencafe.com", wprmI)
, ("glutenfreecuppatea.co.uk", wprmI)
, ("101cookbooks.com", cb101I)
, ("bakerella.com", mvI)
, ("localmilkblog.com", zlI)
, ("smittenkitchen.com", jetpackI)
, ("eatingwell.com", eatingWellI)
, ("bhg.com", eatingWellI)
, ("yummly.com", yummlyI)
, ("simplyrecipes.com", simplyRecipesI)
, ("seriouseats.com", simplyRecipesI)
, ("bettycrocker.com", ingredientLi1)
, ("pillsbury.com", ingredientLi1)
, ("tasty.co", ingredientLi1)
, ("lazycatkitchen.com", ingredientLi2)
, ("deliciouslyella.com", ingredientLi3)
, ("cookingandcooking.com", ingredientLi5)
, ("damndelicious.net", ingredientLi6)
, ("hemsleyandhemsley.com", ingredientLi6)
, ("slenderkitchen.com", ingredientLi7)
, ("everydayannie.com", ingredientLi8)
, ("notwithoutsalt.com", ingredientLi9)
, ("chefspencil.com", ingredientLi10)
, ("shutterbean.com", ingredientLi11)
, ("uitpaulineskeuken.nl", ingredientLi13)
, ("leukerecepten.nl", ingredientLi14)
, ("wsj.com", ingredientLi15)
, ("delish.com", delishI)
, ("thepioneerwoman.com", delishI)
-- , ("epicurious.com", epicuriousI)
, ("spoonacular.com", spoonacularI)
, ("food52.com", food52I)
, ("thekitchn.com", thekitchnI)
, ("eatwell101.com", eatwell101I)
, ("bbcgoodfood.com", bbcGoodFoodI)
]
stepScrapers :: HashMap SiteName StepScraper
stepScrapers = HashMap.fromList
[ ("allrecipes.com", allrecipesS)
, ("cooking.nytimes.com", nytimesS)
, ("food.com", geniusKitchen2S)
, ("geniuskitchen.com", geniusKitchen1S)
, ("tasteofhome.com", geniusKitchen1S)
, ("rachlmansfield.com", tastyS1)
, ("cookieandkate.com", tastyS1)
, ("simpleveganblog.com", tastyS1)
, ("eatyourselfskinny.com", tastyS1)
, ("lexiscleankitchen.com", tastyS1)
, ("sallysbakingaddiction.com", tastyS2)
, ("gimmesomeoven.com", tastyS2)
, ("pinchofyum.com", tastyS2)
, ("alexandracooks.com", tastyS2)
, ("naturallyella.com", tastyS2)
, ("brownedbutterblondie.com", tastyS3)
, ("simple-veganista.com", tastyS4)
, ("foodnetwork.com", foodNetworkS)
, ("cafedelites.com", wprmS)
, ("budgetbytes.com", wprmS)
, ("daringgourmet.com", wprmS)
, ("recipetineats.com", wprmS)
, ("cookingclassy.com", wprmS)
, ("natashaskitchen.com", wprmS)
, ("justonecookbook.com", wprmS)
, ("loveandlemons.com", wprmS)
, ("foodiecrush.com", wprmS)
, ("therecipecritic.com", wprmS)
, ("ambitiouskitchen.com", wprmS)
, ("halfbakedharvest.com", wprmS)
, ("ohsweetbasil.com", wprmS)
, ("myfoodstory.com", wprmS)
, ("easypeasyfoodie.com", wprmS)
, ("veganricha.com", wprmS)
, ("simplydeliciousfood.com", wprmS)
, ("deliciouseveryday.com", wprmS)
, ("iamafoodblog.com", wprmS)
, ("thelastfoodblog.com", wprmS)
, ("thefoodblog.net", wprmS)
, ("onceuponafoodblog.com", wprmS)
, ("anotherfoodblogger.com", wprmS)
, ("minimalistbaker.com", wprmS)
, ("davidlebovitz.com", wprmS)
, ("skinnytaste.com", wprmS)
, ("twopeasandtheirpod.com", wprmS)
, ("sweetandsavorymeals.com", wprmS)
, ("melskitchencafe.com", wprmS)
, ("glutenfreecuppatea.co.uk", wprmS)
, ("101cookbooks.com", cb101S)
, ("bakerella.com", mvS)
, ("localmilkblog.com", zlS)
, ("smittenkitchen.com", jetpackS)
, ("eatingwell.com", eatingWellS)
, ("bhg.com", eatingWellS)
, ("yummly.com", yummlyS)
, ("simplyrecipes.com", simplyRecipesS)
, ("seriouseats.com", simplyRecipesS)
, ("bettycrocker.com", stepLi1)
, ("pillsbury.com", stepLi1)
, ("tasty.co", stepLi2)
, ("damndelicious.net", stepLi3)
, ("lazycatkitchen.com", stepLi4)
, ("deliciouslyella.com", stepLi5)
, ("slenderkitchen.com", stepLi6)
, ("everydayannie.com", stepLi7)
, ("hemsleyandhemsley.com", stepLi8)
, ("notwithoutsalt.com", stepLi9)
, ("cookingandcooking.com", stepLi10)
, ("uitpaulineskeuken.nl", stepLi11)
, ("leukerecepten.nl", stepLi12)
, ("wsj.com", stepLi13)
, ("eatfigsnotpigs.com", stepLi14)
, ("delish.com", delishS)
, ("thepioneerwoman.com", delishS)
, ("food52.com", food52S)
, ("thekitchn.com", thekitchnS)
, ("bbcgoodfood.com", bbcGoodFoodS)
]
-- |Get all ingredient scrapers, ordered by most popular first.
allIngredientScrapers :: [IngredientScraper]
allIngredientScrapers = fmap head . reverse . sortOn length . groupBy ((==) `on` (scrapeMetaName . ingredientScraperMeta)) . sortOn (scrapeMetaName . ingredientScraperMeta) $
HashMap.elems ingredientScrapers <> [ingredientLi4, ingredientLi12]
-- |Get all step scrapers, ordered by most popular first.
allStepScrapers :: [StepScraper]
allStepScrapers = fmap head . reverse . sortOn length . groupBy ((==) `on` (scrapeMetaName . stepScraperMeta)) . sortOn (scrapeMetaName . stepScraperMeta) . HashMap.elems $ stepScrapers
testScrape :: Selector -> Scraper Text Bool
testScrape test = not . Text.null <$> Scalpel.html test
acceptAll :: Scraper Text Bool
acceptAll = pure True
denyAll :: Scraper Text Bool
denyAll = pure True
setIngredientVersion :: Int -> IngredientScraper -> IngredientScraper
setIngredientVersion v scraper = scraper { ingredientScraperMeta = (ingredientScraperMeta scraper) { scrapeMetaVersion = ScrapeVersion v } }
setStepVersion :: Int -> StepScraper -> StepScraper
setStepVersion v scraper = scraper { stepScraperMeta = (stepScraperMeta scraper) { scrapeMetaVersion = ScrapeVersion v } }
simpleIngredientScraper :: Text -> Scraper Text Bool -> Selector -> IngredientScraper
simpleIngredientScraper sName test select = IngredientScraper (ScrapeMeta (ScrapeName sName) inception) test scrape
where
scrape = Scalpel.chroots select (
ScrapedIngredient
<$> Scalpel.text Scalpel.anySelector
)
simpleStepScraper :: Text -> Scraper Text Bool -> Selector -> StepScraper
simpleStepScraper sName test select = StepScraper (ScrapeMeta (ScrapeName sName) inception) test scrape
where
scrape = Scalpel.chroots select (
ScrapedStep
<$> Scalpel.text Scalpel.anySelector
)
debugI :: IngredientScraper
debugI = simpleIngredientScraper "debug" (testScrape "div") "div"
debugS :: StepScraper
debugS = simpleStepScraper "debug" (testScrape "div") "div"
allrecipesI :: IngredientScraper
allrecipesI = setIngredientVersion 2 $ simpleIngredientScraper "allrecipes"
(testScrape ("meta" @: ["content" @= "Allrecipes"]))
("span" @: [Scalpel.hasClass "ingredients-item-name"])
allrecipesS :: StepScraper
allrecipesS = simpleStepScraper "allrecipes"
(testScrape ("meta" @: ["content" @= "Allrecipes"]))
("ul" @: [Scalpel.hasClass "instructions-section"] // "div" @: [Scalpel.hasClass "section-body"])
nytimesI :: IngredientScraper
nytimesI = simpleIngredientScraper "nytimes"
(testScrape ("meta" @: ["content" @= "NYT Cooking"]))
("ul" @: [Scalpel.hasClass "recipe-ingredients"] // "li")
nytimesS :: StepScraper
nytimesS = simpleStepScraper "nytimes"
(testScrape ("meta" @: ["content" @= "NYT Cooking"]))
("ol" @: [Scalpel.hasClass "recipe-steps"] // "li")
geniusKitchen1I :: IngredientScraper
geniusKitchen1I = setIngredientVersion 2 $ simpleIngredientScraper "geniusKitchen1"
(testScrape ("div" @: [Scalpel.hasClass "recipe-ingredients"]))
("div" @: [Scalpel.hasClass "recipe-ingredients"] // "li")
geniusKitchen2I :: IngredientScraper
geniusKitchen2I = setIngredientVersion 2 $ simpleIngredientScraper "geniusKitchen2"
(testScrape ("ul" @: [Scalpel.hasClass "ingredients"]))
("ul" @: [Scalpel.hasClass "ingredients"] // "li")
geniusKitchen1S :: StepScraper
geniusKitchen1S = setStepVersion 2 $ simpleStepScraper "geniusKitchen1"
(testScrape ("div" @: [Scalpel.hasClass "recipe-directions"]))
("div" @: [Scalpel.hasClass "recipe-directions"] // "li")
geniusKitchen2S :: StepScraper
geniusKitchen2S = setStepVersion 2 $ simpleStepScraper "geniusKitchen2"
(testScrape ("ul" @: [Scalpel.hasClass "directions"]))
("ul" @: [Scalpel.hasClass "directions"] // "li")
tastyI1 :: IngredientScraper
tastyI1 = simpleIngredientScraper "tasty1"
(testScrape ("div" @: [Scalpel.hasClass "tasty-recipe-ingredients"]))
("div" @: [Scalpel.hasClass "tasty-recipe-ingredients"] // "li")
tastyI2 :: IngredientScraper
tastyI2 = simpleIngredientScraper "tasty2"
(testScrape ("div" @: [Scalpel.hasClass "tasty-recipes-ingredients"]))
("div" @: [Scalpel.hasClass "tasty-recipes-ingredients"] // "li")
tastyI3 :: IngredientScraper
tastyI3 = simpleIngredientScraper "tasty3"
(testScrape ("div" @: [Scalpel.hasClass "tasty-recipes-ingredients"]))
("div" @: [Scalpel.hasClass "tasty-recipes-ingredients"] // "p")
tastyS1 :: StepScraper
tastyS1 = simpleStepScraper "tasty1"
(testScrape ("div" @: [Scalpel.hasClass "tasty-recipe-instructions"]))
("div" @: [Scalpel.hasClass "tasty-recipe-instructions"] // "li")
tastyS2 :: StepScraper
tastyS2 = simpleStepScraper "tasty2"
(testScrape ("div" @: [Scalpel.hasClass "tasty-recipes-instructions"]))
("div" @: [Scalpel.hasClass "tasty-recipes-instructions"] // "li")
tastyS3 :: StepScraper
tastyS3 = simpleStepScraper "tasty3"
(testScrape ("div" @: [Scalpel.hasClass "tasty-recipes-instructions"]))
("div" @: [Scalpel.hasClass "tasty-recipes-instructions"] // "div" @: [Scalpel.hasClass "tasty-recipes-instructions-body"])
tastyS4 :: StepScraper
tastyS4 = simpleStepScraper "tasty4"
(testScrape ("div" @: [Scalpel.hasClass "tasty-recipe-instructions"]))
("div" @: [Scalpel.hasClass "tasty-recipe-instructions"] // "p")
foodNetworkI :: IngredientScraper
foodNetworkI = IngredientScraper (ScrapeMeta (ScrapeName "foodNetwork") inception) denyAll $
fmap ScrapedIngredient . filter (not . (==) "Deselect All") <$> Scalpel.chroots ("div" @: [Scalpel.hasClass "o-Ingredients__m-Body"] // "span") (Scalpel.text Scalpel.anySelector)
foodNetworkS :: StepScraper
foodNetworkS = StepScraper (ScrapeMeta (ScrapeName "foodNetwork") inception) denyAll $ do
fmap ScrapedStep <$> Scalpel.chroots ("div" @: [Scalpel.hasClass "o-Method__m-Body"] // "li") (Scalpel.text Scalpel.anySelector)
wprmI :: IngredientScraper
wprmI = simpleIngredientScraper "wprm"
(testScrape ("div" @: [Scalpel.hasClass "wprm-recipe"]))
("li" @: [Scalpel.hasClass "wprm-recipe-ingredient"])
wprmS :: StepScraper
wprmS = simpleStepScraper "wprm"
(testScrape ("div" @: [Scalpel.hasClass "wprm-recipe"]))
("li" @: [Scalpel.hasClass "wprm-recipe-instruction"])
cb101I :: IngredientScraper
cb101I = simpleIngredientScraper "cb101"
(testScrape ("div" @: [Scalpel.hasClass "cb101-recipe-main"]))
("li" @: [Scalpel.hasClass "cb101-recipe-ingredient"])
cb101S :: StepScraper
cb101S = simpleStepScraper "cb101"
(testScrape ("div" @: [Scalpel.hasClass "cb101-recipe-main"]))
("li" @: [Scalpel.hasClass "cb101-recipe-instruction"])
mvI :: IngredientScraper
mvI = simpleIngredientScraper "mv"
(testScrape ("div" @: [Scalpel.hasClass "mv-create-ingredients"]))
("div" @: [Scalpel.hasClass "mv-create-ingredients"] // "li")
mvS :: StepScraper
mvS = simpleStepScraper "mv"
(testScrape ("div" @: [Scalpel.hasClass "mv-create-instructions"]))
("div" @: [Scalpel.hasClass "mv-create-instructions"] // "li")
zlI :: IngredientScraper
zlI = simpleIngredientScraper "zl"
(testScrape ("ul" @: ["id" @= "zlrecipe-ingredients-list"]))
("ul" @: ["id" @= "zlrecipe-ingredients-list"] // "li")
zlS :: StepScraper
zlS = simpleStepScraper "zl"
(testScrape ("ol" @: ["id" @= "zlrecipe-instructions-list"]))
("ol" @: ["id" @= "zlrecipe-instructions-list"] // "li")
jetpackI :: IngredientScraper
jetpackI = simpleIngredientScraper "jetpack"
(testScrape ("div" @: [Scalpel.hasClass "jetpack-recipe"]))
("div" @: [Scalpel.hasClass "jetpack-recipe-ingredients"] // "li")
jetpackS :: StepScraper
jetpackS = simpleStepScraper "jetpack"
(testScrape ("div" @: [Scalpel.hasClass "jetpack-recipe"]))
("div" @: [Scalpel.hasClass "jetpack-recipe-directions"])
eatingWellI :: IngredientScraper
eatingWellI = simpleIngredientScraper "eatingWell"
(testScrape ("ul" @: [Scalpel.hasClass "ingredients-section"]))
("ul" @: [Scalpel.hasClass "ingredients-section"] // "li")
eatingWellS :: StepScraper
eatingWellS = simpleStepScraper "eatingWell"
(testScrape ("ul" @: [Scalpel.hasClass "instructions-section"]))
("ul" @: [Scalpel.hasClass "instructions-section"] // "li" // "p")
yummlyI :: IngredientScraper
yummlyI = simpleIngredientScraper "yummly"
denyAll
("li" @: [Scalpel.hasClass "IngredientLine"])
yummlyS :: StepScraper
yummlyS = simpleStepScraper "yummly"
denyAll
("li" @: [Scalpel.hasClass "prep-step"])
simplyRecipesI :: IngredientScraper
simplyRecipesI = simpleIngredientScraper "simplyrecipes"
denyAll
("section" @: ["id" @= "section--ingredients_1-0"] // "li")
simplyRecipesS :: StepScraper
simplyRecipesS = simpleStepScraper "simplyrecipes"
denyAll
("section" @: ["id" @= "section--instructions_1-0"] // "li")
ingredientLi1 :: IngredientScraper
ingredientLi1 = simpleIngredientScraper "ingredientLi1"
(testScrape ("li" @: [Scalpel.hasClass "ingredient"]))
("li" @: [Scalpel.hasClass "ingredient"])
ingredientLi2 :: IngredientScraper
ingredientLi2 = simpleIngredientScraper "ingredientLi2"
(testScrape ("div" @: [Scalpel.hasClass "ingredients-section"]))
("div" @: [Scalpel.hasClass "ingredients-section"] // "li")
ingredientLi3 :: IngredientScraper
ingredientLi3 = simpleIngredientScraper "ingredientLi3"
(testScrape ("li" @: ["itemprop" @= "recipeIngredient"]))
("li" @: ["itemprop" @= "recipeIngredient"])
ingredientLi4 :: IngredientScraper
ingredientLi4 = simpleIngredientScraper "ingredientLi4"
(testScrape ("div" @: [Scalpel.hasClass "ingredients"]))
("div" @: [Scalpel.hasClass "ingredients"] // "li")
ingredientLi5 :: IngredientScraper
ingredientLi5 = simpleIngredientScraper "ingredientLi5"
(testScrape ("div" @: [Scalpel.hasClass "listIngredient"]))
("div" @: [Scalpel.hasClass "listIngredient"] // "li")
ingredientLi6 :: IngredientScraper
ingredientLi6 = simpleIngredientScraper "ingredientLi6"
(testScrape ("li" @: ["itemprop" @= "ingredients"]))
("li" @: ["itemprop" @= "ingredients"])
ingredientLi7 :: IngredientScraper
ingredientLi7 = simpleIngredientScraper "ingredientLi7"
(testScrape ("ul" @: [Scalpel.hasClass "ingredients"]))
("ul" @: [Scalpel.hasClass "ingredients"] // "li")
ingredientLi8 :: IngredientScraper
ingredientLi8 = simpleIngredientScraper "ingredientLi8"
(testScrape ("div" @: [Scalpel.hasClass "ingredient-text"]))
("div" @: [Scalpel.hasClass "ingredient-text"] // "ul" // "li")
ingredientLi9 :: IngredientScraper
ingredientLi9 = simpleIngredientScraper "ingredientLi9"
(testScrape ("div" @: [Scalpel.hasClass "cookbook-container-ingredients"]))
("p" @: [Scalpel.hasClass "cookbook-ingredient-item"])
ingredientLi10 :: IngredientScraper
ingredientLi10 = simpleIngredientScraper "ingredientLi10"
(testScrape ("table" @: [Scalpel.hasClass "ingredients-table"]))
("table" @: [Scalpel.hasClass "ingredients-table"] // "tr")
ingredientLi11 :: IngredientScraper
ingredientLi11 = simpleIngredientScraper "ingredientLi11"
(testScrape ("blockquote" @: [Scalpel.hasClass "recipe-block"]))
("blockquote" @: [Scalpel.hasClass "recipe-block"] // "li")
ingredientLi12 :: IngredientScraper
ingredientLi12 = simpleIngredientScraper "ingredientLi12"
(testScrape ("li" @: [Scalpel.hasClass "structured-ingredients__list-item"]))
("li" @: [Scalpel.hasClass "structured-ingredients__list-item"])
ingredientLi13 :: IngredientScraper
ingredientLi13 = simpleIngredientScraper "ingredientLi13"
(testScrape ("section" @: [Scalpel.hasClass "ingredients-list"]))
("section" @: [Scalpel.hasClass "ingredients-list"] // "li")
ingredientLi14 :: IngredientScraper
ingredientLi14 = simpleIngredientScraper "ingredientLi14"
(testScrape ("ul" @: [Scalpel.hasClass "page-content__ingredients-list"]))
("ul" @: [Scalpel.hasClass "page-content__ingredients-list"] // "li")
ingredientLi15 :: IngredientScraper
ingredientLi15 = simpleIngredientScraper "ingredientLi15"
(testScrape ("ul" @: [Scalpel.hasClass "ingredients-list"]))
("ul" @: [Scalpel.hasClass "ingredients-list"] // "li")
stepLi1 :: StepScraper
stepLi1 = simpleStepScraper "stepLi1"
(testScrape ("ul" @: [Scalpel.hasClass "recipeSteps"]))
("ul" @: [Scalpel.hasClass "recipeSteps"] // "li")
stepLi2 :: StepScraper
stepLi2 = simpleStepScraper "stepLi2"
(testScrape ("ol" @: [Scalpel.hasClass "prep-steps"]))
("ol" @: [Scalpel.hasClass "prep-steps"] // "li")
stepLi3 :: StepScraper
stepLi3 = simpleStepScraper "stepLi3"
(testScrape ("div" @: [Scalpel.hasClass "instructions"]))
("div" @: [Scalpel.hasClass "instructions"] // "li")
stepLi4 :: StepScraper
stepLi4 = simpleStepScraper "stepLi4"
(testScrape ("div" @: [Scalpel.hasClass "method-section"]))
("div" @: [Scalpel.hasClass "method-section"] // "li")
stepLi5 :: StepScraper
stepLi5 = simpleStepScraper "stepLi5"
(testScrape ("section" @: [Scalpel.hasClass "recipe__section"]))
("section" @: [Scalpel.hasClass "recipe__section"] // "li")
stepLi6 :: StepScraper
stepLi6 = simpleStepScraper "stepLi6"
(testScrape ("div" @: [Scalpel.hasClass "step-instructions"]))
("div" @: [Scalpel.hasClass "step-instructions"] // "div" @: [Scalpel.hasClass "step"])
stepLi7 :: StepScraper
stepLi7 = simpleStepScraper "stepLi7"
(testScrape ("div" @: ["id" @= "directions"]))
("div" @: ["id" @= "directions"] // "li")
stepLi8 :: StepScraper
stepLi8 = simpleStepScraper "stepLi8"
(testScrape ("div" @: [Scalpel.hasClass "recipe-main-copy"]))
("div" @: [Scalpel.hasClass "recipe-main-copy"])
stepLi9 :: StepScraper
stepLi9 = simpleStepScraper "stepLi9"
(testScrape ("p" @: [Scalpel.hasClass "cookbook-instruction-item"]))
("p" @: [Scalpel.hasClass "cookbook-instruction-item"])
stepLi10 :: StepScraper
stepLi10 = simpleStepScraper "stepLi10"
(testScrape ("p" @: [Scalpel.hasClass "recipeText"]))
("p" @: [Scalpel.hasClass "recipeText"])
stepLi11 :: StepScraper
stepLi11 = simpleStepScraper "stepLi11"
(testScrape ("div" @: [Scalpel.hasClass "preparation-list"]))
("div" @: [Scalpel.hasClass "preparation-list"] // "li")
stepLi12 :: StepScraper
stepLi12 = simpleStepScraper "stepLi12"
(testScrape ("div" @: [Scalpel.hasClass "page-content__recipe"]))
("div" @: [Scalpel.hasClass "page-content__recipe"] // "div" @: [Scalpel.hasClass "step"])
stepLi13 :: StepScraper
stepLi13 = simpleStepScraper "stepLi13"
(testScrape ("ol" @: [Scalpel.hasClass "steps-list"]))
("ol" @: [Scalpel.hasClass "steps-list"] // "li")
stepLi14 :: StepScraper
stepLi14 = setStepVersion 2 $ simpleStepScraper "stepLi14"
(testScrape ("li" @: [Scalpel.hasClass "instruction"]))
("li" @: [Scalpel.hasClass "instruction"])
delishI :: IngredientScraper
delishI = simpleIngredientScraper "delish"
acceptAll
("div" @: [Scalpel.hasClass "ingredient-item"])
delishS :: StepScraper
delishS = simpleStepScraper "delish"
acceptAll
("div" @: [Scalpel.hasClass "direction-lists"] // "li")
spoonacularI :: IngredientScraper
spoonacularI = simpleIngredientScraper "spoontacular"
denyAll
("div" @: [Scalpel.hasClass "spoonacular-ingredient"])
food52I :: IngredientScraper
food52I = simpleIngredientScraper "food52"
denyAll
("div" @: [Scalpel.hasClass "recipe__list--ingredients"] // "li")
food52S :: StepScraper
food52S = simpleStepScraper "food52"
denyAll
("div" @: [Scalpel.hasClass "recipe__list--steps"] // "li")
-- epicuriousI :: IngredientScraper
-- epicuriousI = simpleIngredientScraper "epicurious"
-- denyAll
-- ("div" @: [Scalpel.hasClass "recipe__ingredient-list"])
thekitchnI :: IngredientScraper
thekitchnI = simpleIngredientScraper "thekitchn"
denyAll
("ul" @: [Scalpel.hasClass "Recipe__ingredients"] // "li")
thekitchnS :: StepScraper
thekitchnS = simpleStepScraper "thekitchn"
denyAll
("ol" @: [Scalpel.hasClass "Recipe__instructions"] // "li")
eatwell101I :: IngredientScraper
eatwell101I = simpleIngredientScraper "eatwell101"
denyAll
("div" @: [Scalpel.hasClass "pf-content"] // "li")
bbcGoodFoodI :: IngredientScraper
bbcGoodFoodI = simpleIngredientScraper "bbcgoodfood"
denyAll
("section" @: [Scalpel.hasClass "recipe__ingredients"] // "li")
bbcGoodFoodS :: StepScraper
bbcGoodFoodS = simpleStepScraper "bbcgoodfood"
denyAll
("section" @: [Scalpel.hasClass "recipe__method-steps"] // "li")