recipe_scrapers 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +20 -0
- data/README.md +54 -0
- data/lib/recipe_scrapers/configuration.rb +119 -0
- data/lib/recipe_scrapers/declaration.rb +85 -0
- data/lib/recipe_scrapers/error_tracker.rb +14 -0
- data/lib/recipe_scrapers/errors.rb +16 -0
- data/lib/recipe_scrapers/http/adapter.rb +50 -0
- data/lib/recipe_scrapers/http/address_guard.rb +90 -0
- data/lib/recipe_scrapers/http/body_limit.rb +45 -0
- data/lib/recipe_scrapers/http/encoding.rb +48 -0
- data/lib/recipe_scrapers/http/follow_redirects.rb +75 -0
- data/lib/recipe_scrapers/models/ingredient.rb +20 -0
- data/lib/recipe_scrapers/models/ingredient_group.rb +20 -0
- data/lib/recipe_scrapers/models/nutrient.rb +19 -0
- data/lib/recipe_scrapers/models/recipe.rb +125 -0
- data/lib/recipe_scrapers/parsers/chain.rb +52 -0
- data/lib/recipe_scrapers/parsers/durations.rb +70 -0
- data/lib/recipe_scrapers/parsers/ingredients.rb +144 -0
- data/lib/recipe_scrapers/parsers/nutrients.rb +47 -0
- data/lib/recipe_scrapers/parsers/quantity.rb +46 -0
- data/lib/recipe_scrapers/parsers/ratings.rb +26 -0
- data/lib/recipe_scrapers/parsers/vocabulary/common.yml +7 -0
- data/lib/recipe_scrapers/parsers/vocabulary/de.yml +5 -0
- data/lib/recipe_scrapers/parsers/vocabulary/en.yml +26 -0
- data/lib/recipe_scrapers/parsers/vocabulary/es.yml +4 -0
- data/lib/recipe_scrapers/parsers/vocabulary/fr.yml +5 -0
- data/lib/recipe_scrapers/parsers/vocabulary/hu.yml +3 -0
- data/lib/recipe_scrapers/parsers/vocabulary/it.yml +4 -0
- data/lib/recipe_scrapers/parsers/vocabulary/ja.yml +2 -0
- data/lib/recipe_scrapers/parsers/vocabulary/nl.yml +4 -0
- data/lib/recipe_scrapers/parsers/vocabulary/pt.yml +8 -0
- data/lib/recipe_scrapers/parsers/vocabulary/ru.yml +7 -0
- data/lib/recipe_scrapers/parsers/vocabulary/scandinavian.yml +3 -0
- data/lib/recipe_scrapers/parsers/vocabulary/sk.yml +3 -0
- data/lib/recipe_scrapers/parsers/vocabulary/tr.yml +2 -0
- data/lib/recipe_scrapers/parsers/vocabulary.rb +120 -0
- data/lib/recipe_scrapers/parsers/yields.rb +30 -0
- data/lib/recipe_scrapers/registry.rb +88 -0
- data/lib/recipe_scrapers/scraper/parsed_fields.rb +69 -0
- data/lib/recipe_scrapers/scraper.rb +199 -0
- data/lib/recipe_scrapers/site_path.rb +21 -0
- data/lib/recipe_scrapers/sites/au/bestrecipes.rb +3 -0
- data/lib/recipe_scrapers/sites/be/15gram.rb +3 -0
- data/lib/recipe_scrapers/sites/br/panelinha.rb +3 -0
- data/lib/recipe_scrapers/sites/br/receitasnestle.rb +3 -0
- data/lib/recipe_scrapers/sites/br/receiteria.rb +3 -0
- data/lib/recipe_scrapers/sites/br/tudogostoso.rb +3 -0
- data/lib/recipe_scrapers/sites/ch/bettybossi.rb +3 -0
- data/lib/recipe_scrapers/sites/ch/migusto.rb +3 -0
- data/lib/recipe_scrapers/sites/ch/swissmilk.rb +3 -0
- data/lib/recipe_scrapers/sites/co/tasty.rb +3 -0
- data/lib/recipe_scrapers/sites/com/365daysofbakingandmore.rb +3 -0
- data/lib/recipe_scrapers/sites/com/40aprons.rb +3 -0
- data/lib/recipe_scrapers/sites/com/750g.rb +3 -0
- data/lib/recipe_scrapers/sites/com/abeautifulmess.rb +3 -0
- data/lib/recipe_scrapers/sites/com/abuelascounter.rb +3 -0
- data/lib/recipe_scrapers/sites/com/acozykitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/addapinch.rb +3 -0
- data/lib/recipe_scrapers/sites/com/adozensundays.rb +3 -0
- data/lib/recipe_scrapers/sites/com/aflavorjournal.rb +3 -0
- data/lib/recipe_scrapers/sites/com/afullliving.rb +3 -0
- data/lib/recipe_scrapers/sites/com/ahealthysliceoflife.rb +5 -0
- data/lib/recipe_scrapers/sites/com/alexandracooks.rb +3 -0
- data/lib/recipe_scrapers/sites/com/allnutritious.rb +3 -0
- data/lib/recipe_scrapers/sites/com/allthehealthythings.rb +3 -0
- data/lib/recipe_scrapers/sites/com/altonbrown.rb +3 -0
- data/lib/recipe_scrapers/sites/com/amazingribs.rb +3 -0
- data/lib/recipe_scrapers/sites/com/amberskitchencooks.rb +3 -0
- data/lib/recipe_scrapers/sites/com/andy_cooks.rb +3 -0
- data/lib/recipe_scrapers/sites/com/anitalianinmykitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/app.rb +27 -0
- data/lib/recipe_scrapers/sites/com/asweetpeachef.rb +3 -0
- data/lib/recipe_scrapers/sites/com/aubreyskitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/averiecooks.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bake_eat_repeat.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bakerbynature.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bakewithzoha.rb +3 -0
- data/lib/recipe_scrapers/sites/com/baking_sense.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bakingmischief.rb +3 -0
- data/lib/recipe_scrapers/sites/com/barefeetinthekitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/barefootinthepines.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bbcgoodfood.rb +3 -0
- data/lib/recipe_scrapers/sites/com/belleofthekitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/betterfoodguru.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bettycrocker.rb +3 -0
- data/lib/recipe_scrapers/sites/com/beyondfrosting.rb +3 -0
- data/lib/recipe_scrapers/sites/com/biancazapatka.rb +3 -0
- data/lib/recipe_scrapers/sites/com/biggerbolderbaking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/billyparisi.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bitsofcarey.rb +3 -0
- data/lib/recipe_scrapers/sites/com/blogghetti.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bluejeanchef.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bonappetit.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bonviveur.rb +3 -0
- data/lib/recipe_scrapers/sites/com/bowlofdelicious.rb +3 -0
- data/lib/recipe_scrapers/sites/com/breadtopia.rb +3 -0
- data/lib/recipe_scrapers/sites/com/brokenovenbaking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/budgetbytes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cafedelites.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cakemehometonight.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cakewhiz.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cambreabakes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/carlsbadcravings.rb +3 -0
- data/lib/recipe_scrapers/sites/com/castironskilletcooking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/celebratingsweets.rb +3 -0
- data/lib/recipe_scrapers/sites/com/chefjackovens.rb +3 -0
- data/lib/recipe_scrapers/sites/com/chefsavvy.rb +3 -0
- data/lib/recipe_scrapers/sites/com/chewoutloud.rb +3 -0
- data/lib/recipe_scrapers/sites/com/chocolatewithgrace.rb +3 -0
- data/lib/recipe_scrapers/sites/com/ciaoflorentina.rb +3 -0
- data/lib/recipe_scrapers/sites/com/closetcooking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cloudykitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/coleycooks.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookedandloved.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookfastrecipes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookieandkate.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookiesandcups.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cooking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookingclassy.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookinglsl.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookingwithjanica.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookpad.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookwell.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cookwithdana.rb +3 -0
- data/lib/recipe_scrapers/sites/com/copykat.rb +3 -0
- data/lib/recipe_scrapers/sites/com/countryliving.rb +3 -0
- data/lib/recipe_scrapers/sites/com/crazyforcrust.rb +3 -0
- data/lib/recipe_scrapers/sites/com/creativecanning.rb +3 -0
- data/lib/recipe_scrapers/sites/com/cuisineaz.rb +3 -0
- data/lib/recipe_scrapers/sites/com/daringgourmet.rb +3 -0
- data/lib/recipe_scrapers/sites/com/dashfordinner.rb +3 -0
- data/lib/recipe_scrapers/sites/com/davidlebovitz.rb +3 -0
- data/lib/recipe_scrapers/sites/com/deliciouslyella.rb +3 -0
- data/lib/recipe_scrapers/sites/com/deliciouslysprinkled.rb +3 -0
- data/lib/recipe_scrapers/sites/com/delish.rb +3 -0
- data/lib/recipe_scrapers/sites/com/delscookingtwist.rb +3 -0
- data/lib/recipe_scrapers/sites/com/dinneratthezoo.rb +3 -0
- data/lib/recipe_scrapers/sites/com/directoalpaladar.rb +3 -0
- data/lib/recipe_scrapers/sites/com/domesticate_me.rb +3 -0
- data/lib/recipe_scrapers/sites/com/downshiftology.rb +3 -0
- data/lib/recipe_scrapers/sites/com/eatingbirdfood.rb +3 -0
- data/lib/recipe_scrapers/sites/com/eatingeuropean.rb +3 -0
- data/lib/recipe_scrapers/sites/com/eatingonadime.rb +3 -0
- data/lib/recipe_scrapers/sites/com/eatliverun.rb +3 -0
- data/lib/recipe_scrapers/sites/com/eatthismuch.rb +3 -0
- data/lib/recipe_scrapers/sites/com/elavegan.rb +3 -0
- data/lib/recipe_scrapers/sites/com/emilybites.rb +3 -0
- data/lib/recipe_scrapers/sites/com/erinliveswhole.rb +3 -0
- data/lib/recipe_scrapers/sites/com/erinscozykitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/errenskitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/everyday_delicious.rb +3 -0
- data/lib/recipe_scrapers/sites/com/everydaypie.rb +3 -0
- data/lib/recipe_scrapers/sites/com/evolvingtable.rb +3 -0
- data/lib/recipe_scrapers/sites/com/familyfoodonthetable.rb +3 -0
- data/lib/recipe_scrapers/sites/com/familyspice.rb +3 -0
- data/lib/recipe_scrapers/sites/com/fantabulosity.rb +3 -0
- data/lib/recipe_scrapers/sites/com/farmhouseonboone.rb +3 -0
- data/lib/recipe_scrapers/sites/com/farmtojar.rb +3 -0
- data/lib/recipe_scrapers/sites/com/feastingathome.rb +3 -0
- data/lib/recipe_scrapers/sites/com/fifteenspatulas.rb +3 -0
- data/lib/recipe_scrapers/sites/com/figjar.rb +3 -0
- data/lib/recipe_scrapers/sites/com/finedininglovers.rb +3 -0
- data/lib/recipe_scrapers/sites/com/fithealthymacros.rb +3 -0
- data/lib/recipe_scrapers/sites/com/fitslowcookerqueen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/food.rb +3 -0
- data/lib/recipe_scrapers/sites/com/foodbymaria.rb +3 -0
- data/lib/recipe_scrapers/sites/com/foodfidelity.rb +3 -0
- data/lib/recipe_scrapers/sites/com/foodrepublic.rb +3 -0
- data/lib/recipe_scrapers/sites/com/forksoverknives.rb +3 -0
- data/lib/recipe_scrapers/sites/com/garlicandzest.rb +3 -0
- data/lib/recipe_scrapers/sites/com/garnishandglaze.rb +3 -0
- data/lib/recipe_scrapers/sites/com/gimmesomeoven.rb +3 -0
- data/lib/recipe_scrapers/sites/com/girlgonegourmet.rb +3 -0
- data/lib/recipe_scrapers/sites/com/girlversusdough.rb +3 -0
- data/lib/recipe_scrapers/sites/com/gloriousrecipes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/glutenfreeonashoestring.rb +3 -0
- data/lib/recipe_scrapers/sites/com/gonnawantseconds.rb +3 -0
- data/lib/recipe_scrapers/sites/com/goodfooddiscoveries.rb +3 -0
- data/lib/recipe_scrapers/sites/com/goodhousekeeping.rb +3 -0
- data/lib/recipe_scrapers/sites/com/grandbaby_cakes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/greatbritishchefs.rb +3 -0
- data/lib/recipe_scrapers/sites/com/halfbakedharvest.rb +3 -0
- data/lib/recipe_scrapers/sites/com/hassanchef.rb +3 -0
- data/lib/recipe_scrapers/sites/com/headbangerskitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/healthywithachanceofsprinkles.rb +3 -0
- data/lib/recipe_scrapers/sites/com/heatherchristo.rb +3 -0
- data/lib/recipe_scrapers/sites/com/hilahcooking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/hogarmania.rb +3 -0
- data/lib/recipe_scrapers/sites/com/homeandplate.rb +3 -0
- data/lib/recipe_scrapers/sites/com/hostthetoast.rb +3 -0
- data/lib/recipe_scrapers/sites/com/houseofnasheats.rb +3 -0
- data/lib/recipe_scrapers/sites/com/houseofyumm.rb +3 -0
- data/lib/recipe_scrapers/sites/com/iamafoodblog.rb +3 -0
- data/lib/recipe_scrapers/sites/com/im_worthy.rb +3 -0
- data/lib/recipe_scrapers/sites/com/inbloombakery.rb +3 -0
- data/lib/recipe_scrapers/sites/com/indianhealthyrecipes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/ingoodflavor.rb +3 -0
- data/lib/recipe_scrapers/sites/com/inspiralized.rb +3 -0
- data/lib/recipe_scrapers/sites/com/itdoesnttastelikechicken.rb +3 -0
- data/lib/recipe_scrapers/sites/com/itsnotaboutnutrition.rb +3 -0
- data/lib/recipe_scrapers/sites/com/izzycooking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/jennycancook.rb +3 -0
- data/lib/recipe_scrapers/sites/com/jimcooksfoodgood.rb +3 -0
- data/lib/recipe_scrapers/sites/com/jocooks.rb +3 -0
- data/lib/recipe_scrapers/sites/com/joyfullymad.rb +3 -0
- data/lib/recipe_scrapers/sites/com/joythebaker.rb +3 -0
- data/lib/recipe_scrapers/sites/com/juliasalbum.rb +3 -0
- data/lib/recipe_scrapers/sites/com/justataste.rb +3 -0
- data/lib/recipe_scrapers/sites/com/justinesnacks.rb +3 -0
- data/lib/recipe_scrapers/sites/com/kennethtemple.rb +3 -0
- data/lib/recipe_scrapers/sites/com/keytomylime.rb +3 -0
- data/lib/recipe_scrapers/sites/com/kitchendreaming.rb +3 -0
- data/lib/recipe_scrapers/sites/com/kitchenstories.rb +3 -0
- data/lib/recipe_scrapers/sites/com/kristineskitchenblog.rb +3 -0
- data/lib/recipe_scrapers/sites/com/krollskorner.rb +3 -0
- data/lib/recipe_scrapers/sites/com/lanascooking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/laurenslatest.rb +3 -0
- data/lib/recipe_scrapers/sites/com/lazycatkitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/lecremedelacrumb.rb +3 -0
- data/lib/recipe_scrapers/sites/com/leitesculinaria.rb +3 -0
- data/lib/recipe_scrapers/sites/com/lekkerensimpel.rb +3 -0
- data/lib/recipe_scrapers/sites/com/letscampsmore.rb +3 -0
- data/lib/recipe_scrapers/sites/com/lifestyleofafoodie.rb +3 -0
- data/lib/recipe_scrapers/sites/com/littleferrarokitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/littlespicejar.rb +3 -0
- data/lib/recipe_scrapers/sites/com/littlespoonfarm.rb +3 -0
- data/lib/recipe_scrapers/sites/com/littlesunnykitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/livelytable.rb +3 -0
- data/lib/recipe_scrapers/sites/com/lolascocina.rb +3 -0
- data/lib/recipe_scrapers/sites/com/lovingitvegan.rb +3 -0
- data/lib/recipe_scrapers/sites/com/madsvin.rb +3 -0
- data/lib/recipe_scrapers/sites/com/makeitdairyfree.rb +3 -0
- data/lib/recipe_scrapers/sites/com/mealprepmanual.rb +3 -0
- data/lib/recipe_scrapers/sites/com/meganvskitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/melissaknorris.rb +3 -0
- data/lib/recipe_scrapers/sites/com/melskitchencafe.rb +3 -0
- data/lib/recipe_scrapers/sites/com/mexicanplease.rb +3 -0
- data/lib/recipe_scrapers/sites/com/minimalistbaker.rb +3 -0
- data/lib/recipe_scrapers/sites/com/ministryofcurry.rb +3 -0
- data/lib/recipe_scrapers/sites/com/modernhoney.rb +3 -0
- data/lib/recipe_scrapers/sites/com/momontimeout.rb +3 -0
- data/lib/recipe_scrapers/sites/com/momswithcrockpots.rb +3 -0
- data/lib/recipe_scrapers/sites/com/motherthyme.rb +3 -0
- data/lib/recipe_scrapers/sites/com/mybakingaddiction.rb +3 -0
- data/lib/recipe_scrapers/sites/com/myjewishlearning.rb +3 -0
- data/lib/recipe_scrapers/sites/com/mykidslickthebowl.rb +3 -0
- data/lib/recipe_scrapers/sites/com/mykoreankitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/myriadrecipes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/myvegetarianroots.rb +3 -0
- data/lib/recipe_scrapers/sites/com/natashaskitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/naturallyella.rb +3 -0
- data/lib/recipe_scrapers/sites/com/noracooks.rb +3 -0
- data/lib/recipe_scrapers/sites/com/norecipes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/notenoughcinnamon.rb +3 -0
- data/lib/recipe_scrapers/sites/com/nourishedbynutrition.rb +3 -0
- data/lib/recipe_scrapers/sites/com/number_2_pencil.rb +3 -0
- data/lib/recipe_scrapers/sites/com/onceuponachef.rb +3 -0
- data/lib/recipe_scrapers/sites/com/onesweetappetite.rb +3 -0
- data/lib/recipe_scrapers/sites/com/organicallyaddison.rb +3 -0
- data/lib/recipe_scrapers/sites/com/ourbestbites.rb +3 -0
- data/lib/recipe_scrapers/sites/com/paleorunningmomma.rb +3 -0
- data/lib/recipe_scrapers/sites/com/panlasangpinoy.rb +3 -0
- data/lib/recipe_scrapers/sites/com/peelwithzeal.rb +3 -0
- data/lib/recipe_scrapers/sites/com/pequerecetas.rb +3 -0
- data/lib/recipe_scrapers/sites/com/pilipinasrecipes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/pinkowlkitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/plantyou.rb +3 -0
- data/lib/recipe_scrapers/sites/com/platingpixels.rb +3 -0
- data/lib/recipe_scrapers/sites/com/platingsandpairings.rb +3 -0
- data/lib/recipe_scrapers/sites/com/plowingthroughlife.rb +3 -0
- data/lib/recipe_scrapers/sites/com/polishfoodies.rb +3 -0
- data/lib/recipe_scrapers/sites/com/practicalselfreliance.rb +3 -0
- data/lib/recipe_scrapers/sites/com/preppykitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/pressureluckcooking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/purelypope.rb +3 -0
- data/lib/recipe_scrapers/sites/com/rachlmansfield.rb +3 -0
- data/lib/recipe_scrapers/sites/com/rainbowplantlife.rb +3 -0
- data/lib/recipe_scrapers/sites/com/realfoodwell.rb +3 -0
- data/lib/recipe_scrapers/sites/com/realmomnutrition.rb +3 -0
- data/lib/recipe_scrapers/sites/com/receitas.rb +3 -0
- data/lib/recipe_scrapers/sites/com/recipeforperfection.rb +3 -0
- data/lib/recipe_scrapers/sites/com/recipegirl.rb +3 -0
- data/lib/recipe_scrapers/sites/com/reciperunner.rb +3 -0
- data/lib/recipe_scrapers/sites/com/recipetineats.rb +3 -0
- data/lib/recipe_scrapers/sites/com/redhousespice.rb +3 -0
- data/lib/recipe_scrapers/sites/com/ricardocuisine.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sallysbakingaddiction.rb +3 -0
- data/lib/recipe_scrapers/sites/com/saltpepperskillet.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sandwichtribunal.rb +3 -0
- data/lib/recipe_scrapers/sites/com/savoringthegood.rb +3 -0
- data/lib/recipe_scrapers/sites/com/savorynothings.rb +3 -0
- data/lib/recipe_scrapers/sites/com/savorythoughts.rb +3 -0
- data/lib/recipe_scrapers/sites/com/scrummylane.rb +3 -0
- data/lib/recipe_scrapers/sites/com/shelikesfood.rb +3 -0
- data/lib/recipe_scrapers/sites/com/simple_veganista.rb +3 -0
- data/lib/recipe_scrapers/sites/com/simplehomeedit.rb +3 -0
- data/lib/recipe_scrapers/sites/com/simplyquinoa.rb +3 -0
- data/lib/recipe_scrapers/sites/com/simplywhisked.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sipandfeast.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sizzlefish.rb +3 -0
- data/lib/recipe_scrapers/sites/com/skinnytaste.rb +3 -0
- data/lib/recipe_scrapers/sites/com/smalltownwoman.rb +3 -0
- data/lib/recipe_scrapers/sites/com/somuchfoodblog.rb +3 -0
- data/lib/recipe_scrapers/sites/com/southernbite.rb +3 -0
- data/lib/recipe_scrapers/sites/com/spainonafork.rb +3 -0
- data/lib/recipe_scrapers/sites/com/spendwithpennies.rb +3 -0
- data/lib/recipe_scrapers/sites/com/spicysouthernkitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/stacyling.rb +3 -0
- data/lib/recipe_scrapers/sites/com/staysnatched.rb +3 -0
- data/lib/recipe_scrapers/sites/com/steamykitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/com/strongrfastr.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sudachirecipes.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sugarhero.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sugarmaplefarmhouse.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sugarspunrun.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sunset.rb +3 -0
- data/lib/recipe_scrapers/sites/com/sweetcsdesigns.rb +3 -0
- data/lib/recipe_scrapers/sites/com/tableanddish.rb +3 -0
- data/lib/recipe_scrapers/sites/com/tasteandtellblog.rb +3 -0
- data/lib/recipe_scrapers/sites/com/tasteofhome.rb +3 -0
- data/lib/recipe_scrapers/sites/com/tastesbetterfromscratch.rb +3 -0
- data/lib/recipe_scrapers/sites/com/tastesoflizzyt.rb +3 -0
- data/lib/recipe_scrapers/sites/com/tastyoven.rb +3 -0
- data/lib/recipe_scrapers/sites/com/tatyanaseverydayfood.rb +3 -0
- data/lib/recipe_scrapers/sites/com/teakandthyme.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thealmondeater.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thebigmansworld.rb +3 -0
- data/lib/recipe_scrapers/sites/com/theclevercarrot.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thecookierookie.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thefoodcharlatan.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thefoodietakesflight.rb +3 -0
- data/lib/recipe_scrapers/sites/com/theglutenfreeaustrian.rb +3 -0
- data/lib/recipe_scrapers/sites/com/theguardian.rb +3 -0
- data/lib/recipe_scrapers/sites/com/theicecreamconfectionals.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thekitchenmagpie.rb +3 -0
- data/lib/recipe_scrapers/sites/com/themagicalslowcooker.rb +3 -0
- data/lib/recipe_scrapers/sites/com/themediterraneandish.rb +3 -0
- data/lib/recipe_scrapers/sites/com/themodernproper.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thepalatablelife.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thepioneerwoman.rb +3 -0
- data/lib/recipe_scrapers/sites/com/theppk.rb +3 -0
- data/lib/recipe_scrapers/sites/com/therecipecritic.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thesaltymarshmallow.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thespicetrain.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thesuburbansoapbox.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thevintagemixer.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thewoodenskillet.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thinlicious.rb +3 -0
- data/lib/recipe_scrapers/sites/com/thishealthytable.rb +3 -0
- data/lib/recipe_scrapers/sites/com/toriavey.rb +3 -0
- data/lib/recipe_scrapers/sites/com/twopeasandtheirpod.rb +3 -0
- data/lib/recipe_scrapers/sites/com/unsophisticook.rb +3 -0
- data/lib/recipe_scrapers/sites/com/valentinascorner.rb +3 -0
- data/lib/recipe_scrapers/sites/com/vanillaandbean.rb +3 -0
- data/lib/recipe_scrapers/sites/com/veganricha.rb +3 -0
- data/lib/recipe_scrapers/sites/com/vegrecipesofindia.rb +3 -0
- data/lib/recipe_scrapers/sites/com/wearenotmartha.rb +3 -0
- data/lib/recipe_scrapers/sites/com/wedishitup.rb +3 -0
- data/lib/recipe_scrapers/sites/com/wellplated.rb +3 -0
- data/lib/recipe_scrapers/sites/com/whatsgabycooking.rb +3 -0
- data/lib/recipe_scrapers/sites/com/wyseguide.rb +3 -0
- data/lib/recipe_scrapers/sites/com/yemek.rb +3 -0
- data/lib/recipe_scrapers/sites/com/zenbelly.rb +3 -0
- data/lib/recipe_scrapers/sites/com/zestfulkitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/de/bofrost.rb +3 -0
- data/lib/recipe_scrapers/sites/de/chefkoch.rb +26 -0
- data/lib/recipe_scrapers/sites/de/eattolerant.rb +3 -0
- data/lib/recipe_scrapers/sites/de/emmikochteinfach.rb +3 -0
- data/lib/recipe_scrapers/sites/de/kochbar.rb +3 -0
- data/lib/recipe_scrapers/sites/de/springlane.rb +3 -0
- data/lib/recipe_scrapers/sites/dk/madensverden.rb +3 -0
- data/lib/recipe_scrapers/sites/dk/sundpaabudget.rb +3 -0
- data/lib/recipe_scrapers/sites/fr/jow.rb +3 -0
- data/lib/recipe_scrapers/sites/fr/madame.rb +35 -0
- data/lib/recipe_scrapers/sites/hu/nosalty.rb +3 -0
- data/lib/recipe_scrapers/sites/hu/sobors.rb +3 -0
- data/lib/recipe_scrapers/sites/info/misya.rb +3 -0
- data/lib/recipe_scrapers/sites/it/cucchiaio.rb +3 -0
- data/lib/recipe_scrapers/sites/it/ricette.rb +3 -0
- data/lib/recipe_scrapers/sites/it/ricetteperbimby.rb +3 -0
- data/lib/recipe_scrapers/sites/me/leckerschmecker.rb +3 -0
- data/lib/recipe_scrapers/sites/menu/1000.rb +3 -0
- data/lib/recipe_scrapers/sites/mx/cocinafacil.rb +3 -0
- data/lib/recipe_scrapers/sites/mx/directoalpaladar.rb +3 -0
- data/lib/recipe_scrapers/sites/mx/recetasnestle.rb +3 -0
- data/lib/recipe_scrapers/sites/net/bellyfull.rb +3 -0
- data/lib/recipe_scrapers/sites/net/castironketo.rb +3 -0
- data/lib/recipe_scrapers/sites/net/feelgoodfoodie.rb +3 -0
- data/lib/recipe_scrapers/sites/net/hungryhappens.rb +3 -0
- data/lib/recipe_scrapers/sites/net/iambaker.rb +3 -0
- data/lib/recipe_scrapers/sites/net/inspiredtaste.rb +3 -0
- data/lib/recipe_scrapers/sites/net/piesandplots.rb +3 -0
- data/lib/recipe_scrapers/sites/net/tidymom.rb +3 -0
- data/lib/recipe_scrapers/sites/nl/leukerecepten.rb +3 -0
- data/lib/recipe_scrapers/sites/nl/projectgezond.rb +3 -0
- data/lib/recipe_scrapers/sites/no/godt.rb +3 -0
- data/lib/recipe_scrapers/sites/no/matprat.rb +3 -0
- data/lib/recipe_scrapers/sites/no/nrk.rb +3 -0
- data/lib/recipe_scrapers/sites/no/tine.rb +3 -0
- data/lib/recipe_scrapers/sites/org/lmld.rb +3 -0
- data/lib/recipe_scrapers/sites/org/marmiton.rb +3 -0
- data/lib/recipe_scrapers/sites/org/nutritionfacts.rb +3 -0
- data/lib/recipe_scrapers/sites/org/thekitchencommunity.rb +3 -0
- data/lib/recipe_scrapers/sites/plus/recette.rb +3 -0
- data/lib/recipe_scrapers/sites/pt/pingodoce.rb +3 -0
- data/lib/recipe_scrapers/sites/pt/teleculinaria.rb +3 -0
- data/lib/recipe_scrapers/sites/recipes/goodstuff.rb +3 -0
- data/lib/recipe_scrapers/sites/recipes/howtocook.rb +3 -0
- data/lib/recipe_scrapers/sites/ru/eda.rb +3 -0
- data/lib/recipe_scrapers/sites/ru/edimdoma.rb +3 -0
- data/lib/recipe_scrapers/sites/ru/gastronom.rb +3 -0
- data/lib/recipe_scrapers/sites/ru/iamcook.rb +6 -0
- data/lib/recipe_scrapers/sites/ru/povar.rb +3 -0
- data/lib/recipe_scrapers/sites/ru/russianfood.rb +8 -0
- data/lib/recipe_scrapers/sites/se/alltommat.rb +3 -0
- data/lib/recipe_scrapers/sites/se/ica.rb +3 -0
- data/lib/recipe_scrapers/sites/se/kiddokitchen.rb +3 -0
- data/lib/recipe_scrapers/sites/se/koket.rb +3 -0
- data/lib/recipe_scrapers/sites/se/recept.rb +3 -0
- data/lib/recipe_scrapers/sites/sk/receptyprevas.rb +3 -0
- data/lib/recipe_scrapers/sources/declared.rb +38 -0
- data/lib/recipe_scrapers/sources/ingredient_groups.rb +74 -0
- data/lib/recipe_scrapers/sources/json_ld.rb +93 -0
- data/lib/recipe_scrapers/sources/microdata.rb +113 -0
- data/lib/recipe_scrapers/sources/open_graph.rb +26 -0
- data/lib/recipe_scrapers/sources/schema_org/ingredient_list.rb +36 -0
- data/lib/recipe_scrapers/sources/schema_org/nutrition_facts.rb +21 -0
- data/lib/recipe_scrapers/sources/schema_org.rb +160 -0
- data/lib/recipe_scrapers/text.rb +59 -0
- data/lib/recipe_scrapers/version.rb +6 -0
- data/lib/recipe_scrapers.rb +137 -0
- metadata +560 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "nokogiri"
|
|
4
|
+
|
|
5
|
+
module RecipeScrapers
|
|
6
|
+
module Text
|
|
7
|
+
MARKUP = /[&<]/
|
|
8
|
+
WHITESPACE = /[[:space:]]+/
|
|
9
|
+
DROPPED = ["", "", ""].freeze
|
|
10
|
+
TEXTLESS = %w[script style template noscript].freeze
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def content(node)
|
|
14
|
+
return nil if node.nil? || TEXTLESS.include?(node.name)
|
|
15
|
+
return node.text if node.text? || node.cdata?
|
|
16
|
+
return nil unless node.element?
|
|
17
|
+
|
|
18
|
+
node.children.filter_map { |child| content(child) }.join
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def normalize(value)
|
|
22
|
+
return nil if value.nil?
|
|
23
|
+
|
|
24
|
+
cleaned = collapse_parentheses(strip_markup(value.to_s))
|
|
25
|
+
cleaned = DROPPED.reduce(cleaned) { |text, dropped| text.delete(dropped) }
|
|
26
|
+
cleaned = cleaned.gsub(WHITESPACE, " ").strip
|
|
27
|
+
cleaned.empty? ? nil : cleaned
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def recode(html, encoding_name)
|
|
31
|
+
return html if encoding_name.nil?
|
|
32
|
+
return html if html.encoding == ::Encoding::UTF_8 && html.valid_encoding?
|
|
33
|
+
|
|
34
|
+
bytes = html.dup.force_encoding(encoding_name)
|
|
35
|
+
bytes.encode(::Encoding::UTF_8, invalid: :replace, undef: :replace)
|
|
36
|
+
rescue ArgumentError
|
|
37
|
+
html
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def strip_markup(value)
|
|
43
|
+
previous = nil
|
|
44
|
+
current = value
|
|
45
|
+
while previous != current && current.match?(MARKUP)
|
|
46
|
+
previous = current
|
|
47
|
+
current = Nokogiri::HTML5.fragment(current).text
|
|
48
|
+
end
|
|
49
|
+
current
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def collapse_parentheses(value)
|
|
53
|
+
return value unless value.include?("((") && value.include?("))")
|
|
54
|
+
|
|
55
|
+
value.gsub("((", "(").gsub("))", ")")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "recipe_scrapers/version"
|
|
4
|
+
require_relative "recipe_scrapers/errors"
|
|
5
|
+
require_relative "recipe_scrapers/error_tracker"
|
|
6
|
+
require_relative "recipe_scrapers/text"
|
|
7
|
+
require_relative "recipe_scrapers/models/ingredient"
|
|
8
|
+
require_relative "recipe_scrapers/models/nutrient"
|
|
9
|
+
require_relative "recipe_scrapers/models/ingredient_group"
|
|
10
|
+
require_relative "recipe_scrapers/models/recipe"
|
|
11
|
+
require_relative "recipe_scrapers/parsers/quantity"
|
|
12
|
+
require_relative "recipe_scrapers/parsers/vocabulary"
|
|
13
|
+
require_relative "recipe_scrapers/parsers/ingredients"
|
|
14
|
+
require_relative "recipe_scrapers/parsers/nutrients"
|
|
15
|
+
require_relative "recipe_scrapers/parsers/chain"
|
|
16
|
+
require_relative "recipe_scrapers/parsers/durations"
|
|
17
|
+
require_relative "recipe_scrapers/parsers/yields"
|
|
18
|
+
require_relative "recipe_scrapers/parsers/ratings"
|
|
19
|
+
require_relative "recipe_scrapers/sources/json_ld"
|
|
20
|
+
require_relative "recipe_scrapers/sources/microdata"
|
|
21
|
+
require_relative "recipe_scrapers/sources/open_graph"
|
|
22
|
+
require_relative "recipe_scrapers/sources/declared"
|
|
23
|
+
require_relative "recipe_scrapers/sources/ingredient_groups"
|
|
24
|
+
require_relative "recipe_scrapers/sources/schema_org"
|
|
25
|
+
require_relative "recipe_scrapers/sources/schema_org/ingredient_list"
|
|
26
|
+
require_relative "recipe_scrapers/sources/schema_org/nutrition_facts"
|
|
27
|
+
require_relative "recipe_scrapers/scraper/parsed_fields"
|
|
28
|
+
require_relative "recipe_scrapers/scraper"
|
|
29
|
+
require_relative "recipe_scrapers/declaration"
|
|
30
|
+
require_relative "recipe_scrapers/registry"
|
|
31
|
+
require_relative "recipe_scrapers/site_path"
|
|
32
|
+
require_relative "recipe_scrapers/http/address_guard"
|
|
33
|
+
require_relative "recipe_scrapers/http/adapter"
|
|
34
|
+
require_relative "recipe_scrapers/http/follow_redirects"
|
|
35
|
+
require_relative "recipe_scrapers/http/body_limit"
|
|
36
|
+
require_relative "recipe_scrapers/http/encoding"
|
|
37
|
+
require_relative "recipe_scrapers/configuration"
|
|
38
|
+
|
|
39
|
+
# Reads structured recipes from cooking websites.
|
|
40
|
+
#
|
|
41
|
+
# The gem reads the schema.org JSON-LD or microdata a page publishes, falls back to OpenGraph, and
|
|
42
|
+
# takes a site declaration where a site publishes neither. {scrape} fetches a page, {parse} reads
|
|
43
|
+
# HTML you already have, and both return a {Models::Recipe}.
|
|
44
|
+
#
|
|
45
|
+
# @example Fetch and read a recipe
|
|
46
|
+
# recipe = RecipeScrapers.scrape("https://www.recipetineats.com/crispy-potato-straws-pommes-paille/")
|
|
47
|
+
# recipe.title # => "Crispy potato straws (Pommes Paille)"
|
|
48
|
+
# recipe.ingredients # => ["1 potato (Aus: Sebago, US: russet, UK: Maris Piper), ...", ...]
|
|
49
|
+
module RecipeScrapers
|
|
50
|
+
class << self
|
|
51
|
+
# Reads a recipe from HTML that is already fetched.
|
|
52
|
+
#
|
|
53
|
+
# @param html [String] the page source
|
|
54
|
+
# @param url [String] the address of the page, used to pick the site and to resolve relative links
|
|
55
|
+
# @param supported_only [Boolean] raise for a host the gem does not support. Pass false to read
|
|
56
|
+
# any page that publishes schema.org or OpenGraph markup
|
|
57
|
+
# @return [Models::Recipe]
|
|
58
|
+
# @raise [UnsupportedSite] when the host is not registered and supported_only is true
|
|
59
|
+
# @raise [RecipeNotFound] when the page has no title or no ingredients
|
|
60
|
+
def parse(html, url:, supported_only: true)
|
|
61
|
+
entry = Registry.for(url)
|
|
62
|
+
raise UnsupportedSite, "no scraper registered for #{url}" if entry.nil? && supported_only
|
|
63
|
+
|
|
64
|
+
scraper = build_scraper(entry, html, url)
|
|
65
|
+
raise RecipeNotFound, "no recipe found at #{url}" unless scraper.recipe?
|
|
66
|
+
|
|
67
|
+
scraper.to_recipe
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Fetches a page and reads its recipe.
|
|
71
|
+
#
|
|
72
|
+
# The page is fetched through {Configuration#connection}, which follows redirects, refuses private
|
|
73
|
+
# addresses and caps the body size, unless you pass your own connection.
|
|
74
|
+
#
|
|
75
|
+
# @param url [String] the address of the recipe page
|
|
76
|
+
# @param connection [Faraday::Connection, nil] the connection to fetch with
|
|
77
|
+
# @param supported_only [Boolean] see {parse}
|
|
78
|
+
# @return [Models::Recipe]
|
|
79
|
+
# @raise [UnsupportedSite] see {parse}
|
|
80
|
+
# @raise [RecipeNotFound] see {parse}
|
|
81
|
+
# @raise [BlockedAddress, TooManyRedirects, ResponseTooLarge] when the fetch is refused
|
|
82
|
+
# @raise [Faraday::Error] when the fetch fails after the configured retries
|
|
83
|
+
def scrape(url, connection: nil, supported_only: true)
|
|
84
|
+
response = (connection || config.connection).get(url)
|
|
85
|
+
parse(response.body, url: url, supported_only: supported_only)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Registers a site by declaration. A shortcut for {Registry.register}.
|
|
89
|
+
#
|
|
90
|
+
# @example
|
|
91
|
+
# RecipeScrapers.register "example.com" do
|
|
92
|
+
# title "h1.recipe-title"
|
|
93
|
+
# ingredients rows: "ul.ingredients li"
|
|
94
|
+
# end
|
|
95
|
+
# @return [Declaration]
|
|
96
|
+
def register(...)
|
|
97
|
+
Registry.register(...)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# The settings every fetch and parse uses.
|
|
101
|
+
#
|
|
102
|
+
# @return [Configuration]
|
|
103
|
+
def config
|
|
104
|
+
@config ||= Configuration.new
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Changes the settings in a block.
|
|
108
|
+
#
|
|
109
|
+
# @example
|
|
110
|
+
# RecipeScrapers.configure do |config|
|
|
111
|
+
# config.timeout = 30
|
|
112
|
+
# end
|
|
113
|
+
# @yieldparam config [Configuration]
|
|
114
|
+
# @return [Configuration]
|
|
115
|
+
def configure
|
|
116
|
+
yield(config)
|
|
117
|
+
config
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Throws the settings away, so the next {config} call starts from the defaults.
|
|
121
|
+
#
|
|
122
|
+
# @return [void]
|
|
123
|
+
def reset_config!
|
|
124
|
+
@config = nil
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
def build_scraper(entry, html, url)
|
|
130
|
+
return entry.new(html, url: url) if entry.is_a?(Class)
|
|
131
|
+
|
|
132
|
+
Scraper.new(html, url: url, declaration: entry)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
Dir[File.expand_path("recipe_scrapers/sites/**/*.rb", __dir__)].each { |file| require file }
|